ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

从ReAct到多Agent协作:架构演进与工程化落地实践

从ReAct到多Agent协作:架构演进与工程化落地实践

1. 从单兵作战到团队协同:AI Agent 架构到底在演进什么

第一次接触 ReAct 范式是在做一个内部知识问答工具的时候。当时的需求很朴素:用户问一个问题,模型能自己判断要不要查资料、查完再回答。我按照 ReAct 的思路搭了一版,跑通的那一刻确实挺兴奋——模型会输出“思考、行动、观察”这样的循环,看起来真的在“推理+执行”。但真正上线之后问题就来了:一个稍微复杂的任务,比如“帮我对比三份文档里的关键指标并生成结论”,单 Agent 就开始顾此失彼,要么忘了中间结果,要么在工具调用上反复横跳,最后给出的答案东拼西凑。

这就是我想聊这个话题的起点。从 ReAct 到多 Agent 协作,本质上不是“模型变聪明了”,而是工程上对“复杂任务如何拆解、如何分工、如何收敛”的一次系统性回答。ReAct 解决的是“单个 Agent 怎么边想边做”,多 Agent 协作解决的是“一群 Agent 怎么像团队一样把一件大事干完”。前者是个人能力问题,后者是组织协作问题。

这篇文章适合三类人看:一是已经用过大模型 API、想进一步做 Agent 应用的开发者;二是正在被单 Agent 的“健忘、跑偏、死循环”折磨的工程同学;三是对多 Agent 架构好奇、但还没找到落地切入口的技术负责人。我会把 ReAct 的核心机制、它的天花板在哪、多 Agent 的几种主流协作模式、以及我自己在工程化过程中踩过的坑,尽量讲透。不堆概念,重点讲“为什么这么设计”和“实际怎么落地”。

需要先说明一点:Agent 这个领域变化极快,很多细节没有唯一标准答案。我下面提到的架构选型、参数配置、协作模式,都是基于常见工程实践和我个人项目经验的合理总结,不是某种“官方标准”。你完全可以按自己的场景调整。

2. ReAct 范式拆解:它为什么好用,又为什么不够用

2.1 ReAct 的核心循环:思考、行动、观察

ReAct 这个名字来自 Reasoning + Acting 的组合,核心思想是让模型在一个循环里交替进行“推理”和“行动”。用最直白的话说,就是让模型不要一上来就给答案,而是先想一步、做个动作、看看结果、再想下一步。

它的典型循环是这样的:

  1. Thought(思考):模型分析当前状态,决定下一步要做什么。
  2. Action(行动):选择一个工具并给出调用参数,比如搜索、计算、查数据库。
  3. Observation(观察):拿到工具返回的结果。
  4. 回到第 1 步,直到模型认为可以给出最终答案。

这个循环看起来简单,但它解决了一个很关键的问题:模型的知识是静态的,而任务是动态的。通过引入工具调用,模型可以在推理过程中主动获取外部信息,而不是硬编在参数里。这就像一个人做菜,不是背下所有菜谱,而是边做边尝、边查资料。

我用一个实际例子说明。假设任务是“计算某产品三个季度的环比增长率并判断趋势”。ReAct 的执行过程大致是:

  • Thought:我需要先拿到三个季度的数据。
  • Action:调用数据查询工具,参数为产品 ID 和时间范围。
  • Observation:返回 Q1=120、Q2=150、Q3=135。
  • Thought:现在计算环比增长率。
  • Action:调用计算工具,计算 (150-120)/120 和 (135-150)/150。
  • Observation:Q2 环比 +25%,Q3 环比 -10%。
  • Thought:数据齐了,可以给出结论。
  • Final Answer:Q2 增长明显,Q3 出现回落,整体趋势先升后降。

这个流程清晰、可解释,而且每一步都有据可查。这也是 ReAct 最大的优点:过程透明,便于调试。

2.2 单 Agent 的天花板在哪里

ReAct 跑通之后,我一度觉得“一个 Agent 打天下”就够了。但项目越做越复杂,问题就暴露出来了。总结下来,单 Agent 的天花板主要体现在四个方面。

第一是上下文膨胀。ReAct 的每一步思考、行动、观察都要塞进上下文。任务一长,上下文里全是历史记录,模型注意力被稀释,容易忘记最初的目标。我遇到过最夸张的一次,一个任务跑了 20 多轮,模型最后完全跑偏,开始回答一个跟原问题无关的东西。

