Token 级事实:生产环境 LLM 的实时幻觉检测
你的大模型刚刚调用了一个工具,收到了准确的数据,但给出的答案仍然是错的。欢迎来到外源性幻觉(extrinsic hallucination)的世界——模型自信地忽略了摆在眼前的真值。
基于我们的 “信号-决策”架构(Signal-Decision Architecture),我们推出了 HaluGate——这是一个基于 Token 级的条件性幻觉检测流水线,可以在错误内容到达用户手中之前将其拦截。无需 LLM 作为裁判,无需 Python 运行时,只需在交付点进行快速、可解释的验证。
问题:幻觉阻碍了生产环境的部署
幻觉已成为在大规模生产中部署大模型最大的障碍。在各行各业——法律(伪造的判例引用)、医疗(不正确的药物相互作用)、金融(编造的财务数据)、客户服务(不存在的政策)中,模式都是一样的:AI 生成了听起来合情合理、看起来权威的内容,但在审查下却经不起推敲。
挑战不在于明显的胡言乱语,而是嵌入在准确响应中的微妙捏造——这些错误需要领域专业知识或外部验证才能发现。对于企业而言,这种不确定性使得部署大模型成为一种负债,而非资产。
场景:当工具有效但模型失效时
让我们具体说明一下。考虑一个典型的函数调用交互:
用户:“埃菲尔铁塔是什么时候建造的?”
工具调用:
get_landmark_info("Eiffel Tower")工具响应:
{"name": "Eiffel Tower", "built": "1887-1889", "height": "330 meters", "location": "Paris, France"}LLM 响应:“埃菲尔铁塔建造于 1950 年,位于法国巴黎,高度为 500 米。”
工具返回了正确的数据。模型的响应包含事实。但其中两个“事实”是虚构的——这就是外源性幻觉,它们直接违背了提供的上下文。
这种失败模式特别阴险:
- 用户信任它,因为他们看到了工具已被调用
- 传统过滤器会漏掉它,因为其中没有有毒或有害内容
- 如果依赖另一个 LLM 来评判,评估成本高昂
如果我们能自动、实时地以毫秒级延迟检测这些错误呢?
洞察:将函数调用作为真值(Ground Truth)
关键的认识在于:现代函数调用 API 已经提供了接地(Grounding)上下文。当用户询问事实性问题时,模型会调用工具——数据库查询、API 调用、文档检索。这些工具结果在语义上等同于 RAG 中的检索文档。

我们不需要构建单独的检索基础设施,也不需要调用 GPT-4 作为裁判。我们从现有的 API 流程中提取三个组件:
| 组件 | 来源 | 用途 |
|---|---|---|
| 上下文 | 工具消息内容 | 用于验证的真值 |
| 问题 | 用户消息 | 意图理解 |
| 回答 | 助理响应 | 需要验证的陈述 |
问题变成了:该回答是否忠实于上下文?
为什么不仅仅使用 LLM 作为裁判?
显而易见的解决方案(调用另一个 LLM 进行验证)在生产环境中存在根本问题:
| 方法 | 延迟 | 成本 | 可解释性 |
|---|---|---|---|
| GPT-4 作为裁判 | 2-5 秒 | $0.01-0.03/请求 | 低(黑盒) |
| 本地 LLM 裁判 | 500ms-2s | GPU 计算 | 低 |
| HaluGate | 76-162ms | 仅 CPU | 高(Token 级 + NLI) |
LLM 裁判还存在以下问题:
- 位置偏差:倾向于偏好某些答案位置
- 详细程度偏差:无论准确性如何,更长的答案得分更高
- 自我偏好:模型偏好与其自身风格相似的输出
- 不一致性:相同的输入可能产生不同的判断
我们需要更快速、更便宜且更具可解释性的方案。
HaluGate:两阶段检测流水线
HaluGate 实现了一种条件性两阶段流水线,在效率和精确度之间取得了平衡:

第一阶段:HaluGate Sentinel(提示词分类)
并非每个查询都需要幻觉检测。考虑以下提示词:
| 提示词 | 需要事实核查吗? | 原因 |
|---|---|---|
| “爱因斯坦是什么时候出生的?” | ✅ 是 | 可验证的事实 |
| “写一首关于秋天的诗” | ❌ 否 | 创意任务 |
| “调试这段 Python 代码” | ❌ 否 | 技术支持 |
| “你对人工智能有什么看法?” | ❌ 否 | 观点请求 |
| “地球是圆的吗?” | ✅ 是 | 事实性主张 |
在创意写作或代码审查上运行 Token 级检测是浪费资源,而且可能会产生假阳性(“你的诗中包含未经支持的陈述!”)。
为什么预分类很重要:Token 级检测随上下文长度线性扩展。对于 4K Token 的 RAG 上下文,检测耗时约 125ms;对于 16K Token,则需约 365ms。在生产负载中,当约 35% 的查询是非事实性时,预分类可实现 72.2% 的效率提升——完全跳过针对创意、编码和观点查询的昂贵检测。
HaluGate Sentinel 是一个基于 ModernBERT 的分类器,它回答一个问题:此提示词是否值得进行事实验证?

