Deep Read

LangChain 概述

 

1. 什么是 LangChain

 

LangChain 是一个用于开发由大型语言模型(LLM)驱动的应用程序的开源框架。它的定位是"LLM 应用的中间件 / 胶水层"——抽象了 LLM 调用、链式组合、工具集成、记忆管理、检索增强等通用能力,让开发者不必从零拼装,把 LLM、工具、数据和业务逻辑像搭积木一样组合成应用。

我们希望大模型应用不仅仅是聊天,更能从已有的数据库或文件中提取信息并执行具体操作。LangChain 正是为此而生:它允许开发者将通义千问、DeepSeek、OpenAI 等大语言模型与外部系统和数据源结合,完成更复杂的操作。

 

也可以借助 Dify、RAGFlow 之类的低代码平台,但自由度受限,对复杂业务适配欠缺;也可以完全自研裸调 SDK,但费时费力。LangChain 提供了现成组件,同时保留了足够的自定义自由度。

地位类比

  • 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-openailangchain-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 / astreama = async),用法相同,供 async/await 异步代码使用。

正因为接口统一,你写好一条链就自动获得同步 / 批量 / 流式 / 异步全套能力,无需为每种场景单独写代码。LangChain 里的 RunnableSequenceRunnableLambdaRunnableParallelRunnablePassthrough 都是这个家族的成员。

管道符 |:把组件串成流水线

| 把上一个组件的输出接到下一个组件的输入,串成一个 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⭐⭐
多步推理 Agentcreate_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