第二是工具选择混乱。当工具数量超过十个,单 Agent 在“该用哪个工具”上就开始犹豫。它可能反复调用同一个工具,或者选了一个不合适的工具还硬着头皮往下走。这不是模型笨,而是决策空间太大了。

第三是错误累积。ReAct 是串行循环,前面一步错了,后面会沿着错误路径继续。比如第一步查错了数据源,后面所有计算和结论都是错的,但模型自己很难发现。

第四是职责不清。一个 Agent 既要理解需求、又要规划步骤、还要调用工具、最后还要组织语言输出。角色太多,每个角色都做不精。这就像让一个人同时当产品经理、程序员和测试,最后哪样都做不好。

提示:如果你现在的单 Agent 任务经常超过 8 到 10 轮工具调用,或者需要同时协调 5 个以上工具,那基本可以考虑往多 Agent 方向演进了。

2.3 从“一个人干活”到“一个团队干活”的思维转变

多 Agent 协作的核心思路,其实就是把单 Agent 身上的多重职责拆开,交给不同的 Agent 分别负责。这跟公司里组建项目团队是一个道理:有人负责拆需求,有人负责执行,有人负责审核,有人负责汇总。

这个思维转变的关键在于:不要指望一个 Agent 既聪明又全面,而是要让每个 Agent 在自己的职责范围内做到可靠。单 Agent 追求的是“全能”,多 Agent 追求的是“分工明确 + 协作顺畅”。

举个生活化的类比。单 Agent 像一个全能型自由职业者,什么都能干,但精力有限,大项目容易崩。多 Agent 像一个工作室,有策划、有执行、有质检,每个人只干自己最擅长的事,通过流程把成果串起来。工作室不一定每个人都是顶尖高手,但整体产出往往比一个全能选手更稳定。

3. 多 Agent 协作的主流架构模式与选型逻辑

3.1 四种常见协作模式对比

多 Agent 不是只有一种玩法。根据任务特点,常见的协作模式大致可以分成四类。我用一个表格先做个总览,再逐个展开。

协作模式核心特征适用场景主要风险
流水线式Agent 按固定顺序接力步骤明确的流程任务单点阻塞,前一步错后全错
主管调度式一个调度 Agent 分配任务任务可拆解、需动态分配调度 Agent 成为瓶颈
辩论式多个 Agent 互相质疑需要高可靠性的判断成本高,可能陷入僵局
黑板式Agent 共享一块公共状态复杂、非线性协作状态管理复杂,易冲突

流水线式最简单,Agent A 做完交给 Agent B,B 做完交给 C。适合那种步骤天然固定的任务,比如“抽取信息 → 校验格式 → 生成报告”。它的优点是流程清晰、容易调试;缺点是缺乏灵活性,中间任何一环卡住,整条线就停了。

主管调度式是我个人最常用的模式。有一个调度 Agent 负责理解总目标、拆解子任务、分发给执行 Agent,最后汇总结果。它像一个项目经理,不亲自干活,但负责协调。这种模式灵活度高,适合任务边界不太固定的场景。

辩论式比较有意思,让多个 Agent 对同一个问题给出不同答案,然后互相挑刺,最后收敛出一个更可靠的结论。适合对准确性要求极高的判断类任务。但它的成本是普通模式的几倍,而且如果设计不好,Agent 之间可能无限争论下去。

黑板式借鉴了经典的多智能体系统思路,所有 Agent 共享一块“黑板”(公共状态区),谁有需要就往上写,谁需要信息就从上面读。它适合那种协作关系复杂、没有固定流程的任务,但状态一致性很难保证,工程实现也最重。

3.2 选型时我实际考虑的三个维度

面对一个具体项目,怎么选协作模式?我一般看三个维度。

第一个维度是任务的可拆解程度。如果任务能清晰地拆成几个独立子任务,主管调度式最合适。如果任务本身就是一条直线流程,流水线式更省事。如果任务拆不开、需要多个视角反复验证,才考虑辩论式。

第二个维度是对可靠性的要求。普通的信息整理任务,流水线或主管调度就够了。但如果是涉及关键决策的分析,比如财务数据核对、合规审查,那辩论式的交叉验证就很有价值,多花点成本换可靠性是值得的。

第三个维度是工程复杂度预算。这一点经常被忽略。辩论式和黑板式的实现复杂度远高于前两种,调试难度也大。如果团队人手有限、上线时间紧,我建议先从主管调度式入手,它性价比最高。

