先分清幻觉长什么样

温度设成 0 只能压随机性,压不住"不知道却硬编"。实际遇到的幻觉可以归成四类:凭空造事实和数字;伪造引用,URL、论文标题、版本号看起来像真的,点开是 404;过时信息,把已经废弃的 API 当现行写法;不存在的包名、函数名、配置项。其中版本号和引用最隐蔽,因为它们太具体了,读者和审校者都容易直接放过。所以校验不能靠"读一遍觉得挺顺"。

能自动化的就别人工

第一条规矩是把输出形态改成可核对的:要求模型按 (claim, source_id, quote) 三元组给结论,每条断言都带来源编号和原文引句,之后程序逐条回查材料里到底有没有这句话,查不到就标未验证。第二条是检索增强,先给材料,明确写"只用材料回答,材料没有就答'材料未提及'",给 abstention 一个合法出口,并把它算作正确行为而不是失败。第三条是确定性校验器:生成代码就编译或跑测试,生成链接就发 HEAD 请求看状态码,生成 SQL 就 EXPLAIN,生成包名就查 registry。

import re, requests

def check_urls(md):
    bad = []
    for url in re.findall(r"https?://[^s)]+", md):
        try:
            r = requests.head(url, timeout=5, allow_redirects=True)
            if r.status_code >= 400:
                bad.append((url, r.status_code))
        except requests.RequestException:
            bad.append((url, "unreachable"))
    return bad

def check_claims(claims, source_text):
    return [c for c in claims if c["quote"] not in source_text]

至于"再让模型自己检查一遍",只能当补充,不能当主校验。模型会以非常自信的语气确认自己上一轮编的东西没错。真要用自查,提示得改成"逐条给出可验证的依据,找不到依据就标记为未验证",而不是"请检查上面有没有错误",后者十有八九回一句"没有错误"。

把校验放进发布流程

博客或文档站点的话,把这几步做成发布前的脚本:抽 URL 校验、抽代码块做语法检查、抽 import 查包名、抽版本号去官方 changelog 比对,任何一步失败就阻断。这样校验不再是"想起来才做"的自律动作。

python scripts/check_urls.py article.md
python scripts/check_imports.py article.md
php -l generated.php
git diff --check

几个具体踩坑

  • 软 404:URL 返回 200 但页面标题是"页面不存在",HEAD 之外还要看一眼内容或标题。
  • 列参考文献必编:让模型"列出参考链接"几乎必然造假,改成"从下面给出的候选文献里挑出相关的"。
  • 版本号幻觉:凡出现"在 v2.3 中新增"这类表述,一律去官方 release notes 核,这是最容易漏的一类。
  • 自查不可信:同一模型复查同一段输出,会稳定地重复同一个错误,换个模型或换确定性校验器才有意义。
  • 校验日志要留:把每次未验证项记下来,回头看就能发现模型在哪个主题上系统性瞎编,进而补材料或改提示词。