首页 / 资讯中心 / 文章详情

Agent 架构实战:从五组件与 ReAct 循环到企业级 Agent OS 落地

Agent 架构实战:从五组件与 ReAct 循环到企业级 Agent OS 落地 ★ FEATURED ARTICLE
做 Agent 的同行大概都有过这种时刻Demo 里把 ReAct 循环跑通信心满满觉得 Agent 架构不过如此等接到企业内部需求才发现模型答对了问题系统却做不对事。我这两年一直在折腾 Agent 架构从脚本串流程一路重构到带调度、带审计的 Agent OS最大的体会是Agent 不是“一个模型”而是一台需要被设计、被约束、被观测的机器。这篇内容围绕五组件、ReAct 循环和私有可控底座展开把 Agent 到底是“怎么转起来的”讲清楚也把企业落地时真正卡人的环节一个个点出来。正在做 Agent 应用或者正在评估企业级落地路线的架构师和开发者可以直接照着这个框架去对照自己的项目。1. 五组件先讲清楚Agent 不是“一个模型”是一台运转的机器1.1 我用的拆法感知、规划、记忆、工具、执行业界聊 Agent 组件说法很多。有的把模型本身算一个组件有的把“反思”“评估”单独拎出来。我自己的习惯是拆成五块感知、规划、记忆、工具、执行。这么拆不是学术洁癖而是因为五块的生命周期、性能瓶颈、故障模式完全不一样工程上必须分开对待。组件核心职责典型落地产物最容易出问题的地方感知理解并清洗输入组装模型可见的上下文输入脱敏、意图判别、提示词模板敏感信息漏过滤上下文乱拼规划目标拆解、策略选择、反思调整Planner 路由、few-shot 模板计划反复变越改越乱记忆保存和检索工作状态、历史结论对话缓存、向量库、摘要器上下文膨胀检索不到关键信息工具把外部能力变成模型可调用的接口工具描述、参数 schema、注册表描述不清晰模型乱调用执行把工具调用落到真实系统并拿回结果执行器、沙箱、结果回传格式权限失控、副作用没拦住感知层常常是被低估的。很多人直接把用户输入塞进 Prompt这不算感知感知要做的是把原始输入清洗成模型容易理解、又不会泄露越权信息的模样。比如企业里用户可能在对话框里粘贴一段包含手机号、工号的日志感知层要能识别并脱敏再决定哪些字段可以进模型上下文。这个动作放在模型外面做比放在模型里面做便宜得多也好审计。规划层是 LLM 推理最集中的地方。目标拆成几步、每一步选什么策略、发现上一步结果不对要不要换方向都在这一层。要注意的是规划不一定每轮都要做。很多稳定项目其实是“一次规划、多轮执行”开头让模型输出一个 Plan后续只针对当前步骤做小范围决策而不是每轮都重新想一遍全局。这样又省 token行为又稳定。记忆层分短期和长期。短期记忆就是当前任务里的对话历史、中间状态长期记忆是跨任务要复用的知识、用户偏好、历史结论。记忆的关键问题永远是三个存什么、怎么取、什么时候忘。存什么取决于任务类型检索顺序会影响模型判断而“什么时候忘”决定了上下文会不会爆炸。工具层是模型和外部世界的接缝。工具描述写得好不好直接决定 Agent 是聪明还是智障。描述含糊的接口模型会传错参数甚至把只读工具当成写工具用。工具层必须做参数校验、超时控制、错误信息归一化让错误以结构化的方式回到 ReAct 循环里而不是抛一个血淋淋的堆栈。执行层是真正动手的那一环也是最需要防御的一环。它不只是 HTTP 调用器而是安全边界哪些 API 能调、以什么身份调、调完结果怎么回传全文、原始响应要不要留档都在执行层定。我把执行层比作公司的前台谁都能进来但每一脚都要登记。1.2 五组件的数据流一个请求走完一台机器五组件不是五个抽屉而是一条闭环流水线。一次真实请求大致是这个路径感知层接住用户输入完成意图判别和脱敏把“用户想干什么”的结论连同必要的上下文传下去。组装系统提示、对话历史、可用的工具清单交给规划层。规划层的 LLM 产出本轮的动作要么是“调工具”要么是“直接回答”要么是“补充追问”。如果动作是调工具工具层根据模型输出的工具名和参数做映射、校验然后把调用请求标准化。执行层真正运行这个调用拿到原始返回做截断、抽取、格式化变成一条 Observation。记忆层把这条 Observation 写回工作记忆同时可能触发长期记忆的检索或更新。整段历史回到规划层开启下一轮推理。这个路径在每轮 ReAct 中都会走一遍直到规划层认为任务完成。关键是组件之间不要越权感知层不要顺手调工具执行层不要替规划层决定下一步。很多翻车现场都是因为某一步想“顺手帮一把”结果整条链路的可观测性就断了。1.3 组件边界的实际意义为替换、裁撤和观测留余地边界清晰最直接的好处是可替换。底座模型要换只需要改规划层的接口和上下文格式知识库要换只需要动记忆层工具从单体接口拆成微服务工具层做适配就行。组件之间用明确的协议连接而不是把逻辑粘在一个大函数里。其次是限流和降级方便。记忆层可以给热门知识做缓存工具层可以给第三方接口做熔断执行层可以按用户身份做配额控制。如果这些东西混在一个模块里任何一个环节出问题整个 Agent 都要重启。最后是可观测性。五组件各留各的日志配合 trace id能一眼看出问题出在“模型想错了”还是“工具打不通”还是“记忆没检索到”。这个对于企业落地来说不是可选项是强制项。我见过太多项目上线后出问题只能看到一句话的 prompt 日志完全没法复盘。2. ReAct 循环原理谁都懂生产环境里全是细节2.1 三段式循环的本质与伪代码ReAct 是 Reasoning and Acting 的简称核心思路是让模型不要一次性把答案憋出来而是边想边做、做了再看、看了再想。它由三个信号组成闭环Thought、Action、Observation。Thought 是模型用自然语言写下判断依据Action 是具体动作要么调用工具要么直接输出最终答案Observation 是工具或环境返回的结果作为下一轮 Thought 的输入。伪代码长这样history [] while not finished and len(history) max_steps: message build_reasoning_prompt(history, available_tools) response llm.chat(message) thought response.get(thinking) action parse_action(response) if action.type finish: return action.answer if action.type tool_call: observation tool_registry.execute(action) history.append(format_observation(thought, action, observation)) else: history.append(format_invalid(action)) # 让模型看到“这个动作不合法”下一轮自己纠正 return fallback_response() # 达到最大步数走降级逻辑这段伪代码很简单生产环境里真正的难点全在循环的控制策略。ReAct 不是一种框架而是一种推理策略它可以跑在裸模型上也可以跑在任何编排框架里。你要理解的是每一轮都会产生一次模型调用循环的轮数直接决定成本和时延。把 6 轮循环压到 3 轮成本就降了一半这不是优化需求这是经营需求。2.2 循环失控的三个典型症状第一个典型症状是空转。模型 Thought 写了一堆但工具调用很稀疏或者反复调用同一个工具拿同样的结果。根因通常是 Observation 太长太乱模型从中提炼不出增量信息。我见过一个案例模型连续四轮调用同一个查询接口只因为接口返回的 JSON 里字段层次太深模型没意识到答案早就回来了。修法不是改 Prompt 让它“别重复”而是把工具返回做结构化摘要把关键字段直接顶到最前面。第二个典型症状是幻觉工具调用。模型调了一个不存在的工具或者把工具名写错。小模型尤其容易这样工具数量一多更是重灾区。修复手段有三件套工具名尽量短且语义唯一解析层对工具名做严格匹配而不是模糊匹配一旦匹配失败把“错误提示”作为 Observation 回传给模型给它一次自纠机会。一次不行就降级不要无限重试。第三个典型症状是上下文爆炸。每轮把完整 Observation 拼进历史跑四轮之后一段一千字的 JSON 就进去了模型根本抓不住重点还会把后面真正重要的信息挤出去。这个问题的解法分两层Observation 先截断再入史只保留任务相关字段历史里的低价值轮次做摘要压缩把一个长任务压成几行“已执行动作结论”。生产环境里还要卡死几个硬指标最大步数建议 5 到 15 轮超过就强停单轮工具超时设 10 到 30 秒整体任务设一个墙钟时间比如 60 秒跑不完就转人工。这些参数最好放在配置中心因为不同任务的合理值差很多写死在代码里只会让你频繁发版。2.3 我在生产环境对 ReAct 做的三处改造第一处是“先计划后循环”。我在第一轮要求模型必须输出一个 Plan里面写清任务分几步、每步依赖什么工具。之后的 ReAct 循环只针对当前步骤做小决策不再每轮重写全局计划。这样既保留了 ReAct 的动态适应能力又避免了模型“计划赶不上变化”的漂移感。实测下来任务完成率比纯 ReAct 高出七八个百分点轮数还更稳定。第二处是 Observation 预处理。工具返回的原始 JSON 完整保留到审计日志里但进入模型上下文之前先用规则或一个小模型抽取关键字段组装成“执行结果失败/成功关键字段xxx错误信息xxx”这种紧凑格式。这一改token 消耗直接降了约三分之一模型也明显更少说胡话。代价是要多维护一层格式化逻辑但它非常值得。第三处是操作预算显式化。我会在系统提示里写清楚“本轮任务你最多还能调用 N 次工具请谨慎选择”。模型看到剩余预算后会更倾向于先查证再下结论而不是随手把能用的工具都点一遍。这种看似不起眼的约束对控制成本和减少误操作比任何技巧都有效。3. 企业级 Agent OS把 Agent 当成一套可治理的系统来管3.1 单 Agent 落生产为什么会“碎”单 Agent 在笔记本上跑得再欢一进企业环境就会碎。碎在哪儿第一是生命周期没人管长任务跑到一半服务重启进程没了状态也不知道去哪了。第二是并发隔离缺失多个用户同时用如果上下文对象是全局共用的用户 A 的数据会串到用户 B 的会话里。第三是工具变成一团乱麻今天加一个接口明天改一个参数没人知道哪些工具还能用、哪些已经被废弃、哪些只允许特定部门调用。这些问题的本质是你没有一个承载 Agent 的“运行环境”。单 Agent 就像一台能算题的计算器而企业要的是一个数据中心有门禁、有监控、有备用电源、有操作记录。Agent OS 就是给 Agent 建这个数据中心。我见过不少团队把 Agent 做成一个常驻内存的大单体所有逻辑都往里面塞。短期看是快长期看每一次改动都会牵一发动全身。真正的解法是把“Agent 本身”和“Agent 运行所需的底座”分开。前者解决业务问题后者解决可靠性、权限、观测和协作问题。3.2 Agent OS 的五个核心模块Agent OS 不是一个需要写多少行代码的东西而是一组职责的集合。我在内部分层时固定了五个模块模块职责具体产物运行时Agent 实例的创建、调度、健康检查、超时管理任务生命周期状态机、异步执行队列状态管理会话状态、任务中间状态、业务状态的隔离与持久化每个任务独立的上下文容器可恢复工具注册中心工具注册、描述管理、参数校验、灰度发布工具元数据库、健康检查脚本可观测性轨迹回放、指标统计、评估集、告警完整记录 thought/action/observation 的可检索日志策略引擎权限判定、审批流、风险动作拦截、操作审计动作分级、审批接口、黑名单白名单运行时这层别看简单卡住很多团队的是“任务中断恢复”。用户问了一半去开会任务挂着重启后能不能从最近一个 Observation 继续我这里采用的做法是给每个 Agent 任务一个持久化状态对象把当前计划、历史记录、剩余预算都序列化存起来。任务中断后按状态对象重新加载而不是一切重来。状态管理要特别强调隔离。每个任务独立上下文容器容器之间不能互相读写。这个容器里存的是什么当前目标、已经执行过的动作列表、最新的 Observation、用户的原始诉求。容器只能由运行时进程访问策略引擎可以读但不能被工具直接碰。这是防止 Agent 在执行工具调用时把内部状态一起读走的最后防线。工具注册中心的价值在于度量和灰度。每个工具都登记负责人、允许调用它的角色、平均耗时、失败率、最近一次验证时间。新增工具先走灰度只在小比例任务里放开失败率超阈值自动摘除。这比在代码里硬编码工具列表要严谨得多。评测下来工具注册中心能把“模型调用失效工具”的概率降一个数量级因为失效工具根本就不会出现在模型可见的清单里。可观测性是企业最容易节省、最后最痛苦的一环。我的建议是从一开始就让每条日志带上 trace id把一次任务的完整轨迹记录下来。轨迹里不仅记录调用了什么工具还要记录模型每一轮的 Thought 原文以及最终答案对应的是哪轮动作的产物。有了这个问题复现才不是玄学。策略引擎单独拎出来讲因为它是“让 Agent 能干活又不闯祸”的阀门。策略分两类动作前的预防比如写库操作需要当前用户有对应权限没有就拒绝动作后的审计比如每次删除操作都记录发起人和审批人。策略引擎不参与业务逻辑它只看工具调用的元信息来决定放行、拦截还是转人审。3.3 多 Agent 协作从编排走向运行时治理企业里很快会遇到多个 Agent 的场景一个客服 Agent、一个运维 Agent、一个数据分析 Agent各管各的。再往后一个复杂任务需要多个 Agent 接力或并行。这时候 Agent OS 的第二个作用出来了消息路由、任务调度、共享记忆。多 Agent 协作我建议先想清楚一个问题你是要让多个模型“互相聊天”还是要模块化分工如果是前者很容易做成两个模型互相客气的死循环如果是后者本质是把一个大任务切成多个小任务分别交给不同 Agent再由主 Agent 汇总。后者稳定得多也更好测。OS 层要为多 Agent 提供三个基础件任务队列、结果回执、冲突裁决。任务队列避免每个 Agent 都在抢同一个工具结果回执让下游 Agent 知道上游到底交付了什么冲突裁决处理两个 Agent 结论不一致的情况通常交给主 Agent 做决断或者直接按预设策略选高置信度的一方。多做这一步多 Agent 系统才不至于沦为玩具。4. 私有可控底座模型、数据、权限三条线怎么取舍4.1 模型线私有化部署与托管 API 的取舍“私有可控底座”这个词在企业里不是赶时髦是被合规和隐私需求逼出来的。很多内容不能离开内网那模型这一环就不可能默认使用外部托管模型 API。私有化部署的开源权重模型和托管 API 之间有一条非常清晰的取舍线。维度私有化部署开源权重模型外部托管模型 API数据出网不出内网原始数据本地处理请求内容会发到外部服务成本结构一次性硬件投入 持续人力维护按 token 付费规模越大越贵性能调优可微调、可换框架、可改采样参数参数有限只能提示词层面调上线周期需要硬件采购、模型适配、运维部署申请 key 就能跑稳定性依赖自身运维能力依赖服务方可用性我的建议是核心业务、含敏感数据的场景直接走私有化探索性场景可以先借托管 API 验证效果但数据要脱敏到可接受程度并且把“迁移回私有化”的工作量提前算清楚。最怕的情况是验证阶段用着顺手后面想搬回内网才发现模型行为对提示词极度敏感一换模型全部结果都要重新测。部署细节上显存估算是一条必算的账模型权重显存约为参数量乘以精度字节数。一个 70B 参数的模型FP16 精度下权重就要占约 140GB 显存这还不算 KV Cache 和中间激活值的开销上下文越长KV Cache 占用越大。所以没有单卡能扛大模型推理多卡张量并行几乎是标配。量化能压缩权重体积比如 INT8 对半砍INT4 再对半砍但量化后的精度损失要在你的评估集上亲自验证别只信宣传。推理性能上关注几个概念连续批处理能提高吞吐KV Cache 管理决定并发上限输出速度直接关系到用户的等待感受。私有化部署的模型通常不如同规模商业闭源模型聪明所以规划层的提示词、工具描述要写得更有耐心上下文组装也要做得更干净才能把这套系统整体体验拉到可用水平。4.2 数据线知识库、缓存、日志的边界控制私有可控底座第二条线是数据。企业知识库做 RAG文档向量化过程必须完全在内网完成向量检索服务也要部署在内网不能让文档内容的外发变成常态。这里有个容易被忽略的细节外部模型接口在调用时请求体如果有文档片段哪怕只是一个句子也算一次数据传输。所以 RAG 场景一旦涉及机密资料路由策略必须是“先本地检索再决定哪些片段能进模型上下文”。缓存层同样要控制边界。我把缓存分成两层热缓存存常见问答的最终答案相似问题命中缓存就直接返回答复不再调用模型。这样做既省钱又降低数据外发频率。缓存里的条目要带有效期和验证机制知识文档更新后相关缓存要主动失效免得 Agent 拿着旧资料一本正经地胡说。日志是另一个边界问题。Agent 执行过程中的输入输出、工具调用记录都要落日志但日志同样承载敏感信息。我这边采用“完整留档 展示脱敏”的方式审计日志里存原始内容查询界面只显示脱敏后的版本只有授权人员能通过受控通道查看原文。日志保留周期按企业制度来定不要盲目拉长保留期越长泄露风险面越大。工具执行的网络边界也要画清楚。Agent 所在容器不该有访问整个内网的权限。我见过一个案例Agent 的工具接口里混入了一个能连内网数据库的通用查询器差点让模型通过注入的方式把全表拖出来。做法是每个工具声明自己的网络白名单执行层按工具名绑定网络策略做不到最小权限的干脆不让上线。4.3 权限线让 Agent 能动手但动手要留痕权限线是私有可控底座里最容易被业务方挑战的一环。业务方总希望“Agent 全自动”但真正出事的时候第一个背锅的必然是那个多给了权限的人。我坚持的原则是工具分级、动作审批、全程留痕。工具分级很简单只读类比如查资料、查状态写操作类比如创建工单、更新字段高危类比如删除数据、发对外消息、转账。不同级别对应不同策略只读类自动放行写操作类默认放行但要记录高危类必须走审批流先由 Agent 生成操作计划人工确认后执行。这个“人机审批”不是拖慢效率是对 Agent 幻觉的最后一道闸。身份传递也很关键。Agent 调用内部系统时尽量带着发起用户的身份而不是用一个共享的服务账号。这样一来权限校验可以按用户做审计也能追溯到具体的人。共享服务账号会让所有操作变成同一个“马甲”出了事什么都查不清。留痕要做到可重放。记录 Agent 在每一步看到的 Thought、选择的 Action、拿到的 Observation、最终结果、异常信息以及整个过程的耗时。这些记录不是为了好看的报表而是为了将来出问题时回答三个问题这个工具是谁调的、依据是什么、谁批准的。5. 一个内部项目的落地复盘从 ReAct Demo 到可交付系统5.1 场景、边界与整体架构讲一个我们内部跑过的项目为了省事就叫它“模拟项目X”。背景是内部 IT 服务台员工有报障、查知识、开权限单三类需求原来靠人工客服在工单系统里流转。我们要做一个服务台 Agent员工拿自然语言描述问题Agent 自己判断类型、查知识库、需要时调用工单系统创建工单。架构分四层接入层负责接收消息和做基础意图分类Agent OS 负责编排、状态、策略和轨迹记录私有化推理服务负责提供模型能力系统连接器负责对接内部知识库、工单系统和统一身份。ReAct 循环跑在 Agent OS 里模型每一轮推理都由私有化服务响应。工具数量我们严格控制在一版 12 个按“查知识”“查资产”“建工单”“更新状态”“升级人工”五个场景分组。这个项目最开始的教训是想一口吃成胖子。第一版我们塞了 23 个工具意图也分了十几种结果模型策略混乱任务成功率只有七成左右。后来砍到 12 个工具、5 组场景成功率一下子涨上来了。工具少模型选择负担就小这是 ReAct 在企业应用里最容易被忽视的一条规律。5.2 关键实测数据与调优记录把一版调优过程中的关键指标列在下面这些数字只是我们单项目的数据但趋势有参考意义指标第一版调优后主要动作任务成功率72%91%工具缩减、Observation 预处理平均循环轮数9.45.2先计划后循环单任务 token 消耗基准线下降约 40%Observation 截断、历史压缩超时/死循环率6.8%0.3%步数上限、操作预算工具调用总失败率14%6%schema 校验、错误回传修正最值得说的是轮数和成本。第一版模型经常在 9 轮以上才收工每轮都是一次模型调用业务方等到没耐心。加入 Plan 机制和观察结构后平均 5 轮左右完成响应时间从平均 30 秒降到 15 秒以内。用户体感完全不一样投诉也少了。token 消耗的下降主要来自 Observation 预处理。工具返回的长 JSON 以往会原文进入下一轮推理产生大量无效注意力现在我们先抽取“成功与否、关键字段、错误信息”三个要素只把这几行送进上下文。模型决策所需信息都在白噪音少了准确率反而升了。5.3 踩过的坑和对应的修复方案坑一工具返回“成功”实际业务没生效。工单系统创建接口返回 200但字段没写全陷入了“表成功、仓失败”的状态。Agent 却自信满满地告诉用户工单已建好。修复方式是给写类工具加“操作校验”步骤创建之后立刻做一次查询确认数据真实落库再用确认后的状态作为 Observation。这个习惯我一直保留到现在。坑二模型传参格式不对。日期字段传成“2024-1-1”系统只认“2024-01-01”。修复不是写死格式化规则而是在工具层做参数校验并把校验失败的原因作为 Observation 回传给模型让它自行修正。几次下来模型学会按 schema 生成错误率从 12% 降到 3% 左右。让模型自己纠错比在代码里兼容每一个错误格式靠谱。坑三并发会话状态串了。原因是没有按任务隔离上下文容器多个请求共用了同一个全局状态。修复很朴素每个任务实例化独立的上下文对象任务结束时显式释放。排查这个问题的过程很痛苦因为问题只在并发量上来时偶现日志又看不出区别。从那以后状态隔离成为我评估任何 Agent 系统的第一道硬指标。坑四模型在长清单归纳时说胡话。私有化模型面对一张几十行的清单容易“总结”出一半对一半错的内容。修复办法是拆步先让模型把清单转成结构化键值对再基于键值对做归纳不要把“读取”和“归纳”放在一步。拆步之后错误明显变少代价是多一轮推理但正确性优先。坑五没有 trace id复盘全靠猜。早期日志只记录最终答案问题一多根本定位不到是哪轮动作出了问题。后来强制所有环节携带 trace id每一步轨迹都落库。这个改动不增加任何业务复杂度但对排查效率的提升是数量级的。现在每看到一个坏结果我能直接回放那条轨迹上每一轮的 Thought 和 Observation。5.4 团队协作中的几个建议代码之外的坑同样值得说。第一个建议是先拿三个工具的小场景跑通全链路再逐步加工具。三个工具能暴露的问题其实已经很多上下文、权限、状态、可观测性全会牵扯到小场景调顺了后面只是量变。第二个建议是必须有人认真打磨工具描述。工具描述越具体模型越不容易误用。写描述的时候把自己当成用户手册作者写明用途、参数含义、返回结构、典型错误。这个工作看起来不像写代码那么“硬核”但它的回报极高。同一个工具描述从两行扩到五段之后误调用率能差一倍。第三个建议是评估集要跟着迭代沉淀。每次实际任务里发现的坏案例都收进回归集模型、提示词、工具描述每次改动都拿回归集跑一遍。没有评估集你根本不知道一次 Prompt 修改是变好了还是变坏了。最后想说上线前务必做影子模式。让 Agent 在真实流量里跑但是只读执行不真正改动业务系统。跑上一周你会看到它的行为分布、工具调用偏好、失败集中在哪些场景。带着这些数据再做一次策略收紧才敢让它真正动手。我在实际项目中就是这么做的影子模式那一周收集到的案例比团队手工构造的测试集有用得多。
阅读完成 · 觉得有帮助?
咨询建站