ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

企业级Agent架构设计:从五组件拆解到ReAct循环的私有可控实践

企业级Agent架构设计:从五组件拆解到ReAct循环的私有可控实践

1. 从"能聊"到"能干活":Agent 架构到底在解决什么问题

很多人第一次接触 Agent 这个概念,脑子里浮现的是"一个更聪明的聊天机器人"。这个理解不能说错,但差得有点远。聊天机器人解决的是"信息问答",而 Agent 解决的是"任务闭环"。这两者之间的鸿沟,比大多数人想象的要宽得多。

我最早做 Agent 相关项目的时候,踩过一个很典型的坑:把一个对话模型接上几个工具调用,就以为自己做了一个 Agent。结果上线之后发现,它确实能调用搜索、能查数据库、能发邮件,但一旦任务稍微复杂一点——比如"帮我分析上周的销售数据,找出异常波动的品类,然后给相关负责人发一份摘要"——它就开始犯迷糊。要么漏掉中间步骤,要么在某个环节反复循环,要么把工具调用的结果理解错了。问题出在哪?出在我只做了"工具调用",没有做"架构设计"。

Agent 架构要解决的核心问题,其实就三个:任务分解、状态管理、执行控制。任务分解是把一个模糊的用户意图拆成可执行的步骤序列;状态管理是让 Agent 在多轮交互中记住自己做到哪了、拿到了什么中间结果;执行控制是决定下一步该做什么、什么时候该停下来。这三个问题不解决,Agent 就只是一个"会调 API 的聊天框"。

而企业级 Agent OS 要解决的,是在这三个问题之上再加一层:私有可控。企业场景和消费级场景最大的区别在于,企业不能接受"黑盒"。你需要知道 Agent 每一步在干什么、用了什么数据、走了什么逻辑、出了问题怎么回溯。这不是技术炫技,这是合规和运维的硬需求。

这篇文章会从五个核心组件讲起,把 ReAct 循环的底层逻辑拆开揉碎,再聊企业级 Agent OS 为什么必须有一个私有可控的底座。每一部分我都会给出实际项目中的设计取舍和踩坑经验,不是纸上谈兵。

提示:如果你现在正在做 Agent 相关的东西,但感觉"能跑但不好用",大概率是架构层面缺了东西,而不是模型不够强。先把架构补齐,再考虑换模型。

2. 五组件拆解:一个 Agent 系统的骨架长什么样

2.1 规划器(Planner):不是所有任务都需要"想清楚再做"

规划器是 Agent 的"大脑皮层",负责把用户输入的任务拆解成可执行的步骤。但这里有一个常见的误区:很多人一上来就追求"完整规划",让模型先把所有步骤列出来再执行。这在简单任务上没问题,但在复杂任务上会出大问题。

原因很简单:规划依赖信息,而信息在执行过程中才会出现。你让 Agent 在第一步就把后面五步全规划好,它只能靠猜。猜错了,后面全盘皆输。

我在实际项目中采用的是分层规划策略:

  • 粗粒度规划:先拆出 3-5 个高层步骤,每个步骤是一个"意图"而不是"具体操作"。比如"获取数据"而不是"调用 get_sales_data 接口"。
  • 细粒度规划:每执行完一个粗粒度步骤,根据实际拿到的结果,再规划下一步的具体操作。

这样做的好处是,Agent 始终基于"已知信息"做决策,而不是基于"猜测"。代价是规划次数变多了,延迟会上升。但在企业场景里,准确性比速度重要得多。

规划器的实现方式也有讲究。纯 Prompt 驱动的规划器灵活但不可控,纯规则引擎的规划器可控但不灵活。我的建议是混合模式:用规则引擎处理高频、确定性的任务(比如"查数据→生成报表→发送"这种固定流程),用模型处理低频、开放性的任务。这样既保证了核心流程的稳定性,又保留了处理长尾场景的能力。

2.2 记忆模块(Memory):短期记忆和长期记忆要分开设计

