前言
LangChain 在 RAG 领域的地位,就像 React 在前端开发中的地位——争议很多,但绕不开。本文不讨论"要不要用 LangChain",而是聚焦在用 LangChain 实现生产级 RAG 的关键技术点,包括很多官方文档里没说清楚的坑。—## 一、RAG 系统的质量三角在动手写代码之前,先理解 RAG 的质量评估框架——RAGAS 三角:答案相关性(Answer Relevance) ▲ / \ / \ / \上下文相关性 ──── 答案忠实度(Context (Faithfulness) Relevance)三个维度缺一不可:-上下文相关性:检索到的片段和问题有多相关?(检索质量)-答案忠实度:生成的答案是否基于检索内容,没有幻觉?(生成质量)-答案相关性:最终回答是否真的回答了用户的问题?(整体质量)优化顺序建议:先优化上下文相关性,再优化答案忠实度,最后调整答案相关性。—## 二、文档解析:被忽视的关键环节大多数 RAG 教程直接从"加载文档"开始,但文档解析质量直接决定 RAG 天花板。### PDF 解析的坑python# 低质量方案(很多教程在用)from langchain.document_loaders import PyPDFLoaderloader = PyPDFLoader("document.pdf")docs = loader.load()# 问题:表格变乱码,多栏排版错位,图表丢失``````python# 高质量方案:使用 marker 或 docling# 安装:pip install marker-pdffrom marker.convert import convert_single_pdffrom marker.models import load_all_modelsmodels = load_all_models()full_text, images, metadata = convert_single_pdf( "document.pdf", models, batch_multiplier=2)# 效果:正确识别表格、多栏排版、公式### 语义切片 vs 固定长度切片固定长度切片(如每 512 tokens 切一刀)会把语义相关的内容切断。语义切片实现:pythonfrom langchain_experimental.text_splitter import SemanticChunkerfrom langchain_openai.embeddings import OpenAIEmbeddings# 使用嵌入模型计算语义边界text_splitter = SemanticChunker( OpenAIEmbeddings(), breakpoint_threshold_type="percentile", # 按相似度百分位切 breakpoint_threshold_amount=95 # 相似度低于95%分位时切割)docs = text_splitter.create_documents([text])效果:语义切片的 RAG 准确率比固定切片高约 15-20%。—## 三、混合检索:BM25 + 向量的最优组合纯向量检索的问题:对精确匹配不友好。“公司的注册资本是多少?”——用户想要精确数字,向量检索可能返回相关但不精确的内容。纯 BM25 关键词检索的问题:无法理解语义相近但措辞不同的查询。解法:混合检索(Hybrid Search)pythonfrom langchain.retrievers import EnsembleRetrieverfrom langchain_community.retrievers import BM25Retrieverfrom langchain_community.vectorstores import Qdrant# 向量检索器vector_store = Qdrant.from_documents(docs, embeddings)vector_retriever = vector_store.as_retriever(search_kwargs={"k": 10})# BM25 检索器bm25_retriever = BM25Retriever.from_documents(docs)bm25_retriever.k = 10# 混合检索:权重 4:6(向量:BM25)ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, vector_retriever], weights=[0.4, 0.6])# 使用docs = ensemble_retriever.invoke("公司注册资本是多少?")权重调优经验:- 以精确信息为主(法律、财务):BM25 权重 0.6- 以语义理解为主(技术问答):向量权重 0.7- 均衡场景:各 0.5—## 四、查询优化:让 AI 理解用户真实意图用户的问题往往不是最优的检索查询。### 查询重写(Query Rewriting)pythonfrom langchain.prompts import ChatPromptTemplatefrom langchain_openai import ChatOpenAIrewrite_prompt = ChatPromptTemplate.from_template("""你是一个查询优化专家。将用户的问题重写为更适合检索的查询。原始问题:{question}要求:1. 扩展关键词(包含同义词、相关术语)2. 消歧义(明确指代对象)3. 拆分多意图问题为单一问题输出格式:重写后的查询(只输出查询,不要解释)""")llm = ChatOpenAI(model="gpt-5-mini")rewriter = rewrite_prompt | llmrewritten = rewriter.invoke({"question": "这个产品怎么用?"})# 输出:"{产品名称} 的使用方法、操作步骤和注意事项"### HyDE(假设文档生成)不用原始问题检索,而是先让 LLM 生成一个"假设答案文档",再用这个文档检索:pythonfrom langchain.chains import HypotheticalDocumentEmbedderhyde_chain = HypotheticalDocumentEmbedder.from_llm( llm=ChatOpenAI(model="gpt-5-mini"), embeddings=OpenAIEmbeddings(), chain_type="stuff")# 生成假设文档并检索similar_docs = hyde_chain.retrieve("解释 transformer 的注意力机制")—## 五、Reranker:提升精准度的最后一道关初始检索(Top-20)→ Reranker 重排序 → 取 Top-5 给 LLMpythonfrom langchain.retrievers import ContextualCompressionRetrieverfrom langchain_community.cross_encoders import HuggingFaceCrossEncoderfrom langchain.retrievers.document_compressors import CrossEncoderReranker# 加载本地 Reranker 模型(BGE-Reranker-v2-m3 是 2026 年中文最佳)model = HuggingFaceCrossEncoder( model_name="BAAI/bge-reranker-v2-m3")# 重排 Top-20 取 Top-5compressor = CrossEncoderReranker(model=model, top_n=5)compression_retriever = ContextualCompressionRetriever( base_compressor=compressor, base_retriever=ensemble_retriever)docs = compression_retriever.invoke("你的问题")性能数据:加 Reranker 后,NDCG@5 平均提升 18%,延迟增加约 150ms。—## 六、生成优化:让 LLM 只说检索到的内容pythonfrom langchain.prompts import ChatPromptTemplateqa_prompt = ChatPromptTemplate.from_messages([ ("system", """你是一个严谨的问答助手。 回答规则:1. 只使用以下检索到的内容回答问题2. 如果检索内容中没有相关信息,明确说"根据现有资料,无法回答此问题"3. 在答案末尾标注信息来源(参考文档标题)4. 不要添加检索内容之外的任何信息检索内容:{context}"""), ("human", "{question}")])—## 七、完整生产级 RAG 流水线pythonfrom langchain_core.runnables import RunnablePassthroughfrom langchain_core.output_parsers import StrOutputParserdef format_docs(docs): return "\n\n".join([ f"[来源: {doc.metadata.get('source', '未知')}]\n{doc.page_content}" for doc in docs ])# 完整 RAG 链rag_chain = ( { "context": rewrite_prompt | llm | (lambda x: x.content) | compression_retriever | format_docs, "question": RunnablePassthrough() } | qa_prompt | llm | StrOutputParser())# 调用answer = rag_chain.invoke("你的问题")—## 八、评估与监控pythonfrom ragas import evaluatefrom ragas.metrics import ( faithfulness, answer_relevancy, context_recall, context_precision)# 准备评估数据集eval_dataset = Dataset.from_dict({ "question": questions, "answer": answers, "contexts": retrieved_contexts, "ground_truth": ground_truths})# 运行评估results = evaluate( eval_dataset, metrics=[faithfulness, answer_relevancy, context_recall, context_precision])print(results)# 输出:# faithfulness: 0.87# answer_relevancy: 0.91# context_recall: 0.83# context_precision: 0.79—## 总结生产级 RAG 的质量提升路径:1.优先修文档解析(换 marker/docling 代替 PyPDF)→ 召回率 +20%2.换语义切片(SemanticChunker)→ 相关性 +15%3.加混合检索(BM25 + 向量)→ 综合精准度 +15%4.加 Reranker(BGE-Reranker)→ Top-5 精准度 +18%5.加查询重写(HyDE / Query Rewriting)→ 复杂问题 +10%按优先级依次实施,每一步都有明确的效果提升,别一口气全上。