模型编造假引用和假 URL

模型给的引用看起来像 Smith et al. 2019,但论文根本不存在;或者给的 URL 一点就 404。引用幻觉为什么发生、怎么彻底压住。

你让模型给一个带引用的研究摘要。回答很流畅,末尾是 Smith et al. (2019). Effects of microbreaks on cognitive performance. Journal of Occupational Psychology, 42(3), 287-301.,看起来很真。你去搜期刊,没这篇。DOI 是假的。更糟的是,URL 域名是真的、但路径一点就 404。这是最伤的幻觉模式之一,因为”错但看似合理”的回答读起来跟正确的没区别,直到有人真去验证才露馅。

最快的修复:如果模型既没有文档库、也没有实时检索工具,就不要让它给引用。一个裸模型,你让它 “cite sources”,它就会编出引用样式的字符串,没有例外。要么用检索到的文本给回答打地基(RAG),要么接一个真实的 search/fetch 工具,然后把输出约束在这些来源(用 ID),并拒掉任何 URL 或 DOI 解析不了的 response。本页剩下的部分就是这几件事怎么做。

引用幻觉是结构性的、不是随机的。训练语料里声明后面不断跟着引用,模型学到的模式就是”声明后面要跟一个引用样式的串”。当它没有真引用时,它照样生成一个引用样式的串。这个本能靠 prompt 压不住,你得把”模型被逼着编”的情景拆掉。

这不是边角问题。一项被 Lancet 报道的研究发现:2023 年大约每 2,828 篇学术论文里有 1 篇含伪造引用,随着 AI 辅助写作普及,到 2026 年初已升到约每 277 篇里有 1 篇。在 2026 年一项覆盖多家商业模型的基准里,引用幻觉率从约 14% 到超过 90% 不等(取决于模型和领域),对抗性 prompt 还能把一些模型推到 90% 以上。

你属于哪一类

动 prompt 之前先跑两个检查,它们告诉你该用哪个修复。

症状可能原因去看
没检索、没工具,引用基本是假的裸模型按训练模式硬编第 1 步、第 5 步
RAG 返回 [],模型还是给了引用检索失败、模型照样答第 2 步
检索到的 chunks 里没引用,模型自己加了模型为显得严谨而硬塞第 2 步、第 4 步
URL 域名真,路径 404格式套出来的 URL 幻觉第 3 步
DOI 看着合法,但解析不到DOI 伪造或 chimera reference第 3 步
作者是真的,论文错的或不存在作者与论文张冠李戴第 4 步、第 7 步

chimera reference(嵌合引用)值得单独点名:模型把一个真实的 DOI 或真实的作者,跟错误的标题、年份或期刊拼在一起。每个零件都存在,组合不存在。这种引用能骗过”DOI 能不能解析”这种简单检查,只有当你把解析出来的元数据跟模型声称的对比时才会露馅。

常见原因

1. 没检索的裸模型被要求引用

“Summarize the research on X and cite sources.”模型没接数据库。它按训练分布生成像样的引用。大部分会是部分或全部假的。

怎么判断:把模型给的 5 个引用扔到 Google Scholar 或 CrossRef 搜。0-1 个真实就是这个 bug。

2. RAG 没检索到内容,但模型照样答

检索层返回空(empty result,或所有 chunk 都低于相似度阈值)。模型没拿到 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——格式合法、registrant 前缀可能甚至是真的,但 DOI 解析不到。

怎么判断:粘到 doi.org,“DOI not found” = 假。截至 2026 年 CrossRef 已索引约 1.8 亿篇学术成果,真 DOI 几乎一定能在那里解析到。

7. 引用作者名落在通用模式上

模型默认常见英语姓:Smith、Jones、Brown、Williams。某个专业领域或非英语领域真实研究的作者姓往往分布很不一样。

怎么判断:非英语领域的 bibliography 一堆通用英语姓——可疑。

最短修复路径

第 1 步:不要让裸模型给引用

这是单点收益最大的修复。模型没文档库还让它引用,伪造率会非常高。

BAD:  "Summarize research on X. Include 5 academic citations."
GOOD: "Summarize the topic of X based on your general knowledge.
       Do NOT include citations, DOIs, or URLs. Mark anything
       specific as 'based on general 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 the excerpts do not cover something, say "Not in provided sources."
Never invent a citation. Never reference a source not in the excerpts.

负面约束很关键。用检索到的文本给回答打地基,在 2026 年的多项研究里能把幻觉降 30-70%,做摘要任务时可以降到 2% 以下,但 RAG 仍会在大约 5-15% 的情况下编内容,多数发生在检索悄悄返回空、或返回了跑题的 chunk 时。所以你还需要第 2 步的空结果护栏和第 4 步的 ID 校验。

在代码里、而不是在 prompt 里加一个显式的”检索为空”分支:

if not retrieved:
    return "No sources found for this query."  # 不要调用模型

第 3 步:程序化校验每个 URL 和 DOI

import re
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 直接拒。要同时抓到 chimera reference(DOI 能解析、但指向错论文),用 CrossRef REST API 查 https://api.crossref.org/works/{doi},把返回的 titleauthor 跟模型声称的对比。DOI 能解析是必要条件,不是充分条件。

第 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 步:用”原生引用”特性,而不是自由文本引用

