☰
手搓生产级 AI Agent 系统(10):用 TaoToken 统一 Key 打通多 Agent 协作、Supervisor 与共享状态
2026/9/26 10:40:30 网站建设 项目流程

1. 多 Agent 协作真正难的地方,不是“多”,而是“乱”

单 Agent 跑通之后,很多人第一反应是“再拆几个 Agent 就生产级了”。我一开始也这么想,直到把市场、财务、法务三个角色塞进同一条链路,才发现问题根本不在模型能力,而在协作协议:Supervisor 反复调用同一个 Sub-Agent、每个 Agent 都复制一份完整对话导致 Token 树状膨胀、两个 Agent 基于不同 State Version 工作、Blackboard 里的临时提案被下游当成正式事实、晚到的结果覆盖了最终结论。

这一篇要解决的就是这些。核心思路是:用 TaoToken 统一 Key 和 API 通道,让 Supervisor 和所有 Sub-Agent 走同一个模型调用入口,然后把控制权、上下文边界、共享状态、预算门禁这四件事用代码固定下来。适合已经写完单 Agent、准备上多 Agent 协作的开发者,也适合正在被“Agent 之间自由聊天同步世界”坑到的人。

读完你能拿到:一份可复制的config.toml与settings.json骨架、Supervisor 路由与 Blackboard 共享状态读写示例、多 Agent 协作链路的验证动作,以及一份排错清单。

2. 前置:用 TaoToken 统一多 Agent 的模型调用入口

多 Agent 系统里最容易被忽略的工程细节是:每个 Agent 都在自己拼 API Key、自己处理重试、自己算成本。一旦拆到 5 个 Sub-Agent,Key 管理、限流、成本归因全乱套。

我的做法是把模型调用收敛到一层:所有 Agent 通过 TaoToken 的 OpenAI 兼容接口访问模型,Key 只在网关侧配置一次,Sub-Agent 拿到的只是“角色 + 能力”,不接触凭证。

TaoToken 在这里承担的是统一 API 通道的角色:Supervisor、Research、Finance、Legal 这些角色共用同一个 base_url 和 Key,但通过不同的 model profile 和 tool 权限做隔离。这样成本归因、并发控制、模型切换都在一处完成,不用在每个 Agent 里重复实现。

你需要先准备两样东西:

  • 一个可用的 API Key,在控制台的 API Keys 页面创建:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
  • 确认接入方式,文档在:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite

API 基地址统一用https://taotoken.net/api,不要带任何查询参数。下面所有配置都基于这个地址。

注意:Key 只放在服务端配置或环境变量里,不要写进前端、不要提交到仓库。Sub-Agent 的 Task Envelope 里只传modelProfile名称,不传 Key。

3. 可复制配置:config.toml 与 settings.json 骨架

先给一份能直接落地的配置。config.toml负责运行时参数,settings.json负责 Agent Catalog 和策略。

3.1 config.toml

[provider] base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" timeout_seconds = 60 max_retries = 2 [provider.concurrency] global_max = 32 per_model_max = 8 per_run_max = 6 per_role_max = 2 [supervisor] max_delegation_depth = 1 max_tasks_per_run = 12 max_children_per_task = 4 default_join_policy = "QUORUM" quorum = 2 plan_version = "v3" [budget] token_limit = 800000 model_call_limit = 400 tool_call_limit = 600 cost_limit = 12.00 deadline_seconds = 900 [budget.reserve_order] reserved_roles = ["security_check", "reviewer", "merge"] [blackboard] schema_version = "bb-v2" max_state_bytes = 2097152 artifact_retention_days = 30 [freshness] maximum_version_lag = 2 maximum_age_seconds = 300 invalidating_paths = ["/plan", "/goal", "/budget_limit"] invalidating_artifact_types = ["market_snapshot", "legal_opinion"]

这里几个参数值得单独说。max_delegation_depth = 1意味着只允许 Supervisor 委派给 Sub-Agent,Sub-Agent 不能再往下委派,这是防止循环委派最省事的做法。reserve_order保证安全检查和 Reviewer 的预算先被预留,否则前面的研究 Agent 花完预算,最后没法验证。

3.2 settings.json

