多代理协作新范式:agency-agents如何搭建AI代理公司 第一次看到 “agency-agents” 这个命名时我愣了一下agents 我懂但 agency 是什么后来把整套结构跑通才明白这个项目要做的不是“训练一个更聪明的智能体”而是把一堆智能体组织成一家能接单、派活、质检、交付的“代理公司”。如果你手上有大堆真实任务又不想把每一步逻辑都写死在脚本里这种“小团队打仗”式的多代理协作模式会很顺手。这个项目解决的是单智能体最常见的一类问题任务一复杂上下文就乱一乱就胡说一胡说就要人肉干预。而 agency-agents 把任务拆成“接待—拆解—执行—审核—交付”几个环节让不同智能体各干各的活每个环节都留人工检查的口子。适合想搭建多代理系统、又不想从零造轮子的开发者参考也适合产品负责人理解 AI 工作流应该怎么组织。1. 从标题拆开说起agency-agents 到底在解决什么问题1.1 为什么是 agent不是 workflow传统自动化流程是固定拓扑A 步骤做完传给 BB 做完传给 C。流程一旦定下来中途遇到没见过的输入就只能报错。而智能体化的工作方式是你给它一个目标让它在边界范围内自己决定调用什么工具、用什么顺序完成。我最早就是从硬编码 workflow 转过来的。有一段时间做批量内容处理逻辑全是if-elif-else条件写了几百行新来一个需求就得改代码。后来换成了“目标 可执行动作”的方式系统松了很多。但随之而来的问题是单个智能体既要理解任务又要拆解步骤还要调用工具、检查输出所有能力挤在一个上下文里效果非常不稳定。agency-agents 的思路是把这些能力拆到不同代理身上模拟一个公司的分工。比如有一个代理专门接待用户、理解需求一个代理专门做任务拆解和排期后面挂几个擅长不同领域的执行代理最后再来一个代理做质检。这比单个智能体在同一个上下文里来回切换角色要稳定得多。1.2 为什么是 agency不是 orchestrator很多人会把这种结构叫 orchestrator但 agency 的含义更偏组织关系。orchestrator 是中央调度所有请求都过一个中心节点而 agency 更像是几个有自主性的角色在一块共享工作板上协作。中心节点只保留最必要的调度职责不控制每个代理的每一步内部行为。我用一个类比来理解传统 orchestrator 像一个电话总机所有分机都得经过它转接而 agency 像一个小公司项目负责人把任务拆完后各团队直接通过公共的“任务板”和“消息箱”协作只在关键节点同步。这样做有个很实际的好处单个执行代理挂了或者返回质量差不会拖死整个链路。调度器只需要把任务重新分配给另一个同类型代理或者把结果打回重做。真实项目里这种容错能力比“每一步都严格可控”更重要因为大模型自身就有随机性你不可能精确预知它下一步输出什么。2. 项目整体设计思路把“任务代理公司”搬进代码2.1 顶层角色定义与目录结构我建议先定义清楚角色再写代码。agency-agents 第一件事就是把“公司岗位”列出来。我的最小角色表如下角色对应职责权限边界入口代理接待用户、判断意图、识别需求是否完整不执行具体任务只负责初筛和转交拆解代理项目经理把大目标拆成可执行子任务安排依赖顺序不直接调用业务工具只产出“任务计划”执行代理领域专家负责具体领域任务比如文案、数据处理、竞品调研只能调用授权的工具和知识库审核代理质检检查执行结果是否满足验收标准只有建议权不能修改执行结果的原始数据交付代理把多个子任务结果汇总成最终输出不允许单独修改子任务内容用户代表在关键节点人工确认需求是否被正确理解可以同意、打回或中止目录结构也按岗位来组织而不是按技术模块来组织。这样新加入一个领域专家时不会动到调度逻辑。agency-agents/ ├── roles/ │ ├── dispatcher.py │ ├── planner.py │ ├── workers/ │ │ ├── researcher.py │ │ ├── writer.py │ │ └── data_ops.py │ └── reviewer.py ├── core/ │ ├── message.py │ ├── router.py │ ├── state.py │ └── tool_registry.py ├── tools/ │ ├── search_tool.py │ ├── doc_reader.py │ └── sqlite_cache.py └── configs/ ├── roles.yaml └── budget.yaml这个结构最核心的点在于每个代理都有自己的独立状态和系统提示词互相之间不共享同一个模型上下文。它们通过消息传递协作而不是把全部背景信息塞进一次请求。2.2 消息路由与上下文传递多代理系统最容易翻车的地方就是上下文。我一开始图省事把所有历史信息都塞进同一个列表结果执行代理读到几千字的对话记录后根本不知道当前该干嘛。后来参考消息队列的做法给每条消息加了一个信封结构。每条消息至少包含消息类型、发送者、接收者、任务 ID、时间戳、内容。重点是任务 ID。同一个真实任务的所有消息都会带上相同的 ID这样每个代理只关心自己参与的“子任务”不用读全量历史。from dataclasses import dataclass from enum import Enum class MessageType(Enum): REQUEST request RESULT result REVIEW review REJECT reject APPROVE approve dataclass class Message: msg_id: str msg_type: MessageType sender: str recipient: str task_id: str payload: dict路由层接收消息后按角色和工具白名单决定投递给谁。比如拆解代理产出子任务列表后路由层会为每个子任务创建一个独立的工作空间然后把对应的执行代理 ID 写入 watcher 列表。后续该子任务的任何消息只投递给在列表里的代理这就避免了上下文污染。我还会做一层“上下文裁剪”当一条消息超过预设阈值时路由层不是简单截断而是先触发一次摘要代理把前序内容压缩成 200 字以内再继续传递。这个摘要代理本身也是一个 agent但它的任务很简单消耗不大。2.3 工具层与权限边界agent 没有工具就只是个聊天机器人但工具给多了它会到处乱跑。我在实操中踩过一个大坑某个执行代理发现自己可以调用文档删除工具于是在一次幻觉状态下把一批中间产物删了。问题不在模型而在我没有设置权限边界。工具注册表里必须有三个东西工具名称、参数 schema、允许调用的角色列表。调用工具时路由层先查权限再执行。任何工具都要有幂等保护也就是同样的参数执行两次结果一致。这个要求对大模型代理特别重要因为代理经常因为超时重试同一动作。TOOL_PERMISSIONS { delete_temp_file: [dispatcher, human_operator], search_knowledge_base: [worker_researcher, worker_writer], write_draft: [worker_writer], update_budget: [human_operator], }同时每个工具要报告自己的“副作用等级”。像只读检索是低风险写入临时文件是中风险删除数据、扣费、发送外部邮件是高风险。高风险动作必须额外带一个人类确认令牌才能执行。这个设计帮我挡掉了不少事故。3. 核心实现与调优实录3.1 任务拆分项目经理的“研究—草稿—审核”三段式我在项目里让拆解代理默认使用“研究—草稿—审核”三段式。它的大致逻辑是任何一个复杂任务先让研究员代理收集素材和约束条件然后让写作/执行代理基于素材产出初稿最后让审核代理对照需求和约束打回或通过。拆解代理输出的计划必须是一个结构化对象而不是长篇自然语言。我用 JSON 强制约束{ task_id: T-2024-001, goal: 生成一份竞品功能对比报告, dependencies: [], steps: [ {id: 1, role: researcher, instruction: 收集至少5个竞品的功能清单}, {id: 2, role: writer, instruction: 整理为对比表格和摘要}, {id: 3, role: reviewer, instruction: 检查数据是否过期来源是否可靠} ] }为了确保输出能稳定解析我用“提示词 正则校验 JSON 修复”三层保险。提示词要求只输出 JSON如果解析失败调用一个小的修复代理把模型输出里的多余解释去掉再不行就把这个计划直接打回给拆解代理重写。实际经验是不要让拆解代理一次拆太多步骤。单个计划最好在 5 个步骤以内超过 5 步容易出现依赖循环。宁可拆浅一点然后在执行过程中动态补充。3.2 子代理返回质量不齐怎么办多代理系统最大的痛点不是跑不起来而是执行代理表面上完成了任务实际上给的是一堆正确但无用的废话。审核代理的价值就在这里但审核也不是万能的。我做法是给审核代理一套明确的拒绝标准。不是让审核代理说“好不好”而是让它按清单检查是否包含具体数据或来源还是空泛表述是否回答了任务中的所有子问题是否跨出了权限边界比如调用了不该用的数据源输出格式是否满足下游步骤的解析要求审核代理每次打回都要写一句具体原因不能只写“质量太差”。这个原因会被附加到原任务消息里再发给执行代理重新处理。执行代理在第二次生成时要看到这条反馈我甚至要求它在响应里先说明“我根据审核反馈做了哪些调整”。这里有个调参的心得审核代理的 temperature 要设置得比执行代理低一般我设到 0.2 或更低。执行代理可以有一点发散度但审核必须保守稳定。否则会出现执行代理好不容易给出个像样结果审核代理却因为自己当天状态不好给人打回造成来回空转。3.3 人机协作与最终审批节点我始终坚持一个原则真正对外交付的东西必须有人工审批。哪怕你的审核代理做得再严格也要让最终结果过一个人类确认节点。这个节点在技术上很简单就是把交付任务挂到一个审批队列里等待操作员响应。我实现了一个简单轮询def wait_for_human_approval(task_id, timeout3600): while True: approval check_approval_queue(task_id) if approval.status approved: return True if approval.status rejected: return False if time_left 0: return default_policy(task_id) time.sleep(5)审批超时后不能直接放行也不能直接拒绝而是根据任务的失败成本选一个默认策略。如果一共有 10 个任务9 个通过审核只有 1 个超时我会倾向放行但标记为“待复核”。如果任务本身是高风险的超时就直接中止。我在命令行环境里做过一个交互版本也接过外部消息平台的审批通道。消息平台版本更实用因为操作员不需要一直盯着终端。审批消息里会附上执行结果摘要和完整结果的链接操作员点“通过”或“打回”就行。3.4 成本与迭代速度的平衡多代理系统的开销是叠加的一个任务跑下来往往会调用好几轮模型接口而且每一轮输出都会被下一个代理完整读取。如果不控制成本很容易翻三四倍。我给项目加了预算控制在系统提示词里告知每个代理它“可以调用的外部搜索次数”和“最大 token 预算”。执行代理如果发现需要更多的信息应该返回“信息缺口”而不是硬着头皮生成。这样很多任务可以在两三轮内收敛而不是无限扩张。实际操作中我还会把执行结果做成语义缓存。同样类型的问题如果输入任务的问题和目标相似度超过一定阈值就直接复用上一次的中间产物不再重新调用执行代理。我目前用一个本地向量库做缓存匹配命中率大概在 30% 左右。在批量处理相似任务时这个缓存直接决定项目能不能跑完。另一个经验是控制重试次数。我曾把“审核打回后重试三次”当成默认设置结果有个任务因为执行代理反复犯同一个错白白消耗了大量 token。后来改成第一次打回由执行代理自己改第二次打回就换一个同类执行代理重新跑第三次再打回就把任务退回到拆解代理说明这个分解方案本身有问题。这个三级策略比我之前死磕同一个代理高效得多。4. 常见问题排查与避坑建议4.1 多代理系统里最典型的四个故障现象可能原因排查方法解决建议执行代理答非所问上下文混入了其他子任务的历史记录检查消息投递列表和 task_id 过滤按任务 ID 隔离上下文不允许跨任务读取代理之间来回循环缺少最大轮数和超时机制查看日志里的消息流转链路给每个任务设置最大跳数比如 8 跳后强制终止审核代理经常误判审核提示词太模糊没有验收清单导出几条被误判的记录看拒绝原因把拒绝条件改成可勾选的客观条目任务卡在中间步骤某个工具返回格式变化导致解析失败看工具调用错误日志给工具接口加一层适配器统一异常返回格式循环问题是最隐蔽的。我在早期遇到过一个案例审核代理打回后执行代理重新生成然后拆解代理发现新结果和原计划不一致又自动调整计划调整完计划后审核代理又基于新计划要求重做。最后整个链路跑了 20 多轮唯一的终止条件是预算耗尽。后来我干脆在整个路由层加了个max_hops计数器。每经过一次消息传递计数器加一超过预设值后路由层不再自动投递而是把当前状态打包发给人类审批队列。宁可让用户来收拾残局也好过程序跑飞没人知道。4.2 你如何知道这套系统是好的很多项目在演示时很惊艳一上真实数据就崩。我在 agency-agents 里维护了一套“黄金任务集”里面大概有几十个标准任务每个都标注了可接受的输出范围和关键检查点。每次改完调度逻辑、换模型、调整提示词我都会先在这套任务集上跑回归。判断标准不是“结果和预期逐字一样”而是“关键约束有没有被满足”。比如任务要求“必须包含至少三个数据来源”那么只要结果里包含三个来源链接就算过如果没包含就算生成得再好也记作失败。这套回归跑一遍也不便宜所以我设置了分级改动提示词时跑精简集改动路由或工具时跑全量集改动底层模型时全量集之外再额外做一轮模拟长任务。这样能避免频繁迭代带来的隐性质量回退。说实话多代理系统很难做到 100% 稳定。我的目标是把关键路径的准确率稳定在 90% 以上同时保证失败时能及时暴露给人工。能做到这两点就已经具备上生产环境的条件了。4.3 可以上生产的几个前提我梳理了几个上生产前必须满足的前提供你对照检查所有代理调用都留审计日志至少要能回答“这个结果是谁在哪个时间点基于哪些输入生成的”。有两级熔断单任务卡死熔断以及整体预算超支熔断。外部工具调用要能被禁用或降级。比如搜索服务不可用时代理应该使用缓存数据而不是一直报错。最终交付内容必须从结构化结果渲染不能直接拿模型原始输出做对外文档。日常运行数据要持续记录尤其是任务分布、打回率和耗时分布。我目前就是把 agency-agents 跑成一个后台服务入口接收任务出口输出结果。调度过程和人工审批并行走日常只需要处理少量打回任务。这套模式比较适合内容生产、竞品调研、知识库整理这类“过程复杂但容错空间大”的任务。它对强规则、低延迟、不可解释性要求很高的系统不适合那类场景还是得用传统代码逻辑。最后再分享一个建议如果准备试这种模式别一开始就搭十几个角色。先从一个最小三人组起步也就是拆解、执行、审核把消息流转和審批节点跑顺再往里面加角色。我在实际使用中的感受是每多一个代理系统的不可预测性不是加一分而是乘一分。真正靠谱的多代理系统不是角色越多越好而是每个角色都不可替代、边界清晰并且随时能被人工按住。