记忆模块是 Agent 的"海马体",负责存储和检索信息。很多人在设计记忆模块的时候,把短期记忆和长期记忆混在一起,结果就是:要么上下文爆炸,要么关键信息丢失。

短期记忆是当前任务执行过程中的工作记忆,包括:用户输入、每一步的执行结果、当前的中间状态。这部分记忆的特点是"生命周期短、访问频率高、容量有限"。我的做法是用一个固定大小的滑动窗口来管理,窗口大小根据模型的上下文长度来定,一般保留最近 10-15 轮交互。

长期记忆是跨任务的知识沉淀,包括:用户偏好、历史任务记录、领域知识。这部分记忆的特点是"生命周期长、访问频率低、容量大"。我的做法是用向量数据库存储,通过语义检索来召回相关记忆。

这里有一个实操中的关键细节:短期记忆写入长期记忆的时机。我的经验是,不要每轮都写,而是在任务完成或任务失败时写入。写入的内容也不是原始对话,而是经过摘要的结构化信息。比如"用户在 3 月 15 日查询了华东区销售数据,关注了退货率异常"这样的记录,比原始对话有用得多。

注意:记忆模块最容易出的问题是"记忆污染"。如果长期记忆里存了大量低质量的历史记录,检索出来的结果会干扰当前任务。定期清理和压缩长期记忆是必须的运维动作。

2.3 工具集(Tools):工具描述的质量决定调用准确率

工具集是 Agent 的"手脚",决定了 Agent 能做什么。但工具集的设计不是"越多越好",而是"越清晰越好"。

我见过很多项目,工具列表列了几十个,结果 Agent 调用准确率极低。问题不在模型,在工具描述。一个好的工具描述应该包含四个要素:

要素说明示例
功能描述这个工具做什么查询指定时间范围内的销售数据
参数说明每个参数的含义和格式start_date: 起始日期,格式 YYYY-MM-DD
返回格式返回什么结构的数据返回 JSON 数组,每项包含品类、销售额、退货率
使用场景什么时候该用这个工具当用户需要分析销售趋势或异常时使用

这四个要素缺一个,调用准确率就会下降。尤其是"使用场景",很多人不写,结果 Agent 不知道该在什么时候调用这个工具。

另一个实操经验是:工具的数量控制在 10-15 个以内。超过这个数量,模型的调用准确率会明显下降。如果业务确实需要很多工具,就做分层:第一层是"工具类别",第二层是具体工具。Agent 先选类别,再选具体工具。

2.4 执行器(Executor):重试、超时、降级一个都不能少

执行器是 Agent 的"运动神经",负责实际调用工具并处理返回结果。这部分看起来简单,但实际项目中最容易出问题的就是这里。

企业级场景下,执行器必须处理三种异常情况:

  • 超时:工具调用超过预期时间。我的做法是设置分级超时,查询类工具 5 秒,写入类工具 10 秒,复杂计算类工具 30 秒。超时后不是直接失败,而是进入重试队列。
  • 失败:工具返回错误。区分可重试错误(如网络抖动)和不可重试错误(如参数错误)。可重试错误最多重试 2 次,每次间隔递增。
  • 降级:工具完全不可用。这时候需要有备用方案,比如返回缓存数据、或者告知 Agent"当前工具不可用,请尝试其他方式"。

这里有一个我踩过的坑:重试逻辑不能放在 Agent 的规划层,必须放在执行器层。因为如果让 Agent 自己决定要不要重试,它可能会陷入"重试→失败→再重试"的死循环。执行器层做重试,对 Agent 是透明的,Agent 只知道"这个工具调用成功了"或"这个工具调用最终失败了"。

2.5 反馈循环(Feedback Loop):让 Agent 知道自己做得对不对

反馈循环是 Agent 的"前额叶",负责评估执行结果并决定下一步。这是五个组件里最容易被忽视、但最重要的一环。