注意:不要一上来就追求最复杂的架构。我见过不少项目,明明一个主管调度式就能解决,非要上黑板式,结果状态同步的 bug 修了两周还没修完。

3.3 一个主管调度式的架构草图

既然主管调度式最常用,我把它展开讲一下。一个典型的主管调度式多 Agent 系统,通常包含这几类角色:

  • 调度 Agent(Orchestrator):理解用户目标,拆解任务,决定调用哪些执行 Agent,最后汇总。
  • 执行 Agent(Worker):每个负责一类具体能力,比如检索、计算、写作、代码执行。
  • 审核 Agent(Critic):对执行结果做质量检查,不合格就打回重做。
  • 记忆模块(Memory):存储中间结果和长期知识,供所有 Agent 读写。

它们之间的数据流大致是:用户请求 → 调度 Agent 拆解 → 分发给执行 Agent → 执行结果写入记忆 → 审核 Agent 检查 → 调度 Agent 汇总输出。

这个架构的关键设计点在于:调度 Agent 不直接干活,只做决策和协调。这样它的上下文不会被具体执行细节污染,能更专注地做全局规划。执行 Agent 则各自保持精简,只关心自己那一小块。

4. 工程化落地的核心细节与实操要点

4.1 Agent 之间的通信协议怎么定

多 Agent 系统最容易出问题的地方,就是 Agent 之间的通信。如果每个 Agent 都用自己的格式说话,整个系统就会乱套。我的经验是:一定要提前定义一套统一的消息结构。

一个实用的消息结构通常包含这些字段:

{ "sender": "orchestrator", "receiver": "retrieval_agent", "task_id": "task_20240101_001", "intent": "retrieve_documents", "payload": { "query": "某产品的季度销售数据", "top_k": 5 }, "constraints": { "timeout_seconds": 30, "max_tokens": 2000 }, "status": "pending" }

这里有几个字段值得说明。task_id用于追踪一个任务的全链路,方便排查问题。intent是意图标识,接收方根据它决定怎么处理。constraints是约束条件,防止某个 Agent 无限消耗资源。status用于状态流转,比如 pending、running、done、failed。

我踩过的一个坑是:早期没定义task_id,结果多个任务并发时,日志混在一起,根本分不清哪条是哪条。后来加上统一 ID,排查效率提升了一大截。

4.2 状态管理与上下文传递的取舍

多 Agent 系统里,状态管理是个绕不开的难题。核心矛盾在于:Agent 之间需要共享信息,但又不能把所有信息都塞给每个 Agent。

我的做法是分层管理状态:

  • 全局状态:任务目标、总体进度、最终约束,所有 Agent 都能读。
  • 局部状态:每个 Agent 自己的中间结果,默认不共享,需要时才通过消息传递。
  • 持久状态:跨任务需要保留的知识,写入外部存储,比如向量库或数据库。

这样做的好处是,每个 Agent 的上下文保持精简,不会被无关信息干扰。代价是需要额外的状态同步逻辑。

具体实现上,我一般用一个中心化的状态管理器,所有 Agent 通过它读写状态。状态管理器负责版本控制,避免并发写入冲突。如果任务对实时性要求不高,也可以用消息队列异步传递状态。

提示:状态管理最忌讳的是“隐式共享”。如果 Agent A 偷偷改了全局状态,Agent B 却不知道,这种 bug 极难排查。所有状态变更都要走显式接口,并且记录日志。

4.3 工具调用的隔离与权限控制

单 Agent 时代,工具调用相对随意。多 Agent 时代,工具必须做隔离。原因很简单:不是每个 Agent 都需要所有工具,给多了反而增加误用风险。

我的做法是按 Agent 角色分配工具集:

Agent 角色可用工具权限级别
调度 Agent任务拆解、状态查询只读
检索 Agent向量检索、关键词搜索只读
计算 Agent计算器、代码执行受限写
写作 Agent文本生成、格式化只读
审核 Agent规则校验、对比分析只读

这样设计之后,每个 Agent 的工具选择空间变小,决策更聚焦,误用概率明显下降。同时,权限控制也提升了系统安全性,比如计算 Agent 的代码执行权限被限制在沙箱内,不会影响其他模块。

4.4 成本与延迟的平衡技巧

多 Agent 系统最大的现实问题就是成本和延迟。多个 Agent 串行或并行调用,token 消耗和响应时间都会成倍增加。我总结了几个实用的平衡技巧。

