调试不是评测:Agent 上线前的四道关
改完一个 Badcase 就以为修好了,结果又冒出三个新问题。一次一条的调试、几十条的评测、改完必做的回归 —— 以及那条让我少走很多弯路的 RAG 排查顺序铁律。
目录
我有一段时间是这么干活的:
用户反馈一个回答不对 → 我打开日志看看 → 改一下提示词 → 再问一遍,对了 → 收工。
直到有一天我发现,同一个问题改了三次。不是没改好,是每次改完都会冒出新的问题:这次修好了引用来源,下次发现格式崩了;修好了格式,又有别的场景开始拒答。
那时候我才分清楚两件事:调试和评测不是一回事。
调试 ≠ 评测
| 维度 | 单次调试 | 批量评测 |
|---|---|---|
| 使用时机 | 搭建过程中,高频发生 | 应用基本成型后、上线前或重要改版后 |
| 样本数量 | 一次 1 条或少量 | 几十到几百条 |
| 目标 | 定位具体链路问题 | 衡量整体效果、版本差异、上线风险 |
| 观察重点 | 日志、变量、节点、工具、最终回复 | 准确率、召回率、完成率、响应时长、Token 成本 |
| 结果形式 | 调试记录和修改动作 | 评测报告、Badcase 列表、指标趋势、回归结论 |
调试是「边搭边修」,评测是「阶段验收」。
为什么不能等全部搭完再测? 因为问题会叠在一起。同一个错误回答,可能来自提示词写得不好、知识没命中、某个变量是空的、工具返回异常、或者输出格式不稳 —— 五种原因混在一起,归因成本极高。你改了提示词,以为是提示词的问题,其实根本不是。
正确的节奏是:先做单次调试把主链路跑通 → 应用成型后用评测集批量验证 → 每次优化后都做回归。
第三句是我用三次返工换来的:不回归,就等于「修好一个问题,引入三个新问题」。
第一关:单次调试五步法
调试看着随意,其实有讲究。五步:
- 明确本轮目标 —— 是验证知识命中、提示词有效性、工具可用性,还是流程能否跑通。不要「随便试试」。
- 输入可解释的问题 —— 对应某个具体知识点、流程节点或边界条件,别随机问。
- 观察完整链路 —— 不只看最终回复,要看中间变量、检索结果、节点输出、工具返回。只看最终输出是调试最大的陷阱。
- 每次只改一个主要变量 —— 别同时改提示词、知识库和流程,改完不知道是哪个起了作用。
- 重新试跑验证 —— 修完后用一两条相邻问题检查有没有引入新问题。
五种必须覆盖的问题类型
测试问题不能随便挑,要覆盖五类:
- 标准问题 —— 验证主路径
- 口语化问题 —— 验证意图理解
- 缺信息问题 —— 验证会不会追问
- 边界问题 —— 验证拒答 / 转人工
- 复杂组合问题 —— 验证多知识、多工具协同
第三类(缺信息)是我以前从来不测的,后来发现它是 Badcase 的重灾区 —— 用户问「这个套餐多少钱」,但没说是哪个套餐,我的系统不会追问,而是猜一个答案给它。这在业务场景里是灾难。
记录六项
每次调试记六件事:问题、期望结果、实际结果、定位原因、修改动作、复测结果。
这六项不只是工作记录 —— 它们是评测集最好的样本来源。你调过的每一个真实问题,都是未来回归测试该覆盖的用例。
第二关:一张快速诊断表
这是我后来用得最多的一张表。遇到 Badcase 不慌,先查表:
| 问题现象 | 优先怀疑 | 排查动作 |
|---|---|---|
| 回答方向完全错 | 意图识别、系统提示词、分支判断 | 查进了哪个分支;提示词是否明确了任务边界 |
| 知识库有答案但没命中 | 切分、检索数量、相似度阈值、关键词表达 | 看检索结果;试同义问法 |
| 命中了知识但回答仍错误 | 提示词未要求基于引用回答 | 强化「仅依据命中内容回答」;加引用要求和兜底 |
| 流程走错节点 | 条件判断、变量提取、节点连接 | 看关键变量值;确认条件表达式和节点顺序 |
| 工具调用失败 | 入参、权限、接口状态、返回格式 | 查入参字段、账号权限、接口返回 |
| 输出格式不稳定 | 提示词格式约束不足 | 补输出模板、字段说明、示例、JSON 容错 |
| 太慢或太贵 | 上下文过长、检索过多、节点过多、模型过重 | 减无效上下文;拆节点;控检索数量;换模型 |
这张表最大的价值是防止你一上来就改提示词。 十次里有七次,问题不在提示词。
第三关:RAG 排查顺序铁律
这是我学到的最有用的一条,单独拿出来说:
先确认有没有知识 → 再确认有没有命中 → 最后才看有没有正确生成。
顺序不能反。
反过来的后果是:你把「知识缺失」「切分错误」「检索范围错」全部误判成提示词问题,然后开始疯狂调提示词 —— 调一天,毫无进展,因为压根不是那儿的问题。
四类典型现象对应的排查项:
| 现象 | 优先排查 |
|---|---|
| 没命中 | ① 文档是否已上传、解析成功、处于可用状态 ② 关键词、召回范围、权限过滤 ③ 切片是否含可独立理解的答案 ④ 用测试问题逐项验证召回 |
| 命中旧文档 | ① 文档版本、更新时间、生效状态 ② 下线或删除过期知识并重建索引 ③ 同名文档与重复切片 ④ 建立版本与发布管理 |
| 答案不完整 | ① 切片是否过短或割裂上下文 ② 调切片重叠、召回数量、相关性阈值 ③ 是否需多段信息组合 ④ 提示词是否要求覆盖关键字段 |
| 引用错误 | ① 对照回答与召回片段 ② 引用字段、文档元数据、变量映射 ③ 避免模型生成未召回的来源 ④ 用标准问题集回归引用准确率 |
切分质量的判据
判断切分好不好,标准只有一条:这个片段能不能独立支撑回答。
三种典型的坏切分:
- 只命中结论,没命中条件 → 用户拿到结论但不知道适用前提
- 只命中数据,没命中表头 → 一堆数字不知道是什么
- 只命中步骤,没命中前置条件 → 照着做做不通
| 切分问题 | 优化方向 |
|---|---|
| 切片过大(含多个主题) | 按标题、条款、问题或业务单元重新切 |
| 切片过小(只有结论没条件) | 增加长度或重叠,必要时用父子级切分 |
| 表格被切坏(表头分离) | 表格按行切分,保留表头范围 |
| 问答被拆散 | 按一问一答整理,或使用问答型知识 |
**「父子级切分」**这个思路我觉得很聪明:用小切片去检索提高精度,命中后返回它所属的大切片作为上下文。两头都要。
检索调优的六项
向量模型、召回数量、检索匹配度、检索策略、重排、检索范围。
要点:围绕固定样本集调参,而不是围绕单条问题反复试。 单条问题调参必然过拟合 —— 你把这一条调到完美,其他九十九条变差了。
| 现象 | 优先动作 |
|---|---|
| 一条都没命中 | 查知识范围、匹配度是否过高、是否需要同义词 |
| 命中太多无关内容 | 提高匹配度,清理低质量文档,优化标题结构 |
| 正确片段在但靠后 | 开启或调整重排(Rerank),减少无关召回 |
| 表格查询不稳定 | 清理表格结构,评估按行切分或数据库方案 |
「正确片段在但靠后」这一条,正是我的项目里重排序(Rerank)缺失造成的。召回的十条里有正确答案,但排在第 8 位,被截断在上下文之外 —— 系统表现得像「没找到」。这个缺口我心里有数,在补。
第四关:回归
每次优化后都要回归。
这不是形式主义。大语言模型应用有个特点:改动的影响面不可预测。你加了一句「请引用来源」,可能同时改善了引用准确率、劣化了回答流畅度、并在某个边界场景触发了不必要的拒答。
回归的做法:保留一批核心样本(覆盖主路径 + 高频 + 边界),每次重要修改后重跑,确认旧问题修好、且没引入新的高风险问题。
完整的闭环是五步:
| 阶段 | 主要动作 | 判断标准 |
|---|---|---|
| 单次调试 | 测试环境逐条试问,查看链路 | 主链路跑通,明显错误可定位 |
| 专项优化 | 调提示词、知识库、RAG、流程、工具 | 同类问题明显改善 |
| 批量评测 | 评测集批量运行 + 自动或人工评测 | 关键指标达到验收标准 |
| 回归验证 | 重要修改后重跑核心样本 | 修好旧问题,未引入新问题 |
| 运营沉淀 | 把线上 Badcase 补进评测集 | 评测集持续覆盖真实业务变化 |
最后一步是关键 —— 评测集不是一次性的。线上真实出现的问题,人工标注后补进评测集,它才会越来越贴近业务实际。
从「可评测」到「可上线」
评测过了也不等于能上线,中间还有一串动作:
- 上线前:基线值、测试集、验收指标、压测、权限确认、降级方案、回滚方案
- 灰度上线:限流小范围观察
- 客户培训:讲清边界 —— 它能做什么、不能做什么
- 持续运营:线上问题分级闭环
- 范围变更:任何扩范围都要重新评估影响
生产环境出事怎么办
有一条我认为必须记牢:
生产环境出现高风险错误时,第一响应不是继续调提示词。
正确顺序是:先确定受影响的用户、版本、场景 → 必要时限制入口 / 关闭能力 / 降级人工 → 保留日志 → 再分析根因、修复、回归复测。
先止血,再治病。继续调提示词的冲动很强烈,但在生产环境里,那是把止血时间花在了调试上。
我的自评
这套方法论学完之后,我拿自己的自适应 RAG 系统对照了一遍:
- 调试:做了,但没有记录规范(六项记录我以前只记「改了啥」)
- 诊断表:完全没用过,以前靠直觉猜
- 排查顺序:反着来的 —— 我总是先改提示词
- 评测:没做,没有评测集,没有基线
- 回归:没做
五项里做到了半项。
好消息是:我现在知道缺什么了,而且这五项的补做成本都不高。坏消息是,在此之前我声称「做过生产级 RAG 系统」其实是虚的 —— 没有评估体系,就没有任何证据能证明我的改进是有效的。
这也是我现在最想尽快补上的一块。重排序和 Ragas 评估各要两三天,性价比极高。
最后
如果你只从这篇文章里带走一句话,我希望是这句:
遇到 Badcase,先问「知识有没有」,再问「有没有命中」,最后才问「提示词写得好不好」。
这条顺序帮我省下的时间,比任何提示词技巧都多。
评论区还没启用。在
src/consts.ts
里填好 Giscus 配置并把
enabled
改成 true
就能开启。