☰
多Agent协作系统搭建:角色分工、任务编排与权限收敛实战
2026/10/10 7:39:13 网站建设 项目流程

“Agency-Agents”这个项目名听着像组织架构图,其实它是我最近在跑的一个模拟项目代号——把多个大模型智能体组织成一支“数字小团队”的协作系统。我为什么会做这件事?因为在过去做Agent应用时,我吃够了“单Agent硬扛复杂任务”的亏:任务一长就丢上下文,工具一多就权限混乱,流程一分支就开始一本正经地胡编。多智能体协作不是把几个模型接口塞进同一个循环里那么简单,它更像开一家微型公司——主管负责拆单,研究员查资料,写手出稿,质检员挑毛病,再用一套协议让他们别打起来。如果你也遇到过“一个提示词写到头还是输出不可控”的困境,这篇内容应该能给你一套直接可抄的骨架。

1. 从单Agent的三个翻车现场说起:为什么必须做编排

1.1 复杂调研做到后半程,Agent开始“一本正经胡编”

我第一次明显感受到单Agent的天花板,是在做一个行业调研类Demo的时候。任务拆成了三步:先读三份资料,再归纳两个细分方向的关键变量,最后对比之后给出建议。前两步输出质量还不错,但到了第三个环节,模型开始把第一个方向的数据和结论复用到了第二个方向上,而且语句极其流畅、逻辑自洽,如果不逐条核对,根本发现不了它已经“串台”了。

排查了很久才想明白:只要任务链条的总信息量超过单个上下文窗口的承载能力,早期关键信息的注意力权重就会被后段的指令稀释。更麻烦的是,模型在压力下倾向于生成看起来合理的连贯内容,而不是承认自己某个信息已经记不清了。那次之后我认定一个原则——让单个模型背负超长链条任务,本质上是在跟注意力机制的天性对抗,再怎么调提示词也只是修补,不是解药。

1.2 工具权限混乱,查询结果竟然覆盖了源文件

另一个让我印象深刻的翻车现场更危险。我在一个Agent身上同时挂了两类工具:检索工具和本地文件写入工具。本意是让它在完成检索之后,把整理好的结论自动写入一个Markdown文件。结果它在某次运行时,把一段“检索摘要原文”直接覆盖写进了源数据文件,等我看日志时,原始资料已经被冲掉了。

这类事故在单Agent系统里几乎是结构性的。所有能力都塞给同一个角色,意味着它默认拥有全部工具的调用权。大模型对“什么时候该调用什么工具”的判断能力远没有我们想象的可靠,尤其当两个工具的接口都长得差不多时,模型很容易选错、用错、甚至把参数传错。吃了一次大亏之后,我意识到“权限收敛”这件事必须靠系统架构去强约束,而不是寄希望于模型的自觉。

1.3 单Agent与多Agent的本质差异

那次事故让我重新审视了一个问题:我们究竟为什么要做Agent?是为了让模型更有自主性吗?不是。我们的核心目的是让模型在可控范围内完成复杂任务。想清楚这一点之后,单Agent方案的弊端就非常明显了——它把一个需要多人协作完成的工作强行压缩给一个“全能人”,而这个人既没有足够的注意力承载度,也没有清晰的责任边界。

相比之下,多智能体协作的思路是从组织架构层面重新设计系统:让每个Agent只负责一个狭窄领域,用协议把任务传递、结果验收、冲突仲裁串起来。用一个生活化的比喻:你不太可能要求一个刚入职的实习生同时完成市场调研、财务核算和法务审阅,但你完全可以安排一个主管把这三件事分给三个专员,再安排一个复核人检查结果。

单Agent与多Agent方案的核心差异,我在推进中列过一个直观的对照表:

维度单Agent方案多智能体协作方案
上下文负担全部任务挤在一个上下文窗口每个Agent只承担子任务的局部上下文
职责边界所有工具归同一角色,权限模糊按角色配置工具白名单,权限收敛
错误传播早期错误会持续影响后续输出通过独立质检节点截断错误扩散
可解释性很难定位是哪一步逻辑出了偏差每类任务有独立日志和验收记录
迭代成本改一个需求要重新调整个提示词单个角色内部调整,不影响全局

