Agent 上线后翻车的 6 种死法:一个 20 万人规模项目的四版重构实录
我们做了一个面向终端用户的业务 Agent,服务 20 万+ 用户,日均对话 50 万+。
前后重构四版,干掉约 90% 的幻觉,P95 从 15s+ 压到 10s 以内。
这篇文章不吹成绩,只讲每一版是怎么把自己坑死的,以及坑死之后想明白了什么。
0. 先说结论:四版没有一版是设计出来的
如果你正在做 Agent 落地,先记住这句话:四版没有一版是"设计"出来的,全是被上一版暴露的问题推着走的。
我们从头到尾都在解同一组矛盾:
- 幻觉——模型胡说
- token 成本——上下文越塞越多
- 响应延迟——推理轮次越多越慢
- 可运维性——改一处,全业务重新评审
这四个是互相拉扯的:要少幻觉就多约束多召回,token 涨、延迟涨;要快就少推理,幻觉涨;要好维护就得拆 prompt,拆开之后各段又互相打架。
判断一个 Agent 团队成不成熟,就看他能不能说清自己这一版的矛盾在哪。说不出来的,基本还停在第一版。
图 1 · 四版演进:每一版都是被上一版推着走的
死法一:强依赖意图识别 —— 每接一个业务,算法就要训一次
起点其实很小
2024 年 11 月,V1 上线。
起因特别朴素:我们拉了每日客服进线的 top10 问题,发现里面有大量是"我这个单为什么被判异常"。用户不知道判定依据,反复进线问。
初衷只是把我自己的重复工作做成 SOP 给用户——不是要做通用智能助手。
架构
前置一个意图识别层,根据静态意图分发到对应的工具或 subagent。
用户 query → 意图识别 → 分发 → 工具/subagent → 回复
它做对了一件事
跑通了 Agent 前后端的 SSE 链路。
这个价值被严重低估。流式链路是整个体验的地基——用户在等待的时候能看到字一个个出来,而不是盯着转圈 15 秒。很多团队到最后才补这块,结果整条链路的超时预算全要重算。
它死在三件事上
- 没有多轮能力——问第二句就接不上
- 强依赖意图——意图判错,后面全错,而且错得非常自信
- 每次业务接入,算法都要重新训练参数——交付周期以周计
第三点是致命的。这意味着每来一个新场景,都要排算法排期、标数据、训模型、评效果。业务方等不起,我们也撑不住。
为什么后来不用传统分类模型
因为 V1 就是那么做的。
分类模型的问题不是不准,是它只能回答"这是哪一类",不能回答"这个单具体指哪一个" ——"这个单"、"上一条"、"刚才说的那个",它完全接不住。而且每加一个场景,算法就要重新训一次。
它唯一的好处是能按意图输出观测指标,利于业务收集收益数据。换句话说,分类模型给你的是可观测性,不是能力。
死法二:全量塞给大模型 —— token 从 3200 涨到 1.2 万
为什么要重构
2025 年,模型能力明显变强了。我们发现这个助手非常傻:已读乱回,多轮输入,回答都一样。
决定重构。核心想法:不强依赖意图识别,让大模型完成整个推理和决策,并支持多轮。
架构:看起来非常标准
网关层 → 鉴权、安全验证、保存对话
上下文层 → 用户信息、工单信息、异常信息
编排层 → RAG 召回
能力层 → tool、skill
core agent→ ReAct 循环推理
模型层 → 云厂商模型服务 / 内部 agent 平台
+ 监控与评测
这个架构放在任何一篇 Agent 架构文章里都挑不出毛病。
它死在一句话上
我们把全量工具和上下文,一股脑全塞给了 core agent。
结果是必然的:
- token 从 3200 暴增到 1.2 万
- 幻觉不断
- 规则越界
- 响应超时
但最致命的不是这些
是没人敢动 prompt。
所有业务共用一个 prompt。改一块,全业务都要重新评审才能上线。
一个 prompt 变成了全公司最不敢碰的文件。改一个字,走三轮评审,拉五个业务方。到最后大家宁愿在代码里加补丁,也不愿意进 prompt——因为补丁至少不会连累别人。
根因
一句话:把「选能力」和「执行能力」混在一起了。
让一个模型既决定"用什么工具",又负责"怎么用工具完成任务",它就会在两个目标之间反复横跳。候选池越大,横跳越厉害。
图 2 · V2 的架构挑不出毛病,死于全量塞入
死法三:加一层编排 —— 压力只是搬了家
做法
在 core agent 前面加一层"编排":把工具描述语料打包灌进知识库,先根据用户 query 用小模型把能力选出来,再交给 core agent 用大模型继续推理。
用户 query → 编排(小模型选能力)→ core agent(大模型推理)
结果
能力确实解耦了。core agent 拿到的工具列表干净了,prompt 也不用再塞全量工具。
但问题没消失,只是从 core agent 转移到了编排层:
- 编排选错,后面全错(而且错得更隐蔽——core agent 会非常努力地用错工具,产出看起来很专业)
- 编排层的语料维护成了新瓶颈
教训
把复杂度往前搬,不叫解决,只叫搬家。
那一版之后我们才想明白:真正的解法不是"谁来选工具",而是怎么让候选池足够小、让选择足够确定。
死法四(转折):分层治理,稳定优先
V4 的核心词是:分层治理、稳定优先、大规模降噪、控幻觉、控成本。
这一版没有换架构,换的是"约束放在哪一层"。
具体做法涉及不少内部设计——工具描述怎么分级、召回策略怎么配、编排该收敛到什么规模——这块是我吃饭的东西,就不逐条展开了。但思路可以讲清楚,思路比参数值钱:
- 同一份工具信息,不该只维护一个版本。 检索要的是"详细"才能算准相似度,选择要的是"精简"才不会把上下文撑爆。用一份语料同时满足两件事,天然是矛盾的——必须按用途拆开,并让两边能对上。
- 改配置不该发版。 工具的说明文字是运营资产,不是代码。它必须能热更,否则每次调描述都要排一次发布窗口,"可运维性"这一项永远是负分。
- 候选池要在模型推理之前就收敛。 不是因为模型选不准,是因为候选池本身就是幻觉的温床——池子越大,模型越倾向于"猜一个看起来对的"。
- 记忆不能原样用。 这条我们踩了很久才想明白,下面单独说。
- 确定的事,压根不该交给模型。 完全确定的链路直接硬编码返回;半确定的(比如从对话里提炼单号)也不走推理,但走分发能力。模型只处理真正不确定的部分。
记忆为什么不能原样用
举个具体的例子。一个异常列表,工具返回的是一个大 JSON。以前我们就把 JSON 原样存进记忆。结果三件事一起发生:
- 模型看到 JSON 里某个数字,就把它当成了异常单号(这是"编造参数"最主要的来源)
- token 白白烧掉
- 指代消除变得极难——模型分不清"这个是列表里的第几条"和"这个是当前这单"
改法只有一句话:存储时不存原始结构,把里面的字段按语义拼成摘要再存。
一个动作同时解决三个问题:防幻觉、省 token、利于指代。
结果
- 约 90% 的幻觉被干掉
- 响应从 15s 以上降到 10s 以下
注意是"约 90%",不是"消灭"。后面我会说还剩什么。
幻觉不是一个问题,是六个
大部分人一说幻觉就加一句"不要编造"。没用的。
因为幻觉不是一个问题,是六个问题。 根因完全不同,药也不同。
| # | 类型 | 表现 |
|---|---|---|
| 1 | 跳过工具 | 该调工具,却直接拿记忆回答,直接返回 |
| 2 | 编造参数 | 没查到异常单,但上下文里有个数字类型,就赋值成单号(工单 ID、用户 ID) |
| 3 | 假成功 | 工具调用失败却报成功——上报接口报错,它返回"已上报成功" |
| 4 | 跨轮污染 | 把 A 单的诊断结论当成 B 单 |
| 5 | 跨单污染 | 同上,跨业务对象污染 |
| 6 | 路由幻觉 | 调一个根本不存在的工具 |
这张表值得抄下来贴墙上。因为很多人是在拿"加禁词"这一味药,去治六种完全不同的病。
图 3 · 幻觉六个入口:它们长在推理链的不同位置
治理有顺序,顺序不能反
架构层:确定性链路剥离、早退、缩小候选池
输入约束:schema 规范、参数格式约束、记忆摘要、强制工具白名单
流程管控:编排层预先收敛工具集
兜底保障:持续评测(实时采样 + 离线回放)
顺序很重要:先在架构上不让它有幻觉的机会,再用输入约束收紧口子,然后用流程管控限制选择空间,最后才用评测兜底。
很多团队是反的——一上来就靠 prompt 加禁词,治不了。禁词能压住"语气",压不住"事实"。
图 4 · 治理四层的顺序:越往下越省事,越往上越费钱
三个真正起作用的动作
一、让模型在上下文里见过"用工具完成任务"的样例。
我们一开始的记忆只存结果,不存工具调用,因为觉得和模型返回冗余。结果模型学会了直接用文本回答——它看到的上下文里,从来没有"靠工具完成"的先例,只有"用话回答"的先例。
这是一个很典型的坑:你训练它看见什么,它就成为什么。 该调工具的场景,记忆里必须留着工具调用的痕迹。
二、把提取规则写进参数 schema。
比如异常单号:多少位、从上下文哪里找、从历史记忆里哪里找。模型不知道你的 ID 格式,你不写清楚,它就编一个凑上去。
三、让候选工具在推理开始前就基本确定。
ReAct 阶段能用哪些工具,理想状态下在编排阶段就定了。如果推理想用的工具不在候选池里,正确处理是重试或追问,不是就地放行。
早退:降幻觉最大的一步,不是让模型变聪明
ReAct 的节奏是:模型 → 调工具 → 回模型 → 再决定。
但有些工具调完就是最终结果,不需要模型再推理。
比如把处理结果卡片推给用户——返回的结果本身就是终态,不需要再把 subagent 结果喂回模型、让它思考"该怎么回复"。
这时候直接结束:省 token,更少一次幻觉机会。
这一条和确定性剥离配合起来,是"幻觉降 90%、15s→10s"的主要来源。
不是靠模型变聪明,是靠不让模型做它不该做的事。 这句话我认为是整个 Agent 工程的纲领。
评测:怎么证明判官自己没判错
一个原则
规则能判的,不给模型;给模型的,必须有锚点、参考答案、证据、可复核。
按这个原则分三层:
| 层 | 场景 | 做法 |
|---|---|---|
| L1 | 规则能判的 | 硬编码直接判,不经过模型。比如调了不该调的工具、该上报的没上报 |
| L2 | 需要理解语义的 | 对照判。必须给判官锚点和工具返回作为证据,不许它自由发挥 |
| L3 | 判官自己也不确定的 | 放弃单次判断,用重复采样收敛 |
评测一定会拟合
就是判官跟着标准答案说,分数越评越高,上线就露馅。
这是评测体系最隐蔽的失效方式——它不会报错,只会让你越来越有信心。
唯一的解法是结构性的:出评测集时按意图分域打标,减少跨域干扰;参与诊断的数据和最终验收的数据必须是两批,物理上不重叠。
如果诊断和打分用同一批数据,模型就是朝着那批数据进化,看起来越来越准,实际什么都没学到。
现状
评测里人工仍占 80% 。这是我们目前最不体面的数字,也是下一步要啃的。
自进化:方案写完了,但还没实现
我们想做的是一条闭环:日志归集 → 自动判卷 → 分层诊断 → 开方 → 人工复核 → 生成新版本 → 重新评测 → 灰度上线 → 实时流量验证。
链路细节这里不展开(它还没跑起来,写出来是空话)。但有一个判断可以先给出来:
自进化最难的不是"发现问题",是"安全地改"。
一个能自动改 prompt 的系统,如果改坏了不能快速回切,它就是负债不是资产。所以这条链的每一环都得能刹车——这是它至今没上线的真实原因。
直接改 prompt,不怕改坏吗
怕。但怕不等于不改,等于给它加约束。
前提是 prompt 必须是分段拼接的,而不是一整坨。角色、边界规则、工具描述、历史记忆、实时上下文、强制注入——每一段职责清晰,出了问题才能定位到段。
在这个前提下,几条硬规矩:
- 一次只允许动极少数几段,且限定字数——逼你改得准,而不是改得多
- 每次改动用 diff 记录,保留快照,随时可回退
- 必须走灰度,必须有一键回切
- 连续打擂失败到一定次数,强制冷却,锁一段时间不许再改,同时告警到群里
最后这条是最反直觉、也最有效的:给系统装一个"冷静期"。 人急了会连续乱改,改得越多越乱,最后没人说得清是哪一版坏的。
关键认识:不是把 prompt 当代码管,是把它当配置 + 实验管。
工具调用失败怎么办:不是异常终止
所有工具调用统一封装,捕获异常,抛自定义异常(带工具返回的错误码)。然后分两类处理:
可重试的(超时、网络波动、IO 异常):自动退避重试若干次,仍失败则返回兜底。这类重试不消耗模型资源,因为重试本身不需要模型参与。
不可重试的:作为 tool response 喂给模型,让模型自己抉择——改参数?换工具?还是兜底回复。
这才是 ReAct 的本质:失败是信息,不是终态。你要做的是把失败正确地表达给模型,而不是替它做决定,也不是让它崩掉。
subagent 异常同理:全局捕获但不抛异常,转成结构化的失败信号,主 agent 收到后自己决策是换域、追问还是兜底。
再往外还有最后一层兜底:轮次上限、思考超时上限,到点直接输出兜底话术,配监控告警和降级策略。这一层不是为了提高效果,是为了保证系统不会无限卡住。
记忆:不是存得越多越好
几个结论,不讲实现:
- 会话内记忆必须有上限,且要有异步压缩机制。上下文不是免费资源,到阈值就必须压。
- 跨会话只需要摘要,不需要详情。 长期记忆我们至今没做——不是做不了,是没想清楚它在客服场景里到底值多少。
- 记忆的写入格式,比存多少重要得多。 前面说的"不存原始结构、拼成语义摘要",是这一条最具体的体现。
现在依然存在的问题(不装作解决了)
- RAG 召回的误触率和漏召率——召回错了,后面全对也没用
- 幻觉依然存在,只是比之前小很多
- 评测人工占比 80%
- 自进化尚未实现,方案写完,没跑起来
写这一段不是为了显得诚实。是因为一个说自己什么都解决了的 Agent 团队,通常只做过 demo。
下一步的方向
在试一个更"确定"的路子:不用生成式模型来做筛选判断,而是用确定性的筛选 + 打分 + 多选,只在给定候选池里输出、只判分不写答案。成本和延迟都比大模型低一个量级,而且类型安全。
用在两个地方:召回后做一次"query 与工具是否匹配"的过滤;再在收敛后的候选池里做多选。原编排模型降级为兜底,只处理低置信且复杂的 query。
效果还没验证,验证完再写一篇。我更愿意先给出判断,再给出结论——反过来就变成卖方案了。
最后:这套东西真正的方法论
回头看四版,真正的进步不是哪个技术选型,而是学会了把不确定性摆到台面上分级:
- 完全确定的 → 硬编码,不走模型
- 半确定的 → 走分发,不走推理
- 不确定的 → 才给模型推理,且必须有锚点、证据、可复核
这个思路同时解释了幻觉治理、评测判卷、自进化三个看起来完全不相关的模块。
图 5 · 把不确定性摆到台面上分级
如果只让我留一句话给正在做 Agent 落地的团队:不要问"怎么让模型更聪明",要问"这件事凭什么要模型来做"。
关于细节
有人会问:工具描述到底怎么分级?召回阈值给多少?判卷怎么投票?改 prompt 的字数限制是多少?
这些我确实没写。原因不复杂:这些数字是我在真实业务里试出来的,脱离那个场景,抄过去大概率是错的。
如果你正在做类似的事,卡在幻觉、成本、延迟、评测任何一环——把你们的具体场景发我,我可以直接说我的判断,比看参数表有用。
做过:面向终端用户的 AI Agent「业务助手」0→1(20 万+ 用户 / 日 50 万+ 对话)、业务运营低代码平台 0→1(新场景周级→天级)、资金安全 5 倍洪峰零资损。