没有反馈循环的 Agent,就像一个闭着眼睛走路的人——它不知道自己走到哪了,也不知道自己走对没有。反馈循环要回答三个问题:

  1. 当前步骤的结果是否符合预期?比如调用了查询工具,返回的数据是否完整、格式是否正确。
  2. 当前任务的整体进度如何?已经完成了几个步骤,还剩几个步骤。
  3. 是否需要调整计划?如果某一步的结果和预期差距很大,是否需要重新规划。

我的做法是在每个步骤执行后,插入一个轻量的"评估节点"。这个评估节点不调用大模型,而是用规则+小模型来做快速判断。只有在大规则判断不确定的时候,才调用大模型做深度评估。这样既保证了反馈的及时性,又控制了成本。

3. ReAct 循环:为什么"想一步做一步"比"想好再做"更靠谱

3.1 ReAct 的本质:把"思考"和"行动"交织在一起

ReAct 这个词拆开就是 Reasoning + Acting,核心思想是让模型在每一步都先"想一下"再"做一下",而不是一次性想完所有步骤再执行。

这个思路看起来简单,但它解决了一个根本问题:模型在行动之前,无法预知行动的结果。传统的"规划-执行"模式要求模型在第一步就规划好所有步骤,但模型没有执行结果作为依据,规划的质量完全取决于它的先验知识。而 ReAct 让模型在每一步都能看到上一步的实际结果,基于实际结果来决定下一步,规划质量自然高得多。

用一个生活化的类比:传统规划模式就像你出门前把一整天的行程全部排好,但路上遇到堵车、遇到朋友、遇到下雨,你的计划全乱了。ReAct 模式就像你边走边看,遇到堵车就绕路,遇到朋友就聊两句,遇到下雨就找个地方躲。最终你到达了目的地,但路径是动态调整的。

3.2 ReAct 循环的四个阶段:观察、思考、行动、评估

一个完整的 ReAct 循环包含四个阶段,我用一个实际例子来说明。

假设用户的任务是:"帮我查一下上个月华东区的销售数据,如果退货率超过 5% 就通知我。"

第一阶段:观察(Observe)

Agent 接收用户输入,并检索相关记忆。它发现:用户之前查询过华东区数据,关注退货率。当前没有可用的缓存数据。

第二阶段:思考(Think)

Agent 分析任务:需要先查数据,再判断退货率,最后决定是否通知。当前第一步是查询数据。它决定调用query_sales_data工具,参数是region=华东, month=上月。

第三阶段:行动(Act)

Agent 调用工具,拿到返回结果:华东区上月销售额 1200 万,退货率 6.2%。

第四阶段:评估(Evaluate)

Agent 检查结果:数据完整,退货率 6.2% 超过 5% 阈值。任务需要继续,下一步是通知用户。

然后进入下一个循环:观察(当前状态是"已获取数据,需要通知")→ 思考(决定调用通知工具)→ 行动(发送通知)→ 评估(通知发送成功,任务完成)。

这四个阶段循环往复,直到任务完成或达到终止条件。

3.3 ReAct 循环的终止条件:什么时候该停下来

ReAct 循环最大的风险是"停不下来"。我见过最夸张的案例,一个 Agent 在某个任务上循环了 200 多轮,烧掉了大量 token,最后还没解决问题。

终止条件必须明确设置,我的做法是设置四层终止条件:

  • 任务完成:Agent 判断任务目标已达成。
  • 最大轮次:设置硬性上限,一般 15-20 轮。超过就强制终止,返回当前结果。
  • 重复检测:如果连续 3 轮的动作和结果高度相似,判定为陷入循环,强制终止。
  • 超时:整个任务设置总超时时间,一般 5-10 分钟。超过就终止。

这四层条件是"或"的关系,任何一个满足就终止。实际项目中,最大轮次和重复检测是最常用的两个。

提示:重复检测的实现不需要很复杂。我用的方法是对每轮的"动作+结果"做一个简单的哈希,如果连续几轮的哈希值相同或高度相似,就触发终止。这个方法简单但有效。

3.4 ReAct 在企业场景下的变体:带约束的循环

纯 ReAct 循环在企业场景下有一个问题:它太自由了。模型可以决定调用任何工具、执行任何操作,这在消费级场景没问题,但在企业场景下不可接受。

我的做法是给 ReAct 循环加上约束层:

  • 工具白名单:不是所有工具都能被调用,根据任务类型和用户权限动态确定可用工具集。
  • 操作审批:涉及写入、删除、发送等敏感操作时,需要经过审批节点。审批可以是自动的(基于规则),也可以是人工的。
  • 审计日志:每一轮的观察、思考、行动、评估都记录到审计日志,支持事后回溯。

这些约束层不改变 ReAct 的核心逻辑,只是在关键节点插入检查。这样既保留了 ReAct 的灵活性,又满足了企业的可控性要求。

4. 企业级 Agent OS:为什么"私有可控"是底线而不是加分项

4.1 企业场景和消费级场景的根本差异

消费级 Agent 和企业级 Agent 的差异,不是"功能多少"的差异,而是"责任归属"的差异。

消费级场景下,Agent 说错话了,用户笑一笑就过去了。企业级场景下,Agent 给错了数据、发错了通知、执行了错误的操作,是要有人负责的。这个责任归属的差异,决定了企业级 Agent 必须满足三个额外要求:

  • 可解释:每一步决策都要有依据,不能是黑盒。
  • 可控制:关键操作要能干预,不能完全放任。
  • 可追溯:出了问题要能回溯,找到是哪一步出了错。

这三个要求,就是"私有可控"的核心含义。

4.2 私有可控底座的三个层次

私有可控底座不是单一技术,而是一个三层架构:

第一层:数据私有

Agent 运行过程中涉及的所有数据——用户输入、工具返回、记忆存储、日志记录——都必须存储在私有环境中。这不是简单的"部署在内网",而是要从数据流的角度确保数据不出边界。

我的做法是在 Agent OS 层面做一个统一的数据网关,所有数据的进出都经过这个网关。网关负责数据脱敏、访问控制、审计记录。这样即使某个组件出了问题,数据也不会泄露。

第二层:模型私有

企业级场景下,模型的选择往往不是"哪个效果最好",而是"哪个能私有部署"。私有部署的模型在效果上可能比公有云模型差一些,但它解决了两个关键问题:数据不出边界、模型行为可控。

我的经验是,对于核心业务逻辑,用私有部署的中等规模模型;对于非核心的辅助任务(如文本摘要、格式转换),可以用公有云的小模型。这样在效果和可控性之间取得平衡。

第三层:流程私有

Agent 的决策流程——规划逻辑、工具调用规则、反馈评估标准——都应该是可配置、可审计的。不能是"模型自己决定"。

我的做法是把流程逻辑从模型里抽出来,做成独立的配置。模型只负责"理解意图"和"生成候选动作",具体执行哪个动作、按什么顺序执行,由配置层决定。这样流程就是可控的、可审计的、可修改的。

4.3 私有可控底座的运维实践

私有可控底座建起来之后,运维是更大的挑战。我总结了三个关键运维动作:

第一,定期审计 Agent 的决策日志。不是等出了问题才看日志,而是定期抽查。我一般每周抽 20-30 条决策记录,检查是否有异常模式。比如某个工具被频繁调用但成功率很低,或者某个类型的任务总是超时。

第二,建立 Agent 行为的基线。记录 Agent 在正常情况下的行为指标——平均轮次、平均耗时、工具调用分布、成功率。当实际指标偏离基线超过阈值时,触发告警。

第三,保持人工干预通道畅通。无论 Agent 多智能,都要保留人工接管的能力。我的做法是在 Agent OS 层面设置一个"暂停"开关,任何时候都可以暂停 Agent 的执行,人工介入处理。

5. 从零搭建一个最小可用的 Agent 系统:我的实操路径

5.1 技术选型:不要一上来就追求"全家桶"

很多人搭建 Agent 系统的第一步是选框架。LangChain、AutoGPT、MetaGPT……每个都看起来很强大。但我的经验是:先用最小依赖跑通核心逻辑,再考虑引入框架。