当然,多Agent也引入新的问题:任务怎么拆、消息怎么传、意见不合时谁拍板。这些恰恰是Agency-Agents项目里最值得拆开讲的部分。

2. 把“数字小公司”搭出来:角色分工与任务协议

2.1 主管、执行者、质检者,各管一摊

我在Agency-Agents里沿用了一套非常朴素的三角色模型,没有设计过于复杂的等级结构,因为从实际效果看,层级越多、传递损耗越大,对模型Agent来说尤其明显。

主管Agent(Orchestrator)负责接收用户需求,把它拆解成若干可独立执行的子任务,并以结构化的方式下发。它不直接产出具体内容,只负责规划和调度。

执行者Agent(Worker)是真正干活的人。每个执行者只对应一个窄领域,比如“资料检索与摘要”“初稿撰写”“数据表格生成”。他们接收主管下发的任务单,完成任务,然后回传结构化结果。

质检者Agent(Reviewer)负责对照验收标准检查执行者的输出,发现事实性错误、缺证引用、逻辑矛盾等问题时给出结构化打回意见。打回不是简单说一句“这个不行”,而是要说明是哪种问题、具体在哪个位置。

这三个角色合在一起,就是一个最精简的“数字代理机构”。你甚至可以把它类比成编辑部:主管定选题,记者写初稿,编辑做校对,校对不通过退回返工。越往后,我越发现这套模型在真实场景中好用的原因只有一个——每个Agent的提示词都极度精简,职责描述清楚,不需要背负无关信息。

2.2 Task Ticket:让每个Agent拿到的都是“工单”而不是“聊天记录”

多智能体系统非常容易失控的一个点是:消息格式不统一。有的Agent返回纯文本,有的返回JSON但有附带说明,有的把上下文全盘转发给下游。如果消息没有统一规范,调度中心很快就会被各种脏数据淹没。

我在Agency-Agents里确定了以Task Ticket为核心的数据结构。一个任务单包含这些关键字段:

字段含义说明
task_id任务唯一编号全局链路追踪的锚点
parent_id父任务编号用于还原任务分发树
status当前状态pending / running / done / revise / timeout
role执行角色指明该任务应该由哪类Agent处理
input_summary输入摘要由主管整理的任务核心信息,而非全量原文
acceptance_criteria验收标准可量化的完成条件,比如“包含至少三条带来源的引用”
required_tools可用工具列表当前任务允许调用的工具白名单
remaining_turns剩余返工次数控制质检打回后的重试上限
deadline截止时间戳一旦超出,任务自动标记失败

执行者的回传格式同样固定为统一JSON结构,我用的是这样一套:

{ "task_id": "sub_001", "status": "done", "content": "此处放任务产出内容", "evidence": ["来源ID_1", "来源ID_2"], "consumption": { "prompt_tokens": 1280, "completion_tokens": 460 }, "note": "任何需要额外说明的信息统一放在这里" }

为什么坚持结构化?因为调度逻辑和质检逻辑都需要机器可读的字段。自由文本看着友好,但一旦进入自动化评估环节,解析的脆弱性会指数级放大。统一格式还能带来一个额外好处——日志可以直接按字段检索,问题排查时效率高得多。

2.3 任务拆解粒度:拆到什么程度才不算过度设计

任务拆解是整个Agency-Agents里最考验经验的部分。拆太粗,执行者还是要面对复杂任务,单Agent翻车的毛病又会复发;拆太细,调度开销和Token成本成倍上涨,每个子任务之间光是传输上下文就要浪费不少预算。

我目前在实践中遵循一个很朴素的判断准则:如果一个子任务的系统提示词加上输入摘要,预计会超过目标模型的单次高质量处理上限(我通常按上下文窗口的六成来估算),那就说明粒度太粗,需要继续拆。另一方面,如果某个子任务只需一两步就能完成,且产出量很小,那大概率是拆得过细了,可以合并给相邻任务。