第一,能并行就并行。如果几个子任务之间没有依赖关系,就让它们并行执行。比如检索和计算可以同时进行,最后再汇总。这能显著降低总延迟。

第二,给每个 Agent 设置 token 上限。不要让某个 Agent 无限生成。我一般给执行 Agent 设 1000 到 2000 token 的输出上限,调度 Agent 稍微宽松一点。

第三,缓存高频结果。很多任务里,检索结果、计算结果是可以复用的。加一层缓存,能省下大量重复调用。

第四,按需唤醒 Agent。不是每个任务都需要所有 Agent 参与。调度 Agent 应该根据任务复杂度,动态决定唤醒哪些 Agent。简单任务可能只需要一个执行 Agent,复杂任务才启动完整团队。

实测下来,做好这四点,多 Agent 系统的成本能控制在单 Agent 的 1.5 到 2 倍左右,而不是想象中的好几倍。延迟方面,并行化做得好,甚至可能比单 Agent 串行循环更快。

5. 完整实操流程:从零搭一个多 Agent 协作系统

5.1 需求拆解与角色设计

假设我们要做一个“行业研究报告生成器”。用户输入一个行业名称,系统自动检索资料、分析数据、生成一份结构化报告。这个任务用单 Agent 做,很容易在检索和写作之间顾此失彼。我们用多 Agent 来拆。

第一步是角色设计。我把它拆成四个角色:

  • 调度 Agent:接收行业名称,规划报告结构,分配任务。
  • 检索 Agent:负责搜集该行业的资料,包括市场规模、主要玩家、趋势。
  • 分析 Agent:对检索结果做归纳,提取关键数据和结论。
  • 写作 Agent:把分析结果组织成一份完整报告。

审核环节我先不单独设 Agent,而是让调度 Agent 在汇总时做一次自检,降低初期复杂度。

5.2 核心代码骨架与关键配置

下面是一个简化的调度逻辑骨架,用 Python 伪代码表示,重点是展示协作流程,不是完整可运行代码。

class OrchestratorAgent: def __init__(self, workers, memory): self.workers = workers # 执行 Agent 字典 self.memory = memory # 共享记忆模块 def run(self, user_request): # 第一步:拆解任务 plan = self.decompose(user_request) self.memory.set("plan", plan) # 第二步:分发检索任务 retrieval_result = self.workers["retrieval"].execute( query=plan["search_query"], top_k=5 ) self.memory.set("retrieval", retrieval_result) # 第三步:分发分析任务 analysis_result = self.workers["analysis"].execute( context=retrieval_result, focus=plan["analysis_focus"] ) self.memory.set("analysis", analysis_result) # 第四步:分发写作任务 report = self.workers["writing"].execute( context=analysis_result, template=plan["report_template"] ) # 第五步:自检并返回 return self.self_check(report) def decompose(self, request): # 调用模型生成任务计划 prompt = f"请把以下需求拆解为检索、分析、写作三个子任务:{request}" return call_llm(prompt, output_format="json")

关键配置方面,有几个参数需要特别注意:

  • 每个 Agent 的模型选择:调度 Agent 用能力强的模型,执行 Agent 可以用更轻量的模型,平衡成本和效果。
  • 超时设置:每个 Agent 调用设置 30 到 60 秒超时,避免单个环节卡死整个流程。
  • 重试策略:检索和分析环节失败可以重试 2 次,写作环节失败直接返回错误,避免生成半成品。
  • 记忆容量:共享记忆设置上限,超过就做摘要压缩,防止上下文无限膨胀。

5.3 一次完整运行的现场记录

我用“新能源汽车行业”做了一次实测。整个过程大致如下:

调度 Agent 先输出计划:检索市场规模和增长率、检索主要厂商、检索政策趋势,然后分析竞争格局,最后生成报告。

检索 Agent 并行跑了三路检索,返回了 12 条相关资料。这里我用了并行,三路检索同时发起,总耗时约 8 秒。

分析 Agent 拿到资料后,提取出关键数据:市场规模、同比增长率、前五大厂商份额。这一步耗时约 6 秒。

写作 Agent 根据分析结果,按“市场概况、竞争格局、趋势判断”三段式生成报告,耗时约 10 秒。

整个流程端到端约 25 秒,token 消耗大约是单 Agent 方案的 1.8 倍。但报告质量明显更稳定,数据引用完整,结构清晰,没有出现单 Agent 常见的“前面查了后面忘”的问题。

