AI Agent 幻觉问题的工程化解决方案
当 AI 一本正经地告诉你错误答案时,它不是在撒谎,它只是产生了幻觉。本文将深入分析幻觉的成因,并提供一套从架构到代码的完整解决方案。
一、什么是 AI 幻觉?
幻觉(Hallucination) 是指大语言模型生成看似合理但实际错误的内容。它的危险之处在于:模型会用非常自信的语气,陈述完全错误的事实。
典型案例
用户:帮我查一下订单 #12345 的状态
AI(幻觉):订单 #12345 已于 2024-01-15 发货,预计 3 天内送达。
实际:数据库中根本没有这个订单
当没有实际的查询业务数据库,这种"自信的错误"比直接说"我不知道"更危险,因为它会误导用户做出错误决策。
幻觉的类型
|
类型 |
示例 |
危害等级 |
|
事实错误 |
"北京人口是 500 万" |
🔴 高 |
|
虚构引用 |
引用不存在的论文、文档 |
🔴 高 |
|
逻辑谬误 |
推理链条看似合理但结论错误 |
🟡 中 |
|
过度泛化 |
用个例推导普遍规律 |
🟡 中 |
|
上下文混淆 |
将 A 项目的配置说成 B 项目的 |
🟠 低 |
二、幻觉的四大根因
2.1 知识边界模糊
模型无法精确区分"我知道"和"我不知道"的边界。
# 模型的"知识"来源
knowledge_sources = {
"训练数据": "截止到某个时间点的互联网文本",
"上下文": "当前对话中的信息",
"工具结果": "通过 API/数据库查询获得的数据"
}
# 问题:模型无法准确判断某条知识来自哪个源
# 导致:将训练数据中的过时信息当作当前事实
2.2 概率生成的本质
LLM 本质是预测下一个 token 的概率分布,而非检索事实:
def generate(prompt):
# 模型生成的是"最可能的回答",而非"最真实的回答"
# 对于 "北京人口是..."
# 可能生成:500万、2000万、3000万...取决于训练数据分布
return most_likely_continuation(prompt)
2.3 上下文理解偏差
用户意图被错误解读:
用户:这个项目用 React 18 的新特性了吗?
AI:是的,项目使用了 React 18 的 Concurrent Rendering、
Suspense、Server Components 等特性。
实际:项目确实用 React 18,但只用了自动更新,没有使用任何新特性
2.4 缺乏自我验证机制
传统软件有断言、测试、类型检查,但 AI Agent 缺乏这些约束:
# 传统代码有运行时验证
def divide(a, b):
assert b != 0, "除数不能为 0"
return a / b
# AI Agent 没有验证机制
def answer_question(query):
# 没有 assert,没有类型检查
# 模型"认为"自己是对的,但可能完全错误
return llm.generate(query)
三、工程化解决方案
方案一:RAG(检索增强生成)
核心思想:让模型基于真实文档回答,而非依赖"记忆"。
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA
class RAGAgent:
def __init__(self, documents_path):
# 1. 文档向量化
self.embeddings = OpenAIEmbeddings()
self.vectorstore = Chroma.from_documents(
documents=load_documents(documents_path),
embedding=self.embeddings
)
# 2. 构建检索链
self.llm = ChatOpenAI(temperature=0) # 降低随机性
self.qa_chain = RetrievalQA.from_chain_type(
llm=self.llm,
retriever=self.vectorstore.as_retriever(
search_kwargs={"k": 5} # 检索 top-5 相关文档
),
return_source_documents=True # 返回来源
)
def answer(self, query):
result = self.qa_chain({"query": query})
# 3. 构建带引用的回答
answer = result["result"]
sources = result["source_documents"]
if sources:
citations = "\n\n".join([
f"📄 来源 [{i+1}]:{doc.metadata['source']}"
for i, doc in enumerate(sources)
])
return f"{answer}\n\n{citations}"
else:
return f"⚠️ 未找到相关文档,以下回答可能不准确:\n{answer}"
# 使用示例
agent = RAGAgent("./docs/")
print(agent.answer("公司的请假制度是什么?"))
输出效果:
根据员工手册,请假制度如下:
- 年假:工龄满 1 年后,每年 5 天
- 病假:每年累计不超过 30 天
- 事假:需提前 3 天申请
📄 来源 [1]:docs/员工手册.pdf
📄 来源 [2]:docs/考勤制度.md
为什么有效?
- 强制基于事实:回答必须来自检索到的文档
- 可追溯:每个回答都有明确来源
- 边界清晰:没有相关文档时,模型会明确表示不确定
方案二:工具调用约束
核心思想:强制 Agent 通过工具获取数据,而非凭空回答。
from langchain.tools import Tool
from langchain.agents import initialize_agent
# 定义数据查询工具
def query_database(sql: str) -> str:
"""查询数据库,返回准确数据"""
try:
result = db.execute(sql)
return json.dumps(result, ensure_ascii=False)
except Exception as e:
return f"查询失败:{e}"
def search_document(query: str) -> str:
"""搜索文档,返回相关内容"""
docs = retriever.search(query, top_k=3)
return "\n".join([doc.content for doc in docs])
tools = [
Tool(
name="DatabaseQuery",
func=query_database,
description="查询数据库获取订单、用户等数据。输入:SQL 查询语句"
),
Tool(
name="DocumentSearch",
func=search_document,
description="搜索文档获取业务规则、政策说明。输入:搜索关键词"
)
]
# 创建受约束的 Agent
agent = initialize_agent(
tools=tools,
llm=ChatOpenAI(temperature=0),
agent="zero-shot-react-description",
verbose=True # 显示推理过程
)
# Agent 会自动判断是否需要调用工具
result = agent.run("订单 #12345 现在什么状态?")
执行过程:
Thought: 需要查询数据库获取订单状态
Action: DatabaseQuery
Action Input: SELECT status FROM orders WHERE id = '12345'
Observation: [{"status": "not_found"}]
Thought: 数据库中没有该订单
Final Answer: 抱歉,系统中没有找到订单 #12345,请确认订单号是否正确。
关键优势:
- 数据查询类问题必须调用工具
- 工具返回的结果是确定性数据,不会产生幻觉
- Agent 的角色从"生成答案"变为"调用工具 + 组织语言"
方案三:多 Agent 交叉验证
核心思想:让多个 Agent 独立回答,找出共识部分。
from typing import List, Dict
import asyncio
class VerificationSystem:
def __init__(self, num_agents=3):
# 使用不同温度增加多样性
self.agents = [
ChatOpenAI(temperature=0.1 * i)
for i in range(num_agents)
]
async def get_answer(self, agent, query: str) -> str:
"""单个 Agent 回答"""
return await agent.agenerate([query])
async def verify(self, query: str) -> Dict:
"""多 Agent 验证"""
# 1. 并行获取多个回答
answers = await asyncio.gather(*[
self.get_answer(agent, query)
for agent in self.agents
])
# 2. 提取事实性声明
all_claims = [
extract_claims(answer)
for answer in answers
]
# 3. 找出共识
consensus = find_intersection(all_claims)
# 4. 找出分歧
disagreements = find_differences(all_claims)
return {
"verified_answer": consensus,
"uncertain_parts": disagreements,
"confidence": len(consensus) / (len(consensus) + len(disagreements)),
"raw_answers": answers
}
def find_intersection(claims_list: List[List[str]]) -> List[str]:
"""找出所有 Agent 都同意的声明"""
if not claims_list:
return []
result = set(claims_list[0])
for claims in claims_list[1:]:
result &= set(claims)
return list(result)
# 使用示例
system = VerificationSystem(num_agents=3)
result = await system.verify("公司的年假制度是什么?")
print(f"✅ 确认内容:{result['verified_answer']}")
print(f"⚠️ 不确定:{result['uncertain_parts']}")
print(f"📊 置信度:{result['confidence']:.2%}")
验证流程:
Agent 1: 年假每年 5 天,工龄满 5 年增加到 10 天
Agent 2: 年假制度:工龄 1 年 5 天,工龄 5 年 10 天
Agent 3: 年假根据工龄递增,1 年 5 天,5 年 10 天,10 年 15 天
共识:年假 5 天起,工龄影响年假天数
分歧:工龄 10 年是否增加到 15 天(只有 Agent 3 提到)
方案四:置信度自评
核心思想:让模型评估自己的回答可靠性。
class ConfidenceAwareAgent:
def __init__(self):
self.llm = ChatOpenAI(temperature=0)
def answer_with_confidence(self, query: str) -> Dict:
# 1. 生成回答
answer = self.llm.generate(query)
# 2. 自评置信度
confidence_prompt = f"""
评估以下回答的准确性(输出 0.0-1.0 的分数):
问题:{query}
回答:{answer}
评分标准:
- 1.0:有明确文档/数据支持
- 0.8-0.9:基于可靠推理,逻辑严密
- 0.6-0.7:有一定依据,但存在不确定因素
- 0.4-0.5:主要靠推断,可能不准确
- 0.0-0.3:高度不确定或可能错误
只输出数字,不要解释。
"""
confidence = float(self.llm.generate(confidence_prompt))
# 3. 根据置信度调整输出
if confidence >= 0.8:
return {
"answer": answer,
"status": "✅ 高置信度",
"confidence": confidence
}
elif confidence >= 0.6:
return {
"answer": f"(仅供参考){answer}",
"status": "⚠️ 中等置信度",
"confidence": confidence
}
else:
return {
"answer": "抱歉,我对这个问题的回答不够确定,建议您查阅官方文档或咨询相关人员。",
"status": "❌ 低置信度",
"confidence": confidence,
"raw_answer": answer
}
# 使用
agent = ConfidenceAwareAgent()
result = agent.answer_with_confidence("Python 3.12 有哪些新特性?")
print(f"{result['status']}(置信度:{result['confidence']:.2f})")
print(result['answer'])
输出示例:
✅ 高置信度(置信度:0.92)
Python 3.12 的主要新特性包括:
1. 改进的错误消息
2. GIL 移除计划(PEP 703)
3. 类型提示增强
⚠️ 中等置信度(置信度:0.65)
(仅供参考)Python 3.12 可能引入了新的语法特性...
❌ 低置信度(置信度:0.25)
抱歉,我对这个问题的回答不够确定,建议您查阅官方文档或咨询相关人员。
方案五:事实核查 Agent
核心思想:专门的 Agent 验证输出中的事实性声明。
class FactChecker:
def __init__(self, knowledge_base):
self.kb = knowledge_base
self.llm = ChatOpenAI(temperature=0)
def extract_factual_claims(self, text: str) -> List[str]:
"""提取文本中的事实性声明"""
prompt = f"""
从以下文本中提取所有事实性声明(可以被验证真假的陈述):
文本:{text}
输出格式(每行一个声明):
1. [声明内容]
2. [声明内容]
"""
return self.llm.generate(prompt).split("\n")
def verify_claim(self, claim: str) -> Dict:
"""验证单个声明"""
# 1. 在知识库中搜索证据
evidence = self.kb.search(claim, top_k=3)
if not evidence:
return {
"claim": claim,
"status": "unverified",
"reason": "未找到相关证据"
}
# 2. 让模型判断证据是否支持声明
verification_prompt = f"""
判断以下证据是否支持该声明:
声明:{claim}
证据:{evidence}
输出:
- "supported":证据明确支持
- "contradicted":证据反驳
- "insufficient":证据不足
"""
status = self.llm.generate(verification_prompt)
return {
"claim": claim,
"status": status,
"evidence": evidence
}
def check(self, text: str) -> Dict:
"""完整的事实核查流程"""
claims = self.extract_factual_claims(text)
results = [self.verify_claim(claim) for claim in claims]
# 统计
supported = [r for r in results if r["status"] == "supported"]
contradicted = [r for r in results if r["status"] == "contradicted"]
unverified = [r for r in results if r["status"] == "unverified"]
return {
"total_claims": len(claims),
"supported": len(supported),
"contradicted": len(contradicted),
"unverified": len(unverified),
"details": results,
"overall_accuracy": len(supported) / len(claims) if claims else 0
}
四、实战案例:构建"诚实"的客服 Agent
结合以上方案,构建一个完整的客服系统:
from dataclasses import dataclass
from typing import Optional, List
@dataclass
class AgentResponse:
answer: str
confidence: float
sources: List[str]
warnings: List[str]
needs_human_review: bool
class HonestCustomerServiceAgent:
"""一个"诚实"的客服 Agent,会明确表达不确定性"""
def __init__(self):
# RAG 系统
self.rag = RAGAgent("./knowledge_base/")
# 事实核查
self.fact_checker = FactChecker("./knowledge_base/")
# 多 Agent 验证
self.verifiers = VerificationSystem(num_agents=3)
# 工具集
self.tools = {
"query_order": query_database,
"search_policy": search_document,
"check_inventory": check_inventory
}
async def answer(self, query: str) -> AgentResponse:
"""主回答流程"""
# Step 1: 判断是否需要工具
if self._needs_tool(query):
tool_name = self._select_tool(query)
tool_result = self.tools[tool_name](query)
return AgentResponse(
answer=tool_result,
confidence=1.0, # 工具结果置信度高
sources=[f"工具:{tool_name}"],
warnings=[],
needs_human_review=False
)
# Step 2: RAG 检索
rag_result = self.rag.answer(query)
# Step 3: 多 Agent 验证
verification = await self.verifiers.verify(query)
# Step 4: 事实核查
fact_check = self.fact_checker.check(rag_result)
# Step 5: 综合判断
final_confidence = (
verification["confidence"] * 0.4 +
fact_check["overall_accuracy"] * 0.6
)
warnings = []
needs_review = False
# 低置信度警告
if final_confidence < 0.6:
warnings.append("此回答置信度较低,建议人工复核")
needs_review = True
# 未验证的事实
for detail in fact_check["details"]:
if detail["status"] == "unverified":
warnings.append(f"「{detail['claim']}」未找到证据支持")
# Step 6: 构建最终回答
if final_confidence >= 0.8:
answer = rag_result
elif final_confidence >= 0.6:
answer = f"(供参考){rag_result}"
else:
answer = (
"抱歉,我对这个问题的回答不够确定。\n"
"建议您:\n"
"1. 查阅官方文档\n"
"2. 联系人工客服\n\n"
f"初步判断:{rag_result}"
)
needs_review = True
return AgentResponse(
answer=answer,
confidence=final_confidence,
sources=[],
warnings=warnings,
needs_human_review=needs_review
)
def _needs_tool(self, query: str) -> bool:
"""判断是否需要调用工具"""
keywords = ["订单", "库存", "余额", "状态", "查询"]
return any(kw in query for kw in keywords)
def _select_tool(self, query: str) -> str:
"""选择合适的工具"""
if "订单" in query:
return "query_order"
elif "库存" in query:
return "check_inventory"
else:
return "search_policy"
# 使用示例
async def main():
agent = HonestCustomerServiceAgent()
queries = [
"订单 #12345 现在什么状态?", # 需要工具
"公司的年假制度是什么?", # RAG + 验证
"CEO 的生日是哪天?", # 应该说不知道
]
for query in queries:
print(f"\n{'='*50}")
print(f"问题:{query}")
result = await agent.answer(query)
print(f"回答:{result.answer}")
print(f"置信度:{result.confidence:.2%}")
print(f"来源:{result.sources}")
if result.warnings:
print(f"⚠️ 警告:{result.warnings}")
if result.needs_human_review:
print("🔔 需要人工复核")
import asyncio
asyncio.run(main())
输出示例:
==================================================
问题:订单 #12345 现在什么状态?
回答:订单 #12345 当前状态为"已发货",物流单号:SF1234567890
置信度:100.00%
来源:['工具:query_order']
==================================================
问题:公司的年假制度是什么?
回答:根据员工手册,年假制度如下:
- 工龄满 1 年:每年 5 天
- 工龄满 5 年:每年 10 天
- 工龄满 10 年:每年 15 天
置信度:85.00%
来源:[]
==================================================
问题:CEO 的生日是哪天?
回答:抱歉,我对这个问题的回答不够确定。
建议您:
1. 查阅官方文档
2. 联系人工客服
置信度:20.00%
⚠️ 警告:['此回答置信度较低,建议人工复核']
🔔 需要人工复核
五、最佳实践总结
5.1 分层防护策略
┌─────────────────────────────────────┐
│ Layer 1: Prompt 约束 │ ← 最简单,效果中等
│ - 明确要求"不知道时说不知道" │
│ - 要求标注信息来源 │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Layer 2: RAG + 工具约束 │ ← 效果显著
│ - 强制基于文档/数据回答 │
│ - 禁止凭空生成事实 │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Layer 3: 多 Agent 验证 │ ← 高可靠性场景
│ - 多个 Agent 独立回答 │
│ - 找出共识,标注分歧 │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ Layer 4: 事实核查 │ ← 最高可靠性
│ - 提取事实性声明 │
│ - 逐条验证证据 │
└─────────────────────────────────────┘
5.2 场景选择指南
|
场景 |
推荐方案 |
理由 |
|
闲聊对话 |
Prompt 约束 |
幻觉影响小,成本优先 |
|
知识问答 |
RAG + 来源标注 |
需要准确性,有文档支持 |
|
数据查询 |
工具约束 |
数据必须准确,不能编造 |
|
关键决策 |
多 Agent + 事实核查 |
错误代价高,需要高可靠性 |
|
内容生成 |
事实核查 |
避免传播错误信息 |
5.3 性能 vs 准确性权衡
|
方案 |
延迟 |
成本 |
准确性 |
|
仅 Prompt |
100ms |
1x |
70% |
|
RAG |
500ms |
2x |
90% |
|
RAG + 验证 |
1500ms |
4x |
95% |
|
完整流程 |
3000ms |
6x |
98% |
建议:根据业务场景选择合适的层级,不必一味追求最高准确性。
六、核心原则
宁可说"不知道",也不要自信地犯错。
在关键业务场景中,一个"诚实但有限"的 Agent 远比一个"博学但不可靠"的 Agent 更有价值。
实施路线图
- 第一周:实施 Prompt 约束 + 简单 RAG
- 第二周:添加工具调用约束
- 第三周:引入置信度评估
- 第四周:部署多 Agent 验证(如果需要)
关键指标
# 监控这些指标来评估改进效果
metrics = {
"幻觉率": "错误但自信的回答比例",
"拒绝率": "正确拒绝回答的比例",
"准确率": "回答正确的比例",
"用户满意度": "用户对回答质量的评分"
}
参考资料
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)