任务粒度还会直接影响质检环节。验收标准越量化,质检Agent越容易做判断。比如不要写“请给出专业分析”,而要写“必须输出三个要点,每个要点附带一条引用来源”。后者不管对执行者还是质检者来说,都是一个边界清晰的任务。

3. 上下文隔离、权限收敛、冲突仲裁:三个决定系统死活的技术点

3.1 上下文隔离:防止“错误观点像流感一样传染”

在多Agent系统中,最隐蔽也最危险的坑叫做“记忆传染”。如果每个Agent都携带全局上下文,那么A产生的一个错误事实会原封不动传给B,B会把它当成既定事实继续推导,形成一条往下游扩散的错误链条。单Agent系统里这个错误最多影响后文的连贯性,多Agent系统里它会变成多个Agent之间相互印证、看起来像真的一样的一整套幻觉。

我采用的策略是上下文隔离。主管给执行者下发的信息不包含完整历史对话,而是只包含一份“任务摘要+证据包”。证据包里有完成该任务所需的原始素材和必要背景,但素材与当前子任务无关的信息全部剔除。这就像公司开项目会,前端组只需要知道接口契约,不需要听后端组讨论数据库索引优化方案。

实际执行时,我在系统提示词里给主管明确加了要求:“当你分派任务时,必须摘出与当前子任务直接相关的信息段落,禁止原样转发全部对话记录。”配合上前面提到的Task Ticket机制,这条约束生效得很稳定。

3.2 权限收敛:给每个Agent一张“白名单”而不是“万能钥匙”

我在翻车现场里吃过工具权限混乱的亏,所以在Agency-Agents里把权限分配做成了角色绑定。每个Agent所能调用的工具,在配置文件中以白名单形式声明,调度器在加载角色时直接做字段校验,模型本身不被授予白名单之外的任何工具接口。

我通常的基础配置是这样:

{ "roles": { "orchestrator": ["task_decompose", "global_state_query"], "researcher": ["web_search", "document_extract", "summarize"], "writer": ["text_generation", "table_format"], "reviewer": ["evidence_check", "diff_compare", "score_report"] } }

写手Agent不可能拿到“删除文件”这类高风险权限,研究员Agent也不可能直接修改产出稿件。别小看这一步,很多看似聪明的多Agent应用崩就崩在权限没有收敛:某层Agent为了完成一个看似无关紧要的动作,意外调用了越权工具,结果一发不可收拾。模型自主能力越强,权限约束就必须越紧,这个道理和现实中的员工权限管理完全一致。

3.3 冲突仲裁:质检打回之后,双方“吵架”怎么收场

执行者返回结果,质检者发现错误并打回,执行者修改后再提交,质检者再看……这套循环看似合理,实际上却是死循环的高发区。模糊需求下,质检者可能每次都能挑出新毛病,执行者每轮都在重跑同一个任务,Token预算哗哗烧完,系统仍然无法收敛。

我的处理办法是把“打回”和“申诉”全部结构化。质检者的打回理由不再是一段自由文本,而是枚举类型加定位信息:

{ "review_verdict": "revise", "issue_types": ["missing_evidence", "factual_error"], "issue_positions": ["第4段第2句", "结论部分第1句"], "suggestion": "请补充第2点结论对应的来源,并修正第4段数据" }

同时,我在任务Ticket里预留了remaining_turns字段,限制最多返工次数。一旦返工次数用完,任务自动升级给主管做终审。主管不重新读全部对话,只依据质检者的错误清单和执行者的修改说明做一个二选一或三选一裁决。这样处理的好处是:即使最后真的要拒绝一个任务,我们也有完整的判定记录。

4. 连踩七个坑之后,故障排查经验汇总与兜底策略

4.1 踢皮球死循环:任务依赖图里藏了个环

