目录
[1. LangChain 是什么](#1. LangChain 是什么)
[2. 核心组件](#2. 核心组件)
[2.1 model:推理引擎](#2.1 model:推理引擎)
[2.2 messages:上下文的标准容器](#2.2 messages:上下文的标准容器)
[2.3 agent:总装配点](#2.3 agent:总装配点)
[2.4 streaming:运行观察机制](#2.4 streaming:运行观察机制)
[2.5 structured output:Agent 接入真实业务的接口](#2.5 structured output:Agent 接入真实业务的接口)
[2.6 核心组件小结](#2.6 核心组件小结)
[3. 工具系统](#3. 工具系统)
[3.1 工具:Agent 的行动接口](#3.1 工具:Agent 的行动接口)
[3.2 工具契约:能力说明书](#3.2 工具契约:能力说明书)
[3.3 ToolRuntime:工具能读取运行时](#3.3 ToolRuntime:工具能读取运行时)
[3.4 Command:工具能修改系统状态](#3.4 Command:工具能修改系统状态)
[3.5 动态工具:工具集合可以动态变化](#3.5 动态工具:工具集合可以动态变化)
[3.6 MCP:工具来源外部化](#3.6 MCP:工具来源外部化)
[3.7 为什么很多"高级能力"最后都落在工具上](#3.7 为什么很多"高级能力"最后都落在工具上)
[4. 中间件与控制系统](#4. 中间件与控制系统)
[4.1 middleware 在 LangChain 里的位置](#4.1 middleware 在 LangChain 里的位置)
[4.2 官方预置中间件](#4.2 官方预置中间件)
[4.2.1 可靠性、容错与成本控制](#4.2.1 可靠性、容错与成本控制)
[4.2.2 上下文管理](#4.2.2 上下文管理)
[4.2.3 安全与治理](#4.2.3 安全与治理)
[4.2.4 任务组织与重型代理环境](#4.2.4 任务组织与重型代理环境)
[4.3 怎么组合官方中间件](#4.3 怎么组合官方中间件)
[4.4 自定义中间件](#4.4 自定义中间件)
[4.4.1 Node-style hooks:适合状态更新、校验、日志](#4.4.1 Node-style hooks:适合状态更新、校验、日志)
[4.4.2 Wrap-style hooks:适合重试、fallback、动态模型、动态工具](#4.4.2 Wrap-style hooks:适合重试、fallback、动态模型、动态工具)
[4.4.3 执行顺序](#4.4.3 执行顺序)
[4.5 Runtime:把"系统依赖"和"模型语料"分开](#4.5 Runtime:把"系统依赖"和"模型语料"分开)
[4.6 Context Engineering:每一轮该给什么](#4.6 Context Engineering:每一轮该给什么)
[4.7 这一章真正要记住什么](#4.7 这一章真正要记住什么)
[5. 核心能力总结](#5. 核心能力总结)
[5.1 你能做什么了](#5.1 你能做什么了)
[5.2 一个生产级示例](#5.2 一个生产级示例)
[5.3 接下来学什么](#5.3 接下来学什么)
写在前面
学 LangChain 觉得别扭?多半是入口选错了。
把它当成"调大模型的库",你看到的就是零散 API:messages、tools、middleware、memory、RAG、MCP、multi-agent,像一堆互不相干的专题。
LangChain 真正在做的是:把模型、上下文、工具、控制逻辑、记忆、知识接入和代理协作,组织成一套能持续运行的 Agent 系统。
这篇文章不写 quickstart 流水账,也不按官方文档顺序。我会按开发者最容易理解的逻辑,带你掌握 LangChain 的核心能力------搭建一个可控、可运行的 Agent 系统。
本文内容
- 核心组件:model、messages、agent、streaming、structured output
- 工具系统:Agent 如何获得行动能力
- 中间件与控制系统:如何让 Agent 可控、可治理、可上线
目标很简单:一篇文章带你掌握 LangChain 的核心开发能力。 看完后你脑子里不是一堆 API 名词,而是一张能直接指导开发的框架地图。
1. LangChain 是什么
先把边界说清楚。
LangChain 不是 prompt 模板库,不是模型 SDK 包装层,也不是聊天机器人脚手架。它是一套面向 Agent 开发的上层框架。
什么叫"上层框架"?
第一,统一模型、消息、工具、结构化输出等基础对象,让你快速搭起一个能运行的 Agent。
第二,提供 middleware、runtime、memory 等控制面,让你管理的不是"一次模型调用",而是一个"会持续执行的系统"。
第三,把 RAG、长期记忆、MCP、多代理这些看似分散的能力,收束到同一个 Agent 开发模型里。
同时也要分清它和周边生态的关系:
|-----------|-------------------------------|
| 组件 | 定位 |
| LangChain | 上层 Agent 框架,负责开发体验和常见抽象 |
| LangGraph | 底层运行时与编排引擎,负责状态、持久化、流式执行、中断恢复 |
| LangSmith | 观测、调试、评测平台 |
LangChain 的核心价值不是"统一调模型",而是"把 Agent 的执行过程工程化"。
后面所有章节,都在展开这句话。
2. 核心组件
一个最基本的 Agent,靠哪些骨架对象跑起来?
先说五个最该先立住的对象:model、messages、agent、streaming、structured output。这五个对象没建立清楚,后面的工具、中间件、记忆、RAG 都会飘着。
2.1 model:推理引擎
任何 Agent 最终都要靠模型完成推理:理解用户问题、决定用不用工具、解释工具结果、生成最终回答。LangChain 在模型层的核心工作,是把不同 provider 的模型调用统一成同一套接口。
python
from langchain.chat_models import init_chat_model
model = init_chat_model("openai:gpt-5.4")
模型在 LangChain 里首先是一个可被系统调度的推理节点。
但模型层并不是 LangChain 最有价值的部分。"调一次模型"本身,不足以构成一个 Agent 框架。
2.2 messages:上下文的标准容器
很多人学 LangChain 的第一个误区,是把消息系统看成"prompt 的另一种写法"。
在 LangChain 里,消息不是语法糖,而是上下文的标准容器。
python
messages = [
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Explain LangChain simply."},
]
这意味着:
- 上下文不再是一段巨大字符串
- 不同角色的内容在系统里有不同语义
- 工具结果、历史对话、记忆摘要、流式事件,最终都会回到消息系统里
memory 要管理消息历史,middleware 经常要裁剪、摘要、编辑消息,streaming 很多时候是在暴露消息级事件,而不是纯 token。
2.3 agent:总装配点
今天的 LangChain,最标准的入口是 create_agent(...)。
python
from langchain.agents import create_agent
agent = create_agent(
model="openai:gpt-5.4",
tools=[],
system_prompt="You are a concise assistant.",
)
create_agent(...) 是总装配点,负责把 model、messages、tools、response_format、middleware、checkpointer、store 装到一起。
agent 本身不是魔法。真正重要的是它把哪些抽象组织起来,以及这些抽象如何一起工作。
2.4 streaming:运行观察机制
很多人从聊天 UI 的角度理解 streaming,把它看成前端体验优化。但在 LangChain 里,streaming 更重要的价值是**"看见 Agent 正在怎么运行"**。
python
for chunk in agent.stream(inputs, stream_mode="updates", version="v2"):
print(chunk)
官方常见的几种流式模式:
updates:看 agent step 和状态变化messages:看消息块或 token 流custom:看工具或节点主动发出的自定义进度
streaming 首先是调试、观察和运维能力,其次才是展示能力。
2.5 structured output:Agent 接入真实业务的接口
如果模型输出还要被程序继续消费,纯自然语言不够稳。这时你需要的不是"让模型尽量按 JSON 输出",而是让框架接管结果结构。
python
from pydantic import BaseModel
from langchain.agents import create_agent
class ContactInfo(BaseModel):
name: str
email: str
agent = create_agent(
model="openai:gpt-5.4",
response_format=ContactInfo,
)
structured output 不是输出格式优化,而是 Agent 接入真实业务的关键接口。
2.6 核心组件小结
到这里,骨架应该清楚了:
- model 负责推理
- messages 负责承载上下文
- agent 负责装配系统
- streaming 负责暴露运行过程
- structured output 负责把结果接到程序世界
系统到这里还只是"能跑起来"。真正让 Agent 接触世界、改写状态、接入外部能力的主轴,是工具。
3. 工具系统
Agent 怎样获得行动能力?
这是 LangChain 最重要的主轴之一。很多后面看起来很"高级"的能力,本质上都还是通过工具落地。
3.1 工具:Agent 的行动接口
模型本身只能推理,不能直接:
- 查数据库
- 调 HTTP API
- 操作文件
- 搜外部知识
- 写入长期记忆
- 把任务交给别的 agent
LangChain 用工具把这些外部能力显式暴露给模型。
python
from langchain.tools import tool
@tool
def get_weather(city: str) -> str:
"""Get weather for a given city."""
return f"{city}: sunny, 25C"
工具不是"给 Python 程序用的函数",而是"给模型调用的能力接口"。
3.2 工具契约:能力说明书
为什么工具经常"选不对""参数填错""该用时不用"?很多时候不是模型太弱,而是工具契约写得太差。
工具契约至少回答三件事:
- 这个工具是干什么的
- 什么时候该用
- 参数分别代表什么
所以工具名、参数名、docstring 都很关键。对模型来说,它看到的不是你的业务代码,而是这份能力说明书。
坏工具契约:
- 名字太泛,如
process_data - docstring 含糊,如
Handle user info - 参数语义不明,如
value,data,type
好工具契约的标准不是"程序员看得懂",而是"模型能稳定选对"。
3.3 ToolRuntime:工具能读取运行时
如果工具只接收参数、只返回字符串,那它只是浅层的 function calling。LangChain 更关键的一步,是让工具能读取运行时。
python
from dataclasses import dataclass
from langchain.tools import ToolRuntime, tool
@dataclass
class Context:
user_id: str
@tool
def query_order(order_id: str, runtime: ToolRuntime[Context]) -> str:
"""Query the current user's order."""
user_id = runtime.context.user_id
return f"user={user_id}, order={order_id}"
工具已经不是孤立函数,而是系统里的运行节点。
通过 ToolRuntime,工具可以访问:
context:本次调用注入的静态依赖,如用户 ID、租户信息、数据库连接state:当前线程的短期状态store:跨线程的长期记忆stream_writer:主动写出自定义流式进度
3.4 Command:工具能修改系统状态
这是 LangChain 工具系统非常关键的一步升级。
工具不一定只"返回文本",它还可以通过 Command 更新状态。一旦能更新状态,工具就不只是取数接口,而会变成控制接口。
from langgraph.types import Command
from langchain.tools import tool
@tool
def mark_vip_customer(user_id: str) -> Command:
"""Mark the current user as VIP in agent state."""
return Command(update={"vip_user_id": user_id})
工具可以参与控制流,而不只是提供信息。
这在很多场景都很重要:
- 工具写入短期状态,影响后续 prompt 或路由
- 工具触发 handoff,把任务切给别的 agent
- 工具把"业务动作"转成"系统状态变化"
3.5 动态工具:工具集合可以动态变化
很多教程会默认 agent 的工具列表在创建时就完全确定。但真实系统里,工具经常是动态的:
- 不同用户权限不同
- 不同租户接入的系统不同
- 某些工具只在某个对话阶段开放
- 工具可能在运行时从远端注册中心或 MCP 服务器加载
LangChain 对动态工具的核心支持点,不在"某个神奇 API",而在 middleware。
python
from collections.abc import Callable
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
@wrap_model_call
def only_show_admin_tools(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
if not request.runtime.context.is_admin:
allowed = [tool for tool in request.tools if tool.name != "delete_user"]
request = request.override(tools=allowed)
return handler(request)
动态工具不是工具层单独的功能,而是工具系统和中间件系统的交叉点。
3.6 MCP:工具来源外部化
很多人把 MCP 学成"一个新协议"。但站在 LangChain 的视角看,它最重要的意义很简单:MCP 让工具不必写死在本地代码里,而可以从外部服务器动态接入。
python
from langchain.agents import create_agent
from langchain_mcp_adapters.client import MultiServerMCPClient
client = MultiServerMCPClient(
{
"browser": {"transport": "stdio", "command": "python", "args": ["browser_server.py"]},
}
)
tools = await client.get_tools()
agent = create_agent("openai:gpt-5.4", tools=tools)
MCP 在 LangChain 里不是平行世界,它最后还是回到工具系统里。
官方文档还强调了一点:MCP 工具本身运行在外部进程里,拿不到 LangGraph runtime;如果你想让 MCP 工具读 context、store、state,要用 interceptor 把这些能力桥接进去。工具系统和运行时系统是绑在一起理解的。
3.7 为什么很多"高级能力"最后都落在工具上
这点一定要看明白,因为它决定了你会不会把 LangChain 学散。
很多表面上是"高级专题"的能力,底层其实都强依赖工具:
- retrieval 常常先做成检索工具
- long-term memory 往往通过工具读写 store
- handoff / multi-agent 常常通过工具触发状态变化
- MCP 本质上是外部工具接入
工具不是一个普通章节,而是 LangChain 从"会说话"走向"会行动"的分水岭。
4. 中间件与控制系统
这是全文最重要的一章。
如果说工具系统解决的是"Agent 能做什么",那么中间件系统解决的是:Agent 在做这些事的时候,如何被控制、约束、治理和稳定运行。
很多人低估 middleware,是因为把它理解成 Web 框架那种"可有可无的扩展层"。但在 LangChain 里,middleware 更接近控制面。
没有它,你当然也能跑一个 agent;但一旦进入真实环境,你马上会碰到这些问题:
- 模型失败了怎么办
- 工具失败了怎么办
- 工具太多,模型总乱选怎么办
- 对话越来越长,上下文爆炸怎么办
- 敏感信息要不要脱敏
- 某些工具调用前要不要人工确认
- 不同用户要不要走不同模型、看到不同工具
这些问题如果都散落在 prompt 和业务代码里,系统很快就会失控。LangChain 把它们收束到 middleware,就是为了把 Agent 的执行过程工程化。
4.1 middleware 在 LangChain 里的位置
middleware 的核心作用不是"改一点 prompt",而是在 Agent 循环的关键节点插手执行。
官方的 Agent 主循环很简单:
- 调模型
- 模型决定是否调用工具
- 执行工具
- 将工具结果回注到上下文
- 再次调模型,直到结束
middleware 就是插在这条链路前后,去做:
- 改模型:动态切换模型、降级、重试
- 改工具集合:按权限过滤、动态加载、MCP 接入
- 改消息上下文:裁剪、摘要、脱敏、注入
- 改错误处理:捕获异常、fallback、告警
- 改中断和恢复策略:HITL 审批、断点续跑
- 改安全和治理规则:限流、审计、合规检查
它不是"装饰层",而是控制层。可以把 middleware 理解成 Agent 系统的"操作系统内核"------它决定了 Agent 能做什么、不能做什么、怎么做、做到什么程度。
4.2 官方预置中间件
如果你直接背中间件类名,很快就会乱。更好的理解方式是:先按"它解决什么问题"分类。
4.2.1 可靠性、容错与成本控制
这一组中间件解决的是:别让 agent 因为模型不稳、工具抖动或循环失控而把系统拖垮。
ModelRetryMiddleware
- 解决什么问题:模型调用的瞬时失败,如 timeout、throttling、临时网络错误
- 什么时候用:生产环境基本都建议加
python
from langchain.agents.middleware import ModelRetryMiddleware
middleware = [
ModelRetryMiddleware(max_retries=3),
]
ToolRetryMiddleware
- 解决什么问题:外部工具调用的瞬时失败
- 什么时候用:工具依赖 HTTP、数据库、第三方 API 时很常见
python
from langchain.agents.middleware import ToolRetryMiddleware
middleware = [
ToolRetryMiddleware(max_retries=3),
]
ModelFallbackMiddleware
- 解决什么问题:主模型失败时切换备用模型
- 什么时候用:要做 provider 容灾,或者希望降级保活
python
from langchain.agents.middleware import ModelFallbackMiddleware
middleware = [
ModelFallbackMiddleware("openai:gpt-5.4-mini", "anthropic:claude-sonnet-4-5"),
]
ModelCallLimitMiddleware
- 解决什么问题:模型循环调用失控,成本和延迟失控
- 什么时候用:担心 agent 进入长循环,或者要严格控费
python
from langchain.agents.middleware import ModelCallLimitMiddleware
middleware = [
ModelCallLimitMiddleware(run_limit=5, thread_limit=10, exit_behavior="end"),
]
ToolCallLimitMiddleware
- 解决什么问题:工具调用过多,尤其是昂贵或限流工具被反复调用
- 什么时候用:搜索、爬虫、数据库、付费 API
python
from langchain.agents.middleware import ToolCallLimitMiddleware
middleware = [
ToolCallLimitMiddleware(tool_name="search", run_limit=3, thread_limit=5),
]
这一组和工具系统的关系很直接:工具让 agent 有了行动能力,而这些中间件负责让行动不会失控。
4.2.2 上下文管理
这一组中间件解决的是:上下文不是越多越好,而是越精准越好。
SummarizationMiddleware
- 解决什么问题:长对话把上下文撑爆
- 什么时候用:多轮线程、长任务、需要长期保留会话连贯性的场景
python
from langchain.agents.middleware import SummarizationMiddleware
middleware = [
SummarizationMiddleware(
model="openai:gpt-5.4-mini",
trigger=("tokens", 4000),
keep=("messages", 20),
),
]
重点不是"自动摘要",而是让旧消息压缩成更便宜、更短的上下文表示。
ContextEditingMiddleware
- 解决什么问题:工具输出太长、太脏、太多,直接塞回消息会污染上下文
- 什么时候用:文件搜索、RAG、网页抓取、长文本工具
python
from langchain.agents.middleware import ContextEditingMiddleware, ClearToolUsesEdit
middleware = [
ContextEditingMiddleware(edits=[ClearToolUsesEdit(keep_most_recent=3)]),
]
LLMToolSelectorMiddleware
- 解决什么问题:工具太多时,主模型被工具描述淹没
- 什么时候用:一个 agent 挂了大量工具,但每次真正 relevant 的只有少数几个
python
from langchain.agents.middleware import LLMToolSelectorMiddleware
middleware = [
LLMToolSelectorMiddleware(model="openai:gpt-5.4-mini", max_tools=5),
]
它本质上不是"工具增强",而是上下文压缩。因为工具描述本身也是上下文的一部分。
4.2.3 安全与治理
这一组中间件解决的是:不是所有内容都该原样进模型,也不是所有动作都该自动执行。
PIIMiddleware
- 解决什么问题:输入、输出、工具参数里包含邮箱、手机号、信用卡号等敏感信息
- 什么时候用:面向真实用户的系统几乎都该考虑
python
from langchain.agents.middleware import PIIMiddleware
middleware = [
PIIMiddleware("email", strategy="redact", apply_to_input=True),
]
可用策略包括 redact、mask、hash、block。guardrails 在 LangChain 里并不是一个平行世界,而是控制系统的一部分。
HumanInTheLoopMiddleware
- 解决什么问题:高风险工具调用不能让 agent 自己拍板
- 什么时候用:发邮件、写数据库、付款、删文件、调用内部管理系统
python
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver
middleware = [
HumanInTheLoopMiddleware(
interrupt_on={"send_email": {"allowed_decisions": ["approve", "edit", "reject"]}}
)
]
checkpointer = InMemorySaver()
HITL 不是"让人参与一下",而是把中断、审批、恢复纳入标准执行流程。
所以把 guardrails、HITL 单独学成"高级专题"其实是不对的。它们本质上是治理型 middleware。
4.2.4 任务组织与重型代理环境
这一组中间件更偏"给 agent 直接注入一整类工作能力"。
其中有些是 LangChain 通用中间件,有些更常见于官方的 Deep Agents 能力栈。理解它们的最佳方式不是背 API,而是看它们给 agent 增加了什么工作环境。
TodoListMiddleware
- 解决什么问题:长任务缺少显式计划,agent 容易丢步骤
- 什么时候用:多步骤任务、代码修改、复杂执行链
python
from langchain.agents.middleware import TodoListMiddleware
middleware = [TodoListMiddleware()]
它的本质不是"多一个 todo 功能",而是给 agent 注入显式任务管理能力。
LLMToolEmulator
- 解决什么问题:某些工具成本高、权限高,或你想先模拟工具效果
- 什么时候用:联调、演示、低成本预演
python
from langchain.agents.middleware import LLMToolEmulator
middleware = [
LLMToolEmulator(),
]
ShellToolMiddleware
- 解决什么问题:给 agent 安全地注入 shell 执行能力
- 什么时候用:代码代理、自动化脚本、运维辅助
python
from langchain.agents.middleware import ShellToolMiddleware
middleware = [
ShellToolMiddleware(workspace_root="/workspace"),
]
FilesystemFileSearchMiddleware
- 解决什么问题:让 agent 拥有 glob / grep 风格的文件搜索能力
- 什么时候用:代码库分析、文档仓搜索、本地知识发现
python
from langchain.agents.middleware import FilesystemFileSearchMiddleware
middleware = [
FilesystemFileSearchMiddleware(root_path="/workspace", use_ripgrep=True),
]
FilesystemMiddleware
- 解决什么问题:给 agent 提供读写文件、编辑文件、短长期文件记忆
- 什么时候用:重型代理、代码代理、以文件系统为主工作区的任务
它更接近"给 agent 配一套工作台",而不只是加一个工具。
SubAgentMiddleware
- 解决什么问题:把复杂任务切给子代理,隔离上下文
- 什么时候用:单 agent 上下文过载,或者不同角色需要独立工作区
它是后面 multi-agent 章节的桥。
4.3 怎么组合官方中间件
中间件不是堆得越多越好。更合理的思路是按问题链路组合:
- 先解决可靠性:
ModelRetryMiddleware、ToolRetryMiddleware、ModelFallbackMiddleware - 再控制成本和失控:
ModelCallLimitMiddleware、ToolCallLimitMiddleware - 再管理上下文:
SummarizationMiddleware、ContextEditingMiddleware、LLMToolSelectorMiddleware - 最后治理高风险动作:
PIIMiddleware、HumanInTheLoopMiddleware
一个典型的生产向组合可能长这样:
python
from langchain.agents import create_agent
from langchain.agents.middleware import (
ModelRetryMiddleware,
ToolRetryMiddleware,
SummarizationMiddleware,
PIIMiddleware,
HumanInTheLoopMiddleware,
)
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model="openai:gpt-5.4",
tools=[...],
middleware=[
ModelRetryMiddleware(max_retries=2),
ToolRetryMiddleware(max_retries=2),
SummarizationMiddleware(model="openai:gpt-5.4-mini", trigger=("tokens", 4000)),
PIIMiddleware("email", strategy="redact", apply_to_input=True),
HumanInTheLoopMiddleware(interrupt_on={"send_email": True}),
],
checkpointer=InMemorySaver(),
)
LangChain 的重点不是"有 agent",而是"能系统地控制这个 agent"。
4.4 自定义中间件
官方预置中间件已经覆盖了很多常见场景。所以正确顺序应该是:
- 先看有没有 built-in
- 没有再自己写
LangChain 的自定义 middleware,大体分两类。
4.4.1 Node-style hooks:适合状态更新、校验、日志
常见节点型钩子有:
before_agentbefore_modelafter_modelafter_agent
它们更适合做轻量控制:打日志、记计数器、做输入校验、写状态字段。
python
from langchain.agents import AgentState
from langchain.agents.middleware import after_model
@after_model
def count_model_calls(state: AgentState, runtime):
return {"model_call_count": state.get("model_call_count", 0) + 1}
node-style hooks 更像在 agent 生命周期节点上加规则。
4.4.2 Wrap-style hooks:适合重试、fallback、动态模型、动态工具
常见包裹型钩子有:
wrap_model_callwrap_tool_call
它们更适合接管真正的模型或工具调用过程。
python
from collections.abc import Callable
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
@wrap_model_call
def choose_model(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
model = "openai:gpt-5.4-mini" if len(request.messages) < 8 else "openai:gpt-5.4"
return handler(request.override(model=model))
wrap-style hooks 不是打补丁,而是在接管执行策略。
4.4.3 执行顺序
如果你配置了多个 middleware,顺序就不是小事。
before_*:按列表顺序执行wrap_*:像洋葱一样嵌套包裹after_*:反向执行
一个实用原则是:
- 越基础、越全局的控制放前面
- 越靠近业务的观察和收尾逻辑放后面
比如:
- 先做 PII 处理
- 再做上下文裁剪
- 再做动态模型或动态工具
- 最后做日志和统计
4.5 Runtime:把"系统依赖"和"模型语料"分开
很多初学者会把所有信息都塞进 prompt。这是 Agent 系统很快失控的原因之一。
LangChain 的 runtime 在这里建立了一条非常重要的边界:
- 什么应该给模型看
- 什么只应该作为系统运行时依赖存在
runtime 里最常用的几部分是:
context:本次调用传入的静态依赖state:当前线程的短期状态store:跨线程长期记忆stream_writer:自定义流式输出execution_info:线程 ID、run ID、attempt 等执行元信息
最小链路可以这样看:
python
from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.tools import ToolRuntime, tool
@dataclass
class Context:
user_id: str
tenant_id: str
@tool
def get_current_profile(runtime: ToolRuntime[Context]) -> str:
return f"user={runtime.context.user_id}, tenant={runtime.context.tenant_id}"
agent = create_agent(
model="openai:gpt-5.4",
tools=[get_current_profile],
context_schema=Context,
)
runtime 的意义不是多给你几个对象,而是把"系统依赖"和"模型语料"分开。
4.6 Context Engineering:每一轮该给什么
LangChain 官方现在非常强调 context engineering。这不是换个新术语,而是在纠正一个旧误区:
Agent 稳不稳,往往不取决于 prompt 写得多华丽,而取决于每一轮到底给了模型什么上下文。
从开发角度看,至少要分清三类上下文。
model context
- 真正送进模型的消息、系统提示、工具描述、摘要信息
tool context
- 工具执行时能访问的运行时依赖,如 context、state、store
life-cycle context
- 在 agent 生命周期不同节点上才可见和可改写的信息,比如模型前后、工具前后、中断恢复前后
这也是为什么 context engineering 必须放在 middleware 这一章讲。因为它不是"提示词技巧",而是"在生命周期里精确安排上下文"的能力。
python
from langchain.agents.middleware import dynamic_prompt, ModelRequest
@dynamic_prompt
def role_aware_prompt(request: ModelRequest) -> str:
role = request.runtime.context.user_role
base = "You are a helpful assistant."
if role == "beginner":
return base + " Explain concepts simply."
return base + " Answer with technical depth."
动态 prompt 不是为了"更花哨",而是为了让上下文在正确的生命周期节点被生成。
4.7 这一章真正要记住什么
到这里,中间件这一章要收住成一句话:
LangChain 最核心的价值,不在 create_agent(...) 本身,而在于它把 Agent 的控制、上下文和治理工程化了。
如果你只会用 model + tools,你只是会搭一个能跑的 agent。如果你真正掌握了 middleware、runtime、context engineering,你才开始会做一个能上线、能治理、能维护的 agent 系统。
5. 核心能力总结
到这里,你应该已经掌握了 LangChain 的核心开发能力。我们来总结一下。
5.1 你能做什么了
学完这篇,你应该能:
- 搭建基本 Agent:用 model、messages、agent 三个核心组件,搭起一个能运行的 Agent
- 赋予行动能力:通过工具系统,让 Agent 能查数据库、调 API、操作文件
- 实现可控执行:用中间件系统,解决重试、限流、上下文管理、安全治理等问题
- 调试和观察:用 streaming 看清 Agent 的执行过程
- 接入真实业务:用 structured output 让模型输出可被程序消费的结构化数据
5.2 一个生产级示例
把今天学的串起来,一个生产级的 Agent 可能长这样:
python
from langchain.agents import create_agent
from langchain.agents.middleware import (
ModelRetryMiddleware,
ToolRetryMiddleware,
SummarizationMiddleware,
PIIMiddleware,
HumanInTheLoopMiddleware,
)
from langchain.tools import tool
from langgraph.checkpoint.memory import InMemorySaver
@tool
def search_database(query: str) -> str:
"""Search the internal database."""
return f"Results for: {query}"
agent = create_agent(
model="openai:gpt-5.4",
tools=[search_database],
middleware=[
# 可靠性
ModelRetryMiddleware(max_retries=2),
ToolRetryMiddleware(max_retries=2),
# 上下文管理
SummarizationMiddleware(
model="openai:gpt-5.4-mini",
trigger=("tokens", 4000),
),
# 安全治理
PIIMiddleware("email", strategy="redact", apply_to_input=True),
HumanInTheLoopMiddleware(
interrupt_on={"send_email": {"allowed_decisions": ["approve", "reject"]}}
),
],
checkpointer=InMemorySaver(),
)
这就是 LangChain 的核心价值:把 Agent 的执行过程工程化。
5.3 接下来学什么
这篇文章解决的是"让 Agent 跑起来 + 可控"的问题。但如果你想让 Agent 更强大,还需要:
- 记忆系统:让 Agent 记住用户、记住历史、记住偏好
- RAG / 知识接入:让 Agent 能按需获取外部知识
- Multi-agent:让多个 Agent 协作完成复杂任务
这些内容,我们在【LangChain】二.LangChain v1.0-高级特性(记忆、RAG 、Multi-Agent )中详细讲解。