首页
/ AutoGPT Platform CoPilot Bot 架构与实践:把 AutoGPT 接入 Discord、Slack 与 Telegram

AutoGPT Platform CoPilot Bot 架构与实践:把 AutoGPT 接入 Discord、Slack 与 Telegram

2026-09-06 13:37:40作者:彭桢灵Jeremy

本文基于 AutoGPT Platform 仓库中 copilot/bot 模块的官方文档(AGENTS.md 直接引用同目录 README.md 的全部内容)并结合实际源码编写,系统讲解 CoPilot Bot 的运行方式、必需环境变量、双类型适配器架构、消息处理与链接(linking)流程,以及接入新聊天平台的完整扩展路径。读完后你将能够:在本地或 Docker 环境中部署并调试该聊天桥接服务,理解 SocketAdapter 与 WebhookAdapter 的设计边界,并知道新增一个聊天平台适配器需要改动哪些文件。

CoPilot Bot 是什么,如何运行

CoPilot Bot 是一个多平台聊天机器人,把 AutoGPT(具体来说是 AutoPilot 会话能力)桥接到 Discord、Slack 和 Telegram 上,文档同时预告了 Teams/WhatsApp 的后续支持计划。它的核心价值在于:用户在熟悉的聊天软件里 @ 机器人或私聊,即可直接与 AutoGPT 对话、上传附件并流式接收回复,同时用量会计费到已链接的 AutoGPT 账户。

官方文档给出的两种运行方式是:

# 作为独立服务运行
poetry run copilot-bot

# 或者随整个平台一起自动启动
# (当 AUTOPILOT_BOT_DISCORD_TOKEN 已设置时,会一并把 bot 拉起来)
poetry run app

从源码看,poetry run copilot-bot 最终进入 入口文件,其 main() 直接调用 run_processes(CoPilotChatBridge()),即以 CoPilotChatBridge 这个 AppService 作为唯一进程入口;也可以等价的用 python -m backend.copilot.bot 启动。服务端口由 Settings().config.copilot_chat_bridge_port 决定(见 app.py)。

一个值得注意的健壮性设计:当没有任何 socket 适配器被配置(比如只部署了 webhook 平台、没设 Discord token)时,CoPilotChatBridge 不会退出,而是进入一个每 3600 秒睡一次的空转循环,保持健康检查端点可用,以便编排器做健康探测与运行时重配置(app.py)。同时 _on_adapters_exit 回调会把适配器任务崩溃时的健康标志置为 False 并清空适配器句柄,使后续出站 RPC 抛出 UnhealthyServiceError 而不是把消息派发到已经断开的网关连接上(app.py)。

本地 Docker 开发:platform_linking_manager 依赖

文档特别强调了一个容易被忽略的前置依赖:bot 的 link/unlink 流程需要通过集群内部 RPC 与 platform_linking_manager 服务通信。该服务在开发/生产环境中作为独立 pod 运行,但在本地是**可选开启(opt-in)**的——通过 bot 这个 Docker Compose profile 控制,避免拖慢常规的 docker compose up

# 方式一:在现有栈旁边单独拉起 linking manager
docker compose up -d platform_linking_manager

# 方式二:通过 profile 标志启动(会一并拉起所有打了 bot 标签的服务)
docker compose --profile bot up -d

文档明确指出:如果不运行该服务,/setup 等发放 token 的流程会失败——后端尝试访问一个不存在的主机,报错表现为 httpx.ConnectError。因此本地调试 /setup/unlink 或链接确认页流程时,先把 platform_linking_manager 拉起来是排障第一步。

必需环境变量与配置

官方文档要求参考 backend/.env.default 获取带完整注释的变量清单,其最小配置如下:

变量 用途
AUTOPILOT_BOT_DISCORD_TOKEN Discord 机器人 token——启用 Discord(socket 网关)适配器
AUTOPILOT_BOT_SLACK_TOKEN + AUTOPILOT_BOT_SLACK_SIGNING_SECRET Slack 机器人 token + 签名密钥——两者都设置后,Slack(webhook / Events API)适配器才会挂载到主后端 API 上
AUTOPILOT_BOT_TELEGRAM_TOKEN + AUTOPILOT_BOT_TELEGRAM_WEBHOOK_SECRET Telegram BotFather token + webhook 密钥——两者都设置后,Telegram(webhook / Bot API)适配器才会挂载,之后还需用 setWebhook 一次性注册 webhook(见下);同时需通过 BotFather 的 /setprivacy 关闭群组隐私模式,否则机器人在群组中看不到 @ 提及
FRONTEND_BASE_URL 前端基础 URL,用于链接确认页面(与后端其余部分共享)
REDIS_HOST / REDIS_PORT 会话 + 线程订阅状态 + copilot 流订阅(继承自共享的后端配置)
PLATFORMLINKINGMANAGER_HOST PlatformLinkingManager 服务 pod 的 DNS 名称(集群内部 RPC)

