外面很多人把 Agent 说得神乎其神,好像只要接个大模型、写两个工具函数,就是一个能自主干活的智能体了。但真正放到生产环境、扛住线上流量之后你才会发现,一个 Agent 能不能稳定跑下去,根本不取决于模型有多聪明,而是工程做得有多糙。我这两年在大厂里从零搭过 Agent 平台,也接手过好几个从 POC 到生产的项目,踩了一堆坑之后总结下来:大厂 Agent 不崩,核心就是把四件事做到位——编排、记忆、可观测、安全。这篇就把我实际落地过程中沉淀下来的经验拆开讲清楚,给正在做 Agent 开发、或者准备把 Agent 推上线的同学一个参考。
1. 先想清楚一件事:Agent 崩不崩,拼的是工程而不是模型
很多人有个误区,认为 Agent 效果差、不稳定,是因为模型不够强。我见过不少团队领导一拍脑袋说“换更强的模型就行”,结果换了 GPT 级别的模型,该崩还是崩。真正的原因在于,Agent 本质上是一个软件系统,不是一次 API 调用。模型只负责其中“理解与决策”这一环,而系统的稳定性取决于你有没有把流程、状态、数据、异常处理这些工程问题设计好。
1.1 为什么大厂 Agent 看起来“不会崩”
大厂的核心优势不是模型,而是他们在工程上做得足够“笨”——把每个环节都设计了兜底,而不是靠模型自由发挥。我举个例子,之前我们做内部运维助手,最早的方案是让模型自己决定调用哪个 API、参数怎么填,结果模型经常发挥创意,把参数格式搞错、调用顺序搞反。后来改成“流程模板 + 模型填槽”的模式,模型只能决定关键参数,执行路径由平台控制,稳定性立刻上去了。
再一个例子是重试机制。模型接口偶发超时、限流、返回格式不合法,这些都是家常便饭。大厂的 Agent 框架普遍内置了指数退避重试、结果校验、降级策略。而很多独立开发的 Agent,只做了一次 try-catch,返回异常就直接给用户道歉,这在线上是不可接受的。
1.2 四个关键词,直接决定 Agent 的生死
我把决定 Agent 稳定性的因素归纳成四个词:编排、记忆、可观测、安全。这四个词看起来分散,其实是一条完整链路。
- 编排:决定 Agent 遇到多步任务时怎么走、走错了怎么办。
- 记忆:决定 Agent 在长对话、多轮任务里怎么保持上下文不丢、不串、不爆。
- 可观测:决定 Agent 出错时你能不能快速定位是模型的问题、工具的问题还是流程的问题。
- 安全:决定 Agent 拿着工具权限时会不会闯祸、被人恶意利用。
这四个词对应了 Agent 从启动到执行再到结束的整个生命周期。任何一个环节出问题,Agent 就会表现得像个不稳定的实习生——时灵时不灵,你还不知道它哪根筋搭错了。下面我一个个展开讲。
2. 第一件事:任务编排不是让模型自由发挥,而是“流程兜底”
任务编排是整个 Agent 架构的骨架。我见过的所有线上翻车事故,几乎都跟编排层设计得太自由有关。很多人受 ReAct 这类论文影响,觉得 Agent 就应该是“模型循环思考-行动-观察”,但实际上纯 ReAct 在复杂任务上的成功率根本无法保障。
2.1 从 ReAct 到 DAG:确定性优先的编排思维
ReAct 的流程是模型自己决定下一步做什么,这在 demo 里很惊艳,但在生产环境就是灾难——你无法预判它会走哪条路,也就无法预判它在哪一步会崩。大厂的做法通常是把任务拆成 DAG(有向无环图),也就是把复杂任务预先分解成步骤,模型只负责在每个节点上做局部决策。
我参与的一个合同审核 Agent 就是典型的 DAG 设计:节点依次是“上传文件 → 解析提取 → 风险规则检查 → 模型总结 → 输出报告”。其中只有“风险规则检查”这一步会调用模型,其他步骤全是确定性代码。这样即使模型在某一步抽风,整个流程也不会失控,最多是这一步的结果质量差一些。
还有很多场景用到了Plan-and-Execute模式:第一轮让模型生成执行计划,后续每个步骤严格按计划执行,每执行完一步就把结果追加进上下文。这比纯 ReAct 好的地方在于,规划是一次性的,后续执行过程不容易跑偏。当然,如果任务本身是探索性的,比如“帮我研究一下某个竞品”,纯 ReAct 会更合适,但这种场景通常也不追求“不崩”,而是追求“结果丰富”。
2.2 Harness 与 Agent 的区别:很多人没搞明白
在 Agent 框架里,Harness 是我们经常听到但又容易混淆的概念。Harness 是跑 Agent 的“外壳”,负责管理工具调用、解析模型输出、组织上下文;Agent 本身则是“大脑”,负责决定下一步做什么。简单类比:Agent 是司机,Harness 是汽车——司机决定往哪开,但方向盘、刹车、油门能不能正常工作,是汽车的事。
我看到很多 Agent 崩掉,问题其实出在 Harness 上而不是模型上。比如模型输出了一段带 markdown 的 JSON,解析出错;或者模型调用工具时参数格式差了一点,Harness 没有做容错就直接报错。所以现在主流框架里,Harness 都会做一层“宽容解析”——模型输出不完全合法时,尝试修复而不是直接失败。
我个人的建议是,如果你在自研 Agent 框架,一定不要把 Harness 和 Agent 逻辑耦合在一起。Harness 要做得“厚”一点,把重试、校验、沙箱、日志全部沉淀进去,这样换模型、换 Agent 策略时,Harness 完全不用动。
2.3 实操要点:用状态机控制 Agent 的生命周期
执行一个 Agent 任务,本质上是一个状态流转过程。我推荐用状态机(State Machine)来管理,而不是靠模型自己保证流程正确。状态一般包括:
| 状态 | 说明 | 异常处理 |
|---|---|---|
| idle | 任务初始化,未开始 | 无 |
| planning | 模型生成执行计划 | 失败则降级为单步执行 |
| executing | 执行工具调用/子任务 | 失败重试,超时熔断 |
| observing | 处理工具返回结果 | 结果解析失败,清洗后重试 |
| waiting | 等待用户输入/人工审批 | 超时自动挂起 |
| finished | 正常结束 | 无 |
| failed | 无法自动恢复的错误 | 记录快照,转人工处理 |
这么设计的好处是,每一步都有明确的前置条件和后置动作,你可以针对每个状态做监控、做告警、做恢复策略。比如 executing 状态连续重试 3 次还失败,就进入 failed 状态,并保存整个执行上下文快照,方便后续排查或者人为诊断。
我踩过的一个典型的坑是:一开始为了“灵活”,没有状态机,直接靠模型描述来推进流程。结果有一次模型在中间步骤突然“失忆”,开始胡说八道,导致整个流程走进死胡同。后来改成状态机,模型只负责在 specific state 里产出决策,执行逻辑全部由代码控制,再也没出现过这种“鬼打墙”式的问题。
3. 第二件事:记忆不是越长越好,管理不好就是灾难
Agent 的记忆问题,本质上是上下文工程问题。很多人觉得给模型塞越多上下文它就越聪明,实际上恰恰相反——上下文越长,模型的注意力越分散,越容易忽略关键信息,还会带来 token 成本暴涨和响应延迟增加。大厂 Agent 的记忆系统,核心工作不是“记住”,而是“忘掉”——有策略地丢掉不重要的信息,保留关键信息。
3.1 上下文爆炸是怎么毁掉 Agent 的
我接手过一个客服 Agent 项目,最初的设计是每轮对话都拼接全部历史消息,跑了不到两周就出问题了:用户说了一句“刚刚我说那个事怎么样了”,模型完全不知道用户指的是哪个事,因为前面的关键信息已经被海量闲聊冲淡了。而且随着上下文增长,单次请求的 token 费用直线上升,响应时间从 1 秒涨到 5 秒以上,用户体感非常差。
这就是没有做记忆管理的典型症状。模型在处理长上下文时,对中间部分信息的注意力会显著下降,这就是所谓的“lost in the middle”现象。你塞进去 10 万 token,模型真正用到的可能就几千 token,其他全是噪音。
3.2 分层记忆:短期、工作、长期怎么划分
我实践下来比较有效的方案是分层记忆,分为三层:
- 短期记忆(Short-term):只保存当前任务或最近几轮对话,通常作为 prompt 的有效部分直接传给模型。
- 工作记忆(Working):保存当前执行计划、已执行步骤、中间结果,让 Agent 能持续推进多步任务。
- 长期记忆(Long-term):保存用户画像、历史偏好、总结性记忆,通过检索按需注入,而不是全量携带。
举个例子,一个购物推荐 Agent 的长期记忆里可能会有“用户偏好运动户外类产品”,但这些不会全量塞进每次请求,而是在用户提到“想买点东西”时,通过向量检索把相关商品类目和历史行为注入到当前上下文。这样既保留了记忆,又不会污染当前轮次的重点。
3.3 记忆清洗与压缩的实操方法
记忆管理最重要的一环是压缩与提炼。我这里分享两个我一直在用的方法:
第一个是滚动式摘要。当对话或任务日志超过一定长度(比如 2000 token),就调用模型对旧内容做一次摘要,然后把摘要作为历史记忆存下来,丢弃原始细节。这比直接截断效果要好得多,因为截断可能把关键信息切掉。我一般会设置一个摘要触发阈值:上下文接近模型窗口的 70% 时,对最早 50% 的内容做摘要压缩,然后继续执行。
第二个是关键信息结构化抽取。从每轮对话中提取结构化信息(用户的需求、提供的材料、确认过的决策),存入数据库或 KV 存储。后续需要时,用规则或模型检索出最相关的几条注入上下文。我常用的是把每轮对话抽象成 {time, user_intent, entities, action, result} 这样的结构,比纯文本日志更容易检索。
还有一个容易被忽略的点:工具返回结果也要做记忆治理。Agent 调用搜索、查数据库后可能拿到很长的返回内容,不能一股脑塞进上下文。我曾经调一个订单查询接口,返回结果有 8000 多行,直接导致后续决策质量急剧下降。后来加了“返回结果摘要”节点,无论工具返回多少内容,到模型之前都先做一轮摘要,控制在 500 token 以内,问题立刻解决。
4. 第三件事:可观测性决定你的 Agent 是“失控”还是“可控”
Agent 系统的调试难度比传统后端高一个量级。传统后端你只要看报错堆栈,基本能定位问题;但 Agent 是“模型决策 + 工具调用 + 外部数据”的混合体,任何一个环节出问题,表象可能都一样——用户觉得“它变傻了”。没有一套完善的可观测体系,你根本无从下手。
4.1 没有 trace 的 Agent,就是黑盒
我接手的一些早期 Agent 项目,日志就只有一句“agent execution terminated due to error”,没有任何上下文数据,这等于什么都没说。是模型输出异常?是工具超时?是 JSON 解析失败?是触发了安全拦截?你完全不知道。这种系统别说优化了,连恢复正常都靠运气。
所以我在任何 Agent 项目里,第一件事就是加 trace(链路追踪)。每一个环节都要记录关键信息:
- 模型调用:输入/输出 token 数、模型名、温度、耗时、返回内容是否合法。
- 工具调用:工具名、入参、出参大小、耗时、状态码、错误信息。
- 流程节点:节点名、进入时间、退出时间、是否走了异常分支。
- 记忆操作:检索到了什么、注入了什么、摘要压缩前后的大小。
如果你用的是成熟的 Agent 框架,很多 trace 能力是内置的;如果是自研,建议直接接 OpenTelemetry 标准,每个 Agent 实例一个 trace ID,贯穿一次完整任务。这样你可以在一个页面里看完整条执行链路,就像调试普通接口一样方便。
4.2 关键指标:token 消耗、延迟、错误率、工具调用失败率
光有 trace 还不够,你还需要一套指标监控,实时反映 Agent 的健康状态。我重点盯这几个:
| 指标 | 预警信号 | 应对措施 |
|---|---|---|
| token 消耗增速 | 单任务 token 消耗异常增长 | 检查是否上下文泄漏、记忆治理失效 |
| 端到端延迟 | P95 延迟持续上涨 | 检查模型响应、工具耗时、重试是否过多 |
| 工具调用失败率 | 失败率超过 5% | 检查工具接口稳定性、参数生成是否正确 |
| 任务完成率 | 完成率低于 90% | 检查编排逻辑、模型输出质量 |
| 重试触发率 | 重试次数过多 | 搜索限流、超时配置,以及解析容错率 |
| 上下文压缩频率 | 高频触发摘要 | 说明单任务过长,调整任务拆分逻辑 |
我在搭建 Agent 监控面板时,始终把一个指标放在第一位:用户可感知的失败率。这个指标不是看 Agent 内部报了多少错,而是看最终用户有没有得到他想要的答案或动作。很多内部错误可能被重试消化掉了,用户无感,那就不是严重问题;但用户反馈“答非所问”,即使系统内部没有任何报错,那也是重大故障,说明决策质量出了问题。
4.3 一个简单的排查流程
当 Agent 出问题时,我一般按下面的顺序排查:
- 先看 trace 里有没有异常,是模型层还是工具层还是流程层。
- 如果是模型层,回放当时的输入和输出,看是不是 prompt 问题或者上下文信息不足。
- 如果是工具层,直接试一下工具接口,看是不是外部依赖挂了。
- 如果是流程层,检查状态机,看是不是走到了预期外的状态。
- 检查记忆层,确认注入的上下文是否准确,有没有过期数据。
有一招我觉得特别实用:在 Agent 执行平台的每个关键节点都支持“重放”功能。也就是说,我可以把某一次任务的全部输入和状态快照拿回来,在测试环境里重新跑一次,甚至在中间某个节点改一下 prompt 再跑。这比对着日志猜要高效太多了。目前一些开源 Agent 框架也开始支持这种 run replay 能力,我建议自研平台一定要考虑做进去。
5. 第四件事:权限与安全是最后一道防线
很多人把 Agent 安全当成上线前的合规检查,其实这是大错特错。Agent 的安全问题,是一旦发生就是大事故的问题。因为 Agent 手里拿着工具权限,它的一句错误决策可能直接触发一笔转账、删除一条数据、发送一封邮件。在大厂里,这甚至是 Agent 能不能上线的“一票否决项”。
5.1 工具越权比模型幻觉更可怕
我见过不少 Agent 事故,最典型的几种是:
- 模型被 prompt injection 诱导,调用不该调用的高危工具(比如从“帮我查天气”被诱导成“帮我转账”)。
- 工具权限过大,Agent 能访问它根本不需要的数据。比如一个只负责汇总日报的 Agent,居然有数据库的写权限。
- 用户在对话中上传了恶意文档,文档内容里藏了指令,模型读到后被带偏,执行了恶意操作。
这些事故的根源不是模型不够聪明,而是权限管控太松。把工具权限全部交给模型决策,等于把方向盘交给了一个容易被人忽悠的司机。
5.2 最小权限、沙箱隔离、确认机制
关于 Agent 安全,我建议一定做三层防护:
第一层是最小权限原则。Agent 生态里每个 Agent 都能配置独立的访问凭证,只给当前任务必需的最小权限。比如一个“汇总周报”的 Agent,只能读周报相关数据,不能碰任何写接口;一个“发邮件”的 Agent,只能调用发邮件工具的指定模板,不能自由编辑任意收件人和内容。
第二层是沙箱隔离。Agent 执行的代码、访问的网络、操作的文件系统,都要跑在隔离环境里。往极端了说,即便 Agent 被诱导执行了恶意脚本,也只能影响沙箱,不能触碰核心资产。我自己在给 Agent 做代码执行功能时,用的是容器隔离加网络白名单,确保 Agent 只能访问白名单内的内网服务,出网全部禁止。
第三层是风险操作的人工确认。凡是涉及转账、删除、发布、发送外部消息这类高风险动作,一律走“Agent 发起 → 系统拦截 → 用户确认 → 再执行”的流程。技术实现上,可以在工具层包一层 guard 函数,检查目标操作的风险等级,超过阈值就返回“需要用户授权”的状态,由前端弹出确认按钮。
5.3 Agent 安全的实操清单
我把自己落地过的安全防线整理成一个清单,你可以直接抄:
| 检查项 | 具体要求 |
|---|---|
| 凭证管理 | 每个 Agent 独立 key,不共用权限,定期轮换 |
| 工具白名单 | 每个任务只能调用白名单内的工具,严禁通配 |
| 数据脱敏 | 模型注入前过滤手机号、身份证、密钥等信息 |
| Prompt 注入防护 | 对用户输入和外部内容做特殊标记,与系统指令隔离 |
| 高危操作审批 | 高危动作必须人工确认,且有操作审计记录 |
| 沙箱隔离 | 代码执行在容器内,文件系统只读,网络白名单 |
| 操作审计 | 每次工具调用都有完整留痕,包括入参、出参、执行者 |
| 限流配额 | 单任务 token 上限、调用次数上限,超限自动熔断 |
安全这里我还想说一个反直觉的经验:越“智能”的 Agent,安全设计要越“笨”。不要相信模型能自己判断“这句话是不是恶意指令”,它就是会被骗。你只有从架构上让它没有权限做危险的事,才能真正安全。
我之前参与过一个内部 Agent 平台,最初把敏感操作权限都放开给模型,理由是想“让 Agent 更自主”。结果测试时一条精心构造的 prompt 直接让 Agent 删了一张测试表。幸好是测试环境,但这件事给团队提了个醒:自主不等于放权,安全必须硬编码在系统里。
6. 常见问题与排查技巧实录
最后这部分,我把自己实际调试 Agent 时碰到的高频问题整理成一张速查表,附带我用的排查思路和解决办法。如果你也正在被这些问题折磨,可以直接对照操作。
6.1 经典故障:agent execution terminated due to error
这个错误大概率不是模型不行,而是中间某个环节没有被兜住。我遇到过的具体原因包括:模型返回的 JSON 里有非法字符、工具超时未处理、上下文超出模型窗口、状态机进入了未定义状态等。
排查步骤很简单,第一步一定先看 trace,定位错误发生在哪个节点。如果发生在模型节点,就把模型的原始输出存下来,再用宽松解析器重新解析一下;如果发生在工具节点,检查是不是工具接口超时或者返回数据格式不符。这个错误之所以臭名昭著,是因为它本身不提供任何上下文,只靠这句话你根本不知道发生了什么,所以一定要配合 trace 数据一起去查。
6.2 测试 Agent:从单测到混沌
Agent 的测试和普通后端不一样。普通后端是“输入固定,断言输出”,但 Agent 是“同样输入,每次输出可能都不一样”。所以我们的测试策略要做成多层次的:
| 测试层级 | 重点验证内容 |
|---|---|
| 单元测试 | 每个工具的入参出参、状态机状态转换是否正确 |
| 模型输出校验测试 | 模型输出格式、JSON 可解析性、意图分类准确性 |
| 场景回归测试 | 固定一批典型任务,跑 10 次统计成功率是否达标 |
| 对抗测试 | 注入恶意 prompt、异常输入,验证安全防护是否生效 |
| 混沌测试 | 随机让某个工具超时或返回异常,验证重试和降级逻辑是否生效 |
我尤其推荐场景回归测试用固定 seed 或者固定温度=0来保证一定的可重复性。虽然模型仍然不完全确定,但温度设为 0 时输出稳定性会提高很多。对于生产环境,我通常要求核心场景的成功率不低于 90%,低于这个数值就直接阻止发布。
6.3 我的一些经验和体会
按照我个人的经验,Agent 想做到“能上线、不崩”,精力分配大概是:20% 花在模型调优上,80% 花在工程兜底上。模型只是决策引擎,真正决定用户体感的是你在这个引擎外面包了多厚的保护层。
如果你刚开始做 Agent,不要一上来就搞复杂的自主规划。先跑通一个“有限步骤 + 确定性流程 + 工具调用”的最小闭环,把 trace 和监控接上,再逐步放开自主性。每放开一个自由度,都要先补上对应的兜底措施。这个顺序走对的话,你的 Agent 会越做越稳;反过来,一上来就想全自主,大概率是上线即翻车。
最后分享一个我在实战中一直用的习惯:每个 Agent 任务结束后,都自动生成一份“执行摘要”,记录这个 Agent 这次干了什么、调用了哪些工具、消耗了多少 token、有没有异常。这样你不仅能对外交代清楚 Agent 的行为,也为后续优化积累了最真实的样本数据。做 Agent 开发和做传统后端最大的区别就是,你不能完全信任代码之外的“智能部分”,所以要靠工程手段把不确定性控制住。这套方法论执行到位了,你的 Agent 距离“不崩”就不远了。