让大模型自己找证据来验证结论,并不能防止胡编乱造
1788 字约 6 分钟
摘要为防止大模型胡编乱造,我们要求它在输出每个分类标签时附上原文引用作为证据。但在几千个真实岗位上跑完之后,结果表明这种做法并不能提供真正的保障。
在用大模型提取招聘岗位的结构化画像时,最让工程师担心的是模型幻觉。
例如,一段 JD 只写了“配合算法团队做数据清洗”,模型却可能把岗位标为“算法工程师”;任职要求中完全没有提到学历,它却自行推断为“本科以上”。
为了防范这类风险,第一版设计中加入了一个看似很严谨的字段:evidence(证据)。
模型在给出每个结论时,都必须同时给出一段引用原文的证据:不仅要说明判断结果,还要摘录出是从哪句话得出的结论。
页面上除了分类标签,还会显示“来源引用”,可解释性看起来很强,排查问题时也一目了然。
但随着处理的数据超过几千条,我开始复盘那些判断错误的案例,发现了一个问题:这些由模型自己提供的“证据”,无法起到防伪的作用。
证据能起到什么作用?
当初之所以保留 evidence,主要是希望达到三个目的:
- 约束推理过程(CoT 效应): 要求模型引用原文,它会更有依据,不容易随意猜测;
- 辅助排查: 出现错误时,可以快速定位模型是在哪里理解错了;
- 前端展示: 向用户呈现“这句话说明该岗位需要三年经验”。
但在单次生成的黑盒机制中,这三个目的都没有达到预期。
为什么模型给出的证据不能作为防伪依据?因为**“判定结论”和“提取证据”来自同一次推理**。 如果模型在注意力计算中已经先入为主地把岗位判为“算法岗”,那么接下来生成证据时,它就会很自然地从原文中挑选包含“机器学习”“模型”等字眼的句子来支持自己的判断。在某些情况下,为了让证据和结论更吻合,它甚至会悄悄改动引用中的几个字。
这就像在法庭上让被告自己出具无罪证明。这并不是独立的第三方核验,而是同一个嫌疑人在编造不在场证明。
一个真实的错误案例原文写道:“负责大模型评测平台的数据流转与工程基建,需与算法团队密切配合。”
- 模型分类:
岗位方向: AI/算法- 模型给出的证据:
引用: "负责大模型评测...需与算法团队密切配合"证据确实出现在原文中,但读过全文就能看出,这是一个典型的后端或大数据工程岗位。证据存在,并不能证明分类正确。
额外的 Token 成本
如果说心理上的安全感只是假象,那么账单上的成本却是实实在在的。
模型每输出一个字段(行业、方向、学历、经验、技术栈、英语要求等),都要完整写出原文引用、字符位置和上下文片段。
此外,第一版还让模型生成一份几百字的“核心职责总结”。
拆开统计 Token 用量后发现:
- 数据库中已经完整保存了官网的原始 JD;
- 结构化字段本身只需要几十个 Token;
- 而模型重复抄写的
evidence和冗余摘要,占用了 40% 以上的输出 Token。
| 实验版本 | 抽取内容 | 平均单次输出 Token | 相对节省 |
|---|---|---|---|
| 带 Evidence 和全文摘要 | 结构化标签、引用段落和总结 | 1,706 Token | 基线 |
| 去掉 Evidence,只输出标签 | 仅保留业务真正使用的标签 | 616 Token | 下降 64% |
在大模型 API 的计费中,输出 Token 的单价是输入 Token 的三到四倍。
也就是说,我们花了最贵的价格,换来的却是既不参与 SQL 筛选、也不被前端高亮使用、无法用于判断正误的内容。
去掉伪证之后,如何做可解释性?
既然模型自己给出的证据不可靠,那么如何控制幻觉?
答案是:把校验的权力从模型手里收回,交给外部规则和独立流程。
- 确定性的检查交给代码: 枚举值是否合法、工作年限下限是否大于上限、学历是否符合层级关系,都可以用 Pydantic 或脚本直接检查,不需要在 Prompt 中与模型讲道理;
- 直接展示原始文本: 数据库中本来就保存着完整的招聘正文。前端需要显示上下文时,可以直接在原始 JD 中做分词高亮,不必让模型充当中间人;
- 用评测集代替主观判断: 挑选 200 个最容易混淆的真实岗位(如算法工程、售前技术支持、全栈运维),建立人工标注的基准集。每次修改 Prompt 后,用测试脚本一键计算准确率的变化。
可解释性属于系统,不属于模型排查问题时,真正有用的信息是:Prompt 模板的版本、模型的型号和版本、当时的 temperature 等参数,以及完整的请求和响应日志。有了这四项,任何一次错误都可以在本地完整复现。这比模型输出的一两句解释有用得多。
删除字段带来的意外影响
在删除 evidence 的过程中,还出现了一个意外情况。
删除 JSON Schema 中的 evidence 和摘要字段后,原本表现稳定的一个分类字段,突然有大批岗位返回了 null。
排查后发现,大模型的输出依赖自回归的概率转移。之前,模型需要先输出一段 evidence,这实际上给了它一次**思维缓冲(Scratchpad)**的机会。去掉这段内容之后,模型要在最前面直接做出高度抽象的分类判断,注意力来不及集中,于是倾向于保守地输出空值。
减少隐式推理的影响字段可以删除,但不能破坏模型的推理顺序。 对于高度依赖语义抽象的字段,我们调整了 JSON 键的输出顺序:先让模型提取具体的“核心技能词”(相当于低成本的定位),再让它输出更高层级的“岗位方向”。这样既减少了长篇引用的 Token,也保持了分类的准确率。
总结
在 LLM 应用的架构设计中,有些看似合理的直觉容易误导我们:
- “让模型输出思考过程”在复杂推理中是有效的;
- 但**“让模型为简单的抽取提供自我证明”,在大多数工程场景中只是增加了成本,并没有提供真正的保障。**
没有下游独立校验程序使用的字段,每多保留一个,都是多付一份成本。
面对模型生成的结果,应当始终保持怀疑。把节省下来的 64% 输出 Token 和计算时间,用于更扎实的前置清洗和更严格的后置规则校验,系统才会真正稳定。