在构建基于大模型的Agent系统时,幻觉问题是最容易被低估却危害极大的缺陷之一。所谓Agent幻觉,是指智能体在回答或执行任务过程中,输出了与真实世界事实不符、或完全没有任何可靠来源支撑的内容。这类内容往往语句通顺、逻辑自洽,普通用户很难一眼识破。因此,专门针对事实错误与虚构内容的测试,已经成为Agent质量保障中不可跳过的环节。

从底层原理来看,大模型本质是基于概率分布预测下一个token的生成器,而非具备真实世界认知的数据库。当上下文缺失关键事实、或用户提问超出训练知识边界时,模型为了维持语言流畅性,会用高概率词序列填补空白,这就产生了虚构。在Agent架构中,如果缺少检索增强或工具校验环节,规划模块又会把这些虚构内容当作中间结论传递给下游动作,导致错误被放大。理解这一点,才能设计出有针对性的测试方案。
很多团队误以为用准确率指标就能覆盖幻觉,其实常规问答准确率只统计最终答案字符串匹配,完全无法区分“不知道”和“编得合理”。我们必须把事实一致性作为独立维度,在测试集里预埋可验证断言,比如“某会议于2023年在柏林召开”,然后检查Agent输出是否违背该断言。只有把虚构从误差里拆出来,测试才真正有意义。
构建带证据链的事实错误测试集
要做可靠的幻觉测试,第一步是准备数据集。与传统NLP评测不同,Agent幻觉测试集每条样本都应包含:原始查询、标准事实声明、支撑证据文本、以及允许的答案边界。证据文本可以是维基百科片段或企业知识库文档,作用是让测试框架能回溯Agent是否依据了正确来源。如果Agent抛出了证据之外的实体或数值,即可标记为疑似虚构。
下面给出一个用Python生成对抗样本的简化脚本,它会在真实事实上随机注入干扰,观察Agent是否跟随错误前提。注意代码里所有特殊字符都已转义,方便直接嵌入测试流水线。
import random
facts = [
{"entity": "公司A", "event": "融资", "amount": "1亿", "city": "上海"},
{"entity": "产品B", "event": "发布", "amount": "无", "city": "深圳"}
]
def make_trap(query_tpl, fact):
# 随机把城市替换成虚构地点,制造事实错误诱饵
fake_cities = ["火星城", "虚都", "幻市"]
if random.random() < 0.5:
fact = dict(fact)
fact["city"] = random.choice(fake_cities)
return query_tpl.format(**fact), fact
q = "请确认{entity}的{event}是否发生在{city}?"
sample, base = make_trap(q, facts[0])
print(sample)
print("标准事实:", base)
上述方法属于静态基准构建,优势是可重复、易量化。但它难以覆盖Agent在多轮对话里逐步编造的情况。因此我们建议在数据集中加入多跳推理样本:先问一个真实子问题,再基于回答追问,看Agent会不会在第二步无中生有。这类样本能暴露规划模块的事实漂移。
另一个常见做法是使用人类专家标注的“红队”语料,由测试人员刻意用模糊指令引诱虚构,比如“你觉得某匿名高管私下怎么看这次并购”。如果Agent给出了具体引语或姓名,就属于典型虚构。把这类语料和自动化样本混合,能兼顾覆盖率和真实攻击面。
用检索回溯与断言比对识别虚构内容
识别虚构不能只靠肉眼,工程上更稳妥的是检索回溯机制。具体思路是:让被测Agent在输出时同步给出引用片段或来源编号,测试框架拿着这些引用去证据库做重合度计算。如果输出中的关键实体在引用里找不到,就判为未溯源虚构。即使模型声称“根据公开资料”,只要链接打不开或内容不匹配,也应计入失败。
断言比对则更严格。我们可以把Agent输出解析为若干三元组(主体,关系,客体),再与标准事实图做差异分析。例如标准事实是(公司A,融资额,1亿),而输出解析出(公司A,融资额,5亿),直接触发事实错误告警。下面是一段做三元组比对的伪代码,展示核心逻辑。
def extract_triples(text):
# 简化:用规则抽取金额与主体
triples = []
if "融资" in text:
import re
m = re.search(r"(S+?)融资(d+亿)", text)
if m:
triples.append((m.group(1), "融资额", m.group(2)))
return triples
def check(standard, pred_text):
pred = extract_triples(pred_text)
for s in standard:
if s not in pred:
return False, "缺失或篡改:" + str(s)
return True, "ok"
std = [("公司A", "融资额", "1亿")]
print(check(std, "公司A融资5亿"))
这种方法的短板在于抽取器本身可能漏检,因此建议配合困惑度或置信度阈值使用。当模型生成某句子的对数概率过低,或自检模块给出“不确定”信号时,即便文本流畅也应人工复核。把置信度低于阈值的输出全部归档,往往能捞出大量隐性幻觉。
在真实业务里,还可以引入外部知识图谱做交叉验证。比如Agent说“某药物获批用于糖尿病”,就调用医药图谱接口确认适应症字段。这种在线校验虽增加延迟,却能把线上虚构率压到可接受范围。测试阶段用同样接口回放,便能量化Agent在工具加持下的幻觉下降幅度。
动态交互测试与持续监控策略
静态测试通过后,仍要在动态交互中验证。Agent常在前端对话里被用户纠正后坚持错误,或为了完成目标任务而隐瞒不确定。我们可以设计状态机测试器,模拟用户连续反问:“你刚才说的城市有证据吗?”观察Agent是否转而编造证据链接。若它生成形如 https://ipipp.com/fake/123 的无效地址,就坐实虚构。
持续监控则把测试左移到生产环境。通过埋点收集线上输出,用异步任务跑事实校验模型,发现疑似幻觉就回流到标注池。这样测试集随业务自然增长,避免一次性基准很快过期。下表对比了三类测试方式的适用阶段。
| 测试方式 | 实施成本 | 发现虚构类型 | 推荐阶段 |
|---|---|---|---|
| 静态基准 | 低 | 明确事实错误 | 研发期 |
| 检索回溯 | 中 | 无溯源虚构 | 准出测试 |
| 动态交互 | 高 | 多轮编造 | 线上监控 |
最后要强调,幻觉测试不是要把Agent逼成拒答机器。合理目标是让它在未知时显式说“无可靠信息”,而非用虚构填充。通过在提示词中写入“无证据请声明未知”,并在测试里给诚实弃权加分,能引导模型行为。只有把事实错误与虚构当成一类独立缺陷来度量,Agent才真正值得托付。
综上,Agent幻觉测试需要证据链数据集、断言比对和动态交互三件套联动。团队应把虚构率写入发布门禁,并结合置信度与溯源覆盖率做综合评分。唯有如此,才能在使用智能体时避开那些看似合理却完全虚假的内容陷阱。