原因很简单:框架会隐藏细节。当你用框架的时候,你看到的是"Agent 执行了任务",但你看不到"Agent 为什么这样执行"。出了问题,你只能猜。而自己从零实现一遍,哪怕代码很粗糙,你对每个环节的理解是完全不同的。

我的最小实现路径是这样的:

# 核心循环的伪代码结构 class MinimalAgent: def __init__(self, planner, memory, tools, executor, evaluator): self.planner = planner self.memory = memory self.tools = tools self.executor = executor self.evaluator = evaluator self.max_turns = 15 def run(self, task): self.memory.add("task", task) for turn in range(self.max_turns): # 观察 context = self.memory.get_context() # 思考 plan = self.planner.plan(context) # 行动 result = self.executor.execute(plan, self.tools) # 评估 evaluation = self.evaluator.evaluate(result, task) self.memory.add("turn", {"plan": plan, "result": result}) if evaluation.is_complete: return evaluation.final_answer return "任务未完成,已达到最大轮次"

这个结构不到 20 行,但它包含了 Agent 的核心逻辑。你可以先把这个跑通,再逐步替换每个组件——把简单的规划器换成更复杂的、把内存记忆换成向量数据库、把规则评估换成模型评估。

5.2 工具集的设计:从 3 个工具开始

工具集不要一上来就设计几十个。我的建议是从 3 个工具开始:

  • 一个查询工具(如搜索或数据库查询)
  • 一个计算工具(如代码执行或数学计算)
  • 一个输出工具(如生成报告或发送消息)

这三个工具覆盖了"获取信息→处理信息→输出结果"的完整链路。先用这三个工具跑通几个简单任务,再根据实际需求逐步增加。

增加工具的时候,遵循一个原则:新工具必须能解决现有工具解决不了的问题。如果两个工具功能重叠,合并它们,而不是都保留。

5.3 评估体系的建立:怎么知道 Agent 做得好不好

Agent 系统的评估比传统软件复杂得多,因为它的输出不是确定性的。同一个任务,Agent 可能走不同的路径,得到不同的结果。

我的评估体系包含三个维度:

维度指标测量方式
任务完成度任务成功率人工标注 + 自动检查
执行效率平均轮次、平均耗时系统自动统计
决策质量工具调用准确率、无效动作比例日志分析

这三个维度里,任务完成度是最重要的,但也是最难自动测量的。我的做法是建立一个"黄金测试集"——人工标注 50-100 个典型任务的标准答案,定期用这个测试集跑 Agent,看成功率的变化。

5.4 上线后的持续迭代:Agent 不是"部署完就完了"

Agent 系统上线只是开始,真正的挑战在迭代。我总结了三个迭代方向:

第一,补充工具。上线后会发现很多任务失败是因为"缺少合适的工具"。根据失败案例,有针对性地补充工具。

第二,优化提示词。规划器和评估器的提示词需要持续优化。我的做法是建立一个"提示词版本库",每次修改都记录版本和效果,方便回溯。

第三,调整约束。上线初期约束可以松一些,让 Agent 有更多探索空间。随着对 Agent 行为的理解加深,逐步收紧约束,提高稳定性。

6. 那些只有踩过才知道的坑

6.1 上下文窗口不是越大越好

很多人觉得上下文窗口越大越好,恨不得把整个知识库都塞进去。但实际项目中,上下文窗口过大反而会降低 Agent 的表现。

原因有两个:一是模型在超长上下文中的注意力会分散,关键信息容易被淹没;二是上下文越长,推理成本越高,延迟越大。

我的做法是精准召回而不是全量塞入。用向量检索找到最相关的 5-10 条信息,而不是把 100 条都塞进去。宁可少而精,不要多而杂。

6.2 工具调用的"幻觉"比内容幻觉更危险

内容幻觉是模型说错话,工具调用幻觉是模型调错工具。后者比前者危险得多,因为调错工具可能产生实际的副作用——发错邮件、改错数据、触发错误的流程。

我的应对方法是双重确认:对于敏感操作,Agent 先输出"我打算调用 XX 工具,参数是 XX",然后由评估节点确认后再执行。这个确认可以是自动的(规则检查),也可以是人工的。

6.3 记忆检索的"相似度陷阱"

向量检索是基于相似度的,但相似不等于相关。我遇到过很多次,检索出来的记忆和当前任务"看起来很像",但实际上完全不相关。

比如用户问"上个月的销售数据",检索出来的可能是"上上个月的销售数据",因为文本相似度很高。但时间范围完全不同。

我的解决方法是混合检索:向量相似度 + 结构化过滤。先用结构化条件(如时间范围、任务类型)过滤,再在过滤结果中做向量检索。这样既保证了相关性,又保证了准确性。

6.4 不要试图让 Agent 处理所有事情

最后一个坑,也是最容易犯的:试图让 Agent 处理所有事情。

Agent 擅长的是"需要灵活决策的任务",不擅长的是"确定性高的任务"。如果一个任务有明确的规则和流程,用传统代码实现比用 Agent 实现更可靠、更高效、更便宜。

我的原则是:能用规则解决的,不用模型;能用简单模型解决的,不用复杂模型;能用单 Agent 解决的,不用多 Agent。每增加一层复杂度,都要有明确的理由。

7. 多 Agent 协作:什么时候需要,什么时候不需要

7.1 多 Agent 的适用场景

单 Agent 搞不定的事情,才需要多 Agent。具体来说,有三种场景:

第一,任务需要不同领域的专业知识。比如一个任务既涉及财务分析又涉及法律合规,单个 Agent 很难同时精通两个领域。这时候可以用两个专业 Agent 分别处理,再汇总结果。

第二,任务需要并行处理。比如需要同时查询多个数据源,单 Agent 只能串行执行,多 Agent 可以并行。

第三,任务需要对抗性验证。比如一个 Agent 负责生成方案,另一个 Agent 负责挑毛病。这种"生成-验证"的模式能显著提高输出质量。

7.2 多 Agent 的通信机制

多 Agent 系统最大的挑战是通信。Agent 之间怎么传递信息、怎么协调行动、怎么解决冲突,这些都需要设计。

我的做法是共享黑板 + 消息队列的混合模式:

  • 共享黑板:所有 Agent 都能读写的公共状态区。每个 Agent 把自己的中间结果写到黑板上,其他 Agent 可以读取。
  • 消息队列:Agent 之间的点对点通信。当一个 Agent 需要另一个 Agent 做特定事情时,发消息到队列。

黑板适合"状态共享",消息队列适合"任务协调"。两者结合,既能保证信息同步,又能保证任务有序。

7.3 多 Agent 的协调成本

多 Agent 系统有一个隐形成本:协调成本。Agent 越多,通信越复杂,出问题的概率越高。

我的经验是,Agent 数量控制在 3-5 个以内。超过这个数量,协调成本会超过收益。如果确实需要更多 Agent,就做分层:上层是协调 Agent,下层是执行 Agent,协调 Agent 负责管理执行 Agent。

8. 写在最后:一些个人体会

做 Agent 系统这几年,最大的体会是:架构比模型重要,工程比算法重要。

很多人把精力花在"换更强的模型"上,但实际项目中,模型能力的提升对整体效果的贡献是有限的。真正决定 Agent 好不好用的,是架构设计——规划器怎么拆任务、记忆怎么管理、工具怎么描述、反馈怎么做。

另一个体会是:不要追求"全自动"。企业级场景下,"人机协作"比"全自动"更现实。让 Agent 处理它擅长的部分,让人处理需要判断的部分,两者配合,效果比纯 Agent 好得多。

最后一个建议:从最小可用系统开始,快速迭代。不要一开始就设计一个完美的架构,先跑通核心逻辑,再根据实际问题逐步优化。Agent 系统的很多问题,只有跑起来才会暴露。坐在那里想,是想不出来的。

RELATED READING

延伸阅读

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