5.4 效果评估与迭代方向

评估多 Agent 系统的效果,我一般看三个指标:任务完成率、结果准确率、平均耗时。上面这个案例,任务完成率 100%,准确率抽样检查约 90%,平均耗时 25 秒。

迭代方向上,我下一步打算加一个审核 Agent,专门检查报告里的数据引用是否和检索结果一致。另外,检索环节可以引入缓存,相同行业的重复请求直接复用结果,进一步降本。

6. 常见问题与排查技巧实录

6.1 Agent 之间互相等待怎么办

这是多 Agent 系统最典型的死锁问题。A 等 B 的结果,B 等 A 的结果,谁也动不了。我遇到过两次,都是因为任务依赖关系没理清。

排查思路是:先把所有 Agent 的依赖关系画成有向图,检查有没有环。如果有环,说明任务拆解本身有问题,需要重新设计。如果没有环,那就是超时设置不合理,某个 Agent 等太久。

解决方法有两个:一是给每个等待设置超时,超时就跳过或降级处理;二是引入异步消息机制,Agent 不等结果,先把能做的做完,结果到了再处理。

6.2 调度 Agent 决策跑偏怎么修

调度 Agent 跑偏的表现是:拆解出的子任务和用户需求对不上,或者分配了错误的执行 Agent。这个问题通常出在调度 Agent 的提示词上。

我的修复经验是:给调度 Agent 的提示词里,明确列出可用的执行 Agent 及其能力边界,并且要求它输出结构化的任务计划。结构化输出能大幅降低跑偏概率。另外,可以在调度后加一道校验,检查子任务是否覆盖了用户需求的所有关键点。

6.3 结果不一致时的收敛策略

多个 Agent 给出不一致的结果,这在辩论式架构里很常见,在主管调度式里也可能出现,比如检索 Agent 返回了两条矛盾的数据。

收敛策略我一般分三步:先看数据源可信度,再看时间新鲜度,最后看多数一致性。如果两条数据来自不同可信度的源,取高可信度的。如果可信度相当,取更新的。如果还分不出来,就让审核 Agent 介入,或者直接标注“存在争议”返回给用户,而不是强行编一个答案。

6.4 常见问题速查表

问题现象可能原因排查方向解决建议
任务卡住不动Agent 互相等待检查依赖图是否有环加超时,改异步
结果偏离需求调度拆解错误检查调度提示词结构化输出+校验
成本异常高重复调用或上下文膨胀看调用日志和 token 统计加缓存,设上限
结果自相矛盾多源数据冲突检查数据源和时间按可信度和新鲜度收敛
响应特别慢串行执行过多分析任务依赖关系能并行的改并行

提示:多 Agent 系统的调试,日志是命根子。每个 Agent 的输入、输出、耗时、token 消耗都要记录,最好带上统一的 task_id。没有日志,排查基本靠猜。

6.5 几个我踩过的坑

第一个坑是过早优化。一开始就想着做完美的架构,结果花了两周设计,代码没写几行。后来改成先跑通最小闭环,再逐步加 Agent,效率高多了。

第二个坑是忽视提示词的版本管理。多 Agent 系统里提示词很多,改了一个忘了另一个,导致行为不一致。后来我把所有提示词集中管理,加了版本号,问题少了很多。

第三个坑是没有降级方案。某个 Agent 挂了,整个流程就断了。后来我给每个关键环节都加了降级逻辑,比如检索失败就用缓存,分析失败就返回原始资料,保证系统不会完全不可用。

7. 多 Agent 协作的边界与我的实际体会

聊了这么多架构和实操,最后说点实在的。多 Agent 不是银弹,它有明确的适用边界。任务足够复杂、单 Agent 确实搞不定的时候,多 Agent 才值得上。如果任务本身简单,硬套多 Agent,只会增加成本和维护负担。

我在实际项目里的体会是:多 Agent 系统的价值,不在于“用了多个 Agent”这个形式,而在于它强迫你把任务拆解清楚、把职责定义明确、把接口约定好。这个拆解和约定的过程,本身就是对业务理解的一次深化。很多时候,把架构设计清楚了,问题已经解决了一半。

另外一个小技巧:初期不要追求 Agent 数量多,两三个角色跑通闭环,比五六个角色互相打架强得多。等流程稳定了,再按需增加角色。多 Agent 协作的工程化,本质上是一个“先跑通、再优化、后扩展”的渐进过程,急不得。

RELATED READING

延伸阅读

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