第一次跑通多Agent流程时,我满心期待,结果系统卡了整整十分钟没有产出。看日志才发现,研究员Agent产生了一个任务,这个任务需要写手Agent的结果,而写手Agent又在等待研究员提供更多资料。两个子任务互相依赖,谁也不先动,完全陷入了“踢皮球”状态。

根因是任务依赖关系形成了环。我后来用了两层防护:第一层,在主管产出任务清单之后,调度器会对任务列表做一次简单依赖校验,用有向无环图的思路检查是否存在循环依赖;第二层,也就是运行期兜底,给每个子任务设置最大迭代次数和超时时间,我常用的参数是timeout_per_task = 120秒,max_iterations = 5。超时一到,任务自动标记失败并交由主管重新规划,而不是无限等下去。多Agent系统里,任何环节都必须有超时和重试上限,这是防止雪崩的底线。

4.2 幻觉级联:A编造的数据被B当成了引用素材

多Agent系统有一个比单Agent更可怕的故障模式——幻觉级联。研究员Agent在整理资料时,由于上下文截断或理解偏差,编造了一个看似合理的数据点,写手Agent拿到这个数据后直接引用进文章,质检Agent如果没有调取原始资料对照,也会默认它是正确的。一个幻觉经过多个Agent层层传递,最终会变成一串带“来源引用”的完整错误结论。

我给出的应对方案是输出协议里强制要求每个关键论断携带evidence字段。执行者不是只输出内容,而是必须给出每个关键结论对应的来源ID列表。质检者拿到输出后首先要过一遍evidence_check工具,验证这些来源ID是否真实存在、能否支撑对应结论。这个机制没法做到100%拦截幻觉,但它能把幻觉限制在单点,而不是让它沿着协作链条扩散成系统级的错误。我的经验是:一旦多个Agent之间连续交互超过三轮,“每个论断带证据”就不再是选项,而是必须。

4.3 Token预算失控:一次重试烧掉双倍的令牌

Token成本失控是我在项目中期最头疼的问题。一次看似普通的子任务执行,模型可能为了“表现更好”反复打磨一段话,消耗的Token远超预期。更糟的是质检打回之后的重试——重试一次,Token消耗基本翻倍,如果循环三轮,一次任务的总成本能顶正常执行的五六倍。

后来我给每个Agent配置了独立的token_budget,比如研究员任务单次预算上限4000 Token,写手单次预算上限6000 Token。执行者一旦接近预算上限,调度器会发送截断指令并强制其完成当前产出。预算字段同时写入Task Ticket的consumption里,每次调用消耗累计统计,如果超出预算,任务以“over_budget”状态返回。这个字段既是成本控制阀,也是性能优化依据——翻日志时一眼就能看出哪些子任务经常超支,从而针对性地做拆解或换模型。

4.4 JSON解析灾难:模型在JSON前后夹带花式文本

我给执行者规定的回传格式是JSON,模型却经常不遵守。有的在JSON前面加一句“以下是结果”,有的在JSON后面加“如果有问题请随时告诉我”。这些看起来无害的文本,一旦进入严格解析器,就会让json.loads直接抛错,整个流程中断。

我加了宽容解析层:先从模型返回文本中截取第一个左花括号到最后一个右花括号之间的内容,再尝试解析;如果解析失败,把原始返回原样保存到日志,绝不静默丢弃。同时我在提示词里明确告诉模型:“所有额外的解释和说明必须写在JSON的note字段内部,禁止在JSON结构之外追加任何文字。”宽容解析兜底了模型的不规范行为,note字段又把自由表达纳入结构化范围,两条措施叠加之后,解析失败率基本可以忽略。

4.5 并发限流:多Agent一起跑,接口先顶不住

多Agent协作天然带来高并发调用需求。当四个执行者并行跑任务时,每个任务里都可能调用多次模型接口和检索接口,瞬时请求量飙升,触发服务端限流是常有的事。第一次遇到限流时我还以为代码有Bug,排了半天才反应过来是并发量太高。

