RAG 检索增强生成:减少幻觉的问答方案
RAG 检索增强生成:减少幻觉的问答方案
大语言模型(LLM)在自然语言处理领域展现出惊人的能力,但在实际应用中,它们存在一个致命缺陷——幻觉(Hallucination),即模型会自信地生成与事实不符的内容。这种问题在需要精确、可溯源的场景中(如企业知识库、医疗咨询、法律问答)是不可接受的。
RAG(Retrieval-Augmented Generation,检索增强生成) 正是为了解决这一问题而提出的架构。它通过将信息检索与文本生成相结合,让模型在回答时“有据可依”,显著降低了幻觉的发生率。本教程将从零开始,带你理解 RAG 的核心思想、工作流程,并动手实现一个最简单的 RAG 问答系统。
为什么需要 RAG?
传统 LLM 的局限
- 知识截止期:模型训练数据具有时间窗口,无法获取最新信息。
- 领域知识不足:通用大模型对垂直领域(如公司内部文档、特定医学文献)了解有限。
- 无法溯源:即使答案正确,也没有办法证明其出处,信息可信度低。
- 幻觉风险:当问题超出知识范围时,模型倾向于“编造”看似合理的回答。
RAG 是怎么解决的?
RAG 的核心思路是:先检索,再生成。在用户提问时,系统并不是直接让大模型凭空作答,而是:
- 从外部知识库(如文档、数据库)中检索与问题最相关的内容。
- 将这些检索到的内容作为“参考上下文”提供给大模型。
- 让模型基于给定的上下文生成最终回答。
这样一来,模型不再依赖自己模糊的记忆,而是基于实时获取的具体资料进行作答,幻觉大幅减少,而且答案的每一部分都可以对应到原始文档的片段,实现了事实层面的可解释性。
RAG 工作流程详解
一个标准的 RAG 系统通常由离线的索引构建和在线的查询处理两部分组成。
离线阶段:知识库索引
目标是将外部文档转换成可供快速检索的向量数据库。
-
文档加载与切割
读取多种格式的源文档(PDF、Markdown、网页),并使用文本分割器(Text Splitter)将长文档切分成较小的语义块(Chunk)。合适的块大小(如 512 token)能平衡语义完整性和检索精度。 -
向量嵌入(Embedding)
使用嵌入模型(如 OpenAI 的text-embedding-3-small,开源的BAAI/bge-large-zh)将每个文本块转换为固定维度的向量。这个向量捕捉了文本的语义信息,语义相似的文本在向量空间中距离更近。 -
向量数据库存储
将所有文本块的向量及其原始文本内容存入向量数据库(如 Chroma、Pinecone、Weaviate、Milvus)。向量数据库支持高效的近似最近邻(ANN)搜索,能够急速响应相似向量查询。
在线阶段:检索与生成
当用户提出问题后,系统执行以下步骤:
-
问题向量化
使用同一个嵌入模型将用户查询转换为查询向量。 -
相似性检索
在向量数据库中检索与查询向量最相似的 Top-K 个文本块(通常 K = 3~10)。这一步返回的是与问题最相关的文档片段。 -
提示组装
将检索到的文本块与原始问题一起,按照预设的提示模板组合成完整的提示词,明确告知模型“请仅根据以下参考资料回答问题”。
示例提示模板:请基于以下参考资料回答用户问题。如果资料中不存在相关信息,请直接说明“无法从提供的资料中找到答案”。 参考资料: {检索到的文本块} 用户问题:{用户原始问题} 回答: -
大模型生成
将组装好的提示发送给生成模型(如 GPT-4、Llama 3),模型在强制的上下文约束下生成答案,从而大幅抑制幻觉。
动手实现一个最简单的 RAG 系统
以下示例使用 Python 和流行的 LangChain 框架,结合 OpenAI 的嵌入和对话模型,构建一个能回答基于本地文档的问题的系统。请确保已安装所需依赖:
pip install langchain langchain-openai chromadb unstructured
1. 准备文档并建立向量库
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
# 加载本地文档
loader = TextLoader("./knowledge.txt", encoding="utf-8")
documents = loader.load()
# 切割文档为适当大小的块
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块最大长度
chunk_overlap=50, # 块之间重叠长度,保持语义连贯
separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""]
)
chunks = text_splitter.split_documents(documents)
# 初始化嵌入模型(这里用 OpenAI,需要 API key)
embedding_model = OpenAIEmbeddings(model="text-embedding-3-small")
# 创建向量数据库并持久化
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=embedding_model,
persist_directory="./chroma_db"
)
vectorstore.persist()
print(f"索引完成,共处理 {len(chunks)} 个文档块")
2. 构建 RAG 问答链
from langchain_openai import ChatOpenAI
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
# 定义检索器(返回最相关的3个片段)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 自定义提示模板,强制模型仅使用上下文
prompt_template = """请严格根据以下参考资料回答问题。如果资料中没有相关信息,请回答“未找到相关信息”。
参考资料:
{context}
问题:{question}
回答:"""
PROMPT = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
# 初始化生成模型
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# 创建检索增强生成链
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff", # 将所有检索到的文档块拼接后一次性送给模型
retriever=retriever,
chain_type_kwargs={"prompt": PROMPT},
return_source_documents=True # 返回参考文档片段以便溯源
)
# 提问测试
query = "什么是RAG?"
result = qa_chain.invoke({"query": query})
print("答案:", result["result"])
print("\n参考来源:")
for doc in result["source_documents"]:
print(f"- {doc.metadata.get('source', '未知来源')}: {doc.page_content[:100]}...")
3. 解读与进阶提示
- 检索精度调优:可以通过调整
chunk_size、chunk_overlap和检索参数k来平衡答案的完整性和相关性。 - 混合检索:纯向量检索有时会漏掉精确的关键词匹配,可结合 BM25 等传统稀疏检索方法,形成混合检索(Hybrid Search),进一步提升召回率。
- 重排序(Rerank):在初始检索后,可以再用一个轻量级模型(如 Cohere Rerank、bge-reranker)对候选片段进行重新打分,确保最相关的片段排在前面。
- 多源数据连接:企业场景中通常需要对接多个数据源(数据库、API、知识库),LangChain 提供了丰富的 Retriever 组件,可以轻松定制。
RAG 的常见挑战与应对
| 挑战 | 描述 | 应对策略 |
|---|---|---|
| 检索失败 | 知识库中不存在相关信息,导致模型无上下文可依。 | 在提示中明确要求模型无信息时坦诚告知,并考虑接入网络搜索兜底。 |
| 上下文过大 | 检索到的文档过长,超出模型上下文窗口。 | 使用 MapReduce、Refine 等链类型分块处理,或对块大小进行更精细控制。 |
| 幻觉仍然存在 | 模型未严格遵循上下文,自行编造。 | 增强提示约束,使用更强大的模型,增加后校验步骤(如事实一致性检查)。 |
| 低质量嵌入 | 嵌入模型无法准确表达领域语义,导致检索不准。 | 使用领域专用嵌入模型,或在自有数据上微调嵌入模型。 |
总结
RAG 架起了大语言模型与外部知识之间的桥梁,是目前解决知识更新、领域适配和幻觉问题最主流的方案之一。通过将检索机制引入生成流程,我们让 AI 的回答不再是“黑箱猜测”,而是每一个论断都有文档支撑的可靠推理。掌握 RAG 的核心原理和基础实现,你就已经迈出了构建可信 AI 应用的关键一步。
从今天开始,试着为自己的私有知识库搭建第一个 RAG 问答机器人吧。你将立刻感受到“有据可查”带来的回答质量的飞跃。