🦜⛓️ LangChain 完全学习手册:看完就能上手
本文基于 LangChain v1.x,包含 LCEL、RAG、Agent 等核心内容,代码均可直接运行。适合有 Python 基础、想动手做 AI 应用的开发者。
目录
- [一、LangChain 是什么](#一、LangChain 是什么 "#%E4%B8%80langchain-%E6%98%AF%E4%BB%80%E4%B9%88")
- 二、环境安装与配置
- 三、六大核心概念详解
- [四、RAG 实战:让 AI 回答你的私有文档](#四、RAG 实战:让 AI 回答你的私有文档 "#%E5%9B%9Brag-%E5%AE%9E%E6%88%98%E8%AE%A9-ai-%E5%9B%9E%E7%AD%94%E4%BD%A0%E7%9A%84%E7%A7%81%E6%9C%89%E6%96%87%E6%A1%A3")
- [五、Agent:让 AI 自主使用工具](#五、Agent:让 AI 自主使用工具 "#%E4%BA%94agent%E8%AE%A9-ai-%E8%87%AA%E4%B8%BB%E4%BD%BF%E7%94%A8%E5%B7%A5%E5%85%B7")
- 六、生产环境最佳实践
- 七、完整项目:智能客服系统
- 八、速查手册
一、LangChain 是什么
1.1 它解决的问题
在 LangChain 出现之前,做一个 AI 应用需要手写大量基础代码:
- 每接一个 LLM(OpenAI、Anthropic、Google...),都要单独写对接逻辑
- 对话历史要自己拼,每次都要手动处理上下文
- Prompt 写死在代码里,根本没法复用
- 想让 AI 调工具、查数据库?从零实现调度逻辑
- RAG 完整流程要写几百行胶水代码
结果 80% 时间在搞基础设施,真正的 AI 逻辑只占 20%。
LangChain 把这些通用模式全都抽象成了可复用的组件,你只需要关心自己的业务逻辑。
1.2 核心能力一览
| 功能 | 解决的问题 |
|---|---|
| 统一模型接口 | 换 GPT-4、Claude、Gemini、本地 Llama,只改一行配置 |
| Prompt 模板系统 | 像写函数一样写 Prompt,支持变量、Few-shot |
| 链式调用(LCEL) | 用 ` |
| 内置记忆管理 | 自动管理对话历史,多种策略开箱即用 |
| RAG 全套工具 | 文档加载、切割、向量化、检索一条龙 |
| Agent 框架 | 让 AI 自主调用工具、搜索、执行代码 |
类比一下:LangChain 之于 AI 开发,就像 Django 之于 Web 开发------不是语言,是让你更快出活儿的框架。
1.3 LangChain 生态
现在 LangChain 已经是个完整生态,三个主要产品:
| 产品 | 定位 | 什么时候用 |
|---|---|---|
| 🦜 LangChain | 核心框架 | 快速构建 LLM 应用、RAG、简单 Agent |
| 🕸 LangGraph | Agent 编排引擎 | 复杂多步骤 Agent、状态机工作流 |
| 🔭 LangSmith | 调试与监控 | 线上 Trace 记录、质量评估 |
本文专注核心框架,LangGraph 和 LangSmith 单独成文。
二、环境安装与配置
2.1 安装
LangChain 是模块化的,按需安装:
bash
# 核心框架(必装)
pip install langchain
# 按你用的模型选一个
pip install langchain-openai # GPT 系列
pip install langchain-anthropic # Claude 系列
pip install langchain-google-genai # Gemini 系列
pip install langchain-ollama # 本地模型
# RAG 相关
pip install langchain-community # 社区扩展,含大量文档加载器
pip install chromadb # 本地向量数据库
# 环境变量
pip install python-dotenv
2.2 配置 API Key
项目根目录建一个 .env 文件:
ini
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-xxxxxxxx
记得把 .env 加进 .gitignore,别把 Key 传上去。
代码里加载:
csharp
from dotenv import load_dotenv
load_dotenv()
2.3 跑通第一个程序
python
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
load_dotenv()
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
response = llm.invoke([HumanMessage(content="用一句话解释什么是 LangChain")])
print(response.content)
看到 AI 回复就说明环境 OK 了。
想换 Claude?只需改两行,其他完全不动:
ini
from langchain_anthropic import ChatAnthropic
llm = ChatAnthropic(model="claude-opus-4-5")
# 后面代码一模一样
这就是统一接口的价值。
三、六大核心概念详解
3.1 模型(Models)
现在用的几乎都是 ChatModel,接受消息列表,返回 AI 消息。
ini
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
from langchain_ollama import ChatOllama
gpt = ChatOpenAI(
model="gpt-4o-mini",
temperature=0.7, # 0=确定,1=有创意
max_tokens=1000,
)
claude = ChatAnthropic(model="claude-opus-4-5", temperature=0)
# 本地模型(需要先装并运行 Ollama)
local = ChatOllama(model="llama3.2")
# 三个用法完全一样
result = gpt.invoke("你好")
print(result.content) # .content 拿到文本
3.2 Prompt 模板
别把 Prompt 写死在字符串里,用模板:
makefile
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "你是一名专业的 {language} 开发专家。"),
("human", "请解释 {topic} 的概念,并给出代码示例。"),
])
# 填充变量
messages = prompt.invoke({
"language": "Python",
"topic": "装饰器",
})
response = llm.invoke(messages)
print(response.content)
好处很直接:变量可以动态传入,Prompt 可以复用,单测也好写。
3.3 LCEL 链式调用(重点)
LCEL(LangChain Expression Language)是最核心的设计,用 | 管道符把组件串起来:
ini
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_template("请用中文简洁介绍:{topic}")
parser = StrOutputParser() # 把 AIMessage 转成纯字符串
# 组合成链:输入 → Prompt → LLM → 解析
chain = prompt | llm | parser
# 单次调用
result = chain.invoke({"topic": "量子计算"})
# 批量处理
results = chain.batch([
{"topic": "机器学习"},
{"topic": "深度学习"},
{"topic": "强化学习"},
])
# 流式输出(打字机效果)
for chunk in chain.stream({"topic": "神经网络"}):
print(chunk, end="", flush=True)
链中每个组件都有 invoke / batch / stream 方法,可以自由组合。
3.4 输出解析器
AI 默认输出文本,解析器把它转成 Python 对象:
python
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain.output_parsers import PydanticOutputParser
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
# 定义你想要的结构
class MovieReview(BaseModel):
title: str = Field(description="电影名")
score: int = Field(description="评分 1-10")
summary: str = Field(description="一句话评价")
parser = PydanticOutputParser(pydantic_object=MovieReview)
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_messages([
("system", "你是影评专家。请按要求格式输出。\n{format_instructions}"),
("human", "评价电影:{movie}"),
])
chain = prompt | llm | parser
review = chain.invoke({
"movie": "星际穿越",
"format_instructions": parser.get_format_instructions()
})
print(review.title) # 星际穿越
print(review.score) # 9(整数,不是字符串)
print(review.summary) # 震撼人心的科幻巨作...
3.5 记忆(Memory)
默认每次 invoke() 是独立的,AI 不记得上文。加记忆的最简单方式是手动维护历史列表:
ini
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage
llm = ChatOpenAI(model="gpt-4o-mini")
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个友好的 AI 助手。"),
MessagesPlaceholder(variable_name="history"), # 历史消息插入点
("human", "{input}"),
])
chain = prompt | llm
history = []
def chat(user_input):
response = chain.invoke({"input": user_input, "history": history})
history.append(HumanMessage(content=user_input))
history.append(AIMessage(content=response.content))
return response.content
print(chat("我叫小明")) # 你好,小明!...
print(chat("你还记得我叫什么?")) # 当然,你叫小明!
3.6 检索器(Retrievers)
RAG 的核心组件,根据问题找相关文档:
ini
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
docs = [
Document(page_content="LangChain 是构建 AI 应用的框架"),
Document(page_content="LCEL 使用 | 管道符组合组件"),
Document(page_content="向量数据库存储文本的数学表示"),
]
# 自动向量化并存入数据库
vectorstore = Chroma.from_documents(docs, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
# 语义检索
results = retriever.invoke("什么是管道符?")
for doc in results:
print(doc.page_content)
四、RAG 实战:让 AI 回答你的私有文档
4.1 RAG 是什么
RAG(Retrieval-Augmented Generation)解决的问题:让 AI 回答训练数据之外的内容,比如公司内部文档、最新资料、私人笔记。
流程分两个阶段:
离线索引(只做一次):文档 → 切块 → 向量化 → 存数据库
在线查询(每次问答):用户提问 → 检索相关块 → 连同问题传给 LLM → 得到答案
4.2 完整实现
python
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.documents import Document
load_dotenv()
# 1. 准备文档(实际场景换成 PyPDFLoader 加载 PDF)
documents = [
Document(page_content="""
公司假期政策:
- 年假:入职满一年后 10 天,每加一年 +1 天,最多 15 天
- 病假:每年 10 天,需提供医院证明
- 婚假:3 天(提前 2 周申请)
- 产假:女员工 128 天,男员工陪产假 15 天
""", metadata={"source": "hr_policy.txt"}),
Document(page_content="""
报销流程:
1. 保存所有发票原件
2. 在 OA 系统填写报销申请
3. 直属上级审批(500 元以上需总监审批)
4. 财务审核,5 个工作日内打款
报销上限:差旅费单次最高 5000 元
""", metadata={"source": "expense_policy.txt"}),
]
# 2. 切割文档
splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块最多 500 字符
chunk_overlap=50, # 块间重叠 50 字符,防止语义断裂
)
chunks = splitter.split_documents(documents)
# 3. 向量化并存入数据库
vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
# 4. 构建 RAG Chain
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", """你是公司的 HR 助手,只根据提供的文档回答问题。
如果文档中没有相关信息,直接说「文档中未找到相关信息」,不要编造。
参考文档:
{context}"""),
("human", "{question}"),
])
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# 5. 问问题
questions = [
"入职满两年有几天年假?",
"报销超过多少需要总监审批?",
"公司有没有年终奖?", # 文档里没有的
]
for q in questions:
print(f"\n问:{q}")
print(f"答:{rag_chain.invoke(q)}")
4.3 常用文档加载器
| 加载器 | 用途 |
|---|---|
PyPDFLoader |
PDF 文件(需 pip install pypdf) |
WebBaseLoader |
网页内容 |
TextLoader |
纯文本 .txt |
CSVLoader |
CSV 数据文件 |
DirectoryLoader |
批量加载整个文件夹 |
UnstructuredWordDocumentLoader |
Word 文档 |
GitLoader |
Git 仓库代码文件 |
五、Agent:让 AI 自主使用工具
5.1 Chain vs Agent
Chain 的执行路径是固定的(A → B → C)。
Agent 不同,它让 LLM 自己决定下一步做什么:要不要调工具、调哪个、拿到结果后怎么处理,一直循环到得出最终答案。
典型的 ReAct 循环:接收问题 → 思考 → 行动(调工具)→ 观察结果 → 继续思考...
5.2 创建带工具的 Agent
python
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.agents import create_tool_calling_agent, AgentExecutor
load_dotenv()
# 定义工具,docstring 是关键------AI 靠它决定用哪个工具
@tool
def get_weather(city: str) -> str:
"""获取指定城市的当前天气。参数:city(城市名,如'北京')"""
data = {
"北京": "晴天,25°C,湿度 40%",
"上海": "多云,28°C,湿度 65%",
"广州": "小雨,30°C,湿度 85%",
}
return data.get(city, f"{city} 暂无数据")
@tool
def calculate(expression: str) -> str:
"""计算数学表达式。参数:expression(如 '2+3*4')"""
try:
return f"{expression} = {eval(expression)}"
except Exception as e:
return f"计算出错:{e}"
# 创建 Agent
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools = [get_weather, calculate]
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个有用的助手,可以使用工具帮助用户。"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"), # Agent 思考过程
])
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 打印中间过程,调试用
max_iterations=5,
)
result = agent_executor.invoke({
"input": "北京今天天气如何?另外 15 × 23 + 7 等于多少?"
})
print(result["output"])
# Agent 会自动决定调两个工具,然后综合回答
5.3 内置工具
不用自己造轮子,LangChain 有大量现成工具:
| 工具 | 功能 |
|---|---|
DuckDuckGoSearchRun |
免费网络搜索,无需 Key |
TavilySearchResults |
高质量网络搜索(需 Tavily Key) |
WikipediaQueryRun |
查询维基百科 |
PythonREPLTool |
执行 Python 代码 |
RequestsGetTool |
发起 HTTP 请求 |
SQLDatabaseTool |
查询 SQL 数据库 |
python
from langchain_community.tools import DuckDuckGoSearchRun
search = DuckDuckGoSearchRun()
print(search.invoke("LangChain 最新版本"))
六、生产环境最佳实践
6.1 容错与 Fallback
ini
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic
# 主模型挂了自动切备用
primary = ChatOpenAI(model="gpt-4o")
backup = ChatAnthropic(model="claude-opus-4-5")
robust_llm = primary.with_fallbacks([backup])
6.2 流式输出
python
chain = prompt | llm | StrOutputParser()
# 同步流式
for chunk in chain.stream({"question": "解释机器学习"}):
print(chunk, end="", flush=True)
# 异步(FastAPI 场景)
async def stream_response(question: str):
async for chunk in chain.astream({"question": question}):
yield chunk
6.3 向量数据库持久化
向量化有费用,做一次存磁盘,下次直接读:
ini
import os
from langchain_community.vectorstores import Chroma
PERSIST_DIR = "./chroma_db"
if not os.path.exists(PERSIST_DIR):
vectorstore = Chroma.from_documents(
documents=chunks,
embedding=OpenAIEmbeddings(),
persist_directory=PERSIST_DIR,
)
else:
# 直接从磁盘加载,无需重新向量化
vectorstore = Chroma(
persist_directory=PERSIST_DIR,
embedding_function=OpenAIEmbeddings(),
)
6.4 开启请求缓存
相同输入不重复调 API,省钱省时间:
python
from langchain.globals import set_llm_cache
from langchain.cache import SQLiteCache
set_llm_cache(SQLiteCache(database_path=".langchain.db"))
# 之后相同的请求直接走缓存
6.5 常见报错
| 错误 | 解决方法 |
|---|---|
AuthenticationError |
API Key 未设置或过期,检查 .env 和 load_dotenv() |
RateLimitError |
请求频率过高,加 time.sleep() 或用指数退避 |
ContextWindowExceededError |
输入 Token 太多,减小 chunk_size,或只保留最近几轮历史 |
OutputParserException |
AI 没按格式输出,Prompt 里加更明确的格式指令 |
ModuleNotFoundError |
缺对应的包,按报错提示 pip install |
七、完整项目:智能客服系统
综合前面所有知识,搭一个支持 RAG + 对话记忆 + 流式输出的智能客服:
python
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from langchain_core.messages import HumanMessage, AIMessage
from langchain_core.documents import Document
load_dotenv()
# 初始化知识库
product_docs = [
Document(page_content="超级充电宝 ProMax:20000mAh,65W 快充,380g,299 元,保修 1 年"),
Document(page_content="退换货:7 天无理由退货,30 天内质量问题免费换新,保留原包装"),
Document(page_content="使用注意:避免高温,不可拆卸,禁止飞机托运"),
]
chunks = RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=30).split_documents(product_docs)
vectorstore = Chroma.from_documents(chunks, OpenAIEmbeddings())
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0, streaming=True)
prompt = ChatPromptTemplate.from_messages([
("system", """你是智能客服。严格基于以下文档回答,文档中没有的内容回复「请联系人工客服」。
产品文档:
{context}"""),
MessagesPlaceholder(variable_name="history"),
("human", "{question}"),
])
chat_history = []
rag_chain = (
{
"context": retriever | (lambda docs: "\n".join(d.page_content for d in docs)),
"question": RunnablePassthrough(),
"history": lambda _: chat_history,
}
| prompt | llm | StrOutputParser()
)
# 对话循环
print("智能客服已启动(输入 quit 退出)")
while True:
user_input = input("\n你:").strip()
if user_input.lower() == "quit":
break
print("客服:", end="")
full_response = ""
for chunk in rag_chain.stream(user_input):
print(chunk, end="", flush=True)
full_response += chunk
print()
chat_history.append(HumanMessage(content=user_input))
chat_history.append(AIMessage(content=full_response))
# 只保留最近 6 轮,防止 Token 超限
if len(chat_history) > 12:
chat_history = chat_history[-12:]
这个项目可以继续扩展:
- 把知识库换成真实 PDF(
PyPDFLoader) - Chroma 换成云端向量库(Pinecone / Weaviate)
- 包成 FastAPI 接口对外提供服务
- 接 LangSmith 监控线上效果
八、速查手册
常用 Import
python
# 模型
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_anthropic import ChatAnthropic
from langchain_ollama import ChatOllama
# Prompt
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
# 输出解析
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain.output_parsers import PydanticOutputParser
# 消息
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
# Runnables
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
# 文档处理
from langchain_core.documents import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 向量库
from langchain_community.vectorstores import Chroma, FAISS
# 文档加载器
from langchain_community.document_loaders import PyPDFLoader, WebBaseLoader, TextLoader
# Agent
from langchain_core.tools import tool
from langchain.agents import create_tool_calling_agent, AgentExecutor
模型参数
| 参数 | 说明 |
|---|---|
temperature |
0~2,越低越确定,越高越有创意。问答用 0,写作用 0.7+ |
max_tokens |
最大输出 Token 数 |
model |
模型名,如 gpt-4o-mini / claude-opus-4-5 |
streaming |
True 开启流式输出 |
timeout |
请求超时秒数 |
max_retries |
自动重试次数,默认 2 |
TextSplitter 参数
| 参数 | 说明 |
|---|---|
chunk_size |
每块最大字符数,Q&A 场景 500-1000 |
chunk_overlap |
块间重叠字符,建议 chunk_size 的 10% |
separators |
切割优先级,默认 ['\n\n', '\n', ' ', ''] |
推荐学习路径
- Week 1:读完本文 → 跑通所有示例 → 独立实现简单 RAG
- Week 2:实现带记忆的对话 → 自定义工具 → 第一个 Agent
- Week 3:深入 LangGraph(复杂 Agent)→ 接入 LangSmith
- Week 4:完整项目 → 部署 API(FastAPI + LangServe)
官方文档:docs.langchain.com · GitHub:github.com/langchain-a...