对照 .env.default 中的实际条目,还有几个文档表格之外的补充项值得了解:

  • AUTOPILOT_BOT_SLACK_CLIENT_ID / AUTOPILOT_BOT_SLACK_CLIENT_SECRET:Slack 的 OAuth 应用凭据,用于多工作区的 “Add to Slack” 安装流程;注释说明静态 token 只是开发工作区的可选兜底,其他工作区安装时会各自通过 OAuth 获得 per-team token。这也解释了为什么 webhook_routes.py 中 Slack 适配器的挂载条件是“signing secret +(client id/secret 或 bot token)”三者满足其一组合。
  • AUTOPILOT_BOT_TELEGRAM_USERNAME:不带 @ 的机器人名,用于生成 “Add bot to Telegram” 的 t.me 链接。
  • .env.default 中直接给出了 Telegram webhook 的一次性注册命令(注释形式):
curl "https://api.telegram.org/bot<TOKEN>/setWebhook" \
  -d "url=<PLATFORM_BASE_URL>/api/copilot-webhooks/telegram/updates" \
  -d "secret_token=<AUTOPILOT_BOT_TELEGRAM_WEBHOOK_SECRET>" \
  -d 'allowed_updates=["message","my_chat_member"]'
  • 同文件还定义了 PLATFORM_LINK_BASE_URL(默认 http://localhost:3000/link),即链接确认页所指向的前端路由。

另外,两个与“token 成对出现”相对应的适配器启用逻辑可以直接在工厂函数中验证:Discord 由 _build_socket_adapters 中的 discord_config.get_bot_token() 门控(app.py),Slack/Telegram 由 build_webhook_adapters 中的凭据判断门控(webhook_routes.py)。

目录结构与模块职责

官方文档给出的 bot/ 目录架构如下,基本与仓库现状一一对应:

bot/
├── app.py              # CoPilotChatBridge(AppService),适配器工厂,出站 @expose RPC
├── config.py           # 共享的(与平台无关的)配置
├── handler.py          # 编排器:路由、链接检查、附件摄取、批处理
├── turn_stream.py      # 流式发送一个批次化回合:分块发送、产物、改名
├── prompt.py           # Prompt + 线程命名组装
├── attachments.py      # 附件上传 + 失败说明
├── command_core.py     # 共享的 /setup + /unlink 策略(各适配器负责渲染)
├── bot_backend.py      # PlatformLinkingManagerClient + stream_registry 之上的薄门面
├── text.py             # 文本切分 + 批次格式化
├── threads.py          # 基于 Redis 的线程订阅跟踪
├── webhook_routes.py   # 把 webhook 适配器的入站路由挂载到主 API 上
└── adapters/
    ├── base.py         # PlatformAdapter(出站契约)+ SocketAdapter / WebhookAdapter + MessageContext
    ├── shared.py       # 平台无关的适配器辅助函数(附件、历史预算、防机器人死循环)
    ├── discord/        # SocketAdapter — Discord Gateway
    │   ├── adapter.py  # 网关连接、事件、发送、创建线程
    │   ├── commands.py # 斜杠命令(/setup、/help、/unlink)
    │   └── config.py   # Discord token + 平台限制参数
    ├── slack/          # WebhookAdapter — Slack Events API
    │   ├── adapter.py       # 入站事件/命令路由、发送、mrkdwn、附件
    │   ├── commands.py      # 斜杠命令(/setup、/help、/unlink)
    │   ├── config.py        # Slack token + 签名密钥 + 平台限制参数
    │   ├── signing.py       # HMAC-SHA256 请求签名验证
    │   ├── text.py          # CommonMark → Slack mrkdwn
    │   └── app-manifest.yaml # 可导入的 Slack 应用定义(scopes、events、commands)
    └── telegram/       # WebhookAdapter — Telegram Bot API
        ├── adapter.py       # 入站 updates 路由、发送、chat 模型映射
        ├── api_client.py    # 薄封装的 httpx Bot API 客户端(JSON + multipart + getFile)
        ├── commands.py      # Bot 命令(/setup、/help、/unlink)
        ├── config.py        # BotFather token + webhook 密钥 + 平台限制参数
        └── text.py          # CommonMark → Telegram HTML

实际仓库中还包含若干文档树未列出的文件,如 outbound.py(出站投递的实现,被 app.py 的 RPC 端点调用)、sessions.py(会话缓存)以及各平台/模块的 *_test.py 测试文件,可作为延伸阅读。

连接器分类学(Connector taxonomy)

这是该模块最核心的设计决策。PlatformAdapter 是核心 handler 所对话的出站契约,它从不出现具体平台名。具体适配器按入站事件到达方式分为两个子类型:

  • SocketAdapter——持有长连接(Discord Gateway、Slack Socket Mode)。由 start/stop 驱动,运行在 copilot-bot pod 中,由 app.py_build_socket_adapters 工厂构建;
  • WebhookAdapter——接收入站 HTTPS POST(Slack Events API、Telegram、以及未来的 Teams、WhatsApp)。它是无状态的,register_routes(app) 会把它挂载到主后端 API 上(经 webhook_routes.pyregister_webhook_adapters),从而直接复用现有的 N 副本部署——不需要专门 pod,天然获得水平扩展。

文档同时给出了一条明确的局部性规则(Locality rule):一切平台特定代码都放在 adapters/<platform>/ 之下;整个 bot/ 目录里只有上述两个工厂函数会指名具体平台,它们的职责仅是根据哪些 token 被设置来决定实例化哪些适配器。抽象契约本身可在 adapters/base.py 中查到,包括 MessageCallback 回调签名、ChannelTypedm/channel/thread 三种渠道类型)以及 MessageHistoryEntryFileAttachmentInboundAttachment 等数据结构。

