三个 Agent 串起跨平台单据纠错流程
作者通过 Switch 连接 Slack 和 Telegram,让三个 Agent 分别协调任务、核对单据证据及联系供应商。流程覆盖定位页码行号、复核差异、接收未点名回复、检查修订文件并交付压缩包。
AI 深度解读
发票写着 LL-STR-050 共 500 件,装箱单却只有 480 件,矛盾都在第 1 页第 3 行。作者做了三个 AI Agent,让它们在 Slack 接单、核对证据,再到 Telegram 找供应商补文件,最后把交付 ZIP 发回 Slack。
这次实践最有价值的地方,是它暴露了跨聊天平台协作的真实难点:供应商不一定回复线程,文件可能丢失,连接会重连,消息会重复。流程能否跑完,很大程度取决于这些边界有没有处理好。
三个 Agent 怎么接成一条业务流程
Reissue 服务于一个小型进口团队。操作员在业务群上传发票和装箱单,提及 @reissue,协调者便开始定位差异,再交给独立的核验者检查,确认后联系供应商补正。
三个角色各有职责:reissue 是协调者,使用 WebSocket agent protocol 8;reissue-examiner 负责核验证据;reissue-liaison 负责对接供应商。后两者运行无界面的 Claude Code,只能使用各自角色范围内的 MCP 工具。
底层采用自托管 switch-core 0.31.0,其中 Telegram 能力来自 server 0.30.0,后续消息跟进和 Agent 间消息使用 0.31.0 的能力。执行 scripts/switch-local.sh up 会在 Docker 中启动 Switch 0.31.0、Postgres 和 Mattermost;本地完整演练可以先用 Mattermost。
接入 Slack、Telegram 则通过 gateway API。注册调用 POST /agents,配置 connection_model: "always_on" 和 message_exchange: true,返回的 api_key 只显示一次。
Telegram 要先在 @botfather 关闭 Group Privacy,再手动建群并加入机器人。创建连接时必须设置 channel_creation_enabled: false,因为机器人不能建群。Switch 通过轮询接收消息,不需要公网 URL。
Slack 走 Socket Mode:从 GET /gateway/collaborations/setup/slack 获取 manifest,配置具有 connections:write 权限的 xapp- token,再通过 /setup/slack/check 校验 xoxb- 和 xapp- token。作者设置 agent_usergroups: false,避开需要付费套餐的用户组能力。
两边接通后,用 connect-rooms --ops <Slack room id> --supplier <Telegram room id> 绑定房间。Telegram 群还要执行 !follow-ups on 和 !assign-agent @reissue-liaison,这样供应商不提及任何人,消息也能到达联络员。由于供应商账号不属于操作员,还需设置 update_agent_detail addressing=anyone。
把机器人拉进群,只完成了接入;明确谁负责接收普通消息,业务才有机会闭环。
Agent 之间通过 send_targeted_message 交接,参数包括 body、target_names 和可选的 thread_id。Switch 管投递,Reissue 在正文内放置 fenced reissue JSON,表达业务事件:DOCUMENT_REVIEW_REQUESTED 发起核验,DOCUMENT_REVIEW_RESULT 返回结果,SUPPLIER_REQUEST_ASSIGNED 分配供应商任务,SUPPLIER_REPLY_RELAYED 回传答复。协调者只接受指定核验者的结果,并给未响应任务设置超时。
重连、重复和空消息,比提示词更容易卡住流程
协调者为每个房间维护一个 /agents/{agent_id}/connection/ws 连接,用 Agent API key 鉴权。连接 ID 根据 Agent 和房间 ID 生成,重连时可以恢复同一条连接。
服务端的 connection_state 返回 generation、cursor 和 heartbeat_interval_seconds;在 0.31.0 中,心跳间隔是 2.0 秒。客户端保存前两个值,再分别作为 expected_generation 和 start_from 传回。
这里有三个具体教训。
首先,收到 ping 后,要在 socket 回调里立即发送 {"type":"pong","cursor":<cursor>},然后才等待业务处理。作者一次 15 秒的核验调用因此没有拖断连接。其次,generation 大约达到 2^33,必须用 bigint,首次真实运行就撑爆了 32 位数据库列。最后,先把事件写入带唯一键的 msg:<room>:<message_id>,再推进 cursor;重复投递撞上唯一键,就不会重复执行。
这就是「至少一次投递」的实际含义:消息允许再来,接收方负责识别已经处理过的事件。
流里出现 gap 时,客户端跳到 resumed_at,再调用 read_context 补读遗漏内容。但作者最初每次重连都会在这里失败,因为房间命令和没有文字的历史条目可能返回 body: null,代码却直接调用了 .includes。
修复是在输入边界统一处理空值:
body: z.string().nullish().transform((body) => body ?? ""),
要看的是 nullish() 后的转换:允许缺失和 null,再归一为空字符串,业务层便不必反复猜输入类型。作者也为实时消息和补读两条路径添加了测试。
另一个容易误判的地方是 API 能力。GET /agents/{id}/ops 在 0.31.0 返回 57 个操作,其中没有 delegate_task。Reissue 会按公布的 input_schema 校验每次 POST /agents/{id}/ops/{name} 请求,而不是凭名称猜接口。
人不按线程回复,文件也不保证一次送达
Telegram 供应商常把新 PDF 直接发到群里,不回复原线程。!assign-agent 能让联络员收到文件,却不能自动补出它属于哪个业务单。
作者采用了一个有限规则:如果这个供应商群只有一个案件等待修订,就把无线程文件归给它。这个规则能用,但前提很明确。多个案件同时等待时,原文没有给出可靠的归属方案。
即便只有一个案件,也会出现时序问题:文件先被协调者处理,案件已经完成,联络员稍后才回复之前的文字消息,仍在催供应商上传文件。消息送对了,业务状态却可能已经变了。
文件本身也有独立链路。PDF 附件以 mxc 引用到达,通过 GET /agents/{agent_id}/rooms/{room_id}/media?mxc=<mxc> 下载;同一路径的 multipart POST 使用 files、caption、thread_id 把 ZIP 发回线程。发往 Telegram 的文件上限为 20 MB,更大的文件改发安全上传链接,不过作者只在 Mattermost 测过这条替代路径。
在 SHP-0290 中,Telegram adapter 的 get_file 超时,而且只尝试一次,最终群消息只有「附件未转发」提示,没有 PDF。联络员主动要求重发,第二次才成功。网络失败重试当时只是上游提案 sandbox-quantum/switch#1689,不能算已有保障。
房间迁移也出过问题:SHP-0286 从 Mattermost 切到 Telegram 后仍保留旧绑定,联络员拒绝了指向错误房间的任务。修复后以配置里的房间为准,并补了回归测试。
我的判断
这篇最可信的结论是:跨平台路由已经跑通,但它距离复杂业务的稳定自动化还有距离。
六次脚本化 Mattermost 运行中,经 Switch 传递的内容都远低于 1 秒到达,未提及 Agent 的供应商回复回到案件的中位耗时为 102 ms。真实 Slack、Telegram 案例 SHP-0287 中,上传 PDF 后 581 ms,线程里出现差异;修订文件到达后,336 ms 进入待报关行审核状态,0.75 秒发出 ZIP。SHP-0290 重发文件后的对应耗时是 0.41 秒和 0.74 秒。
这些数字说明传输和部分状态推进很快,不能代表整单处理速度。脚本运行中核验者需要五轮交互、三次工具调用;SHP-0287 的核验结果在交接后 32.9 秒返回。开篇另有一次答复转交记录为 17 秒,两者衡量的是不同环节,不能混算。
真实案例由同一个人用两个真实账号分别扮演操作员和供应商,过程没有脚本,但也没有覆盖多人并发、多个案件争用同一群等情况。原文没有单 Agent 对照,也没有成本、误判率或长期稳定性数据。三个角色便于分权和复核,这一点合理;是否比单 Agent 更准、更省,仍是待验证的经验判断。
对普通团队而言,先把消息归属、幂等和业务状态做好,比立刻增加 Agent 数量更有把握。
能拿来做什么
- 写 Node 消息客户端时,把心跳响应与耗时任务分开,事件落库成功后再推进 cursor,并用消息唯一键处理重复投递。
- 接入 Agent 平台前,先读取实际操作清单和 schema,再写客户端;同时覆盖
body: null、断线补读和附件下载失败这些输入。 - 做群聊审批、文件补交等流程时,为无线程消息制定归属规则;多个任务同时等待时,应要求明确案件标识,不能直接照搬「只有一个待办」的假设。
- 评估 AI 工作流时,分别记录消息传输、模型核验和最终交付耗时,优先优化真正拖慢流程的环节,并对照单 Agent 方案验证拆分是否划算。