截至 2026 年 6 月,几家主流厂商都提供了把引用绑定到真实来源文本的特性,让模型没法指向一个从没提供过的东西。

  • Anthropic Citations API:在每个 document 内容块上设 citations: {enabled: true}。response 会把文本块和引用对象交错返回,引用对象里带 cited_textdocument_index 以及 start_char_index/end_char_index(PDF 则是页码)。这些是指向你所提供文档的、保证有效的指针,而且 cited_text 不计入 output tokens。注意:Citations 与 Structured Outputs 不兼容,两个一起开会返回 400。
  • OpenAI Responses API 配 web search:开启 web_search 工具,并传 include: ["web_search_call.action.sources"]。最终回答里会带内联的 url_citation 标注,附上每个真正抓取过的页面的标题和 URL。
  • Google Gemini grounding:开启 Google Search grounding,Gemini 3.1 Pro 会为每条经过 grounding 的声明返回 grounding 元数据(支撑用的 snippet 和来源 URI)。

三家的原理是一样的:模型只能引用工具真正返回的内容。没有工具结果,就没有引用。

tools = [{"name": "search_papers", ...}, {"name": "fetch_url", ...}]
# 模型只能引用工具返回的内容。

第 6 步:让”编引用”比”不编”代价更高

IMPORTANT: If you cannot find a real source, write
"No source found" instead of inventing one. A fabricated
citation is treated as a failure; "No source found" is not.

说明后果能让对齐过的模型降低伪造率,但永远不要单靠它,要跟第 2 步 + 第 4 步组合。instruction 只是引导行为,代码才能保证结果。

第 7 步:UI 里把引用做成可验证的独立 claim

引用别只显示纯文本。每个引用应该是可点击链接、点开就是来源,链接 404 时显示一个红色 badge。RAG 场景下,把引用到的 snippet 显示在声明旁边,让读者能确认来源是不是真这么说。把可验证性推到 UI 层是最后一道防线,也是唯一能抓住”人会轻易相信”的 chimera reference 的那道防线。

怎么确认修好了

  1. 取 20 个引用最密集的输出,逐个跑 validate_citations()。坏 URL/DOI 的拒绝率应该是 0。
  2. RAG 场景下,确认第 4 步的 ID 校验在留出测试集上从不抛错,即每个被引用的 ID 都在语料里。
  3. 抽 10 个输出,每个 DOI 都过一遍 CrossRef,对比 title 和 author。零个 chimera reference。
  4. 按模型、按 prompt 模板长期记录伪造率。模型或 prompt 一改就涨的话,你会在用户之前先看到。

哪些情况不是你操作错了

裸 LLM 的训练语料含数百万引用,把”声明要跟引用”内化成了模式。即使指令很强,顶级模型没检索时仍会幻觉相当比例的引用,更小的 open-weight 模型伪造得多得多。对任何需要准确来源的产品,检索都是必选项、不是 nice-to-have。这是模型训练方式的属性,不是你 prompt 写得差的信号。

容易误判的情况

误判成”模型知识缺口”——“它就是不知道最近的论文。“它知道有论文,它没办法 ground 到具体某一篇。知识没问题,可验证性才是问题。修复方案从来不是单换一个更大或更新的模型。

预防建议

  • 没检索的裸模型永远不要直接让它引用。
  • 输出始终约束在检索语料、用显式 ID。
  • post-processing 校验每个 URL 和 DOI,失败的整个 response 拒;能解析的 DOI 再跟 CrossRef 元数据交叉核对。
  • 真正需要论文级输出时,用原生引用特性(Anthropic Citations API、OpenAI web search sources,或 Gemini grounding)。
  • UI 里引用显示为可点击链接,让假引用在点击时暴露。
  • 按模型、按 prompt 模板记录伪造率,长期跟踪。

FAQ

  • 在 prompt 里加 “only cite real sources” 能修吗? 不能。模型以为自己编出来的就是真的,所以”只引用真的”这条指令改变不大。单靠 instruction 在这里效果很低,你需要检索加一道代码侧的校验。
  • 有的模型比其他模型差吗? 是。更小的 open-weight 模型引用伪造率高很多,2026 年一项跨厂商基准的范围从约 14% 到超过 90%(取决于模型和领域)。但顶级模型没检索时也会伪造,所以换更好的模型不能替代 grounding。
  • DOI 能解析,那引用就是真的吧? 不一定。chimera reference 会把一个真 DOI 跟错误的标题、年份或作者拼在一起。信它之前,先把解析出来的 CrossRef 元数据跟模型声称的对比。
  • 我的 RAG 流水线偶尔还是幻觉,为什么? RAG 仍会在大约 5-15% 的情况下编内容,几乎都发生在检索悄悄返回空、或返回了跑题的 chunk 时。加上显式的空结果分支(第 2 步)和语料 ID 校验(第 4 步),检索为空时绝不让模型跑。
  • 能让模型上网拿真引用吗? 能,但要用会返回来源元数据的原生特性(OpenAI web_search sources、Gemini grounding,或一个 fetch_url 工具),而不是自由文本 URL,并且仍要校验每个返回的 URL 能不能解析。

相关阅读

标签: #Prompt 工程 #排查 #llm-output #幻觉 #引用 #rag