消息处理流程(How messaging works)

官方文档将消息流程概括为四步,这里完整继承并结合 handler.py 的源码补充细节:

  1. 用户在某个频道里 @ 机器人;
  2. 适配器的 on_message 回调触发,构造一个 MessageContext 并交给共享的 MessageHandler
  3. Handler 依次完成:
    • 检查用户/服务器是否已链接(经由 bot_backend);
    • 未链接 → 发送带 “Link Account” 按钮的提示(对 DM 用户走 create_user_link_token,对未链接服务器提示 “Ask a server admin to run /setup first”);
    • 已链接 → 对频道消息创建线程、对 DM/已有线程则直接使用现有目标;
    • 在 Redis 中把该线程标记为已订阅(7 天 TTL);
    • 以适配器的 chunk_flush_at 为分块边界,流式回传 AutoPilot 的响应;
  4. 在流式响应进行中到达的消息会被批处理(batched),当前流结束后作为单个后续回合一次性发出。

源码中的几个关键实现细节值得展开:

  • 线程订阅语义threads.py):Redis 键格式为 copilot-bot:thread:{platform}:{thread_id},订阅写入 7 天 TTL 自动过期。handler 中有一条重要的防“劫持”规则——机器人只在自己创建的线程里自动回复;对于被拉进的其他既有线程,每一轮都要求显式 @ 提及,首次被 @ 进线程时会把近期线程历史拉入 prompt 作为上下文,但订阅该线程(handler.py)。/leave 命令或机器人被踢出线程时会调用 unsubscribe 主动清除。
  • 批处理状态机handler.py):每个回复目标(线程 ID 或 DM 频道 ID)维护一个 TargetState,包含 pending 消息队列、pending_file_idsprocessing 标志。若一条消息到达时 processing 为真,它只被追加进队列并立即返回,由正在执行的流在结束后排空整个批次。批次的文件 ID 上限为 MAX_TURN_FILE_IDS = 20,超出部分会被丢弃并记录日志,以避免超过 BotChatRequest.file_idsmax_length 校验。
  • 附件摄取:用户消息里的附件必须由适配器先行下载(受适配器 max_attachment_bytes 限制),再上传到该回合会话的工作区文件夹(/sessions/<id>/),且回合必须运行在同一个会话里,AutoGPT 才能像读取 web 上传一样读取这些文件。为此 handler 为每个目标维护一把会话锁(asyncio.Lock),让并发到达的附件消息收敛到同一个会话,而不是各自建会话把文件拆散(handler.py)。此外 config.py 规定单条消息最多拉取 MAX_INBOUND_ATTACHMENTS = 10 个附件,防止一条带几十个文件的消息扇出成同等数量的上传/扫描任务。
  • 会话 TTL 一致性约束config.pySESSION_TTL(AutoPilot 会话 ID 缓存,每渠道/线程一份)被硬性要求不小于线程订阅 TTL(同为 7 天)。注释解释了原因:若会话缓存比订阅窗口先过期,机器人会在会话已丢失全部对话历史后继续自动回复,转而基于跨会话的陈旧记忆行动,行为是“危险的”;由于每个回合都会刷新该 TTL,活跃对话不会在订阅窗口内丢失上下文。

