ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

多智能体协同实战:从零搭建Agent工作流

多智能体协同实战:从零搭建Agent工作流 有段时间我一直在琢磨一个问题为什么单个大模型在面对真实复杂任务时总是“差点意思”。让它调研市场写出来的内容太空让它写方案数据引用又错得离谱让它同时做多件事做到一半之前的信息就忘了。后来我开始认真研究多智能体协同也就是把任务拆给一群不同角色的智能体去干才慢慢意识到问题出在哪——我们一直在用“一个人”的方式组织AI而真实的生产流程本身就是“一个机构、多个岗位、各司其职”的模式。agency-agents这个方向说白了就是想把这种机构化的协作方式落到代码层面每个Agent是一个角色有自己明确的职责、工具和输出标准通过调度、校验和共享记忆像一个虚拟团队一样把任务从头干到尾。这篇文章我打算把这类项目的设计思路、核心实现、配置细节和调试经验一次讲透尤其适合那些已经会用大模型API、但不想只做“单轮问答”的开发者和产品人。1. 项目概述带着“机构思维”重新设计AI工作流1.1 “agency”这个词到底指什么第一次看到agency-agents这个命名时很多人会困惑agency是“代理机构”还是“代理行为”如果把它放到AI多智能体系统的语境里我倾向于理解为两者兼有。英文里agency有两个核心意思一个是“代理人/机构”强调组织性和分工另一个是“能动性/自主性”强调个体可以独立做决定。一个多智能体系统如果把这两层打通它就不再是“多个提示词拼在一起”而是一套真正有岗位责任、有工作流、有输出质量的虚拟组织。这种设计的直接好处是把“大模型不可控”的风险拆散到不同环节里去管理。你不需要一个超强的全能模型只需要几个很专注的角色各自只做一件事。比如一个角色只负责从原始资料里提炼要点它不写结论另一个角色只负责把要点写成文章它不需要做调研第三个角色只负责挑毛病它的任务就是找茬。这种分工方式表面上增加了系统复杂度实际上却让整体输出的稳定性大幅提升。因为每个环节的输入输出都变简单了模型犯错的概率自然就降下来了。所以这个项目要解决的核心问题不是“怎么调用大模型”而是“怎么把一个大任务拆成多个可以被不同角色可靠执行的小任务再把结果拼装成高质量产出”。它是一个编排层站在模型API之上用代码来定义角色、路由任务、传递上下文、校验结果。如果你已经厌倦了写一次性的prompt调用脚本想构建一个能长期复用、支持复杂流程的AI应用底座这套思路就是你绕不开的一课。1.2 单Agent的瓶颈在哪单纯用一个Agent跑复杂任务最容易遇到的瓶颈有三个。第一个是上下文污染。让一个Agent同时承担“阅读长文档、做分析、写报告”时它必须把一大堆中间结果塞进上下文窗口里或者依赖模型自己“记住”前面的信息。可模型没有真正意义上的记忆它只会反复阅读你塞进去的token。任务越多上下文越堆越长费用越高而模型注意力反而会被无关信息稀释输出质量直线下降。第二个是角色冲突。同一个Agent既当“执行者”又当“审查者”时几乎不可能公正地审查自己的劳动成果。你会发现它写错了数据也照单全收因为它内在的自我一致性倾向会让它倾向维护自己之前的输出。现实中你也不会让写稿的人自己审核自己的稿子AI也一样。第三个是容错困难。单Agent一旦在某一步出错整个流程就坏了。没有中间校验没有独立评审很难定位错误发生在哪一步。而多Agent系统可以通过角色之间的交叉检查把错误拦截在早期环节。机构思维的核心意义就在这里不是把模型变聪明而是把一套生产流程的可靠性管理体系搬过来。1.3 技术选型轻编排优于重框架我在设计这类系统时没有一上来就套某个全流程框架而是先做轻量编排理由很简单重框架的抽象层太多调试链路太长。很多现成的Agent框架自带大量封装出了问题你都不知道是该查调度层、记忆层还是工具调用层。所以我建议自己维护一个精简的“角色注册表 消息路由器 任务状态表”。角色注册表描述谁是谁、它能干什么消息路由器决定一份输出该交给谁任务状态表负责记录每一步的输入输出、耗时、token消耗和校验结果。这套结构在初期只需要几百行核心代码完全够用。等流程成熟了再考虑引入更重的工具链。用这种方式任何一个环节出问题你打开状态表就能看到哪一步挂了、消耗了多少、返回了什么排查效率远高于黑盒框架。2. 核心功能设计把一个Agent拆成一个虚拟团队2.1 角色定义把提示词升级成岗位说明书在agency-agents类型的系统里角色不再是一段孤立的system prompt而是一份“岗位说明书”通常包含四部分职责范围、输入协议、输出协议、可用工具。职责范围划定这个Agent只能做什么、绝不做什么输入协议规定它接收什么样的数据结构输出协议规定它返回什么格式的结果可以是结构化JSON、纯文本、代码块或者一个决策建议可用工具列出它能调用的外部能力比如搜索、数据库查询、计算器。举个例子一个“资料分析员”角色的输出协议可能是“只返回JSON包含source、key_points、confidence三个字段”。这样下游的写作Agent拿到这份JSON时不用自己去大段文本里找重点直接按字段拼接内容就行。这种设计最大的意义是解耦。角色之间不需要理解彼此的语言习惯只需要遵守统一的协议就像不同部门的同事用固定的表格模板交接工作。配置上我习惯用YAML文件来维护角色定义理由是可读性好、方便非技术人员参与调整。系统启动时加载这个文件动态生成Agent对象。每次要调整某个角色的定位或约束改配置文件即可不用动代码。这在实际项目里特别实用因为角色分工往往是要和业务方反复对齐的改代码的方式太慢。2.2 任务协作模式流水线、主管-员工、评审闭环多Agent系统里角色之间到底怎么配合我总结下来主要有三种高频模式。流水线模式适合上下游非常明确的任务。比如“先调研再写稿再发布”每一步的输出就是下一步的输入任务像工厂流水线一样走完。这种模式实现最简单用循环就能搞定但缺点是中间没有反馈回路前面的错误会直接传导到后面。主管-员工模式适合需要动态决策的任务。一个主管Agent负责拆解任务、分派给不同员工Agent、汇总它们的产出。比如“我有一批用户反馈请把它们分成三类每类给出一份改进建议”主管先把任务分配给三个分类Agent再汇总结果。这种模式灵活但要注意设置好主管的上下文容量别让它把所有的原始输入都读一遍否则费用和延迟都会很头疼。评审闭环模式是我在内容生成类项目里用得最多的。它让一个写作Agent先产出初稿然后另一个评审Agent拿着“质检标准”去挑毛病再把修改建议返回给写作Agent重新修改最多循环2-3轮。这相当于在系统里内置了一个“自我修正机制”。实测下来经过一轮评审和修改的内容明显比单轮生成的要完整尤其在数据正确性和逻辑一致性方面提升最明显。三种模式还可以组合。我通常的做法是先用流水线建立主干流程在关键环节插入评审闭环在需要多路并行的任务上用主管-员工模式做分支扩展。整套预案想清楚之后再动手写代码会顺畅很多。2.3 共享记忆与上下文管理别让Agent“忘事”多Agent系统最容易被忽略的工程细节是共享记忆。Agent本身没有记忆每次调用API都是全新会话。你既不能指望它记住上一轮说了什么也不能把全部历史都塞进下一轮调用那样成本会爆炸。我的做法是维护一个轻量的记忆池分三层。短期工作记忆存当前任务的中间结果通常就是各Agent输出的一小段摘要随任务结束而清空长期知识库存那些跨任务复用的信息比如用户偏好、数据字典、术语定义任务状态表记录每一步的调用记录方便追溯和回滚。在具体实现上短期工作记忆就是一个字典键是“环节名”值是“该环节产出的结构化摘要”长期知识库则落到一个简单的向量检索或直接就是一个SQLite表。关键技巧是Agent之间传递消息时不要传长文本只传结构化摘要。比如调研Agent产出3000字的分析传给写作Agent之前先用一段代码把它压缩成“结论、核心论据、数据来源”三个要点。这样一来写作Agent的上下文输入量可能只有原来的五分之一输出质量反而更高因为它没有被无关细节干扰。这个“中间产物摘要化”的做法是我在这个项目里学到的最值得分享的经验之一。3. 核心实现从零搭一个轻量级多Agent工作流3.1 目录结构与运行环境下面我给出一个可以直接抄作业的简化实现思路。运行环境只需要Python 3.10及以上依赖一个能调用大模型API的HTTP客户端就行比如requests或者任何兼容OpenAI接口的SDK。核心目录长这样agency_demo/ ├── config/ │ └── agents.yaml # 角色与流程定义 ├── core/ │ ├── agent.py # Agent对象与调用逻辑 │ ├── dispatcher.py # 任务调度、消息路由 │ ├── memory.py # 三层记忆池 │ └── validator.py # 输出格式校验 ├── main.py # 入口加载配置并启动流程 └── logs/ └── run_20250101.log # 运行日志为什么把这个结构单独拎出来说是因为我发现很多人一开始就把Agent的调用逻辑和业务流程混在一起写最后代码根本没法复用。把“角色”和“流程”拆开让角色定义在配置文件里让流程在dispatcher里跑再加一个validator在关键节点做检查这套分层在后面接RAG、接工具、接人工审核时都会轻松很多。3.2 Agent类的骨架代码Agent类的实现核心不是调用模型本身而是把系统提示词、输入消息、工具列表组装成一次标准的模型请求。下面这段代码为了突出主干逻辑我做了简化实际生产环境还需要加上超时、重试和token统计。from dataclasses import dataclass, field from typing import List, Optional dataclass class Message: sender: str receiver: str content: str msg_type: str text metadata: dict field(default_factorydict) dataclass class Agent: name: str # 角色名 role: str # 角色职责描述 system_prompt: str # 系统提示词 max_tokens: int 2000 # 单次调用最大输出长度 temperature: float 0.3 # 输出随机性 tools: List[str] field(default_factorylist) def run(self, incoming: Message, memory: dict) - Message: # 组装模型请求system_prompt 结构化上下文 历史摘要 prompt build_prompt(self, incoming, memory) # 调用兼容OpenAI格式的接口省略具体HTTP细节 raw_output call_llm( systemself.system_prompt, userprompt, max_tokensself.max_tokens, temperatureself.temperature ) # 校验并结构化输出 validated validator.validate_output(self.name, raw_output) return Message( senderself.name, receiverdispatcher, contentvalidated, metadata{tokens: count_tokens(raw_output)} )这段代码里最关键的一点是每个Agent只接收一条“统一格式的消息”而不是自己去翻历史记录。这样下游消息的构造变得非常可控你只需要决定“上一步的哪个字段要传给下一步”。3.3 Dispatcher怎么把任务路由到正确的角色Dispatcher是这套系统的中枢。它的职责很简单读配置里的流程定义按顺序把任务交给对应的Agent并把Agent的返回值存进记忆池。下面是一个流水线模式的调度核心逻辑class Dispatcher: def __init__(self, agents: dict, memory: Memory): self.agents agents self.memory memory def run_pipeline(self, flow: list, initial_input: dict) - list: current_payload initial_input execution_log [] for step in flow: agent_name step[agent] agent self.agents[agent_name] # 组装该步骤的输入消息 msg Message( senderdispatcher, receiveragent_name, contentformat_as_content(current_payload, step.get(template, {content})), metadata{step_id: step[id]} ) # 执行Agent result_msg agent.run(msg, self.memory.get_context(agent_name)) # 沉淀到任务状态表 execution_log.append({ step: step[id], agent: agent_name, status: ok, tokens: result_msg.metadata.get(tokens, 0), output_preview: str(result_msg.content)[:200] }) # 让下游步骤能拿到最新输出 current_payload result_msg.content return execution_log看到没有这个实现里没有写死任何业务逻辑它不是“调研Agent然后写稿Agent”而是“读配置按step列表跑”。你改不同业务只需要换config里的agents.yaml不换Dispatcher代码。这种抽象看起来平淡但它才是让这套系统在多个项目里复用的关键。3.4 一个实际Demo三步完成“数据分析写稿质检”下面给一个完整示例。设想我拿到一批用户反馈需要输出一份《用户需求分析报告》。我配置了三个角色和一个三步流程。agents: - name: analyst role: 用户反馈分析师 system_prompt: | 你是一名资深用户反馈分析师。输入是一批真实用户反馈原文 请提炼出高频需求、痛点、期待功能三类要点 只输出JSON{demands: [], pain_points: [], expectations: []} 不要输出任何解释文字。 max_tokens: 1500 temperature: 0.2 - name: writer role: 报告撰写者 system_prompt: | 你负责把分析结果改写成一份结构清晰、语言平实的需求分析报告。 报告需包含背景、核心发现、行动建议三个部分。 只输出Markdown正文。 max_tokens: 3000 temperature: 0.6 - name: reviewer role: 质量评审员 system_prompt: | 你负责检查报告的数据引用、逻辑一致性、可执行性。 逐条列出问题并给出修改建议。 只输出问题清单和修改建议不要重写全文。 max_tokens: 1500 temperature: 0.2 flow: - id: analyze agent: analyst template: 用户反馈原文\n{content} - id: write agent: writer template: 分析结果\n{content} - id: review agent: reviewer template: 待审稿\n{content}主流程里我还会加一步把reviewer的输出拼成一段“修改指令”再让writer改一版。这样整个输出结构就变成“分析→写稿→挑错→改稿”。跑一把下来报告的完整度确实比我以前单Agent一次生成的版本好很多尤其在“行动建议”部分Reviewer会揪出很多模棱两可的表述逼着Writer改得更具体。3.5 单Agent和多Agent的对照观察我在拿到一个模拟项目X一批含四个维度的客服反馈数据时专门做了一次同题对比。单Agent方案是“直接让一个模型生成报告”多Agent方案就是上面这个流程。我观察到的差别很明显整理成一个表格供你参考项目单Agent一次生成多Agent分析→写稿→评审→改稿报告结构完整度中等有时缺行动建议高每个模块都有专门角色把关数据引用准确性约七成数据能对上原文评审环节会把引错的数据挑出来重写内容泛化程度偏套话通用建议多偏具体能落到细节总token消耗约1份约2-2.5份端到端时间快慢1-2倍人工返工比例较高明显降低token和时间成本确实上去了但换来的是稳定性和可干预性。在真实业务里我宁可多花一倍token也不愿意在交付时发现整篇报告逻辑不通、数据错乱那种返工成本才是真吓人。此外多Agent还有一个隐性的好处评审角色给出的问题清单本身就是一份“可追溯的质检文档”交付给客户或领导时很有说服力不像单Agent生成的报告改没改过、改得对不对都说不清。4. 实操过程跑通一个最小闭环后如何横向扩展4.1 第一步最小的三个角色闭环无论你最终想把项目做成什么样我强烈建议第一步就做最简的三角色闭环一个执行角色、一个评审角色、一个修改角色。拿“翻译校对”举例执行角色负责翻译评审角色负责找语法错误和漏译修改角色拿着评审意见改。这只需要三个配置项、一个Dispatcher外加一圈简单的for循环一天之内就能跑通。跑通后你真正要做的事不是加更多角色而是观察每一次运行的状态。重点看三样东西每步token消耗占整个流程的比例、评审角色有没有“空转”每次都说没问题、修改角色有没有把评审意见真正落地。这些观察会告诉你系统的瓶颈到底在执行环节的模型能力还是流程本身设计不合理。很多人的多Agent系统性能差都不是模型的问题而是评审角色根本没起到作用它本身就是个复读机。4.2 第二步把外部工具接入Agent角色只靠大模型自身能力很多事还是干不了。比如分析用户反馈之前最好先查询数据库写报告之前最好搜索内部知识库。这时就需要给Agent加工具调用能力。我的做法是在配置里给Agent声明tools字段Dispatcher在组装消息时如果发现当前Agent声明了某个工具就在模型输出里预留一个“工具调用意图”字段解析到意图后先执行工具再把工具结果作为下一轮上下文喂回给模型。这个流程用代码实现也不复杂核心是让工具注册表和管理角色分离。工具注册表是一个dictkey是工具名value是一个函数。Agent不直接调用函数而是返回一个“参数JSON”Dispatcher看到后替它执行。这样Agent永远只是“提出请求”真正干活的是可信的代码而不是模型的自由发挥。这个约束非常重要能有效防止模型生成幻觉数据因为工具返回的真实数据会覆盖掉模型瞎编的内容。4.3 第三步加入人机协同确认点在多Agent系统里不是每一步都适合全自动跑完。我强烈建议在两类节点加入人工确认一类是高成本操作比如给大量用户发通知、调用付费第三方API另一类是决策性节点比如最终报告发布前的签字。实现方式是在Dispatcher的流程定义里加一个“mode: human_review”的步骤Agent产出结果后不直接进入下一步而是推到一个审核队列由人工在Web界面里点击通过或打回修改。这个设计在实际使用时特别重要。因为AI做到最后总是会有一些灰色地带的判断你不可能让系统百分百自主。人工确认点不是偷懒而是给系统留一道安全阀。随着你跑的次数变多你自然会知道哪些节点必须人看、哪些节点可以让模型自己跑这时候再把人工节点逐步取消系统自动化程度才会健康地往上升。5. 常见问题与排查技巧实录5.1 上下文污染Agent之间传了不该传的信息这个问题我在早期项目中踩过好几次。执行Agent输出的时候偶然会把一些思考过程、备选方案甚至自己的“吐槽”也带上然后这些内容被当成正式输出传给下游。下游Agent拿到的输入里混着大量噪声它当然不知道该听哪句产出自然就乱套了。解决办法是在validator里做“协议强校验”。每个角色的输出协议明确规定了字段validator在把结果写入记忆池之前先检查字段是否存在、类型是否正确、有没有多余内容。发现不合格就返回给该Agent重写一次最多重试两次。实测下来加入这个校验之后跨Agent传递的消息质量明显稳定很多下游角色“看不懂上下文”的情况几乎消失。本质上你不是在管模型说什么而是在管它输出的边界。5.2 死循环评审Agent永远说“再改改”当评审Agent和修改Agent组成闭环时一个容易踩的坑是死循环。评审Agent每次输出都是泛泛的语言比如“请进一步优化表达”“请增强逻辑性”修改Agent无从下手改完一轮评审又说同样的话两边就这样空转到预算耗尽。这个问题本质上是评审Agent的“标准”太模糊没有把问题具体化。我的解决办法是给评审Agent的输出协议加硬性要求每条问题必须包含原文引用、问题类型、修改建议三个字段而且必须是一次性列完整。如果它输出不了具体问题点那就视为通过。与此同时给循环加上限最多改两轮。两轮之后无论评审是否还满意直接把结果交给人工。这样既保留了评审的价值又避免了无意义的空转。5.3 上下文冗余每个Agent都在读全文有一段时间我的token消耗涨得很厉害去看日志才发现问题出在流程设计上调研Agent产出了很长的综合材料写作Agent在下游读取时把整份材料都塞进去了。随着流程中出现第三个、第四个角色同样一份长文本被读了好多遍成本自然成倍上涨。后来我改成“按字段路由”的策略。在流程定义里每一步的template不再写死{content}而是写{content.demands}这类字段路径。也就是说写作Agent只能看到前一步输出里“Demands”字段的内容其他非相关内容一概不传。这个改动让流程总token消耗下降了大约四成关键节点的输出质量反而提升了因为模型注意力没被无关信息稀释。这个“字段级路由”的习惯在项目一开始就应该建立中途再改会比较痛。5.4 工具调用失败三个排查方向多Agent系统接了外部工具后出错率最高的环节往往就在工具调用上。排查时我一般按三个方向走先看Agent输出的工具调用参数是否合法比如JSON解析是否成功、参数名和工具期望的是否一致再看工具本身执行是否超时或返回了异常最后看工具返回的数据格式是否能被Agent正常读取。最容易出问题的是第二个方向因为外部API时有抖动一旦工具没返回合法数据Agent会开始“脑补”结果然后一本正经地往下走这才是最危险的。针对这个隐患我做了一个小改良所有工具返回都给一个status字段status不是ok就直接短路不让Agent继续往下推理。宁可让整个流程在这一步停下来也不能让模型拿幻觉数据往下生产内容。对自动化系统来说明确的失败永远比虚假的成功要好处理。5.5 看日志的一些个人习惯多Agent系统调试时日志设计比代码功能本身还重要。我每跑一个任务任务都会输出四条日志线第一条记录流程开始前的配置快照第二条记录每一步的输入摘要和输出摘要第三条记录每一步的token消耗与耗时第四条记录人工确认节点的操作结果。这样任何一个环节拐了弯我都能在事后快速定位。我尤其习惯把“输入摘要”压得很小只保留前100个字符。因为真正的历史细节在记忆池里有日志只是用来快速定位不需要冗余。最近一次排查一个跑偏的案例时我就是靠日志里输出摘要的变化发现某一步传入的字段路径配错了导致下游Agent拿到了一份旧数据。日志简短反而让问题浮出水面。6. 从最小闭环到扩容一点经验总结6.1 先别急着加角色先稳住协议很多人看到多Agent效果不错第一反应是加更多角色什么“翻译官”“润色师”“风格审校”配置越堆越多流程越拖越长。我的真实教训是角色一多流程的延迟和token成本都会成倍增加而且角色之间互相提意见的情况也会变多系统反而更难控制。稳妥的做法是保持最小闭环不变通过优化每个角色的提示词、输出协议和校验逻辑来提升质量等你发现某个环节确实需要专职角色时再以“最小增量”的方式加进去。角色扩容时的准则是我个人的经验之谈每加一个角色必须回答三个问题——它负责的环节是不是当前产出的瓶颈它的输入和输出协议能不能和前一步、后一步无缝衔接它的判断标准是否足够客观三个问题都说不出明确答案的角色大概率只是在增加噪音。6.2 从编排到产品化的最后一步如果这套多Agent工作流要交付给其他人使用最后还需要补一块“人机交互层”。我会在Dispatcher外面包一个简单的Web管理界面把任务提交、进度查看、人工确认、结果审计都放进去。这一步看起来是纯前端工作但对项目落地非常关键。因为真正使用系统的人不是开发者他们需要一个直观的入口看到“现在跑到哪一步了”“为什么卡住了”“这个结果是谁生成的”。我建议把“流程可观测性”当作产品功能来做而不是调试工具。界面上不仅展示每个Agent的状态还展示每个Agent的输入来源和输出摘要。这样使用方一旦发现结果有问题可以直接指出是哪一步不对而不是只能对着最终结果干着急。把多Agent系统从“代码玩具”升级成“生产工具”靠的往往就是这一点点工程化投入。做这类项目到现在我最大的体会不是模型本身有多重要而是“分活”的能力决定系统上限。把大任务拆到什么粒度、什么信息必须结构化传递、哪个环节必须有人确认这些才是真正的技术含量。一次失败的产品实验告诉我说不要在系统不稳定的时候过早追求“全自动化”先让人和Agent一起跑慢慢找到双方的信任边界再逐步把确定性高的环节自动化。多Agent不是银弹它是一套需要长期打磨的组织方式而乐子恰恰在这个打磨过程中。
RELATED READING

延伸阅读

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