尧图精选

AI Agent 从 Demo 到生产:五个“假修复”陷阱与工程化复盘

🕒 发布时间:2026/10/1 6:13:04 📁 来源:尧图网络
把 Agent 从能 demo 推到能产线上用这半年我踩的坑比之前做三年后端加起来还多。今天想聊的不是那种一眼就看穿的报错、崩溃而是五类“看起来解决了”的假修复——当时确实改了代码、调了 Prompt、评测也过了但上线跑一段时间问题换个马甲又回来了甚至带着新问题一起回来。我做的这个 AI Agent 应用本质上是一个基于大模型的多步任务智能体需要自己规划、调用工具、维护中间状态。2026年国内 AI Agent 产品已经不少从智能体中台到垂直场景助手都有。如果你也在从 0 到 1 搭 AI Agent大概率会经历和我一样的阶段原型很快、demo 很爽、一到真实流程就抓瞎。这篇文章不讲架构选型也不讲怎么把 Agent 跑得更快就聊这半年里最值得复盘的五次“假解决”。1. Prompt 调好了其实是把错误转移了——AI Agent 最容易踩的第一个坑1.1 当时那个 bad case模型开始“复读机”了我在做客服辅助 Agent 的时候遇到一个很典型的问题用户在对话里说“帮我查一下 7 月 3 号的订单”Agent 正确调用了查询工具返回了订单列表然后它在回复里把订单信息一个字不差地复述了一遍接着又问“请问您需要我做什么”。用户当然很烦。我同事也吐槽这 Agent 像个复读机。我当时的第一反应就是改 Prompt。在 system prompt 里加了一句“不要复述用户的话或工具返回内容直接给出结论”又补了一条 few-shot 示例告诉模型“正确做法是确认订单状态 给出下一步选项”。试了两个坏例确实解决了。模型不再复述订单而是直接说“您的订单 7 月 3 号已经发货需要我帮您修改地址吗”。我挺满意又随手拿十几个 case 过了一遍没有明显异常就部署了。1.2 复盘一条 prompt 补丁换来了三个新问题一周之后新的 bad case 出现了而且不止一个。第一个问题模型开始“假确认”。用户说“我要把收货地址改成XX”Agent 直接回答“好的已为您修改”。实际上它根本没调修改地址的工具因为我在 Prompt 里加了“不要复述直接给出结论”它把“直接给出结论”理解成了“所有环节都别做多余确认”于是跳过了关键的二次确认步骤甚至在工具未成功执行的情况下直接向用户宣告成功。第二个问题另一个场景的准确率掉了。我们有一个内部知识问答场景原来跑得好好的。我在客服场景加的“不要复述”指令被模型泛化到了所有场景它开始把本应详细解释的内容压缩成一句话用户问“这个产品的退货政策是什么”它只回“请查看官网”因为这个 Prompt 让它觉得“说得越少越好”。第三个问题bad case 越修越多。我每看到一个新的错误输出就往 Prompt 里加一条“不要……”禁令。两个月后system prompt 已经有了三千多字模型行为开始变得四不像既不像复读机也不像能正常对话的助手输出风格从“过于啰嗦”变成了“过于随机”。复盘之后我才明白这个坑的本质是我当时以为“错误输出”是一个可以被文字规则直接碾平的问题但大模型的输出是概率性的Prompt 补丁只是把概率分布往某个方向挤压。压掉一个坏行为的同时会顶起另一个坏行为。我修复的是“表面输出”不是“行为逻辑”。1.3 现在我会先做根因归类再动手改 Prompt再遇到类似的 bad case我不会急着改 system prompt。先花半小时做根因归类至少区分这几种情况理解层问题模型没读懂用户意图比如把“改地址”理解成“查订单”。上下文问题该有的信息没进上下文比如没有把用户地址传进工具调用。工具链路问题工具真正执行了但模型没拿到结果或者拿到了结果没有适当使用。行为规范问题模型理解意图也拿到信息但不知道怎么组织输出。每种根因的解法完全不同。理解层问题可能要重设 few-shot上下文问题要看 RAG 或者会话摘要逻辑工具链路问题要去查工具调用的返回处理只有行为规范问题才适合用 Prompt 约束。另外我建议每次改 Prompt 之前先给 bad case 建一个最小复现用例。这个用例要能稳定复现旧问题改完 Prompt 之后重新跑一遍。如果旧问题消失了但产生了新问题至少能通过回归集发现。在我现在的项目里任何 Prompt 变更都会先跑一遍大约 60 条的基础回归集跑完再放上线。这个习惯帮我挡掉了至少三次上述的“补丁后遗症”。2. Function Calling 看着通了真正要命的是没人校验工具执行结果2.1 看起来通了JSON 解析正确、工具参数合法很多做 AI Agent 的同学都有这个体验一开始最兴奋的时刻是看到模型准确地在用户说“帮我订明早九点去浦东机场的出租车”之后输出了一串工整的 JSON里面是{time: 08:30, destination: 浦东机场, pickup: 用户默认地址}。到了这一步大家通常会说“通了”。我也一样。我一度以“模型能生成正确的 function calling 参数”作为“工具调用能力 OK”的标志。我们当时给 Agent 接了一个预约服务用户说“帮我约后天下午三点的保洁”模型正确输出了时间和服务类型我验证了 JSON 格式觉得链路没问题。但实际上这只验证了半个链路。工具调用要真正解决问题至少要包含四步模型决定调用哪个工具、生成参数、工具实际执行、把执行结果反馈给模型。我当时的验证只覆盖了前两步完全忽略了后两步。而这后两步才是真正决定用户会不会得到服务的环节。2.2 真相比想象中可怕重复下单和假成功有个真实事故让我记忆特别深。预约服务上线没多久我们发现有用户订单列表里出现重复预约同一个保洁订单出现两次时间、地址、服务内容完全一样。一开始我怀疑是用户手误但看了日志才发现Agent 在对话过程中调用了两次创建订单工具。一次是用户说“帮我约保洁”后调用另一次是用户说“好的那我要确认这个时间”后模型竟然又调了一次创建订单接口。为什么会这样因为模型没有判断“这个订单已经创建成功”它看到用户说“确认”就认为是新的动作意图于是又调了一次工具。我们把“工具调用成功”这件事只写在了日志里没有回传给模型状态机模型自然不知道已经创建过了。还有另一个“假成功”案例工具实际执行成功了但返回结构因为后端接口升级变了。模型拿到的工具返回里没有时间字段它就开始自己编“已为您预约时间7月5日下午4点。”实际上后端分配的是 3 点。用户到了 4 点才发现没人来。这些问题的共同点是什么都出在“没有人对工具执行结果做校验”。当时我们只校验了模型输出 JSON 的合法性没有校验“工具是否按预期完成、返回数据是否被正确消费”。2.3 工具调用层的三件事校验、幂等、审计这个坑踩完之后我在 Agent 的工具接入层加了三道保险现在基本成了我的标准做法。第一道是返回结果校验。不能只看 JSON 合法还要对关键业务字段做断言。比如预约场景必须断言创建订单返回里存在订单 ID查询场景必须断言返回里有实际数据条目而不是空数组被误判成“查询成功”。这个校验不是模型做的是代码层显式做的。模型拿到的是校验之后的结果。第二道是幂等设计。像下单、支付、发消息这类有副作用的工具必须支持幂等键。我通常用一个request_id同一个用户同一轮对话里的同一意图只会执行一次。这个 request_id 可以来自对话 ID 意图序列号由 Agent 框架生成而不是依赖模型自己保证。模型不会每次都自觉避免重复但框架可以。第三道是审计日志。记录每次工具调用的完整链路模型输出的原始参数、校验结果、实际执行结果、返回给模型的数据快照。这个日志不是给用户看的是给自己复盘用的。没有它你很难定位“到底是模型调用错了还是工具执行错了”。另外凡是涉及资金、预约、身份修改这类高影响操作我建议必须在工具执行前加一道人工确认闸门。不要让模型独自决定“直接执行”。表面上多了一次交互实际上省掉了大量客诉和返工。3. 评测集自我感动为什么 90% 通过率不能说明你的 Agent 真的能用3.1 手工试 10 个 case觉得“效果还行”做 Agent 应用的人几乎都经历过这种时刻拿 10 个测试问题跑一遍8 个结果满意于是结论是“效果还行”。我当时也是这么干的。后来发现这个“效果还行”几乎没有参考价值。原因有三条。第一这 10 个 case 大概率是你自己写的你心里早就知道期望输出是什么你会下意识避开那些会让系统难堪的提问方式。第二10 个样本太少任何系统在 10 个样本上的表现都有极大偶然性。第三手工跑意味着没有回归机制你今天改了一个 Prompt明天可能就把一周前修的 bug 又带回来了但你不知道。我做客服辅助 Agent 的时候走过一个大弯路连续两周都在“修 bug—上线—发现新 bug—再修”的循环里效率很低。后来我把历史 bad case 全部翻出来发现其中至少有三分之一是两周前我已经“修好并验证过”的问题。因为我没有评测集和回归机制那些修复在一轮又一轮的 Prompt 调整中悄悄丢了。3.2 LLM 自动评测的 90 分怎么来的被手工测试坑过之后我去搭了一套大模型自动评测流程。简单说就是用 GPT/Claude 这类模型当评委给 Agent 的回复打分。第一次跑完成绩很漂亮90 分。团队一看都觉得效果达标了。但我越用越觉得不对。因为同一个 case我换了不同的评分 Prompt 之后分数波动能达到 20 分以上。再仔细一看那 90 分是怎么来的评分 Prompt 里写了“根据准确性和完整性打分”但没有规定“准确性”的具体含义。LLM 评委对模糊的评分维度天然倾向于给高分。尤其是当 Agent 回复得很流畅、措辞很礼貌时评委很容易忽略事实错误。我还试过让同一批 case 跑两次评分只有一次真正检查了工具调用结果有没有错另一次只看语气是否友好。这就是 LLM 评估的“自嗨属性”你告诉他什么重要他就看什么你没告诉他的他自动忽略。3.3 一套评估体系从 50 条高质量数据开始我现在搭的评测体系不再追求大而全而是先用 50 到 80 条高质量数据把基线立住。这些数据全部来自真实会话不是我自己编的。每条数据包含用户输入、期望工具调用序列、期望最终回复、备注的边界条件。评测维度分开看不再只给一个总分。至少分成四个维度任务完成率用户的目标是否真的被解决了不只看了回复文本还看中间的工具调用记录。工具调用准确率该调的工具调对了没有该传的参数传对了没有有没有多余调用、重复调用。安全性有没有幻觉承诺、有没有未经确认就执行高影响操作、有没有泄露不该泄露的信息。成本效率平均对话轮数、平均 token 消耗、平均工具调用次数。这四个维度分开打分你会发现之前那个 90 分根本站不住。可能任务完成率只有 70%其中还有两次重复调用工具成本效率很低。评测跑完还要抽样人工复核尤其是那些 LLM 评委打了高分的 case。我一般每周抽 20 条自己看一遍真实日志确认“高分不是假高分”。这套机制比一个大数字有价值得多。另外提醒一句评测集也要持续更新每产生一个真实 bad case如果确认值得防回归就把它加进评测集。评测集不是一次建完就不动的。4. 记忆加上去Agent 反而更糊涂了——上下文污染实战复盘4.1 加了记忆结果模型抱着过期的偏好不放做多轮对话 Agent早期的苦恼是“忘得快”。用户上一轮说“我预算 5000 左右”下一轮问“帮我推荐一台笔记本”Agent 完全不记得又按默认预算推荐了一堆 3000 到 10000 的。所以很自然地我去加了“记忆”。方案也很朴素把每轮对话都拼到 context 里再把用户关键偏好抽出来存进向量库后续对话先检索再拼装。听起来很合理对吧结果上线之后出现了大问题。有一个用户第一次咨询时说“预算 5000”一周后再次咨询时明确说“预算提高到了 8000”。Agent 检索到了旧记忆居然把 8000 预算的用户又推了一堆 5000 价位的产品。用户问“怎么还是给我看 5000 的我说了预算已经调到 8000 了”Agent 还振振有词“根据您之前的预算偏好我优先推荐了这个区间。”这就是典型的“历史记忆污染当前决策”。我把记忆当成了一种只增不改的静态资料忘了记忆是有时效性的是会过期的。用户的偏好变化、状态重置、甚至是临时性需求都需要被识别和更新。4.2 长上下文是“信息过载”不是“信息丰富”还有一个隐蔽的问题为了“不忘记”我把所有历史都拼进 context。Session 长了以后整个上下文达到几万 token。效果怎么样模型确实记得这轮对话里自己说过什么了但它也开始“过度关注”历史细节经常拿早期对话里的次要信息来回答当前问题甚至因为上下文太长注意力被稀释回答质量下降响应时间也变长了。我后来才意识到对于 Agent 来说上下文不是越丰富越好而是越精确越好。大模型在长上下文中不会自动区分“哪条信息最重要”。你把十条记忆都给它它可能拿一条不相干的旧信息盖过当前的事实。这和人类一样你手里拿着一堆资料反而找不到现在需要的那一页。所以长上下文真正要解决的问题不是“存够多”而是“每次放进 context 的信息是否都是当前决策所需的最小子集”。4.3 记忆分层工作记忆、事实存储、长期偏好现在我的记忆方案分了三层分别对待。工作记忆只保留当前任务闭环内的关键信息比如正在进行的订单、用户刚说的紧急要求。任务结束就清零不累积到下一轮无关对话。事实存储保存那些有明确时间戳、可验证的事实比如“用户 6 月 1 日下单订单 A”“用户 7 月 10 日将预算改为 8000”。每条事实都带时间和来源。凡是新写入的事实和旧事实冲突不是简单覆盖而是把旧事实标记为“已过期”并保留过期记录。这样模型检索时能知道“8000 是最新说法”。长期偏好存那些跨会话稳定成立的偏好比如“用户偏好安静环境”“用户常用地址”。这类信息更新频率低但写入时也要有置信度判断。不能因为用户随口一句“最近想省钱”就把“偏好低价”写成长期偏好。三层记忆写入和读取都有不同的策略。工作记忆随对话走事实存储按时间排序、冲突标记长期偏好需要多次确认或用户显式声明才写入。检索时也不是无脑全返回而是限制返回条数我通常只取 3 到 5 条最相关的并且每条都带上时间上下文让模型知道“这条是三个月前的仅供参考”。这个分层方案不能彻底解决记忆污染但至少把“过期偏好干扰当前决策”这类问题挡在了外面。最重要的是我开始用“记忆不是越多越好”这个视角去看问题而不是一上来就往 context 里塞东西。5. 重试兜底看似稳了其实是把故障时间拉长了三倍5.1 重试三连用户等了三倍时间做 Agent 应用外部依赖非常多大模型服务、业务 API、向量库。只要其中一个抖动Agent 就可能出问题。我最开始的做法很粗暴在 Agent 框架里给所有外部调用都加了重试失败就重试 3 次每次间隔 1 秒。结果一次真实的故障让我印象非常深。那天下班后业务 API 因为数据库连接池满开始报错。我设置的 3 次重试让每个请求在失败之前都要等至少 3 秒到 5 秒而 Agent 在一个任务里可能连续调用 4 到 5 个工具每个工具都失败都重试用户面对的就是一个持续卡顿、迟迟不回复的 Agent。最后虽然没有一个请求直接崩溃但用户侧体验是“Agent 死了”。没人会感谢一个“延迟 30 秒后告诉你请求失败”的助手。我意识到重试看起来让系统更稳了实际上只是把错误延迟了错误并没有消失用户体验反而更差了。5.2 重试的三类错误姿势后来我把重试逻辑单独拿出来复盘发现有三类典型错误。第一类是无差别重试。不管错误类型是什么只要失败就重试。但很多错误是“确定性失败”比如参数校验失败、用户权限不足、业务规则不允许。这类错误你重试一百次结果都一样只会白白消耗资源和时间。第二类是无限次重试或者重试次数太多。有些外部服务长时间不可用时重试只是不断加剧压力。我记得有一次外部接口持续 500 报错Agent 每轮都重试 3 次再配合多轮任务编排瞬间打上去几十个请求把原本只是轻微故障的服务直接打挂了。第三类是重试不带退避策略。失败后立刻重试连续撞墙。正确做法是用线性或指数退避比如第一次等 1 秒、第二次等 3 秒、第三次等 8 秒。但即便这样也要有上限。更严重的是重试失败之后大多时候我们只是返回一个模糊的“系统繁忙请稍后再试”然后把用户晾在那里。这等于把真正的故障事实藏了起来用户不知道到底发生了什么也无法决定要不要等待。5.3 容错不是让系统永不失败而是失败得明明白白我现在处理容错的思路变了。核心目标是让 Agent 在失败时尽快、明白地告诉用户而不是通过重试把失败变隐形。先区分可重试错误和不可重试错误。网络超时、HTTP 503、连接重置这类暂时性错误可以重试但要设上限和退避。参数校验失败、业务规则违反、模型连续输出非法 JSON 这类确定性错误不重试直接走失败分支。再给 Agent 设计明确的失败降级路径。工具调用失败后Agent 不能卡住要输出一句用户可以行动的话比如“查询服务暂时不可用我这边没法马上看到您的订单。您可以留下手机号我会在恢复后短信通知您。”这句话不是模板套话而是真的调用了一个“记录待办”的工具把用户请求转成离线任务。这样用户至少知道自己的请求没有丢。还要给 Agent 设置“最大努力”边界。比如整个任务最多执行 10 个工具调用、最长不能超过 60 秒。一旦超过Agent 主动终止向用户交代“已完成哪几步、还剩哪几步没有完成”。这种诚实反而比硬撑到底更让用户信任。熔断也很重要。当一个外部服务在 30 秒内错误率超过 30%我会触发熔断后续请求直接快速失败走降级路径不再重试。这相当于给下游服务一个喘息时间也避免 Agent 在自己不知道的情况下连环调用一个已经不健康的服务。容错这件事本质上不是让系统永不失败而是让系统在失败时行为可预期、用户可感知、后果可控制。6. 如何识别“看起来解决了”来自半年的几个自我检查方法6.1 “假解决”的三个明显信号踩完这些坑我开始反思一个通用问题怎么在第一次被坑的时候就识别出“这是假解决”我总结了三个信号一旦出现就要警惕。第一个信号同一个问题反复出现只是换了场景。比如你修好了客服场景的重复请求一周后订单场景又出现重复请求。这不是模型变笨了而是你上次的修复没有触及通用机制只是针对单一场景打了个补丁。第二个信号你只验证了“输入输出”没有验证“中间过程”。比如你只看了 Agent 的最终回复没有看它到底调了几次工具、每次都干了什么。出现“回复看起来对但实际没做该做的事”的情况几乎可以断定是假解决。第三个信号你只跑了 happy path没有跑异常路径。比如用户中断了对话、用户提供了模糊信息、工具返回了空数据、外部接口超时。如果你从来不主动测试这些路径那你的 Agent 大概率只是“在理想条件下没问题”。6.2 把“看起来解决了”变成“真的解决了”的四步检查现在我在收尾一个修复任务之前会先按四步过一遍。第一步写复现用例。这个 bad case 必须能稳定触发写成一个固定的测试用例存进项目里。如果连稳定复现都做不到那你根本没有资格说“解决了”。第二步做根因判断。明确说出问题属于哪一层Prompt 行为问题、工具执行问题、记忆检索问题、还是容错机制问题。说不清楚根因的修复往往就是只修了表面。第三步做回归验证。拿一个基础回归集跑一遍确认修复没有破坏其他场景。如果项目还没有回归集那当务之急是建一个哪怕只有 30 条。第四步上线后持续观察一段时间。不要在部署当天就宣布完成至少观察一周的线上日志。因为很多问题只在真实流量分布下才会暴露。6.3 团队协作里值得坚持的三个小习惯最后聊几个团队层面的习惯帮大家少走弯路。第一个习惯每次修完 bug把 bad case 和修复说明一起提交到代码仓库。我们团队现在有一条不成文规则没有附上最小复现用例的修复不允许合入。这逼迫每个人把“为什么这样解决”落到纸面上。第二个习惯每人每月轮流当“评测集委员”负责收集新的真实 bad case更新回归集。这个活儿不能全靠一个人干否则评测集很容易停在自己关心的那几个场景里。第三个习惯线上出问题之后先别急着修先花 10 分钟写一个“问题定位单”写清楚现象、影响范围、可疑原因、验证方式。这个单子不一定要发给谁就是让自己在动手之前把脑中的“想当然”清空一遍。我踩过的那些坑几乎都在“没写定位单就直接加代码”的时候出现的。做 AI Agent 应用最有意思也最折磨人的地方就是它没有标准答案。你永远不知道下一个 bad case 长什么样。但半年下来我最大的体会是真正值钱的不是你能把一个错误修好而是你能识别出自己是不是在“看起来解决了”的路上自嗨。希望这五个复盘能帮你少走一点我们走过的弯路。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →