ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

多智能体协作实战:agency-agents架构设计与避坑指南

多智能体协作实战:agency-agents架构设计与避坑指南 1. 从“agency-agents”这个标题说起它到底在解决什么问题第一次看到“agency-agents”这个标题我脑子里蹦出来的第一反应是这大概率是一个围绕“代理型智能体”做文章的项目。拆开来看“agency”在技术语境里通常指向“代理、中介、能动性”这几层意思而“agents”则直接对应“智能体、代理程序”。把两个词叠在一起基本可以判断这个项目想干的事情是让一组具备自主决策能力的智能体像一家小型机构那样协同运转去完成单靠一个模型或一段脚本搞不定的复杂任务。我在实际接触这类项目之前也踩过不少坑。最早做自动化的时候习惯写一个大而全的脚本把所有逻辑塞进一个文件里结果就是改一处崩三处调试成本高得离谱。后来慢慢意识到真正能落地的方案往往不是“一个超级智能体包打天下”而是“一群各司其职的小智能体分工协作”。agency-agents 这个标题给我的感觉正是冲着这个方向去的——它强调的不是单个 agent 有多强而是“agency”这个组织形态也就是多个 agent 如何被编排成一个有分工、有协作、有反馈回路的整体。那它具体能做什么按照我对这类项目的理解它通常要解决三类问题。第一类是任务拆解问题一个复杂需求进来怎么自动切成若干可执行的子任务第二类是角色分配问题每个子任务该交给什么样的 agent 去处理是检索型、推理型还是执行型第三类是结果汇总问题多个 agent 的输出怎么合并、校验、去重最后形成一个可交付的结果。这三类问题听起来简单真做起来每一步都是坑尤其是当 agent 数量上去之后通信开销和状态一致性会变成新的瓶颈。这个内容适合谁来参考我的判断是它既适合已经有一定编程基础、想从“单脚本自动化”进阶到“多智能体协作”的开发者也适合那些做业务流程自动化、内容生产流水线、数据分析管道的从业者。哪怕你暂时不写代码只是想理解“多智能体协作”这套思路也能从里面拿到不少可迁移的方法论。接下来我会按照“整体设计思路—核心细节—实操过程—问题排查”这条线把这个项目拆开揉碎讲清楚尽量让不同基础的读者都能找到自己能用的部分。2. 内容整体设计与思路拆解2.1 为什么是“机构”而不是“单体”要理解 agency-agents 的设计得先理解它为什么用“agency”这个词而不是简单叫“multi-agents”。我个人的体会是“agency”强调的是一种组织性和能动性它暗示了这套系统里有明确的角色划分、职责边界和协作规则而不是一堆 agent 随意堆在一起。这就像现实中的一家公司如果只是把一群人塞进一个办公室没有岗位、没有流程、没有汇报关系那效率可能还不如一个人单干。多智能体系统也是同样的道理agent 数量多不等于能力强关键看它们之间有没有形成有效的组织结构。从工程角度看选择“机构化”的设计主要是为了对抗复杂度。单个 agent 的 prompt 一旦超过一定长度模型的注意力就会分散输出质量明显下降。我实测下来当一个 prompt 里同时包含“检索资料、分析数据、生成文案、格式校验”四类指令时模型经常顾此失彼要么漏掉格式要求要么把分析做得很浅。而把这四类任务拆给四个专门的 agent每个 agent 的 prompt 都能保持精简聚焦输出质量反而更稳定。这就是分工带来的收益也是 agency-agents 这类项目存在的根本理由。另一个考量是可维护性。单体脚本改起来牵一发动全身而机构化的多 agent 系统每个 agent 可以独立迭代。比如你发现检索环节召回率不够只需要调整检索 agent 的策略不用动推理和执行环节。这种“局部可替换”的特性在长期维护中价值巨大。我在一个内容生产项目里就吃过亏早期所有逻辑写在一起后来想换一个更好的摘要模型结果发现改动会影响到下游三个环节最后只能推倒重来。如果一开始就按 agent 拆分这种替换成本会低很多。2.2 核心架构的几种常见选型多智能体协作的架构业内常见的有几种模式agency-agents 大概率会用到其中一种或几种的组合。第一种是“流水线式”agent 按顺序排列前一个的输出是后一个的输入像工厂流水线一样。这种模式简单直观适合步骤明确、依赖关系线性的任务比如“抓取数据—清洗数据—分析数据—生成报告”。它的缺点是灵活性差一旦某个环节出错整条线都会卡住。第二种是“主管式”有一个协调者 agent 负责拆解任务、分配角色、汇总结果其他 agent 都是执行者。这种模式适合任务类型多变、需要动态调度的场景。主管 agent 相当于项目经理它不干具体活只负责调度。我比较偏好这种模式因为它对任务变化的适应性强新增一类任务只需要注册一个新的执行 agent主管 agent 学会调用它就行。但它也有风险主管 agent 本身可能成为瓶颈如果它的判断出错整个任务就会跑偏。第三种是“黑板式”所有 agent 共享一块公共状态区谁有需要就读取谁有产出就写入。这种模式适合 agent 之间需要频繁交换中间结果的场景比如多个 agent 协同解一道复杂推理题。它的实现难度最高因为要处理并发写入和状态冲突。agency-agents 如果追求通用性很可能会提供多种架构模板让使用者根据任务特点自己选。我的建议是新手先从流水线式入手跑通了再尝试主管式黑板式留到确实有强协作需求时再上。2.3 通信机制与状态管理的关键取舍多 agent 系统里agent 之间怎么通信是个绕不开的设计决策。常见的方式有两种一种是“消息传递”agent 之间通过显式的消息对象交换信息每条消息包含发送者、接收者、内容和元数据另一种是“共享内存”所有 agent 读写同一个状态对象。消息传递的好处是解耦彻底每个 agent 只需要知道自己要发消息给谁、要处理谁发来的消息不用关心全局状态。缺点是当 agent 数量多、交互频繁时消息管理会变得复杂容易出现消息丢失或循环等待。共享内存的好处是简单直接agent 读写状态就像读写全局变量一样。但它的隐患也明显多个 agent 同时写同一个字段时谁后写谁覆盖很容易出现数据不一致。我在一个小型协作项目里用过共享内存方案结果两个 agent 同时更新任务进度导致进度字段来回跳变排查了半天才发现是并发写入的问题。后来改成消息传递虽然代码多写了一些但稳定性提升明显。状态管理还有一个容易被忽视的点就是“中间结果的持久化”。多 agent 任务往往耗时较长如果中间某个 agent 崩溃没有持久化的话整个任务就得从头再来。我的做法是每完成一个关键步骤就把当前状态序列化存一份这样即使后续环节失败也能从最近的检查点恢复而不是全部重跑。这个习惯帮我省下了大量重复计算的时间尤其是在调用外部接口有配额限制的场景下重跑的代价很高。3. 核心细节解析与实操要点3.1 Agent 的角色定义与 Prompt 设计每个 agent 的核心其实就是它的角色定义和对应的 prompt。角色定义决定了这个 agent“是谁、负责什么、边界在哪”prompt 则决定了它“怎么思考、怎么输出”。我在设计 agent 角色时习惯用一句话把职责说清楚比如“你是一个负责从长文本中提取关键事实的检索 agent你只输出事实列表不做任何推断”。这句话里包含了角色、任务和约束三要素缺一不可。约束条件特别重要因为模型天生有“越界”的倾向。如果你不明确告诉它“不做推断”它很可能在提取事实的同时顺手给你加上几句分析而这些分析会污染下游 agent 的输入。我踩过这个坑检索 agent 输出的内容里混进了主观判断结果推理 agent 把判断当事实用最后结论完全跑偏。从那以后我在每个 agent 的 prompt 里都会加一条“禁止事项”明确列出它不该做的事。Prompt 的长度也要控制。我的经验是单个 agent 的 prompt 最好控制在 500 到 800 字之间太短了约束不够太长了模型注意力分散。如果某个 agent 的职责确实复杂宁可再拆一个 agent 出来也不要硬塞进一个 prompt 里。另外prompt 里的示例很重要给一两个输入输出的样例比写一堆抽象描述管用得多。我通常会给每个 agent 配一个“标准输入—标准输出”的示例让模型照着模仿输出格式的稳定性会明显提升。3.2 任务拆解的粒度控制任务拆解是主管 agent 的核心工作也是整个系统里最容易出问题的地方。拆得太粗子任务还是太复杂执行 agent 搞不定拆得太细agent 数量爆炸通信开销和协调成本飙升。我的一般原则是每个子任务应该是一个“单一职责、可独立验证”的工作单元。所谓单一职责就是这个子任务只干一件事所谓可独立验证就是这个子任务的输出对不对能有一个明确的判断标准。举个例子如果任务是“写一份行业分析报告”拆成“收集资料、分析趋势、撰写报告”就太粗了因为“分析趋势”本身还是个复杂任务。更合理的拆法是“收集近一年的相关数据、提取关键指标、计算同比环比、识别异常波动、总结趋势、撰写报告”。这样每个子任务都有明确的输入输出执行 agent 干起来不费劲验证起来也容易。当然拆解粒度不是越细越好如果拆到“计算某一个指标”这种程度agent 数量会失控协调成本反而超过收益。粒度控制还有一个实用技巧就是“先粗后细动态调整”。主管 agent 第一轮先做粗粒度拆解执行过程中如果发现某个子任务执行 agent 反复失败再触发二次拆解把这个子任务进一步细分。这种动态拆解的方式比一开始就追求完美粒度更务实因为很多任务的复杂度只有在执行过程中才会暴露出来。我在一个数据处理项目里用过这个策略效果不错既避免了过度拆解又能在遇到硬骨头时及时细化。3.3 结果汇总与冲突消解多个 agent 的输出汇总到一起时冲突几乎不可避免。两个检索 agent 可能对同一个事实给出不同的数据两个分析 agent 可能对同一个趋势给出相反的判断。这时候就需要一套冲突消解机制。最简单的做法是“投票”多数 agent 的意见为准。但投票有个前提就是各个 agent 的可信度差不多如果有的 agent 明显更可靠投票就不公平了。更合理的做法是“加权投票”或“置信度排序”。给每个 agent 的输出附一个置信度分数汇总时按置信度加权。置信度怎么来可以让 agent 自己在输出时评估也可以由主管 agent 根据历史表现来打分。我通常会让 agent 在输出里带一个“置信度”字段虽然模型自评的置信度不一定准但至少提供了一个排序依据。实测下来结合历史准确率做加权比单纯投票的效果好不少。还有一种情况是“信息互补”而非“信息冲突”这时候就不需要消解而是需要合并。比如一个 agent 提供了数据另一个 agent 提供了背景两者并不矛盾合并起来信息更完整。所以汇总环节的第一步应该是判断多个输出之间是“冲突”还是“互补”。冲突的走消解流程互补的走合并流程。这个判断本身也可以交给一个专门的汇总 agent 来做它的职责就是“读懂所有输入判断关系决定合并还是消解最后输出统一结果”。4. 实操过程与核心环节实现4.1 环境准备与基础依赖动手之前先把环境理清楚。这类多 agent 项目通常需要一个能调用大模型接口的运行环境Python 是最常见的选择因为生态成熟、库多。我一般会建一个独立的虚拟环境避免依赖冲突。基础依赖包括模型调用库、异步任务库、状态管理库以及可选的日志和监控库。异步任务库很关键因为多个 agent 并行执行时同步调用会拖慢整体速度用异步能明显提升吞吐。配置管理也要提前规划。模型接口的密钥、超时时间、重试次数这些参数不要硬编码在代码里统一放到配置文件或环境变量里。我见过太多项目因为密钥写死在代码里换环境时到处找、到处改最后还漏了一处导致线上报错。配置文件建议分环境管理开发、测试、生产各一套用的时候按环境变量切换。另外超时和重试参数要根据实际接口的稳定性来调接口不稳定就把重试次数调高但要注意重试可能带来的重复调用问题。日志系统在调试阶段价值极高。多 agent 系统的执行路径复杂出问题时如果没有详细日志根本不知道是哪个 agent 在哪一步出了错。我的做法是每个 agent 的每次输入输出都记一条日志带上时间戳、agent 名称、任务 ID。这样出问题时顺着任务 ID 就能把整条执行链路串起来。日志级别也要分清楚调试信息用 debug关键节点用 info异常用 error别一股脑全打成 info不然日志文件会大到没法看。4.2 主管 Agent 的调度逻辑实现主管 agent 是整个系统的大脑它的调度逻辑直接决定了任务能不能顺利跑完。我实现主管 agent 时通常分三步走。第一步是“任务解析”把用户输入的原始需求解析成结构化的任务描述包括目标、约束、期望输出格式。这一步可以用模型来做也可以用规则来做看需求的规范程度。需求越不规范越依赖模型解析需求越规范规则解析越稳定。第二步是“任务拆解与分配”根据任务描述拆出子任务列表并给每个子任务匹配执行 agent。匹配的依据是 agent 的能力描述每个执行 agent 注册时都要声明自己擅长什么主管 agent 根据子任务的需求去匹配。这里有个细节就是“能力描述”要写得具体不能太笼统。比如“擅长处理文本”就太宽泛“擅长从长文本中提取结构化事实”就具体得多匹配起来更准。第三步是“执行监控与结果汇总”主管 agent 要跟踪每个子任务的执行状态处理失败重试最后把所有子任务的输出汇总成最终结果。监控环节要设置合理的超时某个子任务卡太久要么重试要么跳过不能让整个任务无限等待。我一般会给每个子任务设一个超时上限超时后先重试一次再失败就标记为“部分完成”继续往下走最后在汇总时说明哪些部分没完成。这种“尽力而为”的策略比“一处失败全盘中止”更实用。4.3 执行 Agent 的标准化接口执行 agent 要实现一个标准化的接口这样主管 agent 才能统一调度。这个接口通常包括几个方法初始化、执行任务、返回结果、清理资源。初始化方法负责加载配置、建立连接执行任务方法接收子任务描述返回执行结果返回结果要遵循统一的格式方便主管 agent 解析清理资源方法负责释放连接、关闭文件等。统一的结果格式很重要。我一般会定义一个结果对象包含状态码、输出内容、置信度、错误信息、耗时这几个字段。状态码标明成功还是失败输出内容是实际结果置信度用于汇总时的加权错误信息在失败时提供排查线索耗时用于性能分析。所有执行 agent 都返回这个格式主管 agent 处理起来就不用为每个 agent 写特殊逻辑代码简洁很多。接口标准化还有一个好处就是方便替换和扩展。想换一个更好的检索 agent只要新 agent 实现了同样的接口直接替换就行主管 agent 那边不用改任何代码。想新增一类能力注册一个新 agent 并声明能力描述主管 agent 就能自动发现并调用它。这种“插件化”的设计让系统的可扩展性大大提升。我在实际项目里就是靠这套接口把检索 agent 从规则匹配换成了模型匹配整个过程只改了一个注册配置其他代码一行没动。4.4 一次完整任务的执行记录拿一个具体任务来走一遍流程会更清楚。假设任务是“分析某类产品的市场反馈并生成摘要”。主管 agent 先解析任务识别出目标是“分析反馈并生成摘要”约束是“基于给定数据”期望输出是“一段摘要文本”。然后拆解成子任务收集反馈数据、清洗数据、提取关键观点、统计观点分布、生成摘要。接着匹配 agent收集和清洗交给数据处理 agent提取和统计交给分析 agent生成摘要交给写作 agent。执行阶段数据处理 agent 先跑把原始数据整理成干净的结构化数据。分析 agent 拿到数据后提取出若干关键观点并统计每个观点出现的频次。写作 agent 最后拿到观点和频次生成一段摘要。主管 agent 在每个环节结束后检查输出确认格式正确、内容非空再触发下一个环节。整个流程跑下来如果数据量不大通常几分钟内能完成。这个过程中我特别关注两个点。一是“数据传递的完整性”每个 agent 的输出要完整传给下一个 agent不能丢字段。我遇到过因为结果对象序列化时漏了字段导致下游 agent 拿不到关键信息的情况排查起来很费劲。二是“异常处理”某个 agent 失败时主管 agent 要能捕获异常记录日志决定是重试还是跳过。这两点做好了整个流程的稳定性就有保障。5. 常见问题与排查技巧实录5.1 Agent 输出格式不稳定的排查输出格式不稳定是多 agent 系统里最高频的问题。表现是同一个 agent同样的输入有时候输出 JSON有时候输出纯文本有时候字段名还变了。这个问题八成出在 prompt 上。模型对格式的遵循程度跟 prompt 里格式说明的明确程度直接相关。如果 prompt 里只是说“输出 JSON”模型可能给你输出带 markdown 代码块的 JSON也可能输出不带代码块的还可能字段名用中文。解决办法是把格式约束写到极致。第一明确给出字段名和字段类型最好给一个完整的示例。第二明确禁止额外内容比如“只输出 JSON不要有任何解释文字不要用代码块包裹”。第三如果模型还是不稳定可以在输出后加一层格式校验和修复用正则或解析库把内容提取出来格式不对就重试。我通常会把“格式校验失败就重试”做成一个通用机制所有 agent 的输出都过一遍校验不合格就让它重新生成重试两三次还不行就报错。还有一个技巧是“降低温度参数”。温度越高输出越随机格式越不稳定。对于需要严格格式的 agent把温度调到接近 0输出会稳定很多。当然温度太低也有副作用就是输出可能过于死板缺乏变化。所以我的做法是格式要求高的 agent 用低温创意类 agent 用高温按需调整。5.2 任务卡死与循环依赖的处理任务卡死通常有两种原因一种是某个 agent 执行超时另一种是 agent 之间形成了循环依赖。超时问题好办给每个 agent 调用设一个超时上限超时就中断并记录。循环依赖麻烦一些比如 A 等 B 的输出B 等 A 的输出两者互相等待永远跑不完。这种问题在流水线架构里少见在主管式和黑板式架构里更容易出现。排查循环依赖我的方法是画一张依赖图把每个 agent 的输入依赖和输出产出标出来看有没有环。如果有环就要打破它要么调整任务拆解让依赖关系变成单向的要么引入一个“中间协调 agent”由它来打破循环先给一方一个初始值让流程能启动起来。我在一个协作推理项目里遇到过循环依赖两个 agent 互相等对方的结论最后是靠引入一个“假设生成 agent”打破的它先给一个初始假设两个 agent 基于假设各自推理再汇总修正。预防循环依赖最好的办法是在设计阶段就把依赖关系理清楚。我的习惯是在拆解任务时顺手画一张依赖图确保没有环。如果发现环当场调整拆解方案别等到运行时才暴露。这个习惯帮我省了很多调试时间因为运行时的循环依赖往往表现为“任务一直不结束”很难定位到具体是哪两个 agent 在互相等。5.3 结果质量波动的优化思路结果质量波动表现为同样的任务有时候输出很好有时候输出很差。这个问题往往不是单一原因造成的需要系统排查。我一般从三个方向入手。第一是“输入质量”检查上游 agent 的输出是不是稳定如果上游输出时好时坏下游自然跟着波动。第二是“prompt 稳定性”检查 prompt 里有没有模糊表述模糊表述会让模型每次理解都不一样。第三是“模型参数”检查温度、top_p 这些参数是不是设得过高过高会导致输出随机性大。优化质量波动我常用的手段是“加约束、加示例、加校验”。加约束是把模糊表述改成明确规则比如把“尽量简洁”改成“不超过 100 字”。加示例是给一两个标准输入输出样例让模型有参照。加校验是在输出后做质量检查不合格就重试。这三招组合起来质量稳定性通常能提升一个档次。另外如果某个 agent 的质量始终上不去可以考虑换一个更适合的模型不同模型在不同任务上的表现差异很大多试几个往往能找到更合适的。还有一个容易被忽视的点是“上下文长度”。如果传给 agent 的上下文太长模型可能抓不住重点输出质量下降。我的做法是在传给 agent 之前先做一轮上下文压缩把无关信息去掉只保留关键内容。这个压缩步骤可以交给一个专门的 agent 来做也可以在上游 agent 输出时就控制长度。上下文精简了模型注意力集中输出质量自然更稳。5.4 常见问题速查表问题现象可能原因排查方向解决建议输出格式不稳定prompt 格式约束不明确检查 prompt 是否有完整示例和禁止项加示例、加禁止项、降低温度任务一直不结束循环依赖或超时未设画依赖图检查是否有环打破循环设置超时上限结果质量波动大输入不稳或参数过高检查上游输出和模型参数加约束、加校验、调低温度某个 agent 反复失败职责过重或 prompt 过长检查该 agent 的任务复杂度拆分 agent精简 prompt汇总结果冲突多缺少冲突消解机制检查汇总逻辑引入加权投票或置信度排序执行速度慢同步调用或串行执行检查是否用了异步改异步能并行的并行这张表是我在实际项目中慢慢攒出来的基本上覆盖了八成以上的常见问题。遇到新问题先对照这张表排查能省不少时间。当然每个项目的情况不一样表里的建议是通用方向具体怎么调还得结合实际情况。6. 我在这类项目里踩过的坑和攒下的经验做多 agent 项目这几年踩的坑不少有些坑现在想起来还觉得冤。最大的一个坑是“过度设计”。刚开始做的时候总想着把架构做得尽善尽美agent 分得特别细通信机制设计得特别复杂结果就是开发周期长、调试难度大最后跑起来的效果还不如一个简单方案。后来我悟了多 agent 系统的复杂度应该跟任务复杂度匹配任务简单就别上多 agent一个 agent 加几个工具函数可能就够了。多 agent 的价值在于处理那些“单 agent 搞不定”的任务如果任务本身不复杂硬上多 agent 就是自找麻烦。第二个坑是“忽视可观测性”。早期我觉得日志不重要代码能跑就行结果出问题时两眼一抹黑不知道错在哪。后来我强制自己每个 agent 的输入输出都记日志关键节点打时间戳任务 ID 贯穿全流程。这套可观测性做起来后排查效率提升了好几倍。现在我的原则是可观测性不是可选项是必选项宁可多花半天做日志也不要花两天排查一个本可以五分钟定位的问题。第三个坑是“prompt 写得太随意”。早期写 prompt 跟写便签似的想到哪写到哪结果就是输出质量全靠运气。后来我总结了一套 prompt 模板包含角色、任务、约束、示例、禁止项五个部分每个 agent 的 prompt 都按这个模板来写。模板化之后输出稳定性明显提升而且新人接手时也容易理解。这个模板我现在还在用算是踩坑踩出来的经验。最后分享一个小心得多 agent 系统的调试最好从“两个 agent”开始。先让两个 agent 跑通一个简单任务确认通信、状态、汇总这些基础机制没问题再逐步增加 agent 数量。一上来就搞五六个 agent出问题时根本不知道是哪个环节的锅。从简到繁逐步验证这个策略帮我省了很多返工的时间。另外每个 agent 最好能单独测试给它一个固定输入看输出是否符合预期单独测通了再放进系统里联调这样定位问题会快很多。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进