LangChain 概述
目录+
1. 什么是 LangChain
LangChain 是一个用于开发由大型语言模型(LLM)驱动的应用程序的开源框架。它的定位是"LLM 应用的中间件 / 胶水层"——抽象了 LLM 调用、链式组合、工具集成、记忆管理、检索增强等通用能力,让开发者不必从零拼装,把 LLM、工具、数据和业务逻辑像搭积木一样组合成应用。
我们希望大模型应用不仅仅是聊天,更能从已有的数据库或文件中提取信息并执行具体操作。LangChain 正是为此而生:它允许开发者将通义千问、DeepSeek、OpenAI 等大语言模型与外部系统和数据源结合,完成更复杂的操作。
也可以借助 Dify、RAGFlow 之类的低代码平台,但自由度受限,对复杂业务适配欠缺;也可以完全自研裸调 SDK,但费时费力。LangChain 提供了现成组件,同时保留了足够的自定义自由度。
- 创始人:Harrison Chase(2022 年开源)
- 语言:Python / JavaScript(TypeScript)
- 官网:https://python.langchain.com/docs/introduction/
- GitHub:https://github.com/langchain-ai/langchain
- 当前版本:LangChain 1.0+(2025),底层基于
langchain-core和langgraph重构
地位类比:
- LangChain = Java 生态中 Spring Boot(脚手架,快速构建应用)+ Apache Camel(集成总线,支持 200+ 工具和服务)的结合体
- LangChain = C++ 生态中的 ROS + gRPC
一句话:它是连接 LLM 能力与现实需求的"数字桥梁",把大模型的原始能力转化为可落地的行业解决方案。
2. LangChain V1.0 重构
LangChain v1.0 是一个专注于构建 Agent 的、可直接用于生产环境的基础框架,标志着 AI 智能体开发正式进入工程化阶段。最核心的变化是基于 LangGraph 重构了底层架构,并引入了全新的 Agent 构建 API。
2.1 全面拥抱 LangGraph
LangChain v1.0 不再是独立的链式调用工具,而是构建在 LangGraph 之上的"Agent 快速通道"。
- 统一运行时:所有 v1.0 的 Agent 都在 LangGraph 运行时上执行,直接获得持久化、流式输出、以及"时光倒流"(Time Travel)调试能力。
- 定位差异:LangGraph 负责底层的图编排和精细控制;LangChain v1.0 提供开箱即用的高层抽象,几行代码就能跑起一个生产级 Agent。
2.2 全新 API:create_agent
这是 v1.0 中最重要的 API,取代了过去的 AgentExecutor 和各种 Chain。
- 标准化入口:比底层 LangGraph 更简单,比旧版 Agent 更灵活。
- 替代旧版:直接替代
langgraph.prebuilt.create_react_agent以及旧版 ReAct Agent 构建方式。
2.3 引入中间件机制
可以像在 Web 开发中一样,在 Agent 的生命周期中插入自定义逻辑(详见第 9 节):
- 拦截与控制:在模型调用前后、工具调用前后插入代码。
- 预置中间件:PII Redaction(脱敏)、Summarization(自动摘要)、Human-in-the-loop(人工审批)等。
2.4 标准化内容块
解决不同大模型(OpenAI、Anthropic、Google 等)之间消息格式不统一的痛点。
- 引入
content_blocks属性,跨提供商统一访问文本、推理过程、引用和工具调用。 - 将内容与原始字符串解耦,使多模态和复杂输出的处理更加类型安全。
2.5 结构化输出改进
- 主循环集成:结构化输出直接集成在 Agent 主循环中生成,不再需要额外的 LLM 调用。
- 降本增效:减少 Token 消耗和延迟,模型可选择直接返回结果或调用工具。
2.6 命名空间清理与迁移
- 精简核心:
langchain包现在只包含构建 Agent 所需的核心组件(Agent、Model、Tools)。 - 遗留代码迁移:旧版 Chains、
AgentExecutor和遗留工具都移到了新包langchain-classic中。 - 向后兼容:安装
langchain-classic即可运行旧项目,同时逐步迁移到新架构。
2.7 其他变动
- Python 版本:放弃 Python 3.9,建议 3.10+。
- LangGraph v1.0:同步发布正式版,承诺核心 API 稳定性。
如何升级:新项目直接用
create_agent和 v1.0 API;旧项目先装langchain-classic保持运行,再逐步用 Middleware 和create_agent替换老的 Chain 和 Executor。
3. LangChain 体系
LangChain 由以下开源库组成:
| 库 | 作用 |
|---|---|
| langchain | 主要入口,构建 LLM 应用所需的核心实现 |
| langchain-core | 生态系统的核心接口和抽象 |
| langchain-community | 第三方集成(向量库、文档加载器等) |
| langchain-classic | 旧版 langchain 实现与组件 |
| 合作伙伴库 | 如 langchain-openai、langchain-anthropic,仅依赖 langchain-core |
| LangGraph | 将步骤建模为图的边和节点,构建有状态多参与者应用 |
| DeepAgents | 能规划、使用子代理、利用文件系统处理复杂任务的代理 |
| LangServe | 将 LangChain 链部署为 REST API |
| LangSmith | 调试、测试、评估和监控 LLM 应用的开发者平台 |
LangChain 简化了 LLM 应用生命周期的各阶段:
- 开发:用开源构建块和组件搭建应用,借助第三方集成和模板快速启动。
- 生产化:用 LangSmith 检查、监控和评估链,持续优化。
- 部署:用 LangServe 将任何链转化为 API。
4. 核心组件(七大部分)
4.1 代理 (Agents)
v1.0 中 Agent 是应用的核心构建块。
- 统一接口
create_agent,取代繁杂的AgentExecutor。 - 核心逻辑:Agent 本质是一个"循环"——接收输入,决定是否调用工具,处理工具结果,重复直到完成任务。
- 底层驱动:默认基于 LangGraph 运行,原生支持状态管理、分支逻辑和持久化。
4.2 模型 (Models)
模型是 Agent 的"大脑"。
- 标准内容块:无论底层用哪个模型,输出(文本、工具调用、推理过程)都统一为标准格式,方便无缝切换。
- Chat Models:v1.0 推荐全面使用 Chat Model 接口(而非纯文本 LLM),以支持多模态输入和结构化交互。
4.3 消息 (Messages)
消息是模型交互的基础数据单元,也是 Agent 的"短期记忆"(由消息列表组成)。
- HumanMessage:用户输入
- AIMessage:模型回复(含思维过程 thought_process 和工具调用 tool_calls)
- SystemMessage:设定 Agent 的行为准则和角色
- ToolMessage:工具执行后的返回结果
4.4 工具 (Tools)
工具是 Agent 连接外部世界(API、数据库、搜索引擎)的桥梁。
- 定义方式:用
@tool装饰器把 Python 函数转换为工具。 - 错误处理:v1.0 优化了工具调用错误处理,参数填错时系统会自动捕获并反馈给 Agent,让其自我修正重试。
4.5 短期记忆 (Short-term Memory)
- 旧版 vs 新版:不再使用
ConversationBufferMemory。 - 线程级持久化:通过 Checkpointer 机制实现,自动保存每一步状态;传入
thread_id即可加载之前的上下文继续任务。
4.6 流 (Streaming)
- 流式 Token:最基础的"打字机效果"。
- 流式进度:实时展示 Agent 执行状态。
- 流式自定义更新:手动发送业务信号(如"已下载 10/100 条数据")。
4.7 结构化输出 (Structured Output)
- 机制:
create_agent通过response_format参数直接配置(如传入 Pydantic 类)。 - 结果:结构化数据会被捕获、验证,并以代理状态的
structured_response键返回。
5. Model I/O
可以把对模型的使用过程拆解成三块:输入提示 (Format) → 调用模型 (Predict) → 输出解析 (Parse),这个整体在 LangChain 中统称为 Model I/O。
| 组件 | 作用 |
|---|---|
| LLM / ChatModel | 封装模型调用(OpenAI、Anthropic、本地模型等) |
| Prompt Template | 结构化 prompt,支持变量插值和 few-shot |
| Output Parser | 把模型输出解析成 JSON、Pydantic 对象等结构化数据 |
5.1 模型 (Model)
LangChain 支持三大类模型:
- 大语言模型(LLM):也叫文本补全模型,接收字符串、返回补全字符串,只能一问一答。OpenAI 的文本补全 API 已停更,国内厂商普遍不支持,不予考虑。
- 聊天模型(Chat Model):主流选择。输入是聊天消息列表,返回聊天消息,支持多轮对话。包装器为
ChatOpenAI;兼容 OpenAI 的模型都可用ChatOpenAI,不兼容的用init_chat_model创建。 - 文本嵌入模型(Embedding Model):将文本转为词向量(详见第 7 节)。
# 通过 LangChain 调用大模型,实现交互
import os
from langchain_openai import ChatOpenAI
MODEL_API_KEY = os.getenv("DASHSCOPE_API_KEY")
client = ChatOpenAI(
api_key=MODEL_API_KEY,
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
model="qwen-max-latest"
)
msg = [
('system', '请将以下的内容翻译成英文'),
('human', '你好,你今天过得好吗?'),
]
result = client.invoke(msg)
print(result)
直接调用有两个问题:① 提示词固定,无法灵活变动;② 原始答复复杂,含大量额外信息。分别用提示词模板和输出解析器解决。
5.2 提示模板 (Prompt Template)
LangChain - 提示模板LangChain - 提示模板 为什么需要提示模板 直接给模型写死一段提示词有两个问题:① 提示词固定,无法根据不同输入灵活变化;② 复制粘贴拼字符串,难以复用和维护。 提示模板(Prompt Template) 就是带 {变量} 占位符的提示字符串。它接收原始用户输入,把变量填进去,生成一段「准备好发给模型」的提示词。好处是:清晰可读、可复用、易维护、参数化生成。 四种常见模板 | 模板 | 适用场景 | | --- | --- | | PromptTemplate | 单条字符串提示,最基础 | | ChatPromptTemplate | 多角色对话提示(system / human / ai),聊天模型首选 | | FewShotPromptTemplate | 给几个示例「教」模型怎么答 | | 部分填充 partial | 先固定一部分变量,其余后续再填(不是独立模板,是通用能力) | 一、PromptTemplate 最基础的字符串模板:一段含 {变量} 的文本,填充后得到完整提示词。 1. 两种用法对比 模板本身只负责「把变量填进字符串」。填好之后既可以手动调用模型,也
5.3 输出解析器 (Output Parser)
输出解析器 (Output Parser)LangChain - 输出解析器 (Output Parser)一句话理解 大模型只会"说人话"——它返回的永远是一段文本字符串。但程序需要的是能直接用的数据(列表、字典、日期、对象)。输出解析器就是这两者之间的翻译官。 看个最直白的例子。你问模型"列出三个机器学习框架": 模型返回(字符串): "TensorFlow, PyTorch, scikit-learn" 这段文本人一看就懂,但对程序来说它只是一坨字符:不能遍历、取不出第二个元素。你得自己写 split(",")、再逐个 strip() 去空格…… 解析器帮你把这步自动做掉: 解析后(Python 列表): ['TensorFlow', 'PyTorch', 'scikit-learn'] 现在 result[0]、len(result)、for 循环都能直接用了。 它的两个职责:一前一后 解析器承担两个职责,放到调用模型的时间线上看就顺了: ①【调用模型之前】 get_format_instructions() 在提示词里加一句:"请用逗号分隔来回答" 目的:让模型按规定格式输出,否则它可能写成 "1. xx 2. xx" ↓
6. 链 (Chain) 与 LCEL
链把模型输入输出整合在一个流程中操作:利用提示模板格式化输入,传给模型,再返回输出。LangChain 的名字正源自其核心设计——用链(Chain)将各组件链接起来构建复杂应用。
v1.0 已把各种内置 Chain 移到
langchain-classic,但 LCEL 作为一种核心思想仍有必要学习。在 v0.1 后,链分为遗留链和 LCEL 链,我们以 LCEL 链为主。
6.1 LCEL(LangChain Expression Language)
LCEL 是一种声明式的组件拼接方式:你只描述"数据要流经哪些组件",而不用手写"先调谁、再把结果传给谁"的胶水代码。一行 | 串起来,运行细节交给 LangChain。
核心抽象:Runnable
LCEL 的地基是 Runnable —— 一套统一的"组件规范"(接口)。可以把它理解成 LLM 世界的 USB 接口:提示模板、模型、输出解析器、检索器……只要实现了这套规范,就都长着同一个"插头",因而能用管道符 | 任意串接。
每个 Runnable 都保证支持三个核心方法——它们都是触发组件运行的入口,区别只在"喂多少输入、怎么拿输出":
| 方法 | 输入 | 输出 | 适用场景 |
|---|---|---|---|
invoke | 单个输入 | 单个输出 | 跑一次、要完整结果 |
batch | 一批输入(列表) | 一批输出(列表) | 一次处理多条,内部并发 |
stream | 单个输入 | 逐块返回 | 打字机式实时输出 |
三者各有对应的异步版
ainvoke/abatch/astream(a= async),用法相同,供async/await异步代码使用。
正因为接口统一,你写好一条链就自动获得同步 / 批量 / 流式 / 异步全套能力,无需为每种场景单独写代码。LangChain 里的 RunnableSequence、RunnableLambda、RunnableParallel、RunnablePassthrough 都是这个家族的成员。
管道符 |:把组件串成流水线
| 把上一个组件的输出接到下一个组件的输入,串成一个 RunnableSequence。最简单常见的链就是"提示词 → 模型 → 解析器"三件套:
chain = prompt_template | client | StrOutputParser()
chain.invoke({"topic": "黑洞"}) # invoke 按下"启动键":数据从左流到右,返回最终结果
只有调用 invoke(或 batch / stream)时链才真正执行;在那之前,chain 只是一条组装好但尚未启动的流水线。
关键点:链(chain)本身也是一个 Runnable,所以可以再嵌套进更大的链里——这就是 LCEL 可无限组合的根本原因。 [[Chain]]
6.2 LCEL 高级特性与组件
LangChain - LCEL 高级特性与组件LangChain - LCEL 高级特性与组件 LCEL(LangChain Expression Language)用 | 把各个 Runnable 串成链。除了 prompt | llm | parser 这种基础用法,还有几个常用组件能把自定义函数、并行分支、数据透传等能力接进链里。 | 组件 | 作用 | | --- | --- | | RunnableLambda | 把普通 Python 函数包装成 Runnable,接进链里 | | RunnableParallel | 多个分支接收同一份输入,并行执行,结果汇总成 dict | | RunnablePassthrough | 把输入原样传递下去,或用 assign 增强后再传 | RunnableLambda —— 把自定义函数加入链 RunnableLambda 把任意普通 Python 函数(自定义函数)包装成一个 Runnable,从而能用 | 接进链里。 案例:在 LCEL 链中用 RunnableLambda 对 LLM 的输出统计字数。 from langchain_core.runnables import
6.3 跟踪和调试
- 方法一:LangSmith——跟踪和评估 LLM 应用的平台,个人开发一定额度内免费。
- 方法二:开启调试——
langchain.debug = True,打印链执行的详细过程。
import langchain
langchain.debug = True
# ... 构建并调用 chain,控制台会打印每步细节
6.4 查看链及其组件
print(chain.input_schema.model_json_schema())
print(chain.output_schema.model_json_schema())
print(chain.get_prompts())
# 打印链的结构图,需 pip install grandalf
chain.get_graph().print_ascii()
6.5 发布应用程序(LangServe)
# 服务端:把链部署为 WEB 服务
from fastapi import FastAPI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate
from langserve import add_routes
from models import get_lc_model_client
client = get_lc_model_client()
prompt_template = ChatPromptTemplate.from_messages(
[
SystemMessagePromptTemplate.from_template("请将以下的内容翻译成 {language}"),
('human', '{text}')
]
)
chain = prompt_template | client | StrOutputParser()
app = FastAPI(title="基于 LangChain 的服务", version="V1.5", description="翻译服务")
add_routes(app, chain, path="/tslServer")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="localhost", port=8000)
# 客户端调用
from langserve import RemoteRunnable
client = RemoteRunnable("http://localhost:8000/tslServer")
print(client.invoke({'language': '意大利文', 'text': '为了部落!'}))
7. Memory 与 RAG
7.1 对话历史管理(Memory)
LangChain - MemoryLangChain - Memory一句话理解 大模型是无状态的——每次调用都是一次"失忆",它根本不记得你上一句说了什么。所谓"多轮对话"的连贯感,其实是每次都把之前的聊天记录一起重新喂给模型装出来的。 Memory(记忆)就是负责"存历史 + 喂回去"这件事的机制。 看个最直白的例子,不带记忆时: 你: 我叫云帆。 AI: 你好,云帆! 你: 我叫什么名字? AI: 抱歉,我不知道你的名字。 ← 它真的忘了 带上记忆后,第二轮发给模型的其实是: [历史] Human: 我叫云帆。 AI: 你好,云帆! [当前] Human: 我叫什么名字? → AI: 你叫云帆。 ← 因为历史被一起送了过去 模型本身没变,变的是我们每次都把对话历史拼进了输入。Memory 就是把这个"拼历史"的过程自动化、并管好"存哪、存多少、怎么取"。 经典记忆策略:存多少、怎么存 历史越攒越长,但模型的上下文窗口和 Token 成本有限,不可能无脑全塞。于是有了几种经典取舍策略: | 策略 | 做法 | 适用场景 | |------|------|----
7.2 RAG(检索增强生成)
LangChain - RAGLangChain - RAG让 LLM 能"读"外部文档再回答——用户的私有数据大多不在大模型的训练集里,而是散落在外部文档、数据库里,LangChain 的数据连接组件负责把这些数据接进来:文档加载器、文档切分、文本嵌入、向量存储、检索器。 核心流程 1. Document Loader:加载 PDF / 网页 / 数据库等 2. Text Splitter:把长文本切成适当大小的 chunks 3. Embedding:把 chunks 向量化 4. Vector Store:存入向量数据库(Chroma、FAISS、Pinecone 等) 5. Retriever:根据用户 query 检索最相关的 k 个 chunks 6. 注入 Prompt:检索结果拼进 prompt → LLM 基于上下文回答 flowchart TD subgraph offline["离线:建立知识库"] D1["1、获取文档Docx2txtLoader"] --> D2["2、文档切分chunk_size=500, overlap=50"] --> D3["3、向量化入库DashScope Em
8. Agents 与工具调用
Agent = LLM + 工具调用能力。LLM 不再只是"回答",而是自主选择调用什么工具、按什么顺序、何时停——规划 → 行动 → 观察 → 再行动的循环。现在火爆的 MCP、Agent2Agent 本质都离不开大模型对工具的调用。
8.1 工具 Tools
工具是代理、链或 LLM 与世界互动的接口,包含:名称、描述、输入的 JSON 模式、要调用的函数、是否将结果直接返回用户。Toolkits 是面向特定目标的多个工具的集合。
8.2 工具调用的几种方式
# 方式一:bind_tools 把工具绑定到模型
import pymysql; pymysql.install_as_MySQLdb()
import os
from langchain.messages import HumanMessage
from langchain_community.utilities import SQLDatabase
from langchain.tools import tool
from models import get_lc_model_client
client = get_lc_model_client()
db = SQLDatabase.from_uri('mysql+mysqldb://root:root123456@127.0.0.1:3306/world?charset=utf8mb4')
@tool
def get_table_names():
"""获取数据库中的所有表名"""
return db.get_table_names()
client_with_tools = client.bind_tools([get_table_names])
resp = client_with_tools.invoke([HumanMessage(content="请从国家表中查询出 China 的所有数据")])
print(resp.tool_calls) # 模型决定调用哪个工具
# 方式二:使用内置工具(如 Tavily 搜索)
from langchain_community.tools import TavilySearchResults
search = TavilySearchResults(max_results=2)
client_with_tools = client.bind_tools([search])
result = client_with_tools.invoke([HumanMessage(content="长沙的天气如何?")])
print(result.tool_calls)
8.3 v1.0 推荐:create_agent
create_agent 自动处理"调用工具 → 观察结果 → 再决策"的完整循环,并基于 LangGraph 支持记忆、状态、持久化。
from datetime import datetime
import subprocess, webbrowser, os
from langchain.agents import create_agent
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import InMemorySaver
@tool
def get_current_time(input: str = "") -> str:
"""获取当前时间"""
return f"当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}。"
@tool
def open_calc(input: str = "") -> str:
"""打开计算器"""
try:
subprocess.Popen(['calc.exe'])
return "计算器已打开"
except Exception as e:
return f"打开计算器失败: {str(e)}"
@tool
def open_browser(url: str) -> str:
"""打开浏览器访问指定网址"""
webbrowser.open(url)
return f"已打开浏览器访问 {url}"
tools = [get_current_time, open_calc, open_browser]
llm = ChatOpenAI(
openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
openai_api_key=os.getenv("DASHSCOPE_API_KEY"),
model_name="qwen-max"
)
agent = create_agent(
model=llm,
tools=tools,
system_prompt="你是人工智能助手,需要帮助用户解决各种问题。",
checkpointer=InMemorySaver() # 短期记忆
)
response = agent.invoke(
{"messages": [{"role": "user", "content": "现在几点了?"}]},
config={"configurable": {"thread_id": "user_1"}}
)
print(response["messages"][-1].content)
8.4 实战:用 Agent 查询数据库
SQLDatabaseToolkit 提供一组数据库工具,配合精心设计的 system_prompt(强制先查表名和 Schema、禁止猜测、禁止写操作),让 Agent 安全地自然语言查库。
import pymysql; pymysql.install_as_MySQLdb()
from langchain.agents import create_agent
from langchain_community.agent_toolkits import SQLDatabaseToolkit
from langchain_community.utilities import SQLDatabase
from langchain.messages import AIMessage
from models import get_ali_model_client, ALI_TONGYI_MAX_MODEL
client = get_ali_model_client(model=ALI_TONGYI_MAX_MODEL)
db = SQLDatabase.from_uri('mysql+mysqldb://root:root123456@127.0.0.1:3306/world?charset=utf8mb4')
toolkit = SQLDatabaseToolkit(db=db, llm=client)
system_prompt = """你是一个精通 MySQL 数据库的 AI 助手。
【极其重要的规则】
1. 绝对不要猜测表名。必须先用工具查看数据库里有哪些表。
2. 绝对不要猜测字段名。确定表名后必须查看表的 Schema。
3. 只有确认了表名和字段名之后,才能编写 SQL。
4. 如果 SQL 执行报错,仔细查看错误信息,修正后重试。
注意:永远不要执行 DROP/DELETE/INSERT/UPDATE 等修改操作;只输出最终自然语言回答。
"""
agent = create_agent(model=client, tools=toolkit.get_tools(), system_prompt=system_prompt)
result = agent.invoke({"messages": [("user", "请从国家表中查询出 China 的相关数据")]})
# 提取实际执行的 SQL
for msg in result['messages']:
if isinstance(msg, AIMessage) and msg.tool_calls:
for tc in msg.tool_calls:
if tc['name'] == 'sql_db_query':
print("执行的 SQL:", tc['args'].get('query'))
print(result["messages"][-1].content)
9. 中间件 (Middleware)
中间件是一种流程控制机制,用于在智能体执行过程中拦截、修改或增强请求与响应的处理逻辑,无需修改核心 Agent 或工具代码。它在每个步骤之前/之后暴露钩子(hooks),是 v1.0 最大的亮点之一。
9.1 内置中间件
参考:https://docs.langchain.com/oss/python/langchain/middleware/built-in
- PIIMiddleware:发送至模型前屏蔽敏感信息
- SummarizationMiddleware:对话历史过长时自动压缩
- HumanInTheLoopMiddleware:工具调用执行前暂停,等待人工审批 / 编辑 / 拒绝
- ModelCallLimitMiddleware:限制模型调用次数,防止无限循环或过高成本
- ToolCallLimitMiddleware:限制工具调用次数(全局或特定工具)
# PIIMiddleware 演示:脱敏
from langchain.agents import create_agent
from langchain.agents.middleware import PIIMiddleware
from langchain.tools import tool
from models import get_lc_model_client
@tool
def read_user_data(user_id: str) -> str:
"""读取用户数据的工具"""
return f"用户 {user_id} 的数据:姓名张三,邮箱 zhangsan@example.com,手机号 13800138000"
agent = create_agent(
model=get_lc_model_client(),
tools=[read_user_data],
middleware=[
PIIMiddleware("email", strategy="redact", apply_to_input=True, apply_to_output=True),
PIIMiddleware(
"phone",
detector=r"(?:13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}",
strategy="redact", apply_to_input=True, apply_to_output=True
),
],
system_prompt="你是一个安全的数据处理助手,严格保护用户隐私"
)
result = agent.invoke({"messages": [{"role": "user", "content": "请读取用户 001 的数据"}]})
print(result["messages"][-1].content)
9.2 自定义中间件
通过在执行流程的特定点运行钩子构建。基于装饰器适合单钩子的快速实现;基于类(继承 AgentMiddleware)适合多钩子的复杂场景。
import re
from typing import Any, Dict
from langchain.agents.middleware import AgentMiddleware
class SensitiveDataMiddleware(AgentMiddleware):
"""自定义脱敏中间件"""
def __init__(self, patterns: list = None):
super().__init__()
self.patterns = patterns or [
(r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+', '[EMAIL]'),
(r'(\+86)?1[3-9]\d{9}', '[PHONE]')
]
def _desensitize(self, text: str) -> str:
for pattern, replacement in self.patterns:
text = re.sub(pattern, replacement, text)
return text
def before_model(self, state: Dict[str, Any]) -> Dict[str, Any]:
"""模型调用前脱敏消息内容"""
for message in state.get('messages', []):
if hasattr(message, 'content') and isinstance(message.content, str):
message.content = self._desensitize(message.content)
return state
def after_model(self, state: Dict[str, Any]) -> Dict[str, Any]:
return state
10. 生态演进与总结
10.1 生态演进
LangChain v0.1 (2023) LangChain v0.2-0.3 (2024) LangChain v1.0 (2025+)
┌─────────────┐ ┌─────────────────────┐ ┌──────────────────┐
│ Chain 为主 │ ──────▶ │ LCEL / Runnable 为主 │ ────▶ │ LangGraph 为主 │
│ AgentExecutor│ │ 流式/批处理/并发 │ │ 有状态图编排 │
│ 记忆模块 │ │ 社区包拆分 │ │ create_agent + │
│ │ │ │ │ Middleware │
└─────────────┘ └─────────────────────┘ └──────────────────┘
- LangGraph:最值得关注的新核心。用有向图(StateGraph)定义 Agent 状态机,支持条件分支、循环、人机交互、持久化。
- LangSmith:调试和监控 LLM 应用的 SaaS 平台(trace、evaluation、prompt hub)。
- LangServe:一键把 LangChain Runnable 部署成 REST API。
10.2 典型场景速查
| 场景 | 关键组件 | 复杂度 |
|---|---|---|
| 聊天机器人 | ChatModel + Memory | ⭐ |
| 文档问答 (RAG) | Loader → Split → Embed → VectorStore → Retriever | ⭐⭐ |
| SQL 自然语言查询 | create_agent + SQLDatabaseToolkit | ⭐⭐ |
| 多步推理 Agent | create_agent + 多个 Tool | ⭐⭐⭐ |
| 复杂工作流 | LangGraph StateGraph + 条件分支 + Checkpointer | ⭐⭐⭐⭐ |
10.3 核心要点
| 要点 | 一句话 |
|---|---|
| 本质 | LLM 应用的中间件 / 胶水层,不是模型也不是应用 |
| 核心抽象 | Chain(流水线)→ Agent(决策循环)→ Graph(状态机) |
| v1.0 标志 | create_agent 取代 AgentExecutor,全面基于 LangGraph,引入中间件 |
| 学习路径 | LCEL 管道 → 输出解析 → Memory → RAG → Tool → create_agent → Middleware |
| 避坑 | 别追旧版 AgentExecutor;用 create_agent;用 langchain-<provider> 而非全局安装;旧代码装 langchain-classic 过渡 |
| 竞品 | LlamaIndex(偏数据 / 索引)、Dify / Coze(低代码)、自研裸调 SDK |