链接流程:/setup 与 /unlink

/setup(把服务器链接到某个 AutoGPT 账户)与 /unlink策略统一放在 command_core.py,各适配器只负责传输(Discord interactions、Slack 表单 POST)与渲染(View 按钮 vs block kit),策略不得在各平台之间漂移。从源码可以看到 setup_reply 的行为:

  • 调用 api.create_link_token(...) 发放服务器链接 token;
  • 若抛出 LinkAlreadyExistsError(服务器已链接),返回 “This server is already linked… Run /unlink to manage the link” 的提示;
  • 成功时生成的文案包含关键提示:“All usage will be billed to your account”(用量计费到发起链接的账户)以及 “This link expires in 30 minutes”(链接 30 分钟过期),并附带确认页按钮——确认页即由 FRONTEND_BASE_URL/link 路由(PLATFORM_LINK_BASE_URL)承载。

handler 侧对 DM 用户未链接的场景也做了竞态防护:若 create_user_link_token 因用户恰好在 resolve_usercreate 之间完成了链接而报 “already exists”,会重新检查一次链接状态,避免在确实未链接时反复骚扰用户(handler.py)。

出站 RPC:让其他服务主动向聊天平台发消息

除了被动响应聊天消息,CoPilotChatBridge 还通过 @expose 装饰器对外暴露一组出站 RPC 端点,供平台其他服务(如 copilot 工具)把消息推入聊天平台(app.py):

RPC 方法 作用
list_channels(platform, user_id) 列出指定用户可通过 bot 发帖的频道,支撑频道名解析与选择器
send_message_to_channel(platform, user_id, channel, content) 以独立消息向频道(按名称或 ID)发帖,投递会校验该用户已链接的服务器
send_dm_to_user(platform, user_id, content) 向用户自己的 DM 发送——目标从用户的 DM 链接解析,绝不接受调用方传入的收件人,保证用户只能给自己发 DM
create_thread_in_channel(platform, user_id, channel, thread_name, content) 在频道中创建独立线程并发布内容

对应的客户端类 CoPilotChatBridgeClient 通过 endpoint_to_async 把这些方法包装为异步 RPC 调用。一个实现要点:webhook 类适配器(Slack/Telegram)的出站半边也是无状态 HTTP 发送器,所以 copilot-bot pod 也会构建它们(不带路由、不挂 handler),使主动 RPC 能触达每一个已配置平台(app.py)。

如何添加一个新平台

官方文档给出了接入新聊天平台的四步流程,这是该模块扩展性的直接承诺——核心 handler、文本工具、线程跟踪和平台 API 均无需改动:

  1. 创建 adapters/<platform>/ 目录,包含 adapter.pycommands.py(如果该平台有命令)和 config.py

  2. adapter.py 继承 SocketAdapter(长连接)或 WebhookAdapter(入站 HTTPS),并实现全部出站 PlatformAdapter 方法——max_message_lengthchunk_flush_atsend_messagesend_linkcreate_threadsend_file 等——外加所属子类型的入站方法(start/stopregister_routes);

  3. config.py 声明该平台的环境变量和平台特定数值(消息长度限制、token 名称等);

  4. 在对应的工厂函数中注册,并以该平台的 token 为门控条件:

    • Socket 型 → app.py::_build_socket_adapters
    • Webhook 型 → webhook_routes.py::_build_webhook_adapters
    if <platform>_config.get_bot_token():
        adapters.append(<Platform>Adapter(api))
    

这一流程与仓库现状互相印证:当前三个工厂判断点分别对应 Discord(socket)与 Slack、Telegram(webhook),新增平台只需照此模式在相应工厂中追加一个 if 分支。各平台适配器目录下均配有 *_test.py(如 discord/adapter_test.pyslack/signing_test.pytelegram/text_test.py),为新适配器补充测试时可参照这些既有用例的写法。

小结

CoPilot Bot 展示了在 AutoGPT Platform 中实现多平台聊天桥接的一套完整工程范式:以“出站契约 + 两种入站子类型”的适配器分类学隔离平台差异,用两个 token 门控的工厂函数把平台名限定在最少数量的文件里,用 Redis 上的 7 天订阅窗口管理线程自动回复的生命周期,并用共享的 command_core 保证跨平台策略一致。文档、.env.default、源码与测试四层材料在仓库中互相印证,为本地部署(poetry run copilot-botdocker compose --profile bot up -d)和二次扩展都提供了清晰的落点。

登录后查看全文
热门项目推荐
相关项目推荐