什么是 RAG?在 LangChain 中如何实现 RAG 应用?
- 标签:LangChain、RAG 检索增强
🏛 业务架构师
RAG 在 LangChain 中的实现,我按组件到链路讲(0.2/0.3 版写法):
核心组件装配:
python
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
# 1. 知识入库
docs = WebBaseLoader(url).load_and_split(
RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50))
embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-zh-v1.5")
vs = FAISS.from_documents(docs, embeddings)
# 2. 检索+生成链
retriever = vs.as_retriever(search_kwargs={"k": 4})
prompt = ChatPromptTemplate.from_messages([
("system", "仅依据 <ctx>{context}</ctx> 回答,标注引用,资料不足则说明。"),
("human", "{question}"),
])
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt | ChatOpenAI(model="qwen-plus") | StrOutputParser()
)
rag_chain.invoke("退货政策是什么")生产化补齐清单(业务重点):
- 检索增强:多路召回(EnsembleRetriever 向量+BM25)+ Rerank 精排 + 元数据过滤(权限、时效);
- 引用溯源:分块带编号与来源元数据,要求模型标注引用;
- 会话支持:加历史管理(RunnableWithMessageHistory)+ 问题改写(结合历史消解指代);
- 质量评测:RAGAS 评命中率/忠实度,badcase 回流迭代。
落地节奏:先用最小链路(上面 20 行)两周验证业务价值,再按 badcase 逐项增强——RAG 的护城河在数据治理和评测迭代,不在代码复杂度。
🏗 系统架构师
RAG(检索增强生成)= 生成前检索相关知识注入上下文;LangChain 实现(LCEL 现代姿势):
python
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_community.vectorstores import FAISS
# 1. 建库(离线)
vectorstore = FAISS.from_documents(docs, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})
# 2. RAG 链(在线)
prompt = ChatPromptTemplate.from_messages([
("system", "仅根据以下资料回答,无依据时回答'资料不足',标注来源[1][2]。\n资料:\n{context}"),
("human", "{question}"),
])
def format_docs(docs):
return "\n\n".join(f"[{i+1}] {d.page_content}" for i, d in enumerate(docs))
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt | ChatOpenAI(model="gpt-4o") | StrOutputParser()
)
rag_chain.invoke("退货政策是什么?")架构师视角的要点(比代码重要):
- 生产化增强:混合检索(EnsembleRetriever:向量+BM25)+ Rerank 提精度;元数据过滤(权限 pre-filter)保安全;引用校验(citation ID ⊆ 检索集合)防假引用;
- 评估配套:recall@K(检索)与 faithfulness(生成)分开设测——没有评测的 RAG 无法迭代;
- 进阶路径:查询改写/扩展(MultiQueryRetriever)→ 父子块(ParentDocumentRetriever)→ 图状态机(LangGraph)处理多跳与循环;
- 流式输出
.stream()、缓存友好布局(system 稳定前缀)是上线标配。
💻 全栈开发专家
RAG 在 LangChain 里的最小完整实现(Python 版,逐环节可运行):
python
from langchain_community.document_loaders import WebBaseLoader
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
# 1. 离线索引:加载→切块→向量化→入库
docs = WebBaseLoader("https://docs.example.com/guide").load()
chunks = RecursiveCharacterTextSplitter(
chunk_size=512, chunk_overlap=64).split_documents(docs)
vs = Chroma.from_documents(
chunks, OpenAIEmbeddings(),
persist_directory="./chroma_db") # 持久化
# 2. 在线链:检索→格式化→生成
retriever = vs.as_retriever(search_kwargs={"k": 4})
prompt = ChatPromptTemplate.from_template(
"仅根据以下资料回答,标注引用,资料不足则回答不知道:\n"
"{context}\n\n问题:{question}")
def fmt(ds): return "\n\n".join(d.page_content for d in ds)
rag = ({"context": retriever | fmt, "question": RunnablePassthrough()}
| prompt | ChatOpenAI(temperature=0) | StrOutputParser())
print(rag.invoke("退货流程是什么"))生产化要补的四处(demo 到上线的距离):
- 元数据:chunk 带 source/时间/权限字段,检索加 filter(
search_kwargs={"filter": {...}}); - rerank: retriever 包一层 ContextualCompressionRetriever(bge-reranker),top50 精排取 5;
- 拒答阈值:检索分数低于阈值直接回「未找到」,防硬答;
- 评测:50 条 golden set 跑 recall@5 和 faithfulness,每次调优回归。
Java 提示:Spring AI 里等价实现是 QuestionAnswerAdvisor(vectorStore) + ChatClient,二十行内搞定,思路一一对应。