Skip to content

RAG 检索增强生成

一句话定义:RAG (Retrieval-Augmented Generation) 是将外部知识检索大模型生成相结合的技术。先从知识库中搜索相关内容,再让 LLM 基于这些内容回答问题。

为什么需要 RAG?

  • LLM 知识有截止日期(如 GPT-5 训练数据到 2024 年底)
  • LLM 不知道你的私有文档(公司内部资料、个人笔记)
  • LLM 会”幻觉”(编造不存在的信息)

RAG 的解决方案:给 LLM 配一个”外挂大脑”——你的知识库。


点击运行,观察 RAG 管道的完整流程:问题 → 向量化 → 检索 → 构建上下文 → LLM 生成

🔍RAG 检索增强生成

💬 用户问题
接收问题
🔢
向量化
🔍
检索文档
📝
构建上下文
🤖
LLM 生成
📚 向量数据库 (文档库)
公司年假政策
员工入职满一年后,每年可享受 15 天带薪年假...
报销流程
员工报销需在 OA 系统提交申请,附上发票...
远程办公指南
员工可申请每周最多 2 天远程办公...
绩效考核标准
绩效考核每季度进行一次,分为 S/A/B/C 四档...
入职培训安排
新员工入职首周需完成 HR 安排的培训课程...
🤖 LLM 生成回答
等待运行 RAG 流程
📝 RAG 工作原理
1️⃣ 接收问题
2️⃣ 向量化查询
3️⃣ 语义检索
4️⃣ 构建 Prompt
5️⃣ LLM 生成

场景对应技术
闭卷考试纯 LLM:只能靠记忆(训练数据),可能记错
开卷考试RAG:可以翻书查资料,更准确
教科书向量数据库:存储所有知识
翻书找答案语义检索:找到相关段落
组织答案LLM 生成:根据资料回答

// RAG 就像给 API 加了一个"数据库查询中间件"
// ❌ 纯 LLM:直接问,可能编造
async function askLLM(question) {
return await gpt.chat(question); // 可能胡说八道
}
// ✅ RAG:先查资料,再回答
async function askWithRAG(question) {
// 1. 检索:从知识库搜索相关内容
const relevantDocs = await vectorDB.search(question, { topK: 3 });
// 2. 增强:把检索结果加入 Prompt
const context = relevantDocs.map(d => d.content).join('\n');
// 3. 生成:让 LLM 基于真实资料回答
const prompt = `
根据以下资料回答问题。如果资料中没有,请说"不知道"。
资料:
${context}
问题:${question}
`;
return await gpt.chat(prompt);
}

┌─────────────────────────────────────────────────────────────┐
│ 离线索引阶段 │
├─────────────────────────────────────────────────────────────┤
│ 文档 → 分块 → 嵌入向量 → 存入向量数据库 │
│ (PDF) (Chunk) (Embedding) (Vector DB) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 在线查询阶段 │
├─────────────────────────────────────────────────────────────┤
│ 用户问题 → 嵌入向量 → 相似度搜索 → Top-K 文档 │
│ ↓ ↓ │
│ └────────────── Prompt ─────────────→ LLM → 回答 │
└─────────────────────────────────────────────────────────────┘

把长文档切成小块(通常 200-1000 字)。

# 为什么要分块?
# - LLM 上下文窗口有限(128k-2M tokens,2025 年)
# - 小块检索更精准
# - 避免噪音干扰
# 常见分块策略
chunk_size = 500 # 每块字数
chunk_overlap = 50 # 块之间重叠(保持上下文连贯)

把文本转成数字向量,语义相近的文本向量也相近。

from sentence_transformers import SentenceTransformer
# 加载嵌入模型
model = SentenceTransformer('all-MiniLM-L6-v2')
# 文本 → 向量
text = "什么是机器学习?"
vector = model.encode(text) # [384] 维向量

用问题向量去数据库中找最相似的文档。

# 相似度计算:余弦相似度
# similarity = (A · B) / (|A| × |B|)
# 检索 Top-K 最相关的文档
results = vector_db.search(
query_vector=question_embedding,
top_k=5
)

把检索到的内容塞进 Prompt,让 LLM 回答。

prompt = f"""
你是一个问答助手。根据以下参考资料回答用户问题。
如果资料中没有相关信息,请直接说"抱歉,我没有找到相关信息"。
参考资料:
{retrieved_docs}
用户问题:{question}
回答:
"""

# LangChain 1.0+ (2025.10 发布)
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
# 1. 加载文档
loader = PyPDFLoader("company_handbook.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 链 (LangChain 1.0 新写法)
llm = ChatOpenAI(model="gpt-4o") # 推荐使用 GPT-4o 或 GPT-5
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
prompt = ChatPromptTemplate.from_template("""
根据以下资料回答问题。如果资料中没有,请说"不知道"。
资料:{context}
问题:{input}
""")
document_chain = create_stuff_documents_chain(llm, prompt)
retrieval_chain = create_retrieval_chain(retriever, document_chain)
# 5. 提问
response = retrieval_chain.invoke({"input": "公司的年假政策是什么?"})
print(response["answer"])

数据库特点适用场景
Chroma轻量、易用、Python 原生本地开发、小型项目
FAISSFacebook 出品、超快大规模、性能要求高
Pinecone云托管、免运维生产环境、团队协作
Milvus开源、分布式企业级、自托管
Weaviate支持混合搜索需要关键词+语义结合

# ❌ 固定长度切分(可能切断句子)
chunks = [text[i:i+500] for i in range(0, len(text), 500)]
# ✅ 智能分块(按段落/句子边界)
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=50,
separators=["\n\n", "\n", "", "", "", " "] # 按优先级切分
)
# 多路召回:同时使用语义检索 + 关键词检索
from langchain.retrievers import EnsembleRetriever
# 语义检索
semantic_retriever = vectorstore.as_retriever()
# 关键词检索(BM25)
keyword_retriever = BM25Retriever.from_documents(docs)
# 混合检索
ensemble = EnsembleRetriever(
retrievers=[semantic_retriever, keyword_retriever],
weights=[0.7, 0.3] # 语义权重更高
)
# 先召回 20 个,再用更精确的模型重排序,取 Top 5
from sentence_transformers import CrossEncoder
# 粗筛:快速召回
candidates = retriever.get_relevant_documents(query, k=20)
# 精排:用 Cross-Encoder 重新打分
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
pairs = [[query, doc.page_content] for doc in candidates]
scores = reranker.predict(pairs)
# 取最高分的 5 个
top_docs = [candidates[i] for i in np.argsort(scores)[-5:]]


维度RAGFine-tuning
知识更新✅ 实时更新知识库❌ 需重新训练
成本✅ 低(仅推理费用)❌ 高(训练费用)
准确性✅ 可溯源⚠️ 可能幻觉
推理能力⚠️ 受限于检索✅ 可学习新模式
适用场景知识问答、客服风格迁移、专业领域

最佳实践:RAG + Fine-tuning 组合使用。



LangChain 文档

RAG 最流行的框架

访问

LlamaIndex 文档

专注数据索引的框架

访问

RAG 论文

原始论文 (Facebook 2020)

arXiv