解决思路很简单:信号量限制并发数 + 指数退避重试。我通常在配置里设定parallel_limit = 3,也就是同时最多允许三个Agent执行任务;每次调用失败后,按1秒、2秒、4秒的间隔递增等待,做指数退避,最多重试三次。这个方案不解决所有限流问题,但基本能避免系统因为瞬时压力打崩溃。真正并行度上限取决于模型接口的配额和服务稳定性,不要盲目追求全并行。

5. 最小可复现Demo:三Agent写作流水线完整跑通过程

5.1 这次Demo的目标与边界

说了这么多经验和坑,还是要落到一个可以动手复现的最小项目上。我设计的Demo是“三Agent写作流水线”:输入一个主题,输出一篇带引用来源的简短文章。系统包含三个角色:主管负责拆任务,一个执行者同时承担资料整理和初稿撰写(为了最小化可以合并),质检者负责对照验收标准检查并给出打回意见。

这个小Demo不需要数据库,不需要复杂的Agent框架,只需要一个主循环、一个任务队列、一个结果池和三个提示词模板。整体大概几百行代码,跑通只需要几小时。

5.2 最小配置示例

{ "project": "Agency-Agents-Writing-Demo", "roles": { "orchestrator": { "model_tier": "fast", "tools": ["task_decompose"] }, "executor": { "model_tier": "balanced", "tools": ["search", "summarize", "draft"] }, "reviewer": { "model_tier": "strong", "tools": ["evidence_check"] } }, "runtime": { "parallel_limit": 2, "timeout_per_task": 120, "max_iterations": 3, "token_budget": { "orchestrator": 800, "executor": 4000, "reviewer": 1200 } } }

这里的model_tier是对不同能力档次模型的抽象,实际可以映射到项目密钥配置里。不同角色使用不同档次的模型是省成本的关键,主管只需要做结构拆解,用便宜的小模型就行;执行者需要产出内容,要用中等档位;质检者需要做综合判断,通常是给最强模型。

5.3 核心循环伪代码

import json import time import uuid def run_writing_pipeline(topic): trace_id = uuid.uuid4().hex[:16] ticket = orchestrator.plan(topic, trace_id) completed = {} for subtask in ticket["subtasks"]: attempts = 0 while attempts < MAX_ITERATIONS: result = executor.execute(subtask, completed) verdict = reviewer.review(subtask, result) if verdict["status"] == "pass": completed[subtask["task_id"]] = result break else: attempts += 1 subtask["feedback"] = verdict final_article = assembler.finalize(ticket, completed) return final_article

这个循环看起来很朴素,但它把Agent系统最核心的机制都包含了:任务下发、执行、验收、打回、重试。在跑复杂版本之前,先把这个小循环吃透,后面加数据库、加消息队列、加分布式都是在这个骨架上长肌肉。

5.4 三个角色的提示词模板参考

主管的任务拆解提示词我写得非常精简,只要求结构输出:

请将用户需求拆解为最多三个子任务。每个子任务必须包含: - task_id: T1/T2/T3 - input_summary: 对该子任务输入的摘要说明 - acceptance_criteria: 可量化的验收标准 - required_tools: 该子任务允许使用的工具列表 全部内容输出为JSON格式,禁止在JSON之外添加任何文字。

执行者的提示词则要同时约束格式和证据:

你负责完成指定子任务。你只能使用本任务允许的工具。 输出必须为JSON,包含status、content、evidence三个字段。 evidence必须是支撑你关键结论的来源ID列表。 如果无法找到支撑证据,请在evidence中如实标注为empty。 禁止在JSON之外输出任何说明文字。

质检者的提示词重点是验收与结构化反馈:

请对照验收标准检查执行结果。 输出必须为JSON,包含review_verdict、issue_types、issue_positions、suggestion四个字段。 issue_types取值范围:missing_evidence、factual_error、incomplete、out_of_scope。 如果全部通过,issue_types为空数组。 禁止在JSON之外输出任何说明文字。

三个提示词共用了一个原则:结构化输出、边界清晰、禁止在JSON外写闲话。这比把每条规定都写得花团锦簇管用得多。

5.5 跑通之后怎么看结果

