06.1 - LangChain 实践指南
定位: 最流行的 RAG 开发框架——LangChain 的核心概念、RAG 构建方式和最佳实践 面试高频度: ⭐⭐⭐⭐ 考查方式: LangChain 架构、LCEL、组件使用
一、这是什么?为什么需要它?
是什么
LangChain 是一个面向 LLM 应用的开发框架,提供了构建 RAG 系统所需的全套组件:文档加载、文本分块、向量存储、检索器、Prompt 模板、语言模型等。
没有 LangChain 的 RAG:从头写每个组件
文档加载器 -> 自己写
文本分块器 -> 自己写
Embedding 封装 -> 自己写
...
使用 LangChain 的 RAG:组装预制组件
document_loaders.PyMuPDFLoader()
text_splitter.RecursiveCharacterTextSplitter()
embeddings.OpenAIEmbeddings()
vectorstores.Chroma()
chains.RetrievalQA()为什么使用 LangChain?
1. 组件化:模块化设计,每个环节可替换
2. 生态丰富:支持几乎所有主流模型和数据库
3. LCEL:声明式 Chain 定义
4. 社区活跃:大量文档和示例
5. 工具链完善:LangSmith(调试) + LangServe(部署)二、原理拆解
2.1 LangChain 核心组件
+------------------------------------------------------------------+
| LangChain RAG 核心组件 |
| |
| Loaders: | TextLoader, PyMuPDFLoader, WebBaseLoader |
| Splitters: | RecursiveCharacterTextSplitter |
| Embeddings: | OpenAIEmbeddings, HuggingFaceEmbeddings |
| Vectorstores:| Chroma, FAISS, Pinecone, Milvus |
| Retrievers: | VectorStoreRetriever, EnsembleRetriever |
| Llms/Chat: | ChatOpenAI, ChatAnthropic, Ollama |
| Chains: | RetrievalQA, ConversationalRetrievalChain |
| LCEL: | RunnableSequence, RunnableParallel |
+------------------------------------------------------------------+2.2 LCEL(LangChain Expression Language)
LCEL 是 LangChain 的声明式 Chain 定义语言,用 | 操作符连接组件:
python
# 传统方式 vs LCEL
# 传统方式(命令式)
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=retriever,
)
# LCEL(声明式)——更灵活
from langchain_core.runnables import RunnablePassthrough
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt_template
| llm
| StrOutputParser()
)2.3 LangChain RAG 完整示例
python
from langchain_community.document_loaders import PyMuPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate
# 1. 加载文档
loader = PyMuPDFLoader("documents/manual.pdf")
docs = loader.load()
# 2. 分块
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=100
)
chunks = splitter.split_documents(docs)
# 3. 向量化 + 存储
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=OpenAIEmbeddings()
)
# 4. 创建检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
# 5. 定义 Prompt 模板
prompt = ChatPromptTemplate.from_messages([
("system", "基于以下文档回答问题。如果找不到答案,说不知道。\n{context}"),
("human", "{question}")
])
# 6. LCEL 构建链
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| ChatOpenAI(model="gpt-4o-mini")
| StrOutputParser()
)
# 7. 调用
result = rag_chain.invoke("年假政策是什么?")
print(result)2.4 LangChain 高级 RAG 配置
python
# 高级配置:混合检索 + Reranker + 历史对话
from langchain.retrievers import EnsembleRetriever
from langchain_community.retrievers import BM25Retriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain.retrievers import ContextualCompressionRetriever
from langchain.chains import create_history_aware_retriever
# 混合检索
ensemble_retriever = EnsembleRetriever(
retrievers=[
vectorstore.as_retriever(search_kwargs={"k": 30}),
BM25Retriever.from_documents(chunks, k=30),
],
weights=[0.5, 0.5]
)
# 加 Reranker
reranker = CrossEncoderReranker(
model_name="BAAI/bge-reranker-v2-m3",
top_n=5
)
retriever = ContextualCompressionRetriever(
base_compressor=reranker,
base_retriever=ensemble_retriever
)
# 历史对话感知
from langchain.chains import create_history_aware_retriever
from langchain_core.prompts import MessagesPlaceholder
qa_prompt = ChatPromptTemplate.from_messages([
("system", "基于文档回答问题..."),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}")
])
chain = create_history_aware_retriever(
llm, retriever, qa_prompt
)三、图解全景
LangChain RAG 组件关系
+------------------------------------------------------------------+
| LangChain RAG 组件关系图 |
| |
| 文档加载 分块 Embedding 向量存储 |
| [Loader] --> [Splitter] --> [Embeddings] --> [VectorStore] |
| | |
| 查询 检索器 复用 | |
| [Query] --> [Retriever] ---------------------------+ |
| | |
| v |
| +----+----+ |
| | Prompt | |
| +----+----+ |
| | |
| v |
| [LLM/Chat] |
| | |
| v |
| [Output Parser] |
| | |
| v |
| [结果输出] |
+------------------------------------------------------------------+四、面试视角
| 问题 | 答案要点 |
|---|---|
| LangChain 的 LCEL 有什么优势? | 声明式、可组合、可流式输出、异步支持、内置重试/回退、易于调试(LangSmith)。比传统 Chain API 更灵活 |
| LangChain 和 LlamaIndex 的核心区别? | LangChain 面向通用 LLM 应用(Chain/Agent/Tool),RAG 是其一。LlamaIndex 专注 RAG 数据层(索引类型多样、查询引擎强大)。两者可互补使用 |
| LangChain RAG 的调试方式? | 1) LangSmith 链路追踪;2) verbose=True 查看中间步骤;3) RunnableLambda 注入调试输出;4) 单元测试各组件 |
| LangChain 的局限? | 1) API 变动频繁(版本升级可能 break);2) 过度封装导致难以定位问题;3) 自定义组件需要理解内部机制;4) 大规模生产需配合其他工具 |
📚 相关链接
- **LlamaIndex实践指南** — 另一主流框架
- **RAG系统部署与监控** — RAG 系统的生产部署
- **检索系统索引** — LangChain 检索组件详解
- <- 返回 **工程化索引**