{ "agents": [ { "role": "supervisor", "description": "目标解析、任务分配、预算控制、Join 与冲突升级", "capabilities": ["plan", "delegate", "merge", "escalate"], "allowedToolCategories": ["read_only", "internal"], "modelProfile": "reasoning-large", "maximumRisk": "HIGH", "promptVersion": "sup-v3" }, { "role": "research", "description": "市场与竞品信息检索,产出结构化 Claim", "capabilities": ["search", "summarize"], "outputArtifactTypes": ["market_snapshot", "claim_set"], "allowedToolCategories": ["web_read", "internal_search"], "modelProfile": "reasoning-medium", "maximumRisk": "LOW", "promptVersion": "res-v2" }, { "role": "finance", "description": "财务测算与收益评估", "capabilities": ["calculate", "model"], "outputArtifactTypes": ["finance_model", "claim_set"], "allowedToolCategories": ["calc", "internal_search"], "modelProfile": "reasoning-medium", "maximumRisk": "MEDIUM", "promptVersion": "fin-v2" }, { "role": "legal", "description": "合规风险识别与条款审查", "capabilities": ["review", "flag_risk"], "outputArtifactTypes": ["legal_opinion", "risk_item"], "allowedToolCategories": ["internal_search"], "modelProfile": "reasoning-large", "maximumRisk": "HIGH", "promptVersion": "leg-v2" } ], "joinPolicy": { "default": "QUORUM", "quorum": 2, "mandatoryRoles": ["legal"], "deadlineFallback": "DEADLINE" }, "handoff": { "maximumTransfers": 2, "userVisible": true, "userConfirmationRequired": true } }

mandatoryRoles是关键:即使 Quorum 已经满足,法务这种高风险角色也不能被跳过。maximumTransfers限制 Handoff 次数,避免两个 Agent 来回踢皮球。

4. Supervisor 路由与 Blackboard 共享状态读写

配置只是骨架,真正决定系统是否可控的是 Supervisor 怎么派活、Blackboard 怎么写。

4.1 Task Envelope 不可变

Supervisor 派给 Sub-Agent 的不是完整对话,而是一个不可变的 Task Envelope:

public record AgentTaskEnvelope( String taskId, String runId, String parentTaskId, AgentRole assignedRole, String objective, List<ArtifactRef> inputs, Set<String> constraints, Set<String> allowedCapabilities, String outputSchemaVersion, long sharedStateVersion, BudgetAllocation budget, CommitToken commitToken, Instant deadline ) {}

Sub-Agent 只拿到当前目标、必要约束、相关 Artifact、允许的 Tool 和输出契约。完整会话里的无关历史、旧事实、其他领域敏感信息全部不进 Envelope。这一步直接决定了 Token 成本是线性还是树状。

4.2 Supervisor 路由伪代码

def route(goal: MultiAgentGoal, catalog: AgentCatalog) -> MultiAgentPlan: candidates = [] for task_def in decompose(goal): for agent in catalog.by_capability(task_def.required_capability): score = ( 0.4 * relevance(agent, task_def) + 0.3 * expected_value(agent, task_def) - 0.2 * estimated_cost(agent, task_def) - 0.1 * estimated_latency(agent, task_def) ) candidates.append((task_def, agent, score)) selected = select_with_budget(candidates, goal.budget) return MultiAgentPlan( planId=new_id(), version=1, tasks=selected, joinPolicy=goal.join_policy, quorum=goal.quorum, budget=goal.budget, planHash=hash_plan(selected), )

注意select_with_budget会先扣掉安全检查和 Reviewer 的预留预算,剩下的才分给可选研究 Agent。

4.3 Blackboard 分区与写入权限

Blackboard 不是一个大 JSON,而是按 Path 授权的工作区:

/goal # 只读,Supervisor 写 /plan # 只读,Supervisor 写 /tasks # Agent 只能更新自己 Task 状态 /artifacts # 只追加,不可原地覆盖 /claims # 只追加 /conflicts # 只追加 /open_questions # 可追加、可关闭 /proposals # Agent 提交,Supervisor/Human 决定 /decisions # 只读,Commit 后写 /budget # 只读,Budget Service 写

Sub-Agent 能做的只有:发布 Artifact、提交 Proposal、更新自己 Task 状态、报告风险。它不能直接改/goal、/final_decision、/approvals、/budget_limit。

4.4 乐观锁写入

共享状态更新必须带版本号,并发冲突不能静默覆盖:

update multi_agent_shared_state set state_json = :state, version = version + 1 where run_id = :runId and version = :expectedVersion;

如果影响行数为 0,说明版本已经变了,当前写入必须走 Proposal 重新评估,而不是重试覆盖。

4.5 Proposal / Commit

public record StateChangeProposal( String proposalId, String runId, String taskId, AgentRole proposer, long baseVersion, List<JsonPatchOperation> changes, List<ArtifactRef> evidence, String reason ) {}

Supervisor、规则引擎或 Human 决定是否 Commit。Commit 前要校验 Commit Token、输入 Artifact 版本和 Shared State 新鲜度。

