RAG检索增强生成实战:用LangChain搭建企业知识库问答系统

检索增强生成(Retrieval-Augmented Generation,RAG)是大模型落地企业场景的核心方案。纯参数化模型存在知识截止、幻觉严重、领域知识不足等问题,RAG通过外挂知识库的方式,让大模型在生成回答前先检索相关文档片段,再基于检索结果生成输出,显著提升回答准确性和可溯源性。

RAG架构原理与核心组件拆解

RAG系统由三个核心环节构成:文档处理与向量化、检索召回、生成回答。文档处理阶段将PDF、Word、Markdown等格式的内容提取为纯文本,按固定长度切分为chunk,每个chunk经过Embedding模型编码后存入向量数据库。检索阶段将用户提问同样编码为向量,在向量数据库中做相似度检索,取Top-K相关片段。生成阶段将检索到的片段与原始提问拼接为Prompt,送入大模型生成最终回答。

关键参数包括chunk_size(切片长度)、chunk_overlap(切片重叠)、top_k(召回数量)、similarity_threshold(相似度阈值)。chunk_size通常设为500-1000字符,overlap设为chunk_size的10%-20%,避免语义被切断。top_k一般取3-5,太少会遗漏上下文,太多会引入噪声。

用LangChain搭建RAG管道:完整代码实现

以下是基于LangChain框架的完整RAG实现,使用Chroma作为向量数据库,OpenAI的text-embedding-3-small做Embedding,GPT-4o做生成模型。

import os
from langchain_community.document_loaders import PyPDFLoader, TextLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 文档加载
loader = PyPDFLoader("knowledge_base.pdf")
documents = loader.load()

# 文本切分
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=800,
    chunk_overlap=150,
    separators=["\n\n", "\n", "。", ",", " "]
)
chunks = text_splitter.split_documents(documents)
print(f"切分为 {len(chunks)} 个片段")

# 向量化与存储
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# 构建检索器
retriever = vectorstore.as_retriever(
    search_type="similarity",
    search_kwargs={"k": 4}
)

# 定义Prompt模板
template = """你是一个知识库问答助手。请严格根据以下检索到的上下文回答问题。
如果上下文中没有相关信息,请明确说明"知识库中未找到相关内容",不要编造答案。

上下文:
{context}

问题:{question}

回答:"""
prompt = ChatPromptTemplate.from_template(template)

# 构建RAG链
llm = ChatOpenAI(model="gpt-4o", temperature=0)

def format_docs(docs):
    return "\n\n".join(f"[片段{i+1}] {doc.page_content}" for i, doc in enumerate(docs))

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | prompt
    | llm
    | StrOutputParser()
)

# 测试问答
question = "公司的退货政策是什么?"
answer = rag_chain.invoke(question)
print(answer)

RAG检索优化:混合检索与重排序

纯向量检索在处理专有名词、缩写、编号等精确匹配场景时效果不佳。混合检索(Hybrid Search)结合BM25关键词检索和向量语义检索,通过Reciprocal Rank Fusion(RRF)算法融合两路结果,召回率显著提升。

from langchain_community.retrievers import BM25Retriever
from langchain.retrievers import EnsembleRetriever

# BM25检索器
bm25_retriever = BM25Retriever.from_documents(chunks)
bm25_retriever.k = 4

# 向量检索器
vector_retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

# 混合检索器(权重可调)
ensemble_retriever = EnsembleRetriever(
    retrievers=[bm25_retriever, vector_retriever],
    weights=[0.3, 0.7]
)

重排序(Rerank)是另一项关键优化。检索阶段取较大的top_k(如20),再用Cross-Encoder模型对这20个片段重新打分排序,取前4个送入生成阶段。Cross-Encoder比Bi-Encoder精度更高但速度更慢,用在小规模重排序上刚好合适。常用的Rerank模型包括bge-reranker-v2-m3、Cohere Rerank API等。

from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerank

compressor = CohereRerank(model="rerank-multilingual-v3.0", top_n=4)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=ensemble_retriever
)

Prompt工程在RAG中的调优策略

RAG系统的Prompt设计直接影响输出质量。temperature设为0确保回答确定性。系统指令中需要明确约束:只基于上下文回答、不得编造、信息不足时声明。对于多轮对话场景,需要用历史记录改写模块将用户追问补全为独立问题,再送入检索器。

from langchain_core.history_aware_retriever import create_history_aware_retriever

# 历史感知检索:将追问改写为独立查询
condense_prompt = ChatPromptTemplate.from_template("""
根据对话历史和最新问题,将其改写为一个独立的检索查询。
不需要回答问题,只需要生成一个用于检索的搜索查询。

对话历史:{chat_history}
最新问题:{input}
检索查询:""")

history_aware_retriever = create_history_aware_retriever(
    llm, ensemble_retriever, condense_prompt
)

Prompt中还可以要求模型引用来源片段编号,增强可溯源性。例如在模板末尾加入”请在回答中标注引用的片段编号,如[片段1]”,用户可据此回溯原文。

RAG系统评估方法与指标

评估RAG系统需要区分检索质量和生成质量。检索质量用Hit Rate(正确文档是否在Top-K中)和MRR(Mean Reciprocal Rank)衡量。生成质量用Faithfulness(回答是否忠于检索内容)、Answer Relevancy(回答是否切题)和Context Relevancy(检索内容是否相关)衡量。Ragas框架提供了这些指标的自动化评估工具。

from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision
from datasets import Dataset

eval_data = {
    "question": ["公司的退货政策是什么?"],
    "answer": [rag_answer],
    "contexts": [[doc.page_content for doc in retrieved_docs]],
    "ground_truth": ["7天内无理由退货,15天内质量问题可换货。"]
}
eval_dataset = Dataset.from_dict(eval_data)
result = evaluate(eval_dataset, metrics=[faithfulness, answer_relevancy, context_precision])
print(result)

构建RAG系统时常见的坑包括:文档切分时表格被截断导致语义丢失,可在切分前用Unstructured库按文档结构提取表格内容单独存储;多语言场景下Embedding模型选择不当导致召回率低,推荐使用multilingual-e5-large或bge-m3等多语言模型;向量数据库随着数据量增长查询变慢,需要定期重建索引或使用HNSW算法优化查询性能。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/rag-jian-suo-zeng-qiang-sheng-cheng-shi-zhan-yong-langchain/

(0)
小编小编
上一篇 15小时前
下一篇 13小时前

相关推荐