做LLM应用的人,应该都有过这种体验:项目上线以后,真正消耗你精力的不是写新功能,而是一天天处理线上冒出来的失败样本。我所在的小组维护着一个面向某业务线的智能问答系统,每天几千次调用,每次调用链路里都藏着路由、提示词、工具调用好几个环节,任何一个环节跑偏,最终响应就会歪掉。刚开始我们处置失败样本的方式很原始:监控平台报出异常,值班同学捞出来看一眼,能当场改提示词就改,改不了就记在文档里等下一版模型。折腾了两个月,失败率纹丝不动。因为这些问题的根源不是模型不够聪明,而是路由分错了路、提示词约束不够、工具返回的数据不对路。救火只能灭掉眼前那场火,火从哪里来的?为什么同类问题换个地方又烧起来?一直没有答案。
后来我们下决心做了一件事:让失败样本进入一个真正能转起来的闭环。简而言之,从样本收集、根因分析、改进动作到回归验证,全部收敛在一张表里,且改进动作定向拆成三类:路由、提示词、工具。你可能觉得这不就是做个表嘛,但真正运转起来之后,团队迭代节奏和心态完全变了。这篇文章就围绕这套方法展开:表怎么设计、每个字段为什么存在、怎么从失败样本反推三大类改进、闭环怎么持续运转,以及我们踩过的那些坑。
适合正在排障和迭代LLM应用的人看,不管你在做客服机器人、智能体、Copilot还是通用问答,只要线上存在失败样本,这套思路都能复用到你的场景里。如果你暂时只在做Demo,也可以提前把这种机制建起来,免得以后被线上问题追着跑。
1. 从救火到排雷:失败样本为什么要进闭环
1.1 单点修复为什么无效
先说我们走过的弯路。最早面对失败样本,我们的反应是“谁的值班谁处理”,遇到一个修一个。举个常见现象:用户问“我昨天买的耳机声音小,想换个新的,怎么操作”,模型回了一段“请检查音量设置、重启设备”的排障建议。值班同学看到反馈,第一反应是改提示词,在开头加一句“请先安抚用户情绪”。第二天又冒出一个类似样本,再改提示词,加一句“不要重复排障”。这么改了两周,提示词变得臃肿不堪,同类问题照样出现。
问题的关键在于,单点修复默认了一个前提:这次失败的原因是提示词没写好。但实际上,这个样本的失败可能来自三个层面。第一,路由层的意图分类把“换货”判成了“使用帮助”,模型根本没有调用售后策略相关的技能;第二,提示词层的售后流程确实缺少“用户表明质量异常时,跳过基础排障”的指令;第三,工具层返回的售后政策数据里,缺少换货条件的结构化字段,即便调了工具也拿不到可用信息。三个层面叠在一起,只改提示词当然没效果。
所以我一直强调一个观点:失败样本不是垃圾,是系统优化的真实线索。每个样本背后都藏着一次“期望行为与实际行为之间的偏差”,这个偏差被哪个环节放大,哪些环节可控,只有通过结构化复盘才能看清。否则你永远在做零散的补丁,而不是在改系统。
1.2 闭环的目标不是消灭失败,而是降低重复失败
做闭环之前必须要有一个预期:我们不是要让失败样本归零,这是不现实的。大模型应用的特点决定了失败永远存在,模型本身有概率性,用户表达有无限种变体,外部工具随时可能出问题。闭环的价值在于让同一类失败尽量不重复发生,或者说,让每次失败都为系统贡献一次可复用的改进。
因此闭环的完整定义是“复盘到迭代的闭环”:从失败样本出发,完成根因分析,拆出路由、提示词、工具三个维度的改进动作,推动落地,再回到线上观察同类样本是否减少。注意,这个链条的终点不是“改进上线”,而是“回归通过”,也就是确认线上的重复失败率确实降下来了。如果只做到一半,比如动作记录在表里但不跟踪,那这张表很快又会变成一张没人看的僵尸表。
顺着这个思路,我们设计了一套适合自己团队的表结构。下面详细拆解每个字段的用途,以及它和“路由_提示_工具”三大维度的关系。
2. 一张表的诞生:失败样本如何变成改进清单
2.1 核心字段:追溯、分类、行动缺一不可
我们最终沉淀下来的复盘表,字段不多,但每个字段都对应一个明确的用途。你可以直接抄这个结构,再按自己业务调整。
| 字段 | 填写时机 | 作用 |
|---|---|---|
| 样本编号 | 收集时 | 唯一标识,关联线上日志和错误追踪ID |
| 触发时间 | 收集时 | 用于判断是否集中爆发,比如发版后、活动期间 |
| 用户输入摘要 | 收集时 | 脱敏后的原始请求,保留关键语义 |
| 预期结果 | 复盘时 | 明确“应该发生什么”,通常是业务规则或兜底策略 |
| 实际结果 | 收集时 | 线上实际返回,包括响应文本、错误码、工具调用记录 |
| 链路阶段 | 复盘时 | 失败发生在路由、提示词生成、工具调用、结果生成哪一段 |
| 根因分类 | 复盘时 | 路由误判、提示词约束缺失、工具数据问题、上下文丢失、模型能力边界等 |
| 路由改进动作 | 复盘时 | 要改动意图分类、技能路由、模型选择等哪些具体项 |
| 提示词改进动作 | 复盘时 | 要新增或修改哪些指令、约束、示例 |
| 工具改进动作 | 复盘时 | 要修复哪些API、Schema、返回数据或重试机制 |
| 优先级 | 复盘时 | P0紧急且影响大,P1影响大但可绕过,P2优化项 |
| 负责人 | 复盘时 | 必须有一个人对动作落地负责 |
| 状态 | 动作执行中持续更新 | 待处理、进行中、已完成、回归通过、已关闭 |
你可能注意到,我们特意把改进动作拆成三列:路由、提示词、工具。这么做不是形式主义,而是为了防止复盘会变成“全员改提示词大会”。很多LLM应用团队有个惯性,一聊到失败就觉得是提示词不行,先加两句指令再说。但实际打开链路日志,你会发现相当比例的失败发生在路由阶段:意图分类错了、技能调用错了、上下文拼接错了,根本轮不到提示词发挥。把动作分列展示之后,团队会自然形成一种潜意识:改进不是只有一条路,要把能动的扳手都检查一遍。
2.2 为什么聚焦“路由_提示_工具”三个维度
你可以把一次LLM交互想象成一条流水线。用户输入的请求先经过路由模块,系统要判断“这个问题该交给哪条链路、哪个模型、哪个技能”;然后进入具体的提示词执行阶段,模型要按照预设的指令和约束生成内容;如果需要外部数据或操作,就还要调用工具。所以这三个维度正好覆盖了流水线上最核心的三个可控环节。
路由层,解决的是“走哪条路”的问题。业务上经常表现为多技能路由、多模型路由,或者意图分类。提示词层,解决的是“怎么把话说清楚”的问题,模型在特定技能下理解任务边界、遵守格式、遵循业务规则。工具层,解决的是“有没有可靠的原料和手”的问题,包括外部API的参数和返回、数据库查询结果、动作执行结果等。三层相互独立又相互影响。路由错了,提示词再好也是对牛弹琴;提示词不行,工具数据再准也生不成好答案;工具不行,前面全对了最终也会卡在数据缺失上。
基于这个模型,我们复盘时有一套标准动作:先定位链路阶段,再归类根因,最后分别看三个维度有什么可改的。这套动作本身就起到了约束作用,告诉团队不要在还没确认链路阶段时就急着动手。
2.3 一张真实复盘表长什么样
以开头那个耳机换货案例为例,最终落表大概是这样的:
| 字段 | 内容 |
|---|---|
| 样本编号 | S20250612-017 |
| 触发时间 | 2025-06-12 14:32 |
| 用户输入摘要 | 昨天买的耳机声音小,想换个新的,怎么操作 |
| 预期结果 | 进入售后-换货流程,先展示换货条件政策,再引导提交申请 |
| 实际结果 | 走了商品使用帮助流程,输出基础排障建议,完全没提换货 |
| 链路阶段 | 意图路由阶段已出错,后续提示词和工具全部按错误技能执行 |
| 根因分类 | 路由误判;提示词缺少质量异常换货的规则;工具政策数据缺少换货条件字段 |
| 路由改进 | 新增“售后-换货”意图;补充3条few-shot示例;路由提示词增加“用户提到换货/退货时优先判定为售后” |
| 提示词改进 | 售后流程提示词增加指令“用户明确表达质量异常并要求换货时,跳过基础排障,直接进入换货路径” |
| 工具改进 | 售后策略查询工具返回增加policy_code和applicable_conditions字段,补充质量问题换货的条件说明 |
| 优先级 | P1 |
| 负责人 | 某开发同学 |
| 状态 | 回归通过 |
这张表本身不神奇,神奇的是它逼着我们把一个失败样本拆成了三个可执行的动作,且每个动作都有负责人和状态。下面分别展开讲讲,每个维度的改进到底怎么从样本里反推出来。
3. 失败样本到路由改进:解决“走错路”的问题
3.1 怎么判断是路由问题而不是提示词问题
这是一个非常关键的判断,因为很多团队把路由问题误当成提示词问题处理,改了半天没有效果。我的经验是,先看链路日志里的技能命中情况。如果系统明明有“售后”这个技能,但样本实际进入了“商品帮助”技能,或者明明应该走专家模型,却命中了轻量模型,那这就是典型的路由问题。另一个信号是同一类输入反复进入错误分支,比如用户只要说“坏了”“想换”“要退”,就大概率被分到基础教程类目,这种规律一旦出现,基本可以断定路由配置出了问题。
还有一种隐蔽的路由问题:类目边界本身含糊。比如“耳机没声音”到底属于“使用帮助”还是“售后维修”,不同的人理解不同,模型更分不清。这时候与其责怪模型,不如回过头看路由表里的类目定义、few-shot示例覆盖范围,这些才是模型做判断的依据。我们后来把“解决代码类目录设计”当成路由改进的核心方法论,而不是在路由提示词里反复加词。
3.2 路由改进的几类具体动作
路由改进动作可以归纳成四类,具体用哪种取决于根因。
第一,调整类目结构和粒度。如果一类输入在两个邻近类目之间反复横跳,说明类目粒度太粗或边界重叠,考虑拆分或合并。第二,补充或修正few-shot示例。这是见效最快的手段,把失败样本作为新示例直接加入路由提示词,但要注意示例的多样性,不能只放几个同质化样本,否则会把模型带偏。第三,增加前置规则。对于强规则类请求,比如包含“换货”“退款”“投诉”等明确的业务关键词,可以在路由层先用规则兜底,不用全指望模型判断。第四,增加二次确认或兜底机制。如果路由输出概率偏低,可以要求模型返回候选技能列表,由业务层做最终裁决。
以耳机换货案例为例,我们在路由层做了两三处改动。先在路由提示词里增加了一条前置指令:“当用户请求包含退换货、退款、质量问题等词时,优先归入售后相关技能。”然后在意图分类的few-shot示例里补了三条真实改写的样本,刻意覆盖不同说法:“想换新的”、“能退吗”、“声音小是不是可以换一个”。最后还在技能路由的返回结构里增加了一个confidence_score字段,低于阈值时由上层规则做兜底。这三步加完,同类型样本的路由准确率从62%提升到了91%,效果立竿见影。
需要提醒的是,路由改进的回归验证尤其重要。因为路由一动,影响的是全量请求的分流,很容易出现“解决了换货场景,却误伤了正常使用咨询场景”的情况。所以路由改动上线后,不光要看目标类型的准确率,还要看相邻类目的准确率有没有下降。
4. 失败样本到提示词改进:解决“话没说清”的问题
4.1 提示词层问题的识别信号
当路由已经确认没问题,技能也调用正确,但模型输出的内容和预期不一致,这时候才轮到提示词层面去反思。常见的信号有三类。第一,同类输入输出极不稳定,同一个问题今天能答对,明天换个说法就答错,说明提示词里的指令不够有约束力,模型处于自由发挥状态。第二,输出格式经常跑偏,该返回JSON的时候给你一段话,该列出条款的时候给你一段散文,说明格式指令不够硬。第三,在长输入或工具返回较多的情况下,模型会丢掉前面给定的某些约束,这个通常是提示词结构里的约束位置不够靠前,或者约束本身和用户的请求存在语义冲突。
我见过最典型的情况是提示词里的指令互相矛盾。比如上面写“请简洁作答”,后面又写“请详细说明换货流程和注意事项”,模型为难,随机选一个执行,结果就是输出不稳定。这种问题在复盘时看单条样本往往看不出来,需要把同类失败样本放在一起对比,才能发现是提示词内部打架。
4.2 提示词迭代如何做才不回退
我们的提示词迭代遵循一个原则:最小化变更,单次只动一个变量。不要一次改五处,否则上线后出了问题你根本不知道是哪一处引起的回归。具体操作分四步。先把失败样本和预期输出摆在一起,明确差距到底出在哪类指令上;然后把要改的指令写成一个独立约束,尽量不触碰原有逻辑;接着在测试集上验证,这个测试集要包含历史通过样本和新增失败样本,防止改好了新问题却弄坏了老功能;最后小流量上线并持续观察一段时间的线上表现。
还是耳机换货的例子。我们定位到售后流程提示词里缺少一个关键指令:当用户已经明确表达“质量有问题”和“想换货”时,应该跳过基础排障,直接进入换货路径。原来的提示词只写了“为用户提供售后帮助”,这个指令太宽泛,模型就会按照默认的理解先给一堆排障建议。我们新增的指令是:“当用户明确表达产品存在质量异常并提出更换/退货需求时,直接进入换货路径,不得重复基础排障步骤。”同时在输出要求里加了格式约束:“先展示换货政策,再给出申请入口指引。”这样改动之后,样本表现稳定了很多。
还要多说一个点:提示词不是越写越长越好。你加了一堆指令,模型的注意力会被稀释,关键约束反而可能失效。如果发现提示词因为复盘积累变得冗长且效果下降,可以考虑把提示词拆分成多个子任务,或者把多变的内容迁移到工具返回的数据里。这也是提示词改进和工具改进联动的地方。
5. 失败样本到工具改进:解决“工具不中用”的问题
5.1 工具层问题怎么暴露出来
工具层问题在复盘表里经常被忽略。因为链路日志里工具调用可能显示成功,返回了200状态码,很少有人会再点开响应体看里面的字段是否齐全。我们的经验是,在复盘时一定要养成交叉检查的习惯:不仅看工具调用是否报错,还要看返回内容是否符合模型的解析预期、是否包含回答用户所必需的信息。
工具类问题通常有三类表现。第一类是显性错误:超时、限流、参数校验失败、API返回500,这类问题一眼就能看到。第二类是隐性数据问题:返回200但字段缺失、列表为空、数据更新延迟、同一个字段在不同场景下返回类型不一致。这类问题更坑,因为模型拿着残缺数据也能硬生成答案,只是答案质量差,不容易归属到工具层。第三类是Schema设计问题:工具的描述写得太含糊、参数定义不清楚、返回结构嵌套过深,导致模型不会调用、调用时传错参、或者拿到结果后不会用。
我自己判断工具是否有问题的土办法是:把失败样本的工具入参和返回值单独打印出来,模拟一次手工调用。如果手工调用都拿不到能支撑答案的数据,那问题一定在工具侧;如果手工调用数据充足而模型还是答错了,再回到提示词层面找原因。这个简单的分离法能省掉大量互相甩锅的会议。
5.2 工具改进的落地方式
工具改进可以分为数据修复和描述优化两类动作。数据修复属于后端工程范畴,比如补齐缺失字段、修正错误数据、调整接口超时时间、增加缓存策略。描述优化则更靠近提示词工程,因为工具本身的description、parameter的说明就是给模型看的,描述不清模型就不会用、乱用。
售后策略工具是我们一个典型例子。最初这个工具返回的只有一段拼接好的“退货政策文本”,没有结构化字段。模型拿到后无法准确提取“质量问题能否换货”这一信息,经常答得含含糊糊。我们把它改成了结构化返回,包含policy_code、policy_name、applicable_conditions、excluded_conditions等字段。同时把工具描述从“查询退换货政策”改成了“根据商品类目和问题类型查询对应售后政策,返回结构化条件,适用于退换货、质量异常等场景”。改完之后,模型不仅调用的频率提高了,拿到的信息也变成可推理的结构化文本,回答质量明显提升。这提示我们:工具不是简单抛给模型一个函数接口就行,它是模型推理的信息底盘,底盘的颗粒度决定了模型能达到的上限。
如果你在维护工具层,建议把常用工具的评价指标也纳入复盘表:调用成功率、参数校验失败率、返回空结果率、平均响应耗时。这些指标放在复盘会上一看,哪类工具在拖后腿一目了然,比到时候从失败样本里一个个翻要高效得多。
6. 闭环转起来:复盘节奏与回归验证
6.1 日常轻复盘和每周深度复盘要分开
闭环要是办不成,往往不是因为方法不对,而是因为节奏不对。如果每天都把所有人拉进会议室,把几十条失败样本一条条过,只能说明流程太笨重。我们经过多次调整,把复盘节奏分成两层:每日轻复盘和每周深度复盘。
每日轻复盘其实不需要开会,值班同学把当天新增的失败样本录入复盘表,标记链路阶段和初步根因,把明显属于规则级别的改进动作直接派下去。比如某个关键词路由错误、某个工具字段缺失,这些不用等待周会,当天就能行动。每日的动作就是把样本“接住”,不要漏掉,也不一定要立刻分析完。
每周深度复盘则专门处理难题和系统性改进。我们固定在周五下午,挑出当前状态为“未解决”的P0、P1级样本,逐个过根因分析,确认为三类改进动作,指定负责人和完成时间。每个样本的讨论尽量控制在十五分钟内,超时就继续收集线索,绝不强行下结论。这套节奏跑顺之后,复盘会不再冗长拖沓,反而成了最能看到项目进展的一小时。
6.2 回归验证和效果度量是闭环的灵魂
闭环不能停留在“上线了”,必须走到“确认有效”才算结束。我们的做法是,每条改进动作上线后,负责人需要在复盘表里把状态置为“回归通过”并附上验证截图或指标。验证方式有两种:一种是把历史失败样本重新跑一遍,看是否修复;另一种是观察连续两周的线上数据,看同类失败样本是否明显减少。两种方式结合,短期的修复效果和长期的稳定性都能兼顾。
度量指标方面,我们重点盯三个:Top失败样本重复率,也就是排名前几位的失败类型是否在改进后持续下降;链路阶段分布,看清失败主要集中在路由层、提示词层还是工具层,指导下一步投入方向;单类改进的回归影响,比如路由改动对相邻类目准确率的影响,提示词改动对历史通过样本的影响。复盘表里“状态”这一列不是装饰,它代表了一个改进动作是否走完了完整闭环。我一直跟我们团队强调:不到“回归通过”,这张表的使命就没有完成。
7. 避坑实录:复盘到迭代路上的典型问题和经验
做这套机制的这半年里,我们也踩了不少坑,有些是认知层面的,有些是执行层面的。整理成一份速查表,权当给大家排雷。
| 典型问题 | 具体表现 | 排查建议 |
|---|---|---|
| 表变成了僵尸表 | 字段填了,状态不动,改进动作没人跟进 | 周会强制过一遍所有非“回归通过”样本,让负责人当场说明阻塞点 |
| 样本缺少链路上下文 | 只有用户提问和最终回答,没有路由和工具调用日志 | 在收集阶段强制关联追踪ID,复盘时直接拉端到端调用链 |
| 只改提示词不改别的 | 提示词越来越长,失败率却不降 | 用“路由_提示_工具”三列检查表卡位,确认每一类动作都考虑过 |
| 路由误伤相邻场景 | 目标类目改好了,旁边类目准确率掉得厉害 | 路由改动必须跑相邻类目回归,不能只验证目标类目 |
| 提示词一次改太多 | 上线后不知道是哪处改动导致新问题 | 坚持最小化变更,一次只动一个约束,定位清晰 |
| 工具脏数据被忽略 | 工具返回200就能通过检查,数据残缺没人管 | 增加返回空结果率、字段缺失率的工具层监控,复盘时抽样核对返回体 |
最后分享一个我特别想说的经验:复盘表里的三千行数据,不如你亲手重构一条链路日志。我一直觉得,做LLM应用的人,不能只看结论式报告,必须亲自去读链路里的路由输出、提示词输入、工具调用记录。很多问题在记录里藏得很深,只有顺着调用链走一遍,才会意识到原来失败不是某一个点坏了,而是多个环节叠加的结果。这张表给了我们一个收集和归纳的工具,但真正让闭环转起来的,还是团队愿意在每个失败样本上多花五分钟去看原始链路。这五分钟,往往比改十句提示词都值钱。