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,就像一个闭着眼睛走路的人——它不知道自己走到哪了,也不知道自己走对没有。反馈循环要回答三个问题:
- 当前步骤的结果是否符合预期?比如调用了查询工具,返回的数据是否完整、格式是否正确。
- 当前任务的整体进度如何?已经完成了几个步骤,还剩几个步骤。
- 是否需要调整计划?如果某一步的结果和预期差距很大,是否需要重新规划。
我的做法是在每个步骤执行后,插入一个轻量的"评估节点"。这个评估节点不调用大模型,而是用规则+小模型来做快速判断。只有在大规则判断不确定的时候,才调用大模型做深度评估。这样既保证了反馈的及时性,又控制了成本。
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 系统的很多问题,只有跑起来才会暴露。坐在那里想,是想不出来的。