我们有一个 LLM 流程,需要读一堆杂乱的输入,产出一个结构化、有层级的输出——具体来说,是从 PDF 和其他源文件里,提炼出一份关于保险数据的、结构清晰的深度理解。一开始没什么花哨的
第一轮迭代:先把 prompt 写对
第一步并不聪明。我们把 instruction 写得更清楚——结构更明确、步骤更具体,边界情况里”正确”到底是什么意思也更少歧义。而且我们不再靠肉眼判断某次改动有没有用,而是把所有改动都跑一遍评测框架:每一次 LM 调用都被完整记录下来——具体的 input 和 output、耗时多久、用了多少 token——这样每一个 prompt 版本都变成了一次真正可衡量的实验,而不是凭感觉。
这段过程很慢、也不酷,但确实有回报——一段时间里稳步提升。后来就不再有回报了。改一段,跑一次评测,数字纹丝不动。这是遇到了天花板,不是 prompt 写得不好。再怎么斟酌字句也不可能突破——我们需要另一个杠杆。
第二轮迭代:给它一个可以参照的东西
下一个想法是加入 few-shot 示例,通过 graph-RAG,按每次请求动态从知识库里检索。不管模型看到的是哪个 case,它都会拿到几个真正相似的历史案例,和 instruction 一起作为参照。
评测分数跳了一截——冲过了天花板,干净利落的一次胜利。然后有几条输出结果感觉不对劲。回复里的某些数值,追溯不到任何真实输入——看起来完全合理、格式也对,只是从错的地方借来的:是检索到的示例,不是正在处理的这个 case。让检索有用的那个特性——拉来真正”相近”的示例——恰恰也是让这件事危险的原因。没有哪个 token 能告诉模型”这里的数字别管,照抄格式就行”。
第三轮迭代:把生成和校验拆开
这次的解法不是把生成用的 prompt 写得更聪明,而是多加一个阶段。生成这一步和第二轮迭代完全一样——instruction、data、example 照样一起进去,照样产出一个中间结果,该有的泄漏风险一个不少。变的是:这个中间结果不再直接算数。它必须先经过一个 validator,而这个 validator 的输入被刻意收窄——只有这个 case 原本的 instruction 和 data,加上需要检查的那个中间结果,仅此而已。它永远不会拿到 example。
这就是整个诀窍。如果中间结果里有个数值,只是因为从 example 里抄来的才存在,validator 没办法确认它——它不在 data 里,而 validator 也从没见过那个 example,不可能认出”这个值没错,只是抄错了地方”。于是它会被标记出来。因为 validator 从结构上就看不到 example,这不是靠更聪明的检查抓到了一个隐蔽的 bug——而是一种架构上的约束,让这个特定的 bug 在这一步根本不可能溜过去。
具体来说,这个 validator 是一个 LLM-as-judge:给它中间结果,加上这个 case 真正的源数据——既包括源文件里的自由文本内容,也包括已经从中提取出来的结构化数据——它会逐条核对输出里的每一个 claim 是否有源数据支撑,返回一个幻觉分数。它的输出不是把分析结果重写一遍,而是在原结果上盖一层高亮——每一条 claim 都被标成”有依据”或”没依据”,并附上理由。
有两个细节让这套东西真正能用,而不只是理论上成立:
- 必须同时检查两层源数据。 只检查自由文本内容会产生大量误报——很多正确的 claim 其实是从结构化数据里得到支撑的,只查文本的话会把它们错误地标成”没依据”。
- 需要一套真正的分类体系,而不是简单的匹配。 我们建了一套 10 条规则的幻觉分类体系,同时列出一份明确的”非幻觉”清单——归一化表达、同义替换、有依据的建议、以及合理的省略,都必须被明确排除在外,否则 judge 会把合理的措辞误判为编造。每条发现都带权重(重大问题的权重远高于轻微问题),而且 judge 必须把每一条发现单独列出来,附带一个和总分对得上的计数——这样分数才是可审计的,而不只是一个数字。
我们拿一个此前 triage 里真实出现过、客户反馈过的幻觉案例来验证——一个我们已经知道正确答案的案例。validator 抓到的,正好就是客户当初反馈的那些问题:两条编造的”承保缺失”结论(分析结果说有两项保障不存在,而实际上是存在的),外加一条推荐——推荐了一项保单里本来就已经包含的保障。同一个失败,这次是被自动抓到的,而不是等客户先发现。
三轮迭代真正教会我们的事
每一轮迭代都是一种完全不同类型的杠杆,而不是把上一轮做得更大:
- prompt 的清晰度有天花板。一旦碰到,再怎么改都只是噪音。
- 检索增强的上下文能突破那个天花板,但它带来的新风险,和检索本身”有多准”成正比。
- 一个在结构上就看不到风险输入的独立阶段——而不只是更聪明的 prompt——才是控制住一个没法靠提示词解决的风险的办法。
如果不是从第一天起就有评测的纪律,这一切都不会被看见。评测框架在第一轮迭代里抓住了那个天花板,也是同一套基础设施,让我们在第三轮迭代里能拿一个已知的真实案例去验证 judge,而不是凭感觉相信它。
现在到了哪一步
validator 目前是离线跑的,针对已经录下来的 trace——这部分已经做完了。接下来的步骤已经排好了:先在真实流量上做近实时的运行,把它的输出归类进一个可信的准确率指标,然后彻底把这个闭环关上——在输出发出去之前就抓住并纠正幻觉,最终修掉底层模板,让某一类幻觉从源头上就不再发生。先做检测,再做源头预防。