目录
- 引言:为什么 LangGraph 1.0 至关重要?
- Agent 开发的痛点:不可控、不可观测、不可持久化。
- 1.0 的核心承诺:稳定性、持久性、控制力。
- 核心架构升级:稳定压倒一切
- “零破坏性变更”承诺。
- 核心原语的定型:State, Nodes, Edges。
- 重磅新功能一:原生持久化与“时间旅行” (Durable State)
- Checkpointer 机制详解。
- 实战:如何配置 Postgres/SQLite Checkpointer。
- API 深度解析:
thread_id与状态快照。
- 重磅新功能二:人机协同 (Human-in-the-Loop) 的终极形态
- 新的
interrupt()API 详解。 Command原语与resume机制。- 实战场景:敏感操作的“断点续传”与人工审批流。
- 新的
- 架构剧变:从
create_react_agent到langchain.agents.create_agent- 为什么要弃用
langgraph.prebuilt? - LangChain 1.0 与 LangGraph 1.0 的关系:分层架构。
- 迁移指南:一步步修改你的代码。
- 为什么要弃用
- 全新概念:Middleware(中间件)—— Agent 的“插件系统”
- Middleware 的工作原理:洋葱模型。
- 核心 Hooks:
before_model,after_model,modify_model_request。 - 实战:编写一个“自动摘要”和“PII 过滤”中间件。
- 数据标准化:Standard Content Blocks (标准内容块)
- 解决“模型碎片化”的痛点。
- 统一的
content_blocks结构详解。 - 如何处理推理 (Reasoning) 与工具调用 (Tool Calls)。
- 状态管理:告别 Pydantic,拥抱 TypedDict
AgentState的演进。- 为什么 Pydantic 状态被移除了?
- 如何在 Middleware 中通过 Schema 验证数据。
- 流式输出 (Streaming) 的增强
stream_mode="updates"vsstream_mode="messages"。- 实时获取 Token 与工具状态。
- 总结与展望
1. 引言:为什么 LangGraph 1.0 至关重要?
在过去的一年里,我们见证了 AI Agent 从实验室的 Jupyter Notebook 走向了企业的生产环境。然而,这一过程充满了痛苦。开发者发现,用简单的 Chain 串联起来的 Agent 脆弱不堪:网络抖动会导致任务丢失,上下文过长会导致模型“发疯”,更可怕的是,当 Agent 决定执行一个危险操作(比如“删除数据库”)时,人类往往来不及阻止。
LangGraph 的出现最初就是为了解决“循环”和“控制流”的问题。而 LangGraph 1.0 则更进一步,它不再仅仅是一个图计算库,它定义了一个**Agent Runtime(代理运行时)**标准。
1.0 的核心关键词是:Stability(稳定性)。 官方明确承诺,核心 API(State, Nodes, Edges)将保持长期稳定,不再会有那种“睡一觉起来代码跑不通了”的恐惧。这对于企业级应用来说,是最大的利好。
2. 核心架构升级:稳定压倒一切
在深入新功能之前,我们必须强调 LangGraph 1.0 的设计哲学。
核心原语的定型
在 0.x 时代,我们可能经历过图定义方式的微调。但在 1.0 中,以下三个概念被永久固化:
- State (状态):Agent 的大脑,通常是一个
TypedDict。所有的组件(Nodes)都通过读写这个状态来通信。 - Nodes (节点):执行具体逻辑的函数(Python 函数)。
- Edges (边):控制流,决定下一个运行哪个节点。
这种设计的精妙之处在于它的透明性。不像某些框架将 Agent 封装成一个黑盒(Black Box),LangGraph 强迫你画出 Agent 的“思维导图”。
3. 重磅新功能一:原生持久化与“时间旅行” (Durable State)
这是 LangGraph 1.0 最具杀伤力的特性。在生产环境中,服务器重启、网络中断是常态。如果你的 Agent 正在执行一个长达 30 步的任务,而在第 29 步服务器挂了,1.0 之前的系统通常意味着“从头再来”。
LangGraph 1.0 引入了原生持久化(Native Persistence)。
Checkpointer 机制详解
Checkpointer 是一个保存每一“步”(Super-step)状态快照的组件。
新增 API:
MemorySaver: 用于开发和测试的内存持久化。SqliteSaver/PostgresSaver: 生产级的数据库持久化。
代码实战:配置持久化
# 1.0 以前你需要自己手写数据库逻辑
# LangGraph 1.0 写法:
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph
# 初始化 Checkpointer
checkpointer = MemorySaver()
# 构建图
builder = StateGraph(MyState)
# ... 添加节点和边 ...
# 编译时传入 checkpointer
graph = builder.compile(checkpointer=checkpointer)
# 运行时传入 thread_id
config = {"configurable": {"thread_id": "user-session-123"}}
graph.invoke(inputs, config=config)
深入理解 thread_id
thread_id 是持久化的核心钥匙。只要你提供了相同的 thread_id,LangGraph 就会自动去数据库里查找上一次的状态,并从那里继续。这不仅实现了“断点续传”,还实现了“长期记忆”。
“时间旅行” (Time Travel) LangGraph 1.0 的持久化不仅仅是“保存”。由于它保存了每一步的快照,你可以通过 API 查询历史状态,甚至让 Agent “回滚”到之前的某一步,修改状态,然后走一条不同的路径。这在调试复杂 Agent 行为时是上帝视角的体验。
4. 重磅新功能二:人机协同 (Human-in-the-Loop) 的终极形态
Agent 不应该是脱缰的野马。LangGraph 1.0 将“人机协同”提升为一等公民(First-class Citizen)。
新增 API:interrupt()
在 1.0 之前,实现“暂停”往往需要复杂的逻辑判断(例如抛出异常或设置特殊标志位)。现在,你可以直接在 Node 内部调用 interrupt。
代码实战:敏感操作审批
from langgraph.types import interrupt, Command
def human_approval_node(state: AgentState):
tool_call = state['tool_calls'][0]
# 核心 API:interrupt
# 程序运行到这里会立即挂起,并将当前状态保存到 Checkpointer
# 参数是返回给前端/用户的提示信息
user_decision = interrupt(f"Agent 想要执行操作: {tool_call}。是否批准?")
# 当 Agent 被“恢复”时,user_decision 将包含用户输入的数据
if user_decision == "approve":
return Command(goto="execute_tool")
else:
return Command(goto="reject_tool")
恢复执行:Command 与 resume
当 interrupt 被触发后,Agent 处于“挂起”状态。要恢复它,你需要再次调用 invoke 或 stream,并传入 Command 对象。
# 第一次运行,触发 interrupt
graph.invoke(..., config=thread_config)
# 输出:__interrupt__: "Agent 想要执行操作..."
# 用户点击“批准”按钮后,恢复运行
# 注意:我们不需要重新输入之前的消息,只需要提供 resume 的值
graph.invoke(
Command(resume="approve"),
config=thread_config
)
这种模式彻底改变了 HITL(Human-in-the-Loop)的开发体验,使得构建复杂的审批流变得像写同步代码一样简单。
5. 架构剧变:从 create_react_agent 到 langchain.agents.create_agent
这是 1.0 版本中最大的 Deprecation(弃用) 和迁移点。
发生了什么变化?
- 旧世界 (LangGraph 0.x): 我们经常使用
langgraph.prebuilt.create_react_agent来快速创建一个 ReAct Agent。 - 新世界 (LangGraph 1.0 + LangChain 1.0): 这个功能被移动并增强到了
langchain.agents.create_agent。
为什么?
langgraph 定位为底层的运行时(Runtime),它只关心图的执行。而 create_react_agent 包含了很多关于 Prompt、Model 选择的高级逻辑,这些属于应用层,因此被移入 langchain。
迁移代码对比
旧代码 (Deprecated):
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
model = ChatOpenAI()
# 旧版可以通过 state_modifier 修改 Prompt,比较隐晦
agent = create_react_agent(model, tools, state_modifier="You are a helpful assistant")
新代码 (LangGraph 1.0 / LangChain 1.0):
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI
model = ChatOpenAI()
# 新版 API 更加清晰,支持 system_prompt 参数
agent = create_agent(
model=model,
tools=tools,
system_prompt="You are a helpful assistant"
)
这看起来只是改了个名字,但背后引入了强大的 Middleware 系统(见下文)。
6. 全新概念:Middleware(中间件)—— Agent 的“插件系统”
这是 LangGraph 1.0 配合 LangChain 1.0 推出的最激动人心的功能之一。如果你熟悉 Web 开发(如 Express.js 或 Django),你会秒懂 Middleware。
在 Agent 的运行循环中(思考 -> 行动 -> 观察),我们经常需要插入一些通用逻辑,比如:
- 日志记录:记录每一次 LLM 的输入输出。
- 上下文管理:当对话太长时,自动触发摘要。
- 安全过滤:在 LLM 发出请求前,检测是否包含敏感信息(PII)。
在 1.0 之前,这些逻辑往往要硬编码在 Node 里,导致业务逻辑与基础设施代码耦合。
Middleware 架构
Middleware 提供了三个核心 Hooks(钩子):
before_model: 在调用 LLM 之前触发。可以修改 Prompt,或者直接返回结果(缓存)。after_model: 在 LLM 返回结果后触发。可以修改输出,或者阻断执行。modify_model_request: 专门用于修改发给 LLM 的参数。
实战:编写一个“自动摘要”中间件
from langchain.agents.middleware import Middleware
class AutoSummarizeMiddleware(Middleware):
def before_model(self, state, config):
messages = state['messages']
if len(messages) > 10:
# 逻辑:如果消息超过10条,生成摘要并替换历史记录
summary = summarize_chain.invoke(messages)
# 修改状态,缩短上下文
return {"messages": [summary] + messages[-2:]}
return None
# 使用中间件
agent = create_agent(
model,
tools,
middleware=[AutoSummarizeMiddleware()]
)
官方还提供了内置的中间件,如 PIIMiddleware(敏感信息过滤)和 HumanInTheLoopMiddleware。
7. 数据标准化:Standard Content Blocks (标准内容块)
在 Agent 开发中,不同模型提供商(OpenAI, Anthropic, Gemini)对“工具调用”、“思维链(Chain of Thought)”的返回格式定义各不相同。这导致开发者要写大量的 if/else 来适配。
LangChain / LangGraph 1.0 引入了 Standard Content Blocks。
无论底层用的是 Claude 还是 GPT-4,所有的 Message 对象现在都有一个统一的 .content_blocks 属性。
结构示例
[
{
"type": "reasoning",
"reasoning": "用户想要查询天气,我应该使用 weather_tool...",
"text": null
},
{
"type": "tool_call",
"name": "weather_tool",
"args": {"city": "Beijing"},
"id": "call_12345"
}
]
新增 API:
message.content_blocks: 惰性解析的标准化内容列表。- 这使得你可以编写一套代码,无缝切换 OpenAI 和 Anthropic 的模型,而不用担心解析逻辑崩溃。
8. 状态管理:告别 Pydantic,拥抱 TypedDict
在 LangGraph 早期版本,我们经常争论 State 应该用 Pydantic Model 还是 TypedDict。
1.0 做出了裁决:AgentState 默认且推荐使用 TypedDict。
为什么? Pydantic 虽然验证功能强大,但在图的流转中(尤其涉及状态合并、Reducer 逻辑时),其严格的校验机制往往会带来不必要的运行时错误。
新最佳实践:
- 定义 State 使用
TypedDict。 - 如果需要数据校验(Validation),请将其放入 Middleware 或 Tool 的定义中,而不是放在全局 State 里。
代码变更:
# Deprecated / 不推荐
# class MyState(BaseModel):
# messages: list[BaseMessage]
# 推荐 (LangGraph 1.0)
from typing import TypedDict, Annotated
from langgraph.graph.message import add_messages
class MyState(TypedDict):
# 使用 Annotated 和 add_messages reducer 是标准范式
messages: Annotated[list, add_messages]
user_info: dict
9. 流式输出 (Streaming) 的增强
Agent 的响应速度往往较慢,因此流式输出是提升用户体验的关键。LangGraph 1.0 对 stream 方法进行了精细化控制。
关键模式 (stream_mode):
values: 每次状态更新时,流式返回完整的 State。适合调试。updates: 仅流式返回增量更新的部分(即 Node 返回的那个 dict)。带宽占用小,适合生产。messages: 专门用于流式传输 LLM 的 Token。这是实现“打字机效果”的核心。
代码示例:
# 同时获取状态更新和 LLM 的 Token 流
async for event in graph.astream_events(inputs, version="v1"):
kind = event["event"]
if kind == "on_chat_model_stream":
print(event["data"]["chunk"].content, end="|")
elif kind == "on_chain_end":
print(f"\n[Node 完成]: {event['name']}")
10. 总结与展望
LangGraph 1.0 的发布,宣告了 Agent 开发进入了工程化阶段。
- 如果你需要构建一个简单的问答机器人,LangChain 的
create_agent配合 Middleware 足以应对。 - 如果你需要构建一个长周期、多步骤、需要人工介入且极度可靠的业务流程(如自动化退款、保险理赔),LangGraph 1.0 提供的 Checkpointer 和图控制流是目前市面上最强的解决方案。
从“玩具”到“工具”,LangGraph 1.0 迈出了坚实的一步。现在,是时候升级你的代码了。