LangChain 文档
RAG 最流行的框架
一句话定义:RAG (Retrieval-Augmented Generation) 是将外部知识检索与大模型生成相结合的技术。先从知识库中搜索相关内容,再让 LLM 基于这些内容回答问题。
为什么需要 RAG?
RAG 的解决方案:给 LLM 配一个”外挂大脑”——你的知识库。
点击运行,观察 RAG 管道的完整流程:问题 → 向量化 → 检索 → 构建上下文 → 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 PyPDFLoaderfrom langchain_text_splitters import RecursiveCharacterTextSplitterfrom langchain_chroma import Chromafrom langchain_openai import OpenAIEmbeddings, ChatOpenAIfrom langchain.chains import create_retrieval_chainfrom langchain.chains.combine_documents import create_stuff_documents_chainfrom 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-5retriever = 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"])from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# 1. 加载文档(自动处理多种格式)documents = SimpleDirectoryReader("./docs").load_data()
# 2. 创建索引(自动分块、嵌入、存储)index = VectorStoreIndex.from_documents(documents)
# 3. 创建查询引擎query_engine = index.as_query_engine()
# 4. 提问response = query_engine.query("公司的年假政策是什么?")print(response)import numpy as npfrom openai import OpenAI
client = OpenAI()
# 1. 文档分块def chunk_text(text, chunk_size=500, overlap=50): chunks = [] start = 0 while start < len(text): end = start + chunk_size chunks.append(text[start:end]) start = end - overlap return chunks
# 2. 获取嵌入向量def get_embedding(text): response = client.embeddings.create( model="text-embedding-3-small", input=text ) return np.array(response.data[0].embedding)
# 3. 余弦相似度def cosine_similarity(a, b): return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# 4. 检索最相关的文档def retrieve(query, documents, top_k=3): query_vec = get_embedding(query) scores = [] for doc in documents: doc_vec = get_embedding(doc) score = cosine_similarity(query_vec, doc_vec) scores.append((score, doc))
# 按相似度排序,取 Top-K scores.sort(reverse=True) return [doc for _, doc in scores[:top_k]]
# 5. 增强生成def rag_query(question, knowledge_base): # 检索 relevant_docs = retrieve(question, knowledge_base, top_k=3) context = "\n\n".join(relevant_docs)
# 生成 response = client.chat.completions.create( model="gpt-4o", # 推荐 GPT-4o 或更新模型 messages=[ {"role": "system", "content": "根据提供的资料回答问题。"}, {"role": "user", "content": f"资料:\n{context}\n\n问题:{question}"} ] ) return response.choices[0].message.content
# 使用示例docs = ["文档1内容...", "文档2内容...", "文档3内容..."]answer = rag_query("什么是RAG?", docs)| 数据库 | 特点 | 适用场景 |
|---|---|---|
| Chroma | 轻量、易用、Python 原生 | 本地开发、小型项目 |
| FAISS | Facebook 出品、超快 | 大规模、性能要求高 |
| 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 5from 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:]]| 维度 | RAG | Fine-tuning |
|---|---|---|
| 知识更新 | ✅ 实时更新知识库 | ❌ 需重新训练 |
| 成本 | ✅ 低(仅推理费用) | ❌ 高(训练费用) |
| 准确性 | ✅ 可溯源 | ⚠️ 可能幻觉 |
| 推理能力 | ⚠️ 受限于检索 | ✅ 可学习新模式 |
| 适用场景 | 知识问答、客服 | 风格迁移、专业领域 |
最佳实践:RAG + Fine-tuning 组合使用。