bearbot 是一个能自我演进的 IM 机器人。它把 pi coding agent 接入 Telegram、QQ 官方机器人和 Slack,让 pi 在群聊和私聊中工作。管理员在聊天中提出需求,agent 编写 pi 扩展、技能、MCP 配置给自己增加功能;改动经过检查后生效,改坏了由独立的 recovery agent 诊断修复,修复不了时进入维护状态,管理员可以从聊天或命令行回滚。
一个容器运行一个 agent,使用一个工作区。需要多个互相独立的 bot 时,用不同的容器名与挂载目录运行多个容器。
完整的设计与实现说明见 DESIGN.md。DESIGN_MULTI_WORKSPACE.md 与 DESIGN_STALE.md 是已放弃的方案,不描述现在的代码。
| 组件 | 目录 | 作用 |
|---|---|---|
bearbotd |
daemon/ |
Go 编写的容器入口。启动并监视其余进程;执行检查、应用与回滚;处理故障并调度 recovery;维护快照;提供 docker exec 使用的命令行 |
| gateway | gateway/ |
运行 chat-sdk 的 Node 进程。连接各 IM 平台与控制台;处理管理员令牌与 /bb 命令;保存管理员、绑定、消息记录(SQLite) |
bearbot-im |
extensions/bearbot-im/ |
加载到 agent 进程中的 pi 扩展。连接 gateway,把消息交给 agent,把回复发回 IM;检查成员发起的回合中的工具调用(classifier);向其他扩展提供订阅与中间件 API |
| bearbot SDK | sdk/index.ts |
其他扩展取得 bearbot-im API 用的辅助模块与类型定义 |
| recovery 扩展 | extensions/bearbot-recovery/ |
recovery agent 使用的工具:读取故障信息、提交修复报告 |
| 自带技能 | skills/ |
bearbot-extension-dev、bearbot-middleware、bearbot-recovery |
| recovery profile 模板 | recovery-profile/settings.json |
recovery 使用的 pi 设置 |
| 示例配置 | config/bearbot.example.toml |
全部配置项与说明 |
docker build -t bearbot .可以用 --build-arg 修改 PI_VERSION、TYPESCRIPT_VERSION、PYTHON_VERSION、BEARBOT_UID、BEARBOT_GID、BEARBOT_GW_UID,默认值写在 Dockerfile 中。
推送 v* 标签(例如 v1.2.3)时,GitHub Actions(.github/workflows/docker.yml)用默认参数构建 linux/amd64 与 linux/arm64 镜像,发布为 ghcr.io/<所有者>/<仓库名>,标签为 1.2.3、1.2 与 latest(预发布版本不更新 latest)。
bearbot 支持三种运行与调试方式:
- Docker Compose 本地部署(推荐):使用仓库预置的 docker-compose.yml 与
local-test/挂载目录,开箱即用。 - Docker 命令行部署:适合自定义路径与生产环境部署。
- 终端控制台调试模式(Console):零 IM 门槛,直接在终端作为内置管理员与 agent 交互。
容器运行时包含三个持久化挂载点。启动前必须确保宿主机上这三个目录均已建立:
| 挂载点 | 宿主机对应(示例) | 职责与内容 |
|---|---|---|
/bearbot/profile |
./local-test/profile 或 /srv/bearbot/profile |
Agent 的 profile(凭据 auth.json、模型定义 models.json、会话记录 sessions/)、Python 虚拟环境、安装的二进制可执行文件 bin/、日志与 Git 快照仓库。 |
/bearbot/workspace |
./local-test/workspace 或 /srv/bearbot/workspace |
Agent 的工作区:记忆 AGENTS.md、Classifier 规则 CLASSIFIER.md、自扩展代码与配置 .pi/(extensions/、skills/、mcp.json)、聊天收到的文件 inbox/。首次启动为空时 daemon 会自动初始化模板。 |
/bearbot/config |
./local-test/config 或 /srv/bearbot/config |
核心配置文件 bearbot.toml、可选的 recovery profile 覆盖配置、维护脚本 hooks。 |
在仓库根目录下运行:
mkdir -p local-test/profile local-test/workspace local-test/config
cp config/bearbot.example.toml local-test/config/bearbot.tomlNote
容器内进程分别以 root(daemon)、bearbot(Agent/Recovery,默认 UID 1000)和 bearbot-gw(Gateway,默认 UID 1001)运行。容器启动时,daemon 会自动检查并修正挂载点下各子目录的属主与权限。
复制项目示例并配置 .env 文件(docker-compose.yml 会自动读取):
cp .env.example .env在 .env 中按需填入模型 API Key 与聊天平台凭据:
# ==============================
# 模型服务凭据
# ==============================
# 方式 A:使用 Anthropic 官方模型服务
ANTHROPIC_API_KEY=sk-ant-api03-...
BEARBOT_RECOVERY_API_KEY=sk-ant-api03-...
# 方式 B:如使用第三方/OpenAI 兼容模型(如 DeepSeek、Kimi、GLM 等),可在 .env 中定义自定义变量:
# OPENAI_API_KEY=sk-...
# ==============================
# IM 平台凭据(按需配置)
# ==============================
# Telegram 机器人令牌(从 @BotFather 获取)
TELEGRAM_BOT_TOKEN=1234567890:ABCdefGhIJKlmNoPQRsTUVwxyZ_example
# QQ 官方机器人凭据(从 QQ 开放平台获取)
QQ_BOT_APP_ID=102030405
QQ_BOT_CLIENT_SECRET=abcdef1234567890abcdef1234567890
# Slack 应用的机器人令牌(xoxb-…,OAuth & Permissions 页面)与 Socket Mode 应用级令牌(xapp-…,需要 connections:write)
SLACK_BOT_TOKEN=xoxb-example
SLACK_APP_TOKEN=xapp-exampleBearbot 由三部分依赖模型的能力组成:Agent 主体、Classifier(安全分类器) 与 Recovery(故障修复 Agent)。
直接在 .env 中提供 ANTHROPIC_API_KEY 和 BEARBOT_RECOVERY_API_KEY,在 bearbot.toml 中配置:
[agent.env]
ANTHROPIC_API_KEY = "${ANTHROPIC_API_KEY}"
[classifier]
enabled = true
model = "anthropic/claude-haiku-4-5-20251001"
[recovery.env]
ANTHROPIC_API_KEY = "${BEARBOT_RECOVERY_API_KEY}"参考 local-test 的多模型配置实践:
- 配置 Agent 模型服务:在挂载目录的
profile/agent/models.json中配置 provider(支持openai-completions接口):{ "providers": { "deepseek": { "name": "DeepSeek API", "baseUrl": "https://api.deepseek.com/v1", "api": "openai-completions", "apiKey": "sk-your-key-here", "models": [ { "id": "deepseek-chat", "name": "DeepSeek-V3", "contextWindow": 65536, "maxTokens": 8192 } ] } } } - 指定 Agent 默认使用的模型:在工作区创建
workspace/.pi/settings.json:{ "defaultProvider": "deepseek", "defaultModel": "deepseek-chat" } - 配置 Classifier 模型:在
local-test/config/bearbot.toml中将[classifier] model指向自定义模型的<服务ID>/<模型ID>:[classifier] enabled = true model = "deepseek/deepseek-chat"
- 配置 Recovery 模型(可选):Recovery 使用独立的 profile,若不使用 Anthropic,可在
config/recovery/下放置settings.json、models.json与auth.json,其中settings.json必须保留defaultProvider。
容器运行后,可随时进入交互式登录命令行:
docker exec -it bearbot bearbotd login登录成功后凭据会自动写入 profile/agent/auth.json。
# 构建镜像并后台启动
docker compose up -d --build
# 查看运行状态
docker exec bearbot bearbotd status
# 实时查看日志
docker compose logs -f bearbot
# 或者使用 bearbotd 专用日志命令查看具体组件
docker exec bearbot bearbotd logs agent -f
docker exec bearbot bearbotd logs gateway -fdocker run -d --name bearbot --stop-timeout 120 --tmpfs /run/bearbot \
-v $(pwd)/local-test/profile:/bearbot/profile \
-v $(pwd)/local-test/workspace:/bearbot/workspace \
-v $(pwd)/local-test/config:/bearbot/config \
--env-file .env \
bearbotImportant
--tmpfs /run/bearbot是必需参数,所有跨进程 Unix Socket 通信均位于此内存文件系统中。--stop-timeout必须设置且大于[daemon] shutdown_grace(默认 90 秒),以确保优雅停止 agent 当前正在执行的回合。
服务启动后,Gateway 会连接配置的 IM 平台(Telegram / QQ / Slack)。Bearbot 采用基于令牌的管理员授权和显式频道绑定机制:
-
生成一次性管理员令牌:
docker exec bearbot bearbotd admin token终端会输出形如
tok-xxxxxxxxxxxxxxxx的令牌(默认 10 分钟内有效)。 -
领取管理员身份:
- 打开 Telegram、QQ 或 Slack,在私聊中将令牌直接发送给机器人(私聊最可靠)。
- 机器人核销成功后会回复:
已成为 bearbot 管理员。之后所有的系统通知(故障报告、修复通知、回滚提醒)都会发送到该聊天。
-
绑定工作频道:
- 将机器人拉入群聊(或在私聊窗口中),发送绑定指令:
/bb attach /bb attach支持以下参数调整触发与回复行为:--trigger mention(默认群聊模式:仅在 @机器人 时触发)--trigger all(处理频道内的所有消息,适用于私聊或专属协作群)--trigger prefix --prefix <前缀>(匹配指定前缀的消息才触发)--reply final|each(final只回复最终结果,each每轮思考均回复)
- 将机器人拉入群聊(或在私聊窗口中),发送绑定指令:
Tip
- Telegram 权限提示:Telegram 群组中机器人要接收非
/开头的消息,必须在 @BotFather 中通过/setprivacy将 Privacy mode 设为Disable,或者直接将机器人提升为群管理员。 - QQ 平台提示:QQ 群与 QQ 单聊在官方平台下用户的 OpenID 不同(属于两个身份)。如需在两处都作为管理员,可分别使用
admin token领取,或在已认证的管理端通过/bb admin add <身份ID>添加。 - Slack 平台提示:使用 Socket Mode,不需要公网地址。应用的 Event Subscriptions 需要订阅
app_mention、message.channels、message.groups、message.im、message.mpim、reaction_added、reaction_removed,并开启 Interactivity;斜杠命令可以不注册,/bb与!bb直接作为普通消息发送即可。频道里要收到普通消息,机器人需要被加入该频道;/bb attach --trigger all时机器人的自己消息不会触发回复。
如果你希望在本地无 IM 账号的情况下快速验证 Agent 功能,可以使用内置的终端控制台。控制台用户拥有内置超级管理员权限(console:operator),无需生成或领取管理员令牌。
- 在
bearbot.toml中确认控制台开启:[platforms.console] enabled = true
- 附加到运行中的容器终端(
docker-compose.yml默认已配置stdin_open: true与tty: true):docker attach bearbot
- 按一下
Enter键即可看到提示符bearbot>:- 直接输入文字并回车即可向 Agent 发送消息。
- 输入
:help查看控制台命令列表。 - 输入
:file <相对工作区的文件路径> [附带文字]向 Agent 发送工作区文件。 - 输入
::<文字>发送以冒号开头的普通消息。 - 在行末输入
\可换行输入多行消息。 - 按快捷键
Ctrl-P然后Ctrl-Q可以脱离(detach)控制台,容器继续在后台运行。
进入聊天或控制台后,你就可以指导 Agent 自我扩展。例如:
- 发送:
“请阅读 docs/ 目录下的开发指南,并为自己编写一个定时天气推送的扩展,放在 .pi/extensions/ 目录下” - Agent 会调用工具编辑
.pi/extensions/。 - 编写完成后,Agent 触发
bearbot_check执行类型检查、位置检查与无害试运行。 - 检查通过后调用
bearbot_apply提交 Git 快照并平滑重启。 - 如果新扩展导致语法错误或崩溃,Bearbot 的独立 Recovery Agent 会接管并自动诊断修复;若修复未达预期,管理员可随时发送
/bb rollback回滚到最近一次稳定快照。
只有管理员可以使用,非管理员发送时不回应。
| 命令 | 作用 |
|---|---|
/bb help |
命令列表 |
/bb here |
当前频道、会话串、绑定设置与 agent 状态 |
/bb attach [--trigger mention|all|prefix] [--prefix <文本>] [--reply final|each] [--interrupt queue|steer] |
绑定当前频道,或修改它的绑定设置 |
/bb detach |
解除当前频道的绑定 |
/bb new |
开启新会话,所有绑定的频道都改用新会话 |
/bb stop |
中止正在进行的回合 |
/bb compact [说明] |
压缩当前会话 |
/bb restart |
重启 agent 进程(等待当前回合结束) |
/bb status |
daemon、agent、平台与绑定的状态 |
/bb repair [说明]、/bb resume |
维护状态下重新运行 recovery 修复,或者不修复直接恢复运行 |
/bb repair --force [说明] |
agent 运行时也可以使用:中止当前回合、停止 agent 进程,建立故障并交给 recovery 修复(例如回合一直不结束、队列中积压了大量消息时);维护状态下与 /bb repair 相同 |
/bb rollback [快照] |
回滚到指定快照,默认为最近一次应用之前的状态 |
/bb snapshot list、/bb snapshot diff <引用> [引用] |
查看快照与快照之间的差异 |
/bb admin list、/bb admin add <身份>、/bb admin remove <身份> |
管理员管理;回复某人的消息发送 /bb admin add 可以直接添加这个人 |
/bb classifier status|on|off |
查看、打开、关闭 classifier |
/bb classifier allow|deny|clear <工具模式…> |
管理 classifier 的放行与拒绝规则 |
!bb <问题> |
在不打断 agent 的情况下询问它正在做什么:一个单独的会话根据当前会话的内容回答,主会话看不到这次问答 |
!steer <文本> |
把这条消息插入自己正在进行的回合,不受绑定的 interrupt 设置限制;不能插入时按普通消息排队 |
在运行中的容器里执行 docker exec bearbot bearbotd <命令>:
| 命令 | 作用 |
|---|---|
status |
全部进程、平台、会话、快照、故障与维护状态 |
logs <daemon|gateway|agent|recovery:<故障id>> [-n 行数] [-f] |
查看日志 |
admin token [--ttl 10m] |
生成一次性管理员令牌 |
admin list、admin revoke <身份> |
管理员管理 |
login |
交互式登录模型服务,需要 docker exec -it |
restart |
重启 agent 进程 |
incident list、incident show <id> |
故障记录 |
repair [说明]、resume |
维护状态下的处理 |
repair --force [说明] |
agent 运行时停止它,建立故障并交给 recovery 修复 |
rollback [快照] |
管理员回滚 |
snapshot list、snapshot diff <引用> [引用] |
快照查看 |
python rebuild |
镜像更换 Python 版本后重建虚拟环境,在 daemon 没有运行时用 docker run --rm <挂载参数> bearbot python rebuild 执行 |
用 docker exec bearbot bearbotd logs gateway -n 50 查看 gateway 的日志,如果其中有 SQLITE_READONLY、EACCES 等错误,bearbotd logs daemon 中反复出现 gateway exited unexpectedly,原因就是挂载目录中文件的属主不正确。用普通用户解压、用 root 解压但没有加 --numeric-owner、或者服务器的 Docker 使用 rootless 模式或 userns-remap,都会让文件的数字属主与容器中的 bearbot(UID 1000)、bearbot-gw(UID 1001)不一致。daemon 启动时只修正各个目录本身的属主与权限,目录中的文件保持原样;gateway 无法写入 gateway.db 而不断退出,daemon 一直等待 gateway 连接,不会启动 agent。daemon 的日志只写入 profile/bearbot/logs/daemon.log,所以 docker compose logs 中看不到任何输出。
容器运行时,在仓库根目录执行 CLEAN.sh:
./CLEAN.sh它在名为 bearbot 的容器中按 DESIGN.md 第 4.3、4.4 节的目录表恢复三个挂载点中全部文件的属主(不跟随符号链接),为工作区恢复 bearbot 组的读写权限与目录的 setgid 位,然后重启容器。profile/ 中的文件权限保持不变,auth.json 等凭据文件仍然只有 bearbot 可以读取。重启后 bearbotd logs daemon 中出现 gateway ready 与 agent ready 即恢复正常。
需要的软件:Go 1.27、Node.js 24、git、Python 3.14(/usr/bin/python3.14)、uv(/usr/bin/uv、/usr/bin/uvx),以及 gateway 控制台测试使用的 util-linux script 与 tmux。
npm ci
npm run build -w gatewaybearbotd 有两个只用于本地测试的全局参数:--root <目录> 把所有路径放在这个目录之下,--rootless 让所有子进程以当前用户运行,不切换用户,不修改属主。目录的布局与需要建立的符号链接见 DESIGN.md 第 16.1 节,daemon/internal/testenv 按同样的方式为每个测试建立目录。
cd daemon && go build -o bin/bearbotd ./cmd/bearbotd
bin/bearbotd --root /tmp/bbroot --rootless run
bin/bearbotd --root /tmp/bbroot --rootless status # 在另一个终端中执行命令行没有 --rootless 时 bearbotd 必须以 root 运行。
测试全部使用真实组件:真实的 bearbotd、gateway、pi 进程,以及 git、uv、npm,不使用 mock。在仓库根目录执行:
| 命令 | 内容 |
|---|---|
npm run build -w gateway |
编译 gateway,daemon 的端到端测试需要它 |
npm run typecheck -w gateway |
gateway 与它的测试的类型检查 |
npm test -w gateway |
gateway 的测试 |
node_modules/.bin/tsc -p extensions/tsconfig.json、node_modules/.bin/tsc -p extensions/bearbot-recovery/tsconfig.json |
bearbot-im、SDK 与 recovery 扩展的类型检查 |
node_modules/.bin/vitest run extensions |
bearbot-im 与 recovery 扩展的测试 |
cd daemon && go vet ./... && go test -count=1 -timeout 40m ./... |
Go 的单元测试与端到端测试;端到端测试约需 11 分钟,超过 go test 默认的 10 分钟上限,所以必须加 -timeout |
- 企业微信适配器(计划放在
packages/chat-adapter-wecom/)。配置中[platforms.wecom] enabled = true时 daemon 拒绝启动。