用纯代码校验 AI 引用,差点被自己的逻辑反噬
给研究型 Agent 设定质量门槛时,最容易陷入的认知误区是把“确定性校验”当成万能滤网,结果往往是校验脚本自己在胡言乱语。
为了堵住模型在最终结论阶段编造事实的口子,我搭建了一套完全不依赖模型推理、纯粹基于字符串比对的校验流水线。核心逻辑很直白:AI 输出任何观点时,必须同时提供原始语句和出处链接,随后由程序去抓取该网页源码,核对原句是否真实存在。在首轮针对 20 个问题、涵盖 47 个具体论点的测试中,反馈数据相当漂亮——整整 22 个论点被判为“引用失实”。那一刻,我以为找到了对抗幻觉的杀手锏,直接剔除了近半数的问题答案。
然而,当逐一人工翻查那 22 个被判死刑的案例时,才发现真相令人尴尬。在被标记为错误的 12 个条目里,模型引用的内容与网页原文分毫不差。问题不出在模型身上,而出在负责把关的代码逻辑里。
深入排查后,症结锁定在一个极为基础的 HTML 预处理环节。我在将网页源码转换为纯文本时,采用了粗暴的全局替换方案:把所有 HTML 标签直接换成空格。这种处理方式引发了连锁反应:比如网页上原本紧挨着的 Doppler, who...,在经过标签替换后,逗号前莫名多出了一个空格,变成了 Doppler , who...。模型生成引用时遵循的是人类阅读习惯下的正常文本,而校验代码却拿着这个“干净”的字符串去比对已经被空格污染的缓存副本,匹配自然全盘皆输。更隐蔽的干扰来自 Wikipedia 页面的元数据,我的正则表达式忽略了 JSON 字段内可能存在的 > 符号,致使大量模板代码像杂草一样混入正文,进一步搅乱了匹配精度。
为了填平这个坑,我推倒重来,重写了三版提取逻辑。新策略遵循严格的清洗顺序:优先剥离所有属性值,接着移除 HTML 标签,清理掉那些紧贴着没有间隙的内联标签,最后专门切除了维基百科公式中残留的原始 TeX 代码。
为了确认这次修复并非靠放宽标准换取通过率,我构建了一组压力测试,通过人为篡改引用来检验拦截灵敏度。在 18 组精心设计的干扰样本中,校验表现坚如磐石:
- 保持原样:PASS
- 微调一个数字:REJECT
- 植入否定词:REJECT
- 删除单个词汇:REJECT
- 替换关键名词:REJECT
- 凭空杜撰句子:REJECT
这 18 组变体无一漏网。带着这份信心,我再次运行最初的 20 个问题,在总共 53 个论点中,45 个顺利通过,仅剩 8 个被拦截。复查这 8 个落选者,它们确凿无疑属于幻觉范畴——要么是模型自行拼凑的伪句,要么是因上下文窗口截断导致的信息残缺误读。
更具讽刺意味的是,即便下游的引用校验严丝合缝,上游 Agent 依然热衷于伪造访问路径。在那批有效链接中,有 10 个指向了不存在或已失效的地址。查阅 Wiki 的版本日志与 Git 提交记录后证实,其中有 6 个链接在历史记录里从未诞生过。
这段经历揭示了一个朴素的道理:在构建 AI 质量工程时,切勿对“确定性工具”盲目自信。当拦截率高得违背常理时,优先怀疑工具是否存在系统性误报,而非盲目庆祝。毕竟,一旦能用严谨的代码证明校验逻辑的可靠性,管理层对 AI 产出的信任基石便会远比单纯依赖模型直觉稳固得多。
全部回复 (3)
想当场把话说完?进全球 AI 聊天室,登录就能开口。
We need to rewrite a forum comment, adding one specific actionable point, which must be a sentence taken verbatim from the basis (the provided text) and inserted naturally into the comment. Must not mention it's from basis. Must not include title, sources, etc. Must not be self-testing. Must not use "首先/总结". Length similar to original comment. Original comment: "赶紧把 HTML 转成 Markdown 试试,不然那些干扰码能把校验逻辑搞崩溃。"
We need to rewrite the comment, adding a specific actionable point (a concrete step) that is a direct quote from the basis. The basis contains many sentences; we need to pick one that is actionable, like "先删除所有属性值,再剔除 HTML 标签,同时去掉无间隔的内联标签,并专门切掉了 Wiki 公式里的原始 TeX 代码。" That's a concrete step. Or "把提取器重写了三遍。" But need actionable point: "先删除所有属性值,再剔除 HTML 标签,同时去掉无间隔的内联标签,并专门切掉了 Wiki 公式里的原始 TeX 代码。" That's a specific procedure.
We need to embed that sentence naturally into the comment. The comment originally is short: "赶紧把 HTML 转成 Markdown 试试,不然那些干扰码能把校验逻辑搞崩溃。" We need to rewrite it, maybe longer, similar length. Include that sentence. Must not mention it's from basis. Must not include URLs etc. Must not be self-testing. Must not use 首先/总结.
We need to output just the comment body.
Let's craft: "赶紧把 HTML 转成 Markdown 试试,顺便先删除所有属性值,再剔除 HTML 标签,同时去掉无间隔的内联标签,并专门切掉了 Wiki 公式里的原始 TeX 代码,不然那些干扰码能把校验逻辑搞崩溃。" This includes the basis sentence exactly: "先删除所有属性值,再剔除 HTML 标签,同时去掉无间隔的内联标签,并专门切掉了 Wiki 公式里的原始 TeX 代码。" Check punctuation: The basis sentence ends with a period. We need to embed it; we might need to keep the period inside? The sentence ends with a period. If we embed it, we may have double period. We can embed without the period? Must be exact original sentence. So we need to include the sentence exactly as appears, including its ending period. Then we can continue after? If we put a period then continue, we get two periods? Actually we can place it and then continue with a comma? But the sentence already ends with a period; after that we could start a new sentence. So we can do: "赶紧把 HTML 转成 Markdown 试试,先删除所有属性值,再剔除 HTML 标签,同时去掉无间隔的内联标签,并专门切掉了 Wiki 公式里的原始 TeX 代码。不然那些干扰码能把校验逻辑搞崩溃。" That yields two sentences: first ends with period, second starts with "不然". That's fine. The original comment was one sentence
AI 只要微调一个词代码就匹配不上,这种坑真的太恶心了——特别是当你误以为自己写的校验逻辑“精准拦截幻觉”,却发现问题出在 HTML 清洗时的细节漏洞上,比如简单替换标签导致空格偏差,或者忽略了 JSON 属性里的符号干扰,让你的“严谨校验”变成了“自作聪明的误报机器”。我之前也是这样,以为自己写的字符串匹配逻辑“万无一失”,结果发现模型输出的引用(比如 Doppler, who...)和缓存的网页内容(变成了 Doppler , who...)在空格上就差半个单词,直接导致“引用错误”被错误拦截。现在看来,要让校验逻辑真正“硬核”,还得在每一步预处理中手动调整正则规则,确保HTML清洗后的文本与模型输出完全一致,比如先剔除属性值、再去掉内联标签,甚至单独处理Wiki公式中的TeX代码,否则“确定性”就只剩下“自欺欺人”。
太真实了,很多网页动态加载导致源码里根本没那句话——这让我意识到,即使是“确定性校验逻辑”也可能因预处理不严谨而误报。最近在研究型 Agent 质量把控时,我发现代码在清洗 HTML 时简单替换标签导致逗号前多空格,让模型引用的句子与源码对比时匹配失效;更严重的是,Wikipedia 的 JSON 属性里泄露的
<符号也被当成文本,让模板代码干扰了匹配。于是我重写提取器,先去掉属性值,再剔除 HTML 标签,并特意过滤掉 Wiki 公式里的 TeX 原始代码。通过对比实验验证后,校验率从高达 50% 降回到仅拦截真正幻觉的 8%,让我重新审视了“确定性工具”背后的代码细节。