第一次跑通这个Demo时,我只关注两件事:第一,任务是否全部在超时时间内完成;第二,质检者的打回次数是否收敛。如果打回次数超过两次,大概率是验收标准写得不够量化,或者执行者缺少必要的输入摘要。通过看每个子任务的入参、出参、消耗Token,基本能定位是哪一环出的问题。别急着加花哨功能,先把这条最原始的链路调到稳定输出,再思考扩展。

6. 从Demo走向实际项目:日志链路、断点恢复与成本控制

6.1 没有trace_id,多Agent系统出了问题根本无处下手

单Agent系统的调试已经够让人头疼了,多Agent系统如果不做链路追踪,情况会变成一场灾难。一个任务经过主管、执行者、质检者、重试、仲裁等多层流转,任何一环出错都可能导致最终结果异常。如果没有全局可检索的日志链路,靠肉眼猜是哪一层出了问题,效率极低。

我从第一天起就给Agent运行加了trace_id。每一次完整任务生成一个trace_id,该任务下的所有子任务、工具调用、模型请求、返回内容都打上这个标记。日志按统一JSON行格式落盘,包含时间戳、角色名、入参摘要、出参结构、耗时、Token消耗。排查问题时直接按trace_id检索,整条链路的所有活动一目了然。这一步看似只是工程习惯,却是项目能持续迭代的基石。

6.2 断点重入:进程崩了不许从头再来

多Agent系统的单次任务可能持续较长时间,中间会出现模型接口超时、进程崩溃、磁盘满等非预期故障。如果每次崩溃都从第一子任务重新执行,Token成本和等待时间都不可接受。

我采用的结果是Checkpoint机制:每个子任务在完成并超出后立即把结果写入本地缓存,缓存持久化到磁盘文件或轻量数据库。系统重启后,调度器先检查哪些子任务已完成,然后从失败位置继续执行。这里我吃过一次亏:早期为了图快,把缓存放在内存字典里,一次进程重启瞬间丢失全部进度,之后我规定无论如何必须落盘。稳重要大于性能,这一步没有商量余地。

6.3 成本与延迟的平衡策略

多Agent系统最大的隐藏成本在模型调用,而很多调用是可以被优化掉的。我目前常用的三个策略:

模型分层。主管这类只要做结构拆解的角色,用最便宜的小模型;执行者用中等档位;质检者做综合判断用最强模型。成本节省效果非常直观,而输出质量几乎没有下降,因为每个角色本来就不需要“过度聪明”。

结果缓存。相同或相似任务的结果缓存起来,再次遇到时直接复用。实现上可以按任务主题和关键参数做一个简易哈希索引,命中缓存就跳过执行。缓存等于净赚的成本。

串并行结合。无依赖的子任务可以并行,有依赖的必须串行。并行度不宜设太高,既容易触发限流,也让日志变乱。我一般从2开始逐步上调,观察限流频率和系统稳定性后再确定最合适的并行值。

6.4 我现在的选型习惯

项目跑到现在,我已经形成一套比较稳定的选型习惯:日常的简单问答、单文件改写、纯文本提取,直接用单Agent,速度快、成本低。一旦任务具备“调研—分析—成稿—校验”这类流水线特征,或者需要多种工具联合参与,才把Agency-Agents这套协作骨架搬出来。多Agent不是万能药,真正的价值在于让复杂任务具备可拆分、可验收、可追溯的结构。对一个偏“功能型”的Agent系统来说,结构其实比聪明更重要。

Agency-Agents这个项目给我的最大收获不是哪段代码跑得多漂亮,而是让我认清了Agent系统的稳定输出从来不是靠一个超强模型、一段超长提示词堆出来的,它要靠边界清晰的职责划分、机器可读的协议和一层层兜底机制才能实现。如果你正在做的项目也出现了类似“单个Agent怎么调都不稳定”的苗头,不妨先别急着换更强的模型,试着把任务拆开,让不同角色各管一摊,再给他们加上超时、预算和验收机制,可能比你想的还要有效。

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

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

立即咨询