该模型基于以下精心策划的组合进行训练:
需要事实核查(正类):
- 问答:SQuAD, TriviaQA, Natural Questions, HotpotQA
- 真实性:TruthfulQA(常见误区)
- 幻觉基准:HaluEval, FactCHD
- 信息查询对话:FaithDial, CoQA
- RAG 数据集:neural-bridge/rag-dataset-12000
无需事实核查(负类):
- 创意写作:WritingPrompts, 故事生成
- 代码:CodeSearchNet 文档字符串, 编程任务
- 观点/指令:Dolly 非事实性, Alpaca 创意类
通过原生 Rust/Candle 集成,该二元分类实现了 96.4% 的验证准确率,推理延迟约 12ms。
第二阶段:Token 级检测 + NLI 解释
对于归类为寻求事实的提示词,我们运行一个双模型检测流水线。
Token 级幻觉检测
与输出单个“有幻觉/无幻觉”标签的句子级分类器不同,Token 级检测可以精确识别哪些 Token 在上下文中没有得到支持。

模型架构:
Input: [CLS] context [SEP] question [SEP] answer [SEP]
↓
ModernBERT Encoder
↓
Token Classification Head (Binary per token)
↓
Label: 0 = Supported, 1 = Hallucinated (for answer tokens only)关键设计决策:
- 仅回答分类:我们仅对回答片段中的 Token 进行分类,不包括上下文或问题
- 跨度合并:连续的幻觉 Token 被合并为跨度,以提高可读性
- 置信度阈值:可配置的阈值(默认 0.8),以平衡精确率和召回率
NLI 解释层
仅仅知道某个内容是幻觉是不够的,我们需要知道为什么。NLI(自然语言推理)模型会针对上下文对每个检测到的跨度进行分类:

| NLI 标签 | 含义 | 严重程度 | 动作 |
|---|---|---|---|
| CONTRADICTION(矛盾) | 陈述与上下文冲突 | 4 (高) | 标记为错误 |
| NEUTRAL(中立) | 上下文不支持该陈述 | 2 (中) | 标记为不可验证 |
| ENTAILMENT(蕴含) | 上下文支持该陈述 | 0 | 过滤掉假阳性 |
为什么该集成奏效:单独的 Token 级检测在幻觉类上仅能达到 59% 的 F1 分数——近一半的幻觉会被漏掉,且 1/3 的标记是假阳性。我们曾尝试训练一个统一的 5 分类模型(支持/矛盾/捏造等),但它仅达到 21.7% 的 F1 分数——Token 级分类根本无法区分为什么某处是错误的。这种两阶段方法将平庸的检测器变成了一个可操作的系统:检测器提供召回能力(捕捉潜在问题),而 NLI 提供精确度(过滤假阳性)和可解释性(归类为什么每个跨度都有问题)。
与“信号-决策”架构的集成
HaluGate 并非孤立运行,它作为一种新的信号类型和插件,深度集成到了我们的 “信号-决策”架构 中。
fact_check 作为信号类型
正如我们拥有关键字、Embedding 和领域信号一样,fact_check 现在是一类头等信号。

这允许决策根据查询是否为事实寻求类进行条件处理。
注意:即使是前沿模型在不同版本之间也表现出幻觉差异。例如,GPT-5.2 的系统卡片显示了与以前版本相比可测量的幻觉增量,这突显了无论模型如何先进,持续验证都至关重要。
decisions:
- name: "factual-query-with-verification"
priority: 100
rules:
operator: "AND"
conditions:
- type: "fact_check"
name: "needs_fact_check"
- type: "domain"
name: "general"
plugins:
- type: "hallucination"
configuration:
enabled: true
use_nli: true
hallucination_action: "header"请求-响应上下文传播
关键挑战:分类发生在请求时,但检测发生在响应时。我们需要跨越此边界传播状态。

