LangGraph 深度实战:从能跑的 Agent 到可控、可恢复、能上线的工作流

LangGraph 深度实战:从能跑的 Agent 到可控、可恢复、能上线的工作流

这两年很多人做 Agent,第一阶段都差不多:先让模型能调用工具,再让它多轮思考,最后跑出一个还不错的 demo。问题通常出在第二阶段之后。只要你想把它接到真实业务里,麻烦就会一起冒出来:中途失败怎么办,人工审核怎么插进去,状态怎么保存,长任务怎么恢复,多个步骤之间怎么共享上下文,复杂流程到底该让模型自由发挥,还是老老实实按工作流走。

LangGraph 真正有价值的地方,不是“再做一个 Agent 框架”,而是它把 Agent 从一次性对话,变成了一个可以编排、可持久化、可中断、可恢复的状态机。 这也是为什么我会把它看成一个更偏工程的工具,而不是一个只适合 demo 的玩具。

官方文档对 LangGraph 的定位非常明确:它是一个面向长期运行、可持久化、有状态 Agent 的低层编排框架,核心能力包括 durable execution、streaming、human-in-the-loop、memory 和 subgraphs;而且 LangChain v1 的 create_agent 本身也是运行在 LangGraph 之上。换句话说,LangChain 适合快速起步,LangGraph 适合你开始认真处理控制流和可靠性的时候。

为什么很多 Agent Demo 一进生产就变形

先说结论:大多数 Agent 不是死在“模型不够强”,而是死在“流程不够稳”。你把一个 ReAct agent 跑通,不代表你已经解决了真实业务问题。线上系统关心的通常不是模型会不会想,而是这些更不性感的问题:

  • 执行到一半挂了,能不能从中间恢复。
  • 调用外部工具前,能不能先让人审核。
  • 长任务跨多个回合,状态怎么保存。
  • 不同步骤之间,哪些信息该共享,哪些不该共享。
  • 复杂任务是让一个大 Agent 全包,还是拆成多个可控节点。

LangGraph 对这些问题的回答,不是“给你一个更聪明的 prompt”,而是给你一套图结构运行时:用 State 管共享状态,用 Node 表示步骤,用 Edge 和条件路由控制执行流,再用 checkpointer 做持久化。官方文档也一直在强调这一点:LangGraph 的重点不是高层 Agent 包装,而是 agent orchestration。尤其在 v1 之后,这套 graph primitives 和运行时模型保持稳定,主打的是默认可靠性,而不是再堆一层魔法抽象。

什么时候该用 LangGraph,而不是普通 Agent API

我的判断很简单。

  • 如果你只是做一个能调用几种工具的聊天助手,用高层 agent API 往往更省事。
  • 如果你已经开始关心恢复执行、人工审批、复杂路由、多阶段状态共享、子流程复用,那就应该认真看 LangGraph。

官方文档也基本是这个意思:LangGraph 是低层能力层,适合需要 durable execution、streaming、human-in-the-loop 和更细粒度控制的场景;如果只是想快速起步,可以先用 LangChain 的 agent abstraction。这里最重要的一点不是“谁更高级”,而是你要解决的是原型问题,还是系统问题

一个真实可落地的案例:做一个带人工审批的邮件分诊 Agent

比起空讲概念,我更建议用一个小而完整的例子理解 LangGraph。这里我们用官方文档里很常见的一类场景:邮件处理。目标不是做一个“什么都懂”的超级 Agent,而是做一个可上线、可回放、可中断、可插人工审核的邮件分诊工作流。

假设系统要完成这些事:

  • 读取一封用户邮件。
  • 判断这是售后、退款、销售咨询,还是普通问题。
  • 如果风险高,比如涉及退款或法律措辞,先暂停,等人工批准。
  • 批准后调用不同工具,比如创建工单、写 CRM 记录、生成回复草稿。
  • 任何一步失败,都能从上次状态恢复。

这类任务特别适合 LangGraph,因为它不只是“模型 + 工具”这么简单,而是一个明确的状态流。

第一步:先设计 State,不要先设计 prompt

很多人上来先写 prompt,这是做 demo 的思路。做 LangGraph,应该反过来:先定义状态。因为状态决定了后续节点之间怎么协作,也决定了哪些信息会被持久化。

from typing import TypedDict, Literal, Optional

class EmailState(TypedDict, total=False):
    email_id: str
    raw_email: str
    category: Literal["support", "refund", "sales", "other"]
    risk_level: Literal["low", "medium", "high"]
    draft_reply: str
    ticket_id: str
    crm_note_id: str
    approved: bool
    error: str

这一步非常关键。State 不是顺手放几个变量,它是你的 Agent 系统边界。 哪些字段要被保存,哪些字段要给后续节点读,哪些字段会影响路由,都应该在这里想清楚。

第二步:把节点写成“窄职责”,而不是“大杂烩 Agent”

LangGraph 最适合的写法,不是让一个节点又分类、又做风险判断、又调工具、又写回复。更稳的做法是把职责拆开,让每个节点只做一件相对清晰的事。

def classify_email(state: EmailState) -> dict:
    # 调模型,产出 category 和 risk_level
    return {
        "category": "refund",
        "risk_level": "high"
    }


def draft_reply(state: EmailState) -> dict:
    return {
        "draft_reply": "我们已经收到您的退款请求,正在处理中。"
    }


def create_ticket(state: EmailState) -> dict:
    return {
        "ticket_id": "TICKET-1024"
    }

这样做的好处是,出了问题更好调试,单个节点也更容易单测。工程里最怕的是一个“全能节点”,看起来省代码,实际上把 prompt、工具调用、业务规则和异常处理全糊在一起,后面几乎没法维护。

第三步:用条件路由,把“模型自由”限制在该限制的地方

这是 LangGraph 和普通 Agent 写法的一个核心区别。不是所有决策都该交给模型。有些决策应该由程序明确控制,比如高风险邮件必须进人工审批。这种地方就应该写成显式路由。

from langgraph.graph import StateGraph, START, END

workflow = StateGraph(EmailState)
workflow.add_node("classify_email", classify_email)
workflow.add_node("draft_reply", draft_reply)
workflow.add_node("create_ticket", create_ticket)

workflow.add_edge(START, "classify_email")


def route_after_classify(state: EmailState):
    if state["risk_level"] == "high":
        return "human_review"
    return "draft_reply"

workflow.add_conditional_edges(
    "classify_email",
    route_after_classify,
    {
        "human_review": "human_review",
        "draft_reply": "draft_reply"
    }
)

这类写法背后的思路很值得借鉴:让模型负责生成判断,让系统负责执行规则。 很多 Agent 项目之所以后期一团乱,就是因为连业务硬规则都想让模型自己“理解”。这在 demo 里看着很聪明,在生产里通常很危险。

第四步:人工审批不要自己瞎造轮子,直接用 interrupt

LangGraph 一个非常实用的能力是 human-in-the-loop。官方文档里给出的机制很直接:当节点里调用 interrupt() 时,图会暂停,状态会通过 persistence 层保存下来,等外部输入回来后再恢复执行。这比很多团队自己拼 webhook + 数据库 + 状态标记靠谱得多。

from langgraph.types import interrupt


def human_review(state: EmailState) -> dict:
    decision = interrupt({
        "email_id": state["email_id"],
        "risk_level": state["risk_level"],
        "draft_reply": state.get("draft_reply", "")
    })
    return {"approved": decision["approved"]}

这里最重要的工程点是:想做人工审批,就一定要配 checkpointer。 官方文档明确说明 human-in-the-loop 依赖 persistence,因为系统必须能在中断后安全恢复。很多人看到 interrupt 很兴奋,结果没把持久化层接好,最后暂停是能暂停,恢复全靠运气。

第五步:持久化不是可选增强,而是 Agent 进入真实业务的入场券

这是 LangGraph 和很多轻量 Agent 库最拉开差距的地方。官方 persistence 文档写得很明白:checkpointer 不只是为了 memory,它还承担线程级状态保存、恢复执行、支持 human-in-the-loop 等职责。短期记忆本质上也是状态的一部分,会随线程一起被持久化。

from langgraph.checkpoint.memory import MemorySaver

checkpointer = MemorySaver()
app = workflow.compile(checkpointer=checkpointer)

实际生产里你当然不会一直用内存版 checkpointer,但这个例子足够说明问题:一旦你需要恢复、回放、人工介入、长任务分段执行,持久化就不再是“优化项”,而是基础设施。

Subgraph 才是复杂 Agent 系统真正该学的东西

很多人聊 LangGraph 时,注意力都放在“图”本身,但我觉得更值得学的是 subgraph。官方文档对 subgraph 的定义很直接:一个 graph 可以作为另一个 graph 的节点使用。这件事看起来只是代码组织,实际上它决定了你的系统以后能不能扩展。

比如上面的邮件系统,完全可以把“生成回复草稿”做成一个独立子图,内部再拆成:

  • 提取关键诉求。
  • 查历史订单或上下文。
  • 生成回复草稿。
  • 做语气和合规检查。

主图不需要知道子图内部怎么实现,只要知道输入输出。这种结构很适合团队协作,也很适合后面把某个子流程单独优化。真正复杂的 Agent 系统,最后都不是一个大图,而是一组能复用的子图。

Deep Agents 值得看,但别把它当银弹

最近 LangChain 体系里也在推 Deep Agents。官方文档给出的方向很明确:通过内置 task 工具生成子代理,做上下文隔离、子任务拆分和长期记忆。这条路线很适合复杂 research、规划、文件系统操作之类任务。

但我自己的判断是:Deep Agents 很适合探索复杂任务,不适合拿来替代一切显式工作流。 当你的业务里存在硬规则、审批节点、明确 SLA、确定性分支时,LangGraph 的显式 graph 仍然更可靠。能编排的地方尽量编排,必须开放探索的地方再交给 agent autonomy,这个边界感很重要。

我建议的 LangGraph 落地方法

如果你准备在项目里认真用 LangGraph,我建议按这个顺序推进:

  • 先定义 State,明确哪些字段真的要跨步骤共享。
  • 把节点写窄,每个节点只负责一种清晰职责。
  • 把硬业务规则写成路由,不要交给模型瞎猜。
  • 尽早接 checkpointer,不要等出故障才补。
  • 对高风险步骤优先接 human-in-the-loop。
  • 复杂流程尽早拆成 subgraph,别等一个大图长成泥球。

这套方法的核心不是“把图画漂亮”,而是让 Agent 系统逐步具备软件系统该有的可维护性。

LangGraph 适合谁,不适合谁

它很适合:

  • 已经不满足于聊天式 Agent,开始做流程型 Agent 的团队。
  • 需要恢复执行、人工审核、长任务持久化的系统。
  • 想把“模型能力”和“业务控制”拆开的开发者。

它不太适合:

  • 只想两小时内搭个工具调用 demo 的人。
  • 还没搞清楚任务边界,就先上多节点多子图架构的人。
  • 希望框架替自己自动解决系统设计问题的人。

说到底,LangGraph 不是让 Agent “更神”,而是让 Agent 更像一个能被工程团队接管的系统

结论

如果只让我给一个判断,我会说:LangGraph 最值得投入时间的地方,不是它能把 Agent 变复杂,而是它能把复杂 Agent 变得可控。

在今天这个阶段,很多团队并不缺一个能调用工具的 LLM 代理,缺的是一个出了问题能恢复、关键步骤能审核、长任务能持续运行、结构上还能继续扩展的 Agent 系统。LangGraph 在这件事上,确实提供了一套比“继续堆 prompt”和“继续包一层 agent loop”更靠谱的答案。

我的建议是重度关注,但别盲目上复杂图。先从一个具体流程切入,比如客服分诊、工单处理、内容审核、销售线索处理,把 State、路由、持久化、人工审核这四件事真正跑通。你会很快发现,Agent 真正难的不是会不会思考,而是能不能稳定地把事情做完。

参考资料

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