Learn-Claude-Code | 笔记 | Collaboration | s10 Team Protocols:用 FSM 与 request_id 拆解多智能体协作

发布时间:2026/10/8 12:39:24
Learn-Claude-Code | 笔记 | Collaboration | s10 Team Protocols:用 FSM 与 request_id 拆解多智能体协作 1. 从 s09 的自由通信到 s10 的协议握手多智能体协作为什么需要 FSM在 s09 里我们已经把多个 teammate 组织成了一个团队lead 可以 spawn 成员每个成员有自己的 inbox通过 JSONL 文件互相发消息。这套机制解决的是“能不能通信”的问题。但当你真正把它跑起来很快就会撞上一个更棘手的问题有些协作动作不是聊天而是握手。举个最直接的例子。lead 想让某个 teammate 停下来如果只是发一句“请停止工作”对方可能正在写文件写到一半也可能 inbox 里还有未处理消息系统根本不知道它是正常退出还是被强行中断。再比如一个 teammate 想在大改代码前先提交计划等 lead 批准后再执行如果只靠自由文本lead 收到一条“这是我的计划”之后根本无法判断这条消息是不是一次正式审批请求也无法追踪它当前是 pending 还是已经 approved。这两个场景的共同点是它们都需要请求与响应之间的关联关系以及明确的状态转移。一条响应不能只是“我同意”它必须说明自己在回复哪一次请求一个请求发出去之后也不是“有没有消息回来”这么简单而是会经历 pending - approved 或 pending - rejected。这其实就是一个最小的有限状态机FSM。s10 Team Protocols 要解决的就是这个问题当团队协作里出现需要确认、需要关联请求与响应、需要明确状态流转的动作时系统该如何把这些动作从普通消息提升成协议。它引入了两个协议——shutdown protocol 和 plan approval protocol两者作用领域不同但建立在同一个核心模式上用相同的 request_id 关联请求和响应用同一个 FSM 表达状态流转。这篇文章会沿着 FSM 状态机与 request_id 请求追踪这条主线把 s10 的设计拆开讲清楚。我会给出可复制的协议配置片段与 request_id 生成规则演示一次完整协作链路的验证步骤并对照真实报错做排查。如果你正在自己的项目里做多智能体协作这套模式可以直接搬过去用。2. TaoToken 前置准备把 Claude Code 接入可观测的协作环境在动手改代码之前先把运行环境搭好。s10 的调试过程需要频繁查看模型返回的 tool_use block、tracker 状态和 inbox 文件所以一个稳定的模型接入点是前提。我用的是 TaoToken 的 API 来做模型调用它的 Base URL 和 Key 配置方式和 Anthropic 官方 SDK 兼容改起来很省事。先说清楚要准备什么。你需要一个 API Key以及对应的 Base URL。TaoToken 的 API 地址是 https://taotoken.net/api这个地址不加任何查询参数直接作为 SDK 的 base_url 使用。官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content上面有模型列表和接入文档。如果你用的是 Claude Code 这类命令行工具配置方式是在 settings 文件里指定环境变量。我实测下来最稳妥的做法是同时设置 ANTHROPIC_BASE_URL 和 ANTHROPIC_API_KEY 两个变量这样 SDK 初始化时会自动读取不需要在代码里硬编码。具体路径和原文保持一致放在项目根目录的 .claude/settings.json 里。对于 s10 这种需要多轮工具调用的场景模型选择上建议用支持 tool_use 的模型。因为整个协议流程依赖模型正确调用 shutdown_response 和 plan_approval 这两个工具如果模型不支持结构化工具调用协议根本跑不起来。你可以在模型对话页面先测试一下模型是否能正确返回 tool_use block确认没问题再接入代码。还有一个容易被忽略的点s10 的 teammate 是在独立线程里跑 agent loop 的每个线程都会调用模型。如果你的 API 有并发限制spawn 多个 teammate 时可能会遇到 429 错误。建议先在单 teammate 场景下把协议流程跑通再逐步增加并发。我试过同时 spawn 三个 teammate在默认配置下偶尔会触发限流后来把 spawn 间隔拉开就稳定了。配置完成后你可以先用一个最简单的请求验证连通性。下面这段代码可以直接复制运行确认 Base URL 和 Key 生效import anthropic client anthropic.Anthropic( base_urlhttps://taotoken.net/api, api_key你的_API_Key ) response client.messages.create( modelclaude-sonnet-4-20250514, max_tokens256, messages[{role: user, content: 回复 OK 两个字母}] ) print(response.content[0].text)如果返回了内容说明接入没问题。接下来就可以进入协议配置环节了。3. 可复制配置request_id 生成规则与 FSM tracker 片段这一节是整篇文章的核心。s10 的协议层并不复杂但有几个关键配置必须写对否则 request_id 对不上FSM 状态就会卡在 pending 永远不流转。我把可复制的片段整理出来你可以直接放进自己的项目。首先是 request_id 的生成规则。s10 用的是 uuid4 的前 8 位这个长度在单机多线程场景下足够用碰撞概率极低。生成代码就一行import uuid req_id str(uuid.uuid4())[:8]注意这里用的是切片取前 8 位不是完整的 uuid。这样做的好处是日志和调试信息更短肉眼比对 request_id 时不容易看错。如果你要做分布式部署建议改成完整 uuid 或者加前缀区分节点。然后是两张 tracker 表。这是 s10 新增的核心数据结构职责是存请求的跟踪状态而不是消息正文import threading shutdown_requests {} plan_requests {} _tracker_lock threading.Lock()shutdown_requests 的结构是 {req_id: {target, status}}plan_requests 的结构是 {req_id: {from, plan, status}}。status 的初始值都是 pending流转后变成 approved 或 rejected。_tracker_lock 用来保证多线程读写这些共享字典时的安全性因为每个 teammate 都在独立线程里跑不加锁会出现状态覆盖。接下来是协议消息的发送片段。以 shutdown_request 为例lead 侧发起请求时做三件事生成 request_id、登记 tracker、通过 MessageBus 发消息def handle_shutdown_request(teammate: str) - str: req_id str(uuid.uuid4())[:8] with _tracker_lock: shutdown_requests[req_id] {target: teammate, status: pending} BUS.send( lead, teammate, Please shut down gracefully., shutdown_request, {request_id: req_id}, ) return fShutdown request {req_id} sent to {teammate} (status: pending)对应的 teammate 侧响应片段关键是带回同一个 request_id并更新 tracker 状态if tool_name shutdown_response: req_id args[request_id] approve args[approve] with _tracker_lock: if req_id in shutdown_requests: shutdown_requests[req_id][status] approved if approve else rejected BUS.send( sender, lead, args.get(reason, ), shutdown_response, {request_id: req_id, approve: approve}, ) return fShutdown {approved if approve else rejected}plan approval 的片段结构完全一样只是方向反过来teammate 发起lead 响应。teammate 提交计划时生成 request_id 并登记 plan_requestslead 审批时根据 request_id 找到记录并更新状态。这里有一个必须写全的三件套Base URL、Key、Model ID。无论你用的是 CC Switch、Cline MCP 还是 Codex 的 auth.json这三个字段缺一不可。以 settings.json 为例{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: 你的_API_Key, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }Model ID 要和你实际使用的模型一致写错了会在第一次请求时就报 model not found。我踩过的坑是复制了别人的配置但没改 Model ID结果 teammate spawn 出来之后一直卡在第一次 loop排查了半天才发现是模型名不对。FSM 的状态流转规则很简单但必须严格遵守pending 只能转到 approved 或 rejected不能从 approved 再转回 pending。如果你在代码里允许状态回退会出现同一次请求被重复审批的问题。建议在更新状态前加一个判断只有当前状态是 pending 时才允许更新。4. 验证请求一次完整协作链路的成功结果配置写完之后最重要的是验证整条链路能跑通。我用文档里给出的 prompt 做了一次完整调试先 spawn alice 作为 coder然后请求她 shutdown。整个过程分几个阶段每个阶段的输出都能在日志里看到。第一阶段是 lead 的第一次 loop。模型返回的 response.content 里有一个 TextBlock 和一个 ToolUseBlock工具调用是 spawn_teammate(namealice, rolecoder, prompt...)。执行后.team/config.json 里新增了一条成员记录status 是 working同时启动了一条新的 teammate 线程。tool_result 返回 Spawned alice (role: coder)。这一步对应的是“先有对象再谈协议”。第二阶段是 lead 的第二次 loop也是 shutdown protocol 的真正起点。模型调用 shutdown_request(teammatealice)handle_shutdown_request 内部生成了 request_id比如 d08982e3然后在 shutdown_requests 里登记了一条 {target: alice, status: pending}。同时 MessageBus 把一条结构化消息写进了 alice.jsonl{ type: shutdown_request, from: lead, content: Please shut down gracefully., request_id: d08982e3 }tool_result 返回 Shutdown request d08982e3 sent to alice (status: pending)。注意这里显式说出了 pending说明协议进入了 FSM 的第一阶段。第三阶段是 alice 的第二次 loop。她在新一轮 _teammate_loop 开始时读取 inbox把那条 shutdown_request 作为 user 消息注入 messages。模型这次没有返回文本而是直接调用 shutdown_response(request_idd08982e3, approveTrue, reasonShutting down gracefully as requested)。执行后发生两件事shutdown_requests[d08982e3][status] 从 pending 更新为 approvedalice 通过 MessageBus 给 lead 的 inbox 回写了一条 shutdown_response 消息里面带回了同一个 request_id 和 approve: true。第四阶段是状态变更。alice 的 loop 内部因为 block.name shutdown_response 且 approve 为 True把 should_exit 置为 True下一轮开始前 break。最后 member[status] 被写成 shutdownconfig.json 里 alice 的状态从 working 变成了 shutdown。整个链路验证下来几个关键点都确认了shutdown 不是粗暴 kill 线程而是正式的请求-响应握手协议身份靠 request_id 关联不靠自然语言约定系统在 tracker 表里显式维护状态teammate 收到请求后调用专用协议工具响应协议结果真正驱动了生命周期从 working 进入 shutdown。如果你想验证 plan approval可以用这个 promptSpawn bob with a risky refactoring task. Review and reject his plan. 流程和 shutdown 对称只是请求方向反过来。bob 提交计划时生成 request_id 并登记 plan_requestslead 审批时根据 request_id 找到记录把状态改成 rejected再通过 inbox 把结果发回给 bob。5. 本篇常见错排查401、local proxy failed 与 reading choices协议跑不通的时候报错信息往往指向几个固定位置。我把调试过程中遇到的和社区里反馈比较多的几类问题整理出来对照排查会快很多。第一类是 401 authentication_error。这个最直接就是 Key 不对或者没生效。检查三件事ANTHROPIC_API_KEY 是否写对有没有多余空格ANTHROPIC_BASE_URL 是否指向 https://taotoken.net/api注意这个地址不加 UTM 参数settings.json 的路径是否正确Claude Code 读的是项目根目录下的 .claude/settings.json。如果三个都没问题用第 2 节那段 Python 代码单独测一下能排除是 SDK 配置问题还是代码问题。第二类是 local proxy failed 或 connection refused。这个通常出现在你本地有代理配置残留的时候。检查环境变量里有没有 HTTP_PROXY 或 HTTPS_PROXY如果有就临时清掉再试。另外确认网络能正常访问 Base URL可以用 curl 测一下连通性。这类报错和协议层无关是接入层的问题先解决接入再谈协议。第三类是 reading choices 相关的报错比如 NoneType object has no attribute choices 或者 reading choices failed。这个一般出现在模型返回结构不符合预期的时候。在 s10 场景下最常见的原因是模型没有正确返回 tool_use block而是返回了纯文本。这时候要检查两件事Model ID 是否支持 tool_usesystem prompt 里有没有明确要求模型使用协议工具。s10 的 teammate system prompt 里有一句 Respond to shutdown_request with shutdown_response如果这句丢了模型可能就用自然语言回复了导致后续解析失败。第四类是 OAuth 相关的报错比如 OAuth token expired 或 invalid_grant。如果你用的是 OAuth 方式接入token 过期后会报这个。解决办法是重新走一遍授权流程或者改用 API Key 方式接入。在 s10 这种需要长时间运行多线程的场景下API Key 比 OAuth 更稳定因为不涉及 token 刷新。第五类是 request_id 对不上导致的状态卡死。表现是 shutdown_requests 里一直有 pending 记录但永远不变成 approved。排查方法是打印 alice.jsonl 和 lead.jsonl 的内容比对 request_id 是否一致。常见原因是 teammate 在调用 shutdown_response 时没有把收到的 request_id 传进去或者传成了新生成的 ID。记住一个原则响应里的 request_id 必须和请求里的完全一致不能重新生成。第六类是 teammate spawn 之后没有任何输出。这个多半是线程启动失败或者模型调用卡住了。检查 spawn 的线程是不是 daemon 线程主线程退出时会不会把子线程带走。另外确认 config.json 的写入权限如果目录不可写spawn 会在保存配置时静默失败。排查的时候建议按这个顺序先确认接入层没问题401、proxy再确认模型返回结构正确choices、tool_use最后确认协议层状态流转request_id、tracker。大部分问题在前两步就能定位。6. 把协议层用起来从可观测协作到长期编码s10 真正带来的变化不是多了几个工具而是让团队协作从“消息交换”升级成了“结构化协调”。消息负责传递信息但决定系统行为的是 tracker 里的状态以及它从 pending 走向 approved 或 rejected 的过程。这意味着你可以查询任意一次请求当前处于哪个阶段而不是只能猜“对方回没回”。如果你要把这套模式用到自己的项目里有几个实用建议。第一request_id 的生成和传递要统一封装不要在每个工具里各写各的否则很容易出现格式不一致。第二tracker 的读写一定要加锁多线程环境下不加锁会出现状态覆盖而且这种 bug 很难复现。第三FSM 的状态流转要加校验只允许 pending - approved/rejected不允许回退避免重复审批。第四协议消息的 type 字段要和其他普通消息区分开方便在 inbox 里过滤和调试。对于需要长期跑编码任务或 Agent 协作的场景建议把协议层和 Coding Plan 结合起来用。Coding Plan 适合持续性的编码工作而协议层负责协调多个 Agent 之间的握手和审批。两者配合可以让团队在长时间运行中保持可观测、可追踪。你可以在 https://taotoken.net/api-keys 生成和管理 Key在 https://taotoken.net/doc 查看完整的接入文档包括模型列表和参数说明。如果只是想先验证模型对协议工具的支持情况可以直接在模型对话页面测试输入一段包含 shutdown_request 场景的 prompt看模型是否能正确返回 tool_use block。确认没问题之后再把配置搬进代码。整套流程跑通之后你会发现多智能体协作的可靠性提升很明显。以前靠自然语言“猜”对方意图的地方现在都有明确的 request_id 和状态机兜底。这也是从简单协作走向可靠系统的关键一步。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询