RequestContext 结构承载了所有必要的状态。
RequestContext:
# Classification results (set at request time)
FactCheckNeeded: true
FactCheckConfidence: 0.87
# Tool context (extracted at request time)
HasToolsForFactCheck: true
ToolResultsContext: "Built 1887-1889, 330 meters..."
UserContent: "When was the Eiffel Tower built?"
# Detection results (set at response time)
HallucinationDetected: true
HallucinationSpans: ["1950", "500 meters"]
HallucinationConfidence: 0.92hallucination 插件
幻觉插件是针对每个决策进行配置的,允许进行精细控制。
plugins:
- type: "hallucination"
configuration:
enabled: true
use_nli: true # Enable NLI explanations
# Action when hallucination detected
hallucination_action: "header" # "header" | "body" | "block" | "none"
# Action when fact-check needed but no tool context
unverified_factual_action: "header"
# Include detailed info in response
include_hallucination_details: true| 动作 | 行为 |
|---|---|
header | 添加警告标头,继续传递响应 |
body | 将警告注入响应体 |
block | 返回错误响应,不转发 LLM 输出 |
none | 仅记录,无用户可见操作 |
响应头:可操作的透明度
检测结果通过 HTTP 标头进行通信,使下游系统能够实现自定义策略。
HTTP/1.1 200 OK
Content-Type: application/json
x-vsr-fact-check-needed: true
x-vsr-hallucination-detected: true
x-vsr-hallucination-spans: 1950; 500 meters
x-vsr-nli-contradictions: 2
x-vsr-max-severity: 4对于未经证实的事实响应(当工具不可用时):
HTTP/1.1 200 OK
x-vsr-fact-check-needed: true
x-vsr-unverified-factual-response: true
x-vsr-verification-context-missing: true这些标头支持:
- UI 免责声明:当置信度低时向用户显示警告
- 人工审核队列:将标记的响应路由到人工审核
- 审计日志:跟踪未经证实的陈述以符合合规性
- 条件阻断:拦截高严重性的矛盾
完整流水线:三条路径

| 路径 | 条件 | 增加的延迟 | 动作 |
|---|---|---|---|
| 路径 1 | 非事实性提示词 | ~12ms (仅分类器) | 直接通过 |
| 路径 2 | 事实性 + 无工具 | ~12ms | 添加警告标头 |
| 路径 3 | 事实性 + 可用工具 | 76-162ms | 完整检测 + 标头 |
模型架构深度解析
让我们看一下驱动 HaluGate 的三个模型:

HaluGate Sentinel:二元提示词分类
架构:ModernBERT-base + LoRA 适配器 + 二元分类头
训练::
- 基础模型:
answerdotai/ModernBERT-base - 微调:LoRA (rank=16, alpha=32, dropout=0.1)
- 训练数据:来自 14 个数据集的 50,000 个样本
- 损失函数:具有类权重的 CrossEntropy(处理不平衡)
- 优化:AdamW, lr=2e-5, 3 个轮次
推理::
- 输入:原始提示词文本
- 输出:(class_id, 置信度)
- 延迟:CPU 上约 12ms
LoRA 方法允许在保留预训练知识的同时进行高效微调。训练期间仅更新 2.2% 的参数(149M 中有 3.4M)。
HaluGate Detector:Token 级二元分类
架构:ModernBERT-base + Token 分类头
输入格式:
[CLS] The Eiffel Tower was built in 1887-1889 and is 330 meters tall.
[SEP] When was the Eiffel Tower built?
[SEP] The Eiffel Tower was built in 1950 and is 500 meters tall. [SEP]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Answer tokens (classification targets)输出:每个回答 Token 的二元标签 (0=Supported, 1=Hallucinated)
后处理:
- 仅过滤预测到回答片段
- 应用置信度阈值(默认:0.8)
- 将连续的幻觉 Token 合并为跨度
- 返回带有置信度分数的跨度
HaluGate Explainer:三向 NLI 分类
架构:在 NLI 上微调的 ModernBERT-base
输入格式:
[CLS] The Eiffel Tower was built in 1887-1889. [SEP] built in 1950 [SEP]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
Premise (context) Hypothesis (span)输出:带有置信度的三向分类
- ENTAILMENT (0):上下文支持该陈述
- NEUTRAL (1):无法从上下文中确定
- CONTRADICTION (2):上下文与陈述冲突
严重程度映射:
| NLI 标签 | 严重性分数 | 解释 |
|---|---|---|
| ENTAILMENT(蕴含) | 0 | 可能是假阳性——过滤掉 |
| NEUTRAL(中立) | 2 | 陈述不可验证 |
| CONTRADICTION(矛盾) | 4 | 直接事实错误 |
为什么原生 Rust/Candle 至关重要
所有三个模型都通过 Candle(Hugging Face 的 Rust ML 框架)原生运行,并具有到 Go 的 CGO 绑定。

