你让模型给一个研究摘要带引用。回答很流畅,末尾是 “Smith et al. (2019). Effects of microbreaks on cognitive performance. Journal of Occupational Psychology, 42(3), 287-301.”——看起来很真。你去搜——期刊里没这篇。DOI 是假的。更糟的——模型给的 URL 域名真实但路径 404。引用幻觉是最伤的失败模式之一,因为”错但看似合理”的输出在人眼里是被奖励的,直到有人去验证。
引用幻觉是结构性的、不是随机的。训练数据里包含大量引用的模型学到”声明后面要跟着引用样式的字符串”。它不知道真实引用时也会照样生成一个引用样式的串。靠 prompt 压不住——你得拆掉”模型必须编”的情景。
常见原因
1. 不带检索的 base model 被要求引用
“Summarize the research on X and cite sources.”模型没接数据库。它按训练分布生成像样的引用。大部分会是部分或全部假的。
怎么判断:把模型给的 5 个引用扔到 Google Scholar 搜。0-1 个真实就是这个 bug。
2. RAG 没检索到内容但模型照样答
检索层返回空(empty result,或全部低于相似度阈值)。模型没拿到 context 仍然自信回答——还编了引用支撑这个自信。
怎么判断:log 检索到的 chunks。RAG 返回 [] 但模型仍带引用——它编的。
3. 检索到的 chunks 里没引用、模型还硬塞
RAG 拿回了 3 段关于 microbreaks 的文本,里面一个引用都没有。模型在答案末尾仍写 “(Smith, 2019)” 来显得严谨。
怎么判断:在 retrieved chunks 里搜引用字符串。找不到 = 模型造的。
4. 真作者套到了错论文上
John Smith 是真作者,2017 年写过别的主题。模型把一个 2019 年关于近似主题的论文按到了他头上。作者真,论文假。
怎么判断:搜作者名 Scholar 有结果、但搜引用里的论文标题没结果。
5. URL 幻觉来自高自信的模式匹配
“Source: https://stackoverflow.com/questions/1234567/how-to-foo”——域名真实、slug 格式对,但 question 不存在。模型按格式生成 URL。
怎么判断:点 URL,404 或 “no results” = 假。
6. DOI 伪造
模型输出 https://doi.org/10.1234/jop.2019.42.3.287——格式合法、registrar code 可能甚至真,但 DOI 解析不到。
怎么判断:粘到 doi.org,“DOI not found” = 假。
7. 引用作者名落在通用模式上
模型默认常见英语姓——Smith、Jones、Brown、Williams。某个专业领域真实研究的作者姓往往分布很不一样。
怎么判断:非英语领域的 bibliography 一堆通用英语姓——可疑。
最短修复路径
第 1 步:base model 没检索就不要让它给引用
这是单点收益最大的修复。模型没文档库还让它引用,幻觉率会到 80%+。
BAD: "Summarize research on X. Include 5 academic citations."
GOOD: "Summarize the topic of X based on your general knowledge.
Do NOT include citations or URLs. Mark anything specific
as 'based on common knowledge, please verify.'"
第 2 步:用 RAG,并约束在检索到的源里
You will receive 3 document excerpts below.
Answer the user's question using ONLY these excerpts.
For every claim, cite which excerpt it came from: [1], [2], [3].
If excerpts don't cover something, say "Not in provided sources."
Never invent a citation. Never reference a source not in the excerpts.
负面约束很关键。
第 3 步:程序化校验每个 URL 和 DOI
import requests
def validate_citations(text):
urls = re.findall(r'https?://[^\s)]+', text)
dois = re.findall(r'10\.\d+/[^\s)]+', text)
bad = []
for url in urls:
try:
r = requests.head(url, timeout=5, allow_redirects=True)
if r.status_code >= 400: bad.append(url)
except Exception: bad.append(url)
for doi in dois:
r = requests.head(f"https://doi.org/{doi}", timeout=5, allow_redirects=True)
if r.status_code >= 400: bad.append(doi)
return bad
包含失效引用的 response 直接拒。
第 4 步:RAG 场景下,校验引用 token 在检索库里
allowed_sources = set(chunk['id'] for chunk in retrieved)
cited = extract_citation_ids(model_output)
fake = cited - allowed_sources
if fake:
raise ValueError(f"Model cited sources not in corpus: {fake}")
第 5 步:换成 tool-using agent 拿真引用
现代方案:给模型一个 search() 或 fetch_paper() 工具。它调工具、拿真结果、引用真文本。没工具 → 没引用。
tools = [{"name": "search_papers", ...}, {"name": "fetch_url", ...}]
# 模型只能引用工具返回的内容
第 6 步:在 prompt 里让伪造引用”代价高”
IMPORTANT: If you fabricate a citation, the user will lose
trust in this entire system. Saying "I don't have a real source"
is always better than inventing one.
说明后果有时能让对齐过的模型降低伪造率——但永远不能单靠这个,必须跟第 2 步 + 第 4 步组合。
第 7 步:UI 里把引用做成可验证的独立 claim
引用别只显示文本。每个引用是可点击链接打开来源——404 时显示红色 badge。把可验证性推到 UI 层是最后一道防线。
哪些情况可能不是你操作错了
base LLM 的训练语料含数百万引用。它内化了”声明要跟引用”作为模式。没有检索时,即使顶级模型也会幻觉 20-40% 的引用。RAG 对任何需要准确来源的产品都是必选项,不是 nice-to-have。
容易误判的情况
当成”模型知识缺口”——“它就是不知道最近的论文。“它知道有论文;它没办法 ground 具体某一篇。知识没问题,可验证性才是问题。
预防建议
- 没检索的 base model 永远不要直接让它引用。
- 输出始终约束在检索语料、用显式 ID。
- post-processing 校验每个 URL 和 DOI,失败的整个 response 拒。
- 真正需要论文级输出时,换成 tool-using agent 配
search()工具。 - UI 里引用显示为可点击链接,让假引用在点击时暴露。
- 按模型 / 模板记录幻觉率,长期跟踪。
FAQ
- 写 “only cite real sources” 能修吗? 不能。模型以为编出来的就是真的。单靠 instruction 在这里效果低。
- 有的模型比其他模型差吗? 是——小的 open-weight 模型引用幻觉率高很多。但顶级模型没检索时也会幻觉。
相关阅读
- AI 编造事实
- AI 幻觉出不存在的文件路径
- Prompt 缺少来源层级
- Prompt 缺少 context 层级
- 模型自己补足缺失细节
- AI 回答太空泛
- 没定义成功标准
- 评估标准含糊
- AI 编造错误的 API 签名
- 输出很漂亮但没法执行
标签: #Prompt 工程 #排查 #llm-output #幻觉 #引用 #rag