5. 验证请求与成功结果

配置和代码就位后,用一条最小链路验证:Supervisor 派两个 Sub-Agent 并行,Blackboard 收到两个 Artifact,Merge 产出结论。

5.1 发起一次多 Agent Run

curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "reasoning-large", "messages": [ {"role": "system", "content": "你是 Supervisor,负责目标解析与任务分配。"}, {"role": "user", "content": "评估方案A是否值得推进,需要市场、财务、法务三方输入。"} ], "metadata": { "run_id": "run_20250101_001", "role": "supervisor", "plan_version": "v3" } }'

5.2 期望的 Trace 结构

multi_agent.run ├─ router ├─ supervisor.plan ├─ budget.reserve ├─ task.research ├─ task.finance ├─ task.legal ├─ join ├─ merge ├─ review └─ human

5.3 成功判定的几个硬指标

指标期望值说明
stale_result_commit_total0晚到结果被拒绝
commit_rejected_total{reason}可解释拒绝原因可归因
context_duplication_rate< 0.25重复上下文占比
task_success_rate≥ 0.90必需 Task 成功率
unresolved_blocking_conflicts0阻塞冲突清零

如果context_duplication_rate超过 0.25,基本可以断定 Context Builder 把完整会话塞给了每个 Sub-Agent,需要回到 Task Envelope 检查。

6. 本篇常见错排查

6.1 Supervisor 重复调用同一 Agent

现象:Trace 里同一个 role 出现多次,Task 内容高度相似。

排查:检查planHash是否在重试时被重新生成。正确做法是 Plan 一旦生成就绑定planHash,重试复用原 Plan,只重跑失败 Task。

6.2 Sub-Agent 复制完整上下文

现象:multi_agent_context_duplication_tokens飙升。

排查:确认 Sub-Agent 的输入来自ContextManifest而不是原始消息列表。Context Builder 只应包含当前目标、必要约束、相关 Artifact、允许 Tool 和输出预留。

6.3 共享状态被覆盖

现象:两个并行 Task 提交后,只有一个 Artifact 生效。

排查:检查是否用了乐观锁。version不匹配时必须走 Proposal,不能直接 update。

6.4 晚到结果污染最终结论

现象:Task 已被取消,但结果仍然写入了/artifacts。

排查:提交时校验 Commit Token 和 Task 状态。状态为SUPERSEDED或CANCELLED的 Task,提交直接返回TASK_NOT_ACTIVE。

6.5 预算被前面 Agent 花完

现象:Reviewer 无法执行,最终结论没有验证。

排查:确认reserve_order生效,安全检查和 Reviewer 的预算在 Task 启动前就被原子预留。

6.6 多数投票形成集体幻觉

现象:三个 Agent 结论一致,但都基于同一份数据、同一个模型。

排查:记录model family、evidence source、prompt lineage。三票一致不等于三个独立证据,真正的冗余验证要求不同证据、不同模型或规则、独立 Context。

6.7 Handoff 来回跳转

现象:两个 Agent 互相转交,用户看到身份反复切换。

排查:检查HandoffPolicy.maximumTransfers和allowedTargets。控制权回收必须在 Policy 中定义,不能自由跳转。

6.8 版本 Gap 导致状态错乱

现象:本地投影版本 15,收到事件版本 18。

排查:不要直接应用事件,读取 Version 18 的 Snapshot 替换本地投影。消费者必须检测版本 Gap。

7. 下一步:把 Key 和通道固定下来,再谈协作

多 Agent 协作的复杂度不在模型,而在协议。Supervisor 管目标和预算,Sub-Agent 处理专业任务,Artifact 承载可复用事实,Shared State 记录正式状态,Blackboard 管理提案与冲突,Commit Gate 阻止旧结果,Reviewer 和 Human 控制最终风险。

而这一切的前提,是模型调用入口先统一。如果你还在每个 Agent 里各配一份 Key、各写一套重试,协作层再漂亮也会被凭证和成本问题拖垮。建议先把 TaoToken 的 Key 和 API 通道固定下来:

  • 创建 Key:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite
  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
  • 需要长期跑编码类 Agent 或 Supervisor 编排,可以看 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite
  • 想先验证模型在多 Agent 场景下的表现,直接进模型对话:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite

下一篇会继续实现代码与浏览器沙箱、安全执行与风险控制。在那之前,先把这一篇的config.toml和settings.json跑通,确认 Trace 里stale_result_commit_total为 0、context_duplication_rate低于 0.25,再往上叠功能。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询