此方法的优势:
| 方面 | Python (PyTorch) | 原生 (Candle) |
|---|---|---|
| 冷启动 | 5-10s | <500ms |
| 内存 | 每个模型 2-4GB | 每个模型 500MB-1GB |
| 延迟 | +50-100ms 开销 | 接近零开销 |
| 部署 | 需要 Python 运行时 | 单个二进制文件 |
| 扩展 | GIL 争用 | 真正的并行 |
这消除了对单独 Python 服务、Sidecar 或模型服务器的需求——一切都在进程内运行。
延迟细分
以下是生产流水线中每个组件的测得延迟:
| 组件 | P50 | P99 | 备注 |
|---|---|---|---|
| 事实核查分类器 | 12ms | 28ms | ModernBERT 推理 |
| 工具上下文提取 | 1ms | 3ms | JSON 解析 |
| 幻觉检测器 | 45ms | 89ms | Token 分类 |
| NLI 解释器 | 18ms | 42ms | 跨度分类 |
| 总开销 | 76ms | 162ms | 当检测运行时: |
总开销(76-162ms)与典型的 LLM 生成时间(5-30 秒)相比可忽略不计,使得 HaluGate 在同步请求处理中非常实用。
配置参考
幻觉缓解的完整配置:
# Model configuration
hallucination_mitigation:
# Stage 1: Prompt classification
fact_check_model:
model_id: "models/halugate-sentinel"
threshold: 0.6 # Confidence threshold for FACT_CHECK_NEEDED
use_cpu: true
# Stage 2a: Token-level detection
hallucination_model:
model_id: "models/halugate-detector"
threshold: 0.8 # Token confidence threshold
use_cpu: true
# Stage 2b: NLI explanation
nli_model:
model_id: "models/halugate-explainer"
threshold: 0.9 # NLI confidence threshold
use_cpu: true
# Signal rules for fact-check classification
fact_check_rules:
- name: needs_fact_check
description: "Query contains factual claims that should be verified"
- name: no_fact_check_needed
description: "Query is creative, code-related, or opinion-based"
# Decision with hallucination plugin
decisions:
- name: "verified-factual"
priority: 100
rules:
operator: "AND"
conditions:
- type: "fact_check"
name: "needs_fact_check"
plugins:
- type: "hallucination"
configuration:
enabled: true
use_nli: true
hallucination_action: "header"
unverified_factual_action: "header"
include_hallucination_details: true超越生产环境:将 HaluGate 作为评估框架
虽然 HaluGate 专为实时生产使用而设计,但同样的流水线也可以支持离线模型评估。我们不是拦截实时请求,而是通过检测流水线馈送基准数据集,以系统地测量各模型的幻觉率。

评估工作流
评估框架将 HaluGate 视为幻觉评分器:
- 加载数据集:使用现有的 QA/RAG 基准(TriviaQA, Natural Questions, HotpotQA)或带有上下文-问题对的企业自定义数据集
- 生成响应:针对每个查询使用提供的上下文运行受测模型
- 检测幻觉:将 (上下文, 查询, 响应) 三元组通过 HaluGate Detector
- 分类严重性:使用 HaluGate Explainer 对每个标记的跨度进行归类
- 汇总指标:计算幻觉率、矛盾比率以及按类别细分的结果
局限性与范围
HaluGate 特别针对外源性幻觉——即工具/RAG 上下文提供验证基础的情况。它有已知的局限性:
HaluGate 无法检测的内容
| 局限性 | 示例 | 原因 |
|---|---|---|
| 内源性幻觉 | 模型在没有工具调用时说“爱因斯坦出生于 1900 年” | 没有可验证的上下文 |
| 无上下文场景 | 用户询问事实性问题,但未定义工具 | 缺少真值 |
透明降级
对于归类为寻求事实但缺乏工具上下文的请求,我们明确将响应标记为“未经证实的事实”,而不是静默通过。
x-vsr-fact-check-needed: true
x-vsr-unverified-factual-response: true
x-vsr-verification-context-missing: true这种透明度允许下游系统适当处理不确定性。
致谢
HaluGate 构建在研究界的优秀工作之上:
- Token 级检测架构:受 KRLabs 的 LettuceDetect 启发——这是基于 ModernBERT 的幻觉检测的开创性工作
- NLI 模型:构建在 tasksource/ModernBERT-base-nli 之上——高质量的 NLI 微调
- 训练数据集:TruthfulQA, HaluEval, FaithDial, RAGTruth 以及其他公开可用的基准
我们感谢这些团队在推进幻觉检测领域所做的工作。
总结
HaluGate 将原则性的幻觉检测带入了生产 LLM 部署中:
- 条件验证:跳过非事实性查询,验证事实性查询
- Token 级精度:确切知道哪些主张不受支持
- 可解释的结果:NLI 分类告诉你为什么某些内容是错误的
- 零延迟集成:原生 Rust 推理,无需 Python Sidecar
- 可操作的透明度:标头支持下游策略强制执行
下次当你的 LLM 调用工具、收到准确数据但答案仍然错误时——HaluGate 将在用户察觉之前将其拦截。
资源:
加入讨论:在 vLLM Slack 的 #semantic-router 频道分享你的用例和反馈