你辛辛苦苦搞了个LLM应用,上线第一天用户就反馈"答非所问"“编造事实”“格式混乱”。你打开日志一看,满屏的翻车记录,但根本不知道从哪开始修。
今天这篇文章,我从一个真实的场景切入:5条badcase如何通过三轮迭代清零,再对比线上生产环境是怎么做这件事的。不是理论,是手敲代码跑通的。
先说结论
LLM应用的质量问题,本质上是个闭环问题,不是一次性解决的事。核心就五个字:发现-分析-修复-验证-确认。你把这个闭环跑起来,质量就会螺旋上升;跑不起来,就是在bug堆里打地鼠。
场景:5条badcase的来历
假设你跑了一遍Agent ChatBot的测试,发现5个问题:
- 用户问"Java的垃圾回收机制有哪些",RAG没召回G1相关文档
- 用户问"G1回收器特点",LLM直接编造"G1不支持堆压缩"
- Agent调用天气API,把"北京"传成了"beijing",API不认
- 用户正常问"推荐一本书",被InputGuard误判为Prompt注入拦截了
- LLM返回的JSON缺少summary字段,Schema校验挂了
这5条badcase覆盖了LLM应用最常见的5种失败类型:检索失败、生成幻觉、工具调用错误、安全误判、格式不规范。
第一步:别急着修,先收集
大部分人的第一反应是"赶紧改Prompt试试"。错。先收集,把badcase结构化存下来。
我设计了5种失败类型枚举和4级严重程度(CRITICAL > HIGH > MEDIUM > LOW),每条badcase用Builder模式构建:
Badcasebc=newBadcase.Builder("G1回收器有什么特点?","G1回收器不支持堆压缩,只能用于实验环境。",FailureType.HALLUCINATION).expectedOutput("G1支持堆压缩,是生产级回收器").severity(Severity.CRITICAL).source("AgentJudgeEvaluator").description("LLM完全编造了错误信息").build();为什么用Builder?因为线上badcase的字段会不断增加(trace_id、model_version、token_count…),Builder模式加字段不破坏已有代码。
收集器支持按类型/严重程度/来源三个维度过滤,还能按严重程度降序排序。CRITICAL排最前面,先修最致命的。
第二步:分析,找出"先修哪个"
收集完不是按顺序修,是按优先级修。优先级怎么定?
我算了一个得分:优先级 = 严重程度 × 10 + 同类型出现频率。为什么加频率?因为如果幻觉问题出现了10次,就算单条是MEDIUM,也值得优先修–说明Prompt或模型本身有系统性问题。
分析器还会针对每种失败类型给出具体建议:
- 检索失败-> 增大Top-K + 引入Rerank重排序
- 生成幻觉-> System Prompt加约束"仅基于上下文回答" + 启用幻觉检测器
- 工具调用错误-> 参数Schema校验 + 工具描述加参数示例
- 安全误判-> 收窄InputGuard正则 + 加白名单机制
- 格式不规范-> JSON Schema强校验 + 缺字段自动补默认值
5条badcase分析完,修复队列长这样:#1幻觉(CRITICAL) -> #2检索失败(HIGH) -> #3工具调用错误(HIGH) -> #4安全误判(MEDIUM) -> #5格式问题(LOW)。
第三步:闭环,改一轮测一轮
这是最关键的一步。改完不算完,得验证改了有没有用。
我设计了一个五步闭环:REGISTER(拍快照)-> ANALYZE(分析)-> FIX(实施改进)-> RETEST(重新测试)-> COMPARE(对比决策)。
每轮迭代前后各拍一个快照,记录badcase总数、各严重程度数量、回归测试通过/失败数。改进后badcase减少且回归全通过 -> 确认发布;否则 -> 回滚换方案。
三轮迭代的结果:
迭代1: 修复CRITICAL幻觉 -> 5→4 badcase ✅确认 迭代2: 修复HIGH检索+工具 -> 4→2 badcase ✅确认 迭代3: 修复MEDIUM安全+LOW格式 -> 2→0 badcase ✅确认5条badcase,三轮清零,回归测试全程29/29通过。这就是闭环的力量。
线上真实打法:教学版的壳 vs 生产级的核
教学版教你的是思维模型,线上多出来的是工程化外壳。我直接说差异。
采集方式完全不同。教学版手动add,线上靠三个通道:用户点👎按钮自动落库、隐式信号(同一问题问两次以上=第一次没答好)、LLM-as-a-Judge抽样巡检1%~5%对话自动评分。存储不是内存List,是ES+全链路trace,包含model_version、retrieved_docs、tool_calls、latency、token_count等几十个字段。
分析不是跑一次main。线上是Airflow每天凌晨定时跑,结果推Grafana看板看趋势。CRITICAL突增超阈值直接触发PagerDuty告警,半夜也得起来看。根因分析不是简单按类型统计,是下钻到具体原因–是换了模型版本?某条Prompt改了?知识库更新引入的?
验证不是simulatePass。线上拿几百到几千条badcase数据集真实重跑,跑回归套件,用LLM-as-a-Judge重新评分,对比改进前后准确率/召回率/幻觉率/满意度。验证通过后不直接发布,是灰度:5%流量切新版观察1~3天,指标好就全量,差就回滚。
一个真实案例。某团队上线RAG问答系统,用户反馈"回答不准"。他们做的第一步不是改Prompt,是加埋点收集badcase,一周攒了200多条。分析发现70%是检索失败,根因是Embedding模型对中文支持差。换了个中文Embedding模型后,召回率从62%提到85%。灰度5%跑了两天,badcase率降了60%,全量发布。整个过程一周,数据驱动每一步决策。
设计模式不是装逼,是真有用
这三步代码用了三个设计模式,每个都有实际理由:
Builder模式构建Badcase:线上badcase字段会从10个涨到30个,Builder加字段不改调用方代码。如果用构造函数,加一个参数所有new的地方都得改。
策略模式定义FixAction:不同badcase的修复逻辑完全不同,策略模式让你每个修复方案独立演进,不互相耦合。
备忘录模式做Snapshot:每轮迭代的指标快照需要持久化存储,方便回溯历史趋势。备忘录模式让快照本身不可变,保证对比数据可信。
写在最后
LLM应用的质量管理,核心不是"一次性做到完美",是"持续发现并修复"。闭环跑起来,每一轮迭代都让badcase少一点,质量就螺旋上升。
教学版的五步闭环(REGISTER->ANALYZE->FIX->RETEST->COMPARE)是骨架,线上的自动采集、定时调度、灰度发布是肌肉。骨架你已经在Day6搭好了,剩下的工程化能力,在实际项目里逐步补齐就行。
下一篇我们搞Day7实战:把这个闭环接到真实的Agent ChatBot项目上,跑一个能用的迷你版自动化测试+评估Pipeline。
一起从Java后端转型大模型应用开发。有问题评论区聊。