RAG(Retrieval-Augmented Generation)完全指南
1. 什么是 RAG?
RAG(Retrieval-Augmented Generation,检索增强生成) 是一种将信息检索 与大语言模型生成能力相结合的 AI 技术框架。
核心思想:在让 LLM 生成答案之前,先从外部知识库中检索相关信息,然后将这些信息作为"参考资料"一起送给 LLM,让它基于事实生成更准确、更可靠的回答。
通俗理解:
- 传统 LLM:靠"死记硬背"的训练知识回答问题(容易过时、幻觉)
- RAG:先"翻书查资料",再"组织语言回答"(像开卷考试)
2. 为什么需要 RAG?
传统 LLM 的局限
| 问题 | 说明 |
|---|---|
| 知识截止日期 | GPT-4 知识截止于 2023 年,不知道之后发生的事 |
| 幻觉问题 | 对未知问题会编造看似合理但错误的答案 |
| 缺乏私有知识 | 不知道企业内部文档、个人数据 |
| 更新成本高 | 重新训练或微调大模型极其昂贵 |
RAG 如何解决
| 解决方案 | 原理 |
|---|---|
| 实时检索 | 每次回答都查询最新外部数据 |
| 事实支撑 | 基于检索到的文档生成,减少幻觉 |
| 接入私有库 | 企业文档、数据库作为检索源 |
| 无需重训练 | 只更新知识库即可获取新知识 |
3. RAG 工作流程
3.1 整体架构图
arduino
用户提问:"什么是RAG?"
↓
┌─────────────────┐
│ 1. 检索阶段 │
│ 向量数据库检索 │
└────────┬────────┘
↓
检索到相关文档片段
["RAG是一种结合检索和生成的技术...", ...]
↓
┌─────────────────┐
│ 2. 增强阶段 │
│ 构建增强提示词 │
└────────┬────────┘
↓
最终 Prompt:
"基于以下参考资料回答:
[文档1] RAG是...
[文档2] 它由检索器和生成器组成...
问题:什么是RAG?"
↓
┌─────────────────┐
│ 3. 生成阶段 │
│ LLM 生成回答 │
└────────┬────────┘
↓
最终答案:"RAG(检索增强生成)是一种..."
3.2 三个阶段详解
第一阶段:索引(预处理,离线)
python
# 伪代码示例
documents = ["公司年报.pdf", "技术文档.docx", "FAQ.txt"]
# 1. 文档切分
chunks = split_documents(documents, chunk_size=500)
# 2. 向量化(Embedding)
embeddings = embedding_model.encode(chunks)
# 3. 存入向量数据库
vector_db.insert(chunks, embeddings)
第二阶段:检索(在线)
python
# 用户提问
query = "去年公司营收多少?"
# 1. 问题向量化
query_embedding = embedding_model.encode(query)
# 2. 相似度检索
relevant_chunks = vector_db.search(query_embedding, top_k=5)
# 返回最相似的5个文档片段
第三阶段:生成(在线)
python
# 3. 构建增强 Prompt
prompt = f"""
基于以下参考资料回答用户问题:
参考资料:
{relevant_chunks}
用户问题:{query}
请基于参考资料回答,如果资料中没有相关信息,请明确说明。
"""
# 4. 调用 LLM
answer = llm.generate(prompt)
4. RAG 核心组件
4.1 Embedding Model(嵌入模型)
将文本转换为向量(一组数字),用于语义相似度计算。
| 模型 | 维度 | 特点 |
|---|---|---|
| OpenAI text-embedding-3-small | 1536 | 商业,效果最好 |
| OpenAI text-embedding-3-large | 3072 | 更高精度 |
| BGE (BAAI) | 1024 | 开源,中文友好 |
| M3E | 768 | 中文轻量级 |
| Sentence-BERT | 384-768 | 经典开源 |
4.2 Vector Database(向量数据库)
专门存储和检索向量的数据库。
| 数据库 | 特点 | 适用场景 |
|---|---|---|
| Pinecone | 全托管云服务 | 不想运维 |
| Milvus | 开源,功能最强 | 生产级大规模 |
| Qdrant | 高性能,Rust 编写 | 高性能需求 |
| Chroma | 轻量,易上手 | 原型开发 |
| Weaviate | 内置多种模型 | 全功能 |
| FAISS | Facebook 库,内存型 | 研究/小规模 |
| pgvector | PostgreSQL 扩展 | 已有 PG 生态 |
4.3 LLM(生成模型)
负责生成最终答案的大语言模型。
| 模型 | 特点 |
|---|---|
| GPT-4 | 最强,但贵 |
| GPT-3.5 | 性价比高 |
| Claude | 长上下文,安全 |
| Gemini | Google 生态 |
| 文心一言 | 国产合规 |
| 通义千问 | 阿里生态 |
| Llama 3 | 开源可私有化 |
| ChatGLM | 国产开源 |
4.4 Chunking Strategy(分块策略)
如何切分文档是关键。
| 策略 | 说明 | 适用场景 |
|---|---|---|
| 固定长度 | 按 token 数切分 | 通用 |
| 语义切分 | 按段落/句子边界 | 自然文档 |
| 递归切分 | 从大块到小块尝试 | 通用最佳实践 |
| 按文档结构 | 按 Markdown/HTML 标题 | 结构化文档 |
python
# 示例:递归切分
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块 500 字符
chunk_overlap=50, # 重叠 50 字符(保持上下文连贯)
separators=["\n\n", "\n", "。", ",", " "] # 优先按段落切
)
5. RAG 的进阶技术
5.1 查询改写(Query Rewriting)
用户问题可能表述不佳,先让 LLM 改写为更适合检索的形式。
arduino
原始问题:"那家做数据库的公司去年咋样?"
↓ 改写
改写后:"PingCAP 公司在 2023 年的营收和业务表现如何?"
5.2 HyDE(Hypothetical Document Embeddings)
先让 LLM 生成一个假设性答案,再用这个答案去检索。
arduino
问题:"RAG 有哪些优点?"
↓ LLM 先生成假设答案(可能不准确,但相关词汇丰富)
假设答案:"RAG 可以减少幻觉、实时更新知识、接入私有数据..."
↓ 用假设答案检索(比原始问题语义更丰富)
检索到更相关的文档
5.3 重排序(Re-ranking)
初次检索返回 Top-K(如 20 个),再用更精细的模型重新排序,取 Top-N(如 5 个)。
python
# 初检:20 个候选
candidates = vector_db.search(query, top_k=20)
# 重排序:用 cross-encoder 模型精排
reranker = CrossEncoder('BAAI/bge-reranker-base')
scores = reranker.predict([(query, doc) for doc in candidates])
# 取 Top-5
final_docs = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)[:5]
5.4 上下文压缩(Context Compression)
检索到的文档可能很长,用 LLM 提取最相关部分。
原始检索文档(1000 tokens)→ LLM 提取 → 压缩后(200 tokens)
5.5 Self-RAG(自反式 RAG)
让 LLM 自我评估检索结果和生成答案的质量。
- 检索是否相关?→ 不相关则重新检索
- 答案是否基于事实?→ 不是则调整
- 答案是否完整?→ 不完整则补充检索
6. RAG vs 其他技术对比
| 技术 | 知识更新 | 幻觉风险 | 私有数据 | 成本 | 可解释性 |
|---|---|---|---|---|---|
| 纯 LLM | ❌ 截止日期 | 高 | ❌ 无法接入 | 低(推理) | 低 |
| 微调 LLM | ⚠️ 需重新训练 | 中 | ✅ 可融入 | 高(训练) | 低 |
| RAG | ✅ 实时更新 | 低 | ✅ 易接入 | 中(检索+推理) | 高(可溯源) |
| 长上下文 LLM | ⚠️ 每次输入 | 中 | ⚠️ 受长度限制 | 高(输入 token 多) | 中 |
7. RAG 应用场景
7.1 企业知识库问答
arduino
员工问:"年假申请流程是什么?"
系统:检索公司 HR 文档 → 给出准确步骤 + 链接
7.2 智能客服
arduino
用户问:"我的订单 12345 什么时候到?"
系统:检索订单系统 + 物流 API → "预计明天下午 3 点"
7.3 医疗辅助(合规场景)
arduino
医生问:"这种药物的禁忌症?"
系统:检索最新药品说明书 + 医学文献 → 给出带引用的答案
7.4 代码助手(接入私有代码库)
arduino
开发者问:"用户认证模块怎么调用?"
系统:检索公司内部代码仓库 → 给出示例代码
7.5 法律文书分析
arduino
律师问:"这个合同中的免责条款有什么风险?"
系统:检索相关法律条文 + 类似判例 → 风险分析报告
8. RAG 实现示例(LangChain + OpenAI)
python
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI
# 1. 加载文档
loader = PyPDFLoader("company_manual.pdf")
documents = loader.load()
# 2. 切分
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = text_splitter.split_documents(documents)
# 3. 向量化并存入数据库
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(chunks, embeddings)
# 4. 创建 RAG Chain
qa_chain = RetrievalQA.from_chain_type(
llm=ChatOpenAI(model="gpt-3.5-turbo"),
retriever=vectorstore.as_retriever(search_kwargs={"k": 5}),
return_source_documents=True # 返回引用来源
)
# 5. 提问
result = qa_chain.invoke({"query": "年假有多少天?"})
print(result['result'])
print("参考资料:", result['source_documents'])
9. RAG 的挑战与解决方案
| 挑战 | 说明 | 解决方案 |
|---|---|---|
| 检索质量 | 检不到相关内容 | 查询改写、HyDE、多路召回 |
| 上下文长度 | 塞入过多 token | 压缩、重排序、精选取 Top-K |
| 速度延迟 | 检索+生成两步 | 缓存、并行检索、小模型 |
| 知识冲突 | 资料与 LLM 预训练矛盾 | 提示工程(强调参考资料优先) |
| 数据安全 | 私有数据外泄 | 私有化部署、本地模型、数据脱敏 |
10. 总结
RAG 是目前落地 LLM 应用最实用的架构,它:
- ✅ 让 LLM 能够访问最新、私有的知识
- ✅ 显著减少幻觉,提高答案可信度
- ✅ 可解释性强(可溯源到具体文档)
- ✅ 成本可控,无需频繁重训练
- ✅ 易于迭代(更新知识库即可)
一句话总结:
RAG = 检索(找到相关资料)+ 增强(拼接到提示词)+ 生成(LLM 组织答案)
文档版本:v1.0
最后更新:2026-05-18