Skip to content

LangGraph 思维模式:5 步构建 AI Agent 方法论

简单来说

LangGraph 就是教你如何把一个复杂的 AI 任务拆成"流水线工序",每个工序干一件事、共享一块"公告板"来传递信息,然后按规则决定下一步干啥。本质上是让你的 AI Agent 从"一团乱麻"变成"井井有条的流程图"。


🎯 本节目标

学完本节,你将能够:

  • 掌握 LangGraph 的 5 步构建方法论
  • 理解 Node、State、Edge、Command 的设计原则
  • 学会 4 种错误处理策略
  • 能够独立设计一个完整的 Agent 架构

核心痛点与解决方案

痛点:AI 做复杂任务时像没头苍蝇

想象一下:你让一个 AI 处理客服邮件,它要同时考虑:

  • 这封邮件在说什么?
  • 紧急程度如何?
  • 要不要查文档?
  • 要不要创建 Bug 工单?
  • 需不需要人工介入?
  • 最后怎么回复?

如果不做任何架构设计,你的代码可能会变成这样:

typescript
if (这个) {
  then 那个
} else if (另一个) {
  then 又一个
} else if (...) {
  // 无限嵌套...
}

典型的"面条代码",调试噩梦。

痛点具体表现
逻辑混乱一个巨大的 if-else 函数,改一处动全身
状态乱飞中间数据到处传,不知道谁用了什么
无法恢复出错了只能从头再来,浪费算力
调试困难打断点打到怀疑人生

解决:LangGraph 的分而治之

痛点LangGraph 的解法
逻辑混乱把流程拆成独立的 Node(节点),每个节点只干一件事
状态乱飞用统一的 State(状态) 作为"公告板",所有数据都贴在这
无法恢复Checkpointer(检查点) 保存进度,失败可从断点恢复
调试困难每个节点的输入输出清清楚楚,配合 LangSmith 可视化

LangGraph 痛点与解法对照


生活化类比:专业客服中心

想象你开了一家客服中心,每天收到海量客户邮件。你不可能让一个人从头到尾处理所有事情,所以你设计了一套流水线:

                        [ 分拣员小王 ]

         ┌────────────────────┼────────────────────┐
         │                    │                    │
  [ 查文档的小李 ]      [ 记 Bug 的小张 ]      [ 主管老陈 ]
         │                    │                    │
         └────────────────────┼────────────────────┘

                        [ 写回复的小美 ]

              ┌───────────────┴───────────────┐
              │                               │
       [ 主管老陈审批 ]                  [ 直接发送 ]

LangGraph 概念对照表:

LangGraph 概念客服中心类比具体作用
Node(节点)每个工位上的员工小王负责分类、小李负责查文档、小美负责写回复
State(状态)流转的工单夹里面夹着客户邮件原文、分类结果、查到的资料、草稿回复
Edge(边)工单传递路线小王分类完给小李/小张/老陈
Command(命令)工单上的批注"分类完毕,这是技术问题,转给小李查文档"
interrupt()等待主管签字主管不在?先把工单放着,等主管回来继续
Checkpointer每个工位的存档柜万一停电了,恢复后从最近完成的工位继续

客服中心流水线类比


5 步构建方法论

Step 1:画出工作流程图

首先,把你要自动化的流程可视化出来。

示例需求:构建一个客服邮件处理 Agent

用户需求:
1. 读取客户邮件
2. 分类(紧急程度、问题类型)
3. 简单问题 → 查文档
4. Bug 报告 → 创建工单
5. 紧急/复杂问题 → 人工介入
6. 起草回复
7. 高优先级需审核后发送

画成流程图:

     START


   ┌──────────┐
   │ 读取邮件  │
   └────┬─────┘


   ┌──────────┐
   │ 分类意图  │
   └────┬─────┘

   ┌────┼────┬────────────┐
   │    │    │            │
   ▼    ▼    ▼            ▼
 查文档  Bug  人工审核   直接起草
   │   工单    │           │
   │    │      │           │
   └────┴──────┴───────────┘


              ┌──────────┐
              │ 起草回复  │
              └────┬─────┘

            ┌──────┴──────┐
            │             │
            ▼             ▼
       人工审核       直接发送
            │             │
            └──────┬──────┘


                  END

💡 关键洞察

  • 有些节点做决策(分类意图、起草回复决定是否需要审核)
  • 有些节点做执行(查文档、发送邮件)
  • 先画图,再写代码

客服邮件处理 Agent 工作流

Step 2:识别每个节点的类型

不同类型的节点需要不同的处理方式:

节点类型特点示例
LLM 步骤需要理解、分析、生成文本分类意图、起草回复
数据步骤从外部获取信息查文档、查客户历史
动作步骤执行外部操作发送邮件、创建工单
人工步骤需要人类介入审核高优先级回复

为每个节点定义:

typescript
// LLM 步骤
classifyIntent: {
  静态上下文: "分类标准、紧急程度定义",
  动态上下文: "邮件内容、发件人信息",
  期望输出: "结构化的分类结果"
}

// 数据步骤
searchDocumentation: {
  参数: "从意图和主题构建查询",
  重试策略: "是,指数退避",
  缓存: "常见查询可缓存"
}

// 动作步骤
sendReply: {
  执行时机: "审核通过后",
  重试策略: "是,网络问题重试",
  不可缓存: "每次发送都是唯一操作"
}

// 人工步骤
humanReview: {
  上下文: "原邮件、草稿回复、紧急程度",
  期望输入: "通过/拒绝 + 可选的修改内容",
  触发条件: "高优先级、复杂问题"
}

四种节点类型分类

Step 3:设计 State(状态)

State 是所有节点共享的"公告板",是整个系统的核心。

设计原则:只存原始数据,不存格式化文本

typescript
import { StateSchema } from "@langchain/langgraph";
import * as z from "zod";

const EmailClassificationSchema = z.object({
  intent: z.enum(["question", "bug", "billing", "feature", "complex"]),
  urgency: z.enum(["low", "medium", "high", "critical"]),
  topic: z.string(),
  summary: z.string(),
});

const EmailAgentState = new StateSchema({
  emailContent: z.string(),
  senderEmail: z.string(),
  emailId: z.string(),
  
  classification: EmailClassificationSchema.optional(),
  
  searchResults: z.array(z.string()).optional(),
  customerHistory: z.record(z.string(), z.any()).optional(),
  
  responseText: z.string().optional(),
});

💡 人话解读:

"我定义了一个工单夹,里面可以放:邮件原文、发件人、分类结果、查到的资料、草稿回复。有些格子一开始是空的(optional),后面的工位会填上。"

为什么只存原始数据?

存原始数据存格式化文本
不同节点可以用不同方式展示格式固定,难以复用
改提示词不用改状态结构改格式要改状态定义
调试时看到真实数据调试时看到加工后的内容

Step 4:构建节点函数

节点就是一个简单的函数:读取状态 → 干活 → 返回更新

分类节点示例:

typescript
import { Command, GraphNode } from "@langchain/langgraph";
import { ChatAnthropic } from "@langchain/anthropic";

const llm = new ChatAnthropic({ model: "claude-sonnet-4-5-20250929" });

const classifyIntent: GraphNode<typeof EmailAgentState> = async (state) => {
  const structuredLlm = llm.withStructuredOutput(EmailClassificationSchema);
  
  const classificationPrompt = `
    分析这封客户邮件并分类:
    
    邮件内容: ${state.emailContent}
    发件人: ${state.senderEmail}
    
    请提供意图、紧急程度、主题和摘要。
  `;
  
  const classification = await structuredLlm.invoke(classificationPrompt);
  
  let nextNode: string;
  if (classification.intent === "billing" || classification.urgency === "critical") {
    nextNode = "humanReview";
  } else if (classification.intent === "question" || classification.intent === "feature") {
    nextNode = "searchDocumentation";
  } else if (classification.intent === "bug") {
    nextNode = "bugTracking";
  } else {
    nextNode = "draftResponse";
  }
  
  return new Command({
    update: { classification },
    goto: nextNode,
  });
};

💡 人话解读:

"分拣员小王的工作:用 AI 判断这封邮件是什么类型、紧不紧急。然后根据情况派单:

  • 紧急账单问题?直接找主管!
  • 普通问题?先去查查资料
  • 说是 Bug?建个工单追踪
  • 其他情况?直接写回复"

人工审核节点示例:

typescript
import { interrupt } from "@langchain/langgraph";

const humanReview: GraphNode<typeof EmailAgentState> = async (state) => {
  const humanDecision = interrupt({
    originalEmail: state.emailContent,
    draftResponse: state.responseText,
    urgency: state.classification?.urgency,
    action: "请审核这封回复",
  });
  
  if (humanDecision.approved) {
    return new Command({
      update: { responseText: humanDecision.editedResponse || state.responseText },
      goto: "sendReply",
    });
  } else {
    return new Command({ update: {}, goto: END });
  }
};

💡 人话解读:

"到了主管老陈这里:

  1. 先把工单放他桌上(interrupt),然后整个流水线暂停
  2. 老陈啥时候回来、看完、签字,流水线才继续
  3. 签字同意?往下送去发送
  4. 不同意?这单结束,他自己处理"

Command 路由与 interrupt 暂停机制

Step 5:连接节点成图

最后一步:把所有节点连起来。

typescript
import { StateGraph, START, END, MemorySaver } from "@langchain/langgraph";

const workflow = new StateGraph(EmailAgentState)
  .addNode("readEmail", readEmail)
  .addNode("classifyIntent", classifyIntent)
  .addNode("searchDocumentation", searchDocumentation, { 
    retryPolicy: { maxAttempts: 3 } 
  })
  .addNode("bugTracking", bugTracking)
  .addNode("draftResponse", draftResponse)
  .addNode("humanReview", humanReview)
  .addNode("sendReply", sendReply)
  
  .addEdge(START, "readEmail")
  .addEdge("readEmail", "classifyIntent")
  .addEdge("sendReply", END);

const memory = new MemorySaver();
const app = workflow.compile({ checkpointer: memory });

💡 人话解读:

"把所有工位连起来:

  • 起点 → 读邮件 → 分类(分类后各自决定去哪)
  • 发送完毕 → 终点
  • 查文档工位如果网络抖动,自动重试 3 次
  • 整条线开启自动存档功能"

注意:图结构很简洁,因为路由逻辑在节点内部通过 Command 处理。


错误处理四象限

不同的错误需要不同的处理策略:

错误类型谁来修策略代码示例
短暂错误系统自动重试策略网络抖动、API 限流
LLM 可恢复AI 自己存错误到 State,让 AI 重试工具调用失败
需要用户人类interrupt() 暂停缺少账户 ID
意外错误开发者直接抛出未知 Bug

1. 短暂错误:自动重试

typescript
workflow.addNode(
  "searchDocumentation",
  searchDocumentation,
  { retryPolicy: { maxAttempts: 3, initialInterval: 1.0 } }
);

2. LLM 可恢复:存错误让 AI 看到

typescript
const executeTool: GraphNode<typeof State> = async (state) => {
  try {
    const result = await runTool(state.toolCall);
    return new Command({
      update: { toolResult: result },
      goto: "agent",
    });
  } catch (error) {
    return new Command({
      update: { toolResult: `工具错误: ${error}` },
      goto: "agent"
    });
  }
};

3. 需要用户:暂停等待

typescript
const lookupCustomer: GraphNode<typeof State> = async (state) => {
  if (!state.customerId) {
    const userInput = interrupt({
      message: "需要客户 ID",
      request: "请提供客户的账户 ID",
    });
    return new Command({
      update: { customerId: userInput.customerId },
      goto: "lookupCustomer",
    });
  }
  // 继续处理...
};

4. 意外错误:直接抛出

typescript
const sendReply: GraphNode<typeof State> = async (state) => {
  try {
    await emailService.send(state.responseText);
  } catch (error) {
    throw error;  // 让开发者去修
  }
};

错误处理四象限矩阵


真实场景案例

场景 1:简单问题(全自动)

用户:"怎么重置密码?"

读邮件 → 分类(问题类) → 查FAQ文档 → 起草回复 → 直接发送

全程自动,3 秒搞定。

场景 2:紧急问题(人工介入)

用户:"我被扣了两次钱!!!"

读邮件 → 分类(紧急+账单) → 【暂停等主管】

主管上线 → 审核/修改回复 → 恢复发送

系统不会傻傻地自动回复敏感问题,而是等人工介入。

场景 3:服务器故障恢复

正在查文档时,数据库宕机了

读邮件 [存档] → 分类 [存档] → 查文档 [失败!]

                            服务器恢复后

                            从"查文档"重试(不用从头来)

这就是 Checkpointer 的威力。


设计原则总结

原则 1:一个节点只干一件事

好处:

  • 调试方便(知道是哪个环节出问题)
  • 恢复精确(不用重做已完成的工作)
  • 可复用(同一个查文档节点可以用在多个流程)

原则 2:State 只存原始数据

好处:

  • 灵活格式化(不同节点可以用不同方式展示同一数据)
  • 便于调试(看到的是原始数据,不是加工后的提示词)
  • 易于演进(改提示词不用改状态结构)

原则 3:节点自己决定下一步

好处:

  • 逻辑内聚(分类逻辑和路由逻辑放一起)
  • 图结构简洁(不用画一堆条件边)
  • 可追踪(看节点代码就知道它能去哪)

一图总结

┌─────────────────────────────────────────────────────────────┐
│                    LangGraph 5 步方法论                       │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   Step 1: 画流程图                                          │
│       ↓                                                     │
│   Step 2: 识别节点类型(LLM/数据/动作/人工)                   │
│       ↓                                                     │
│   Step 3: 设计 State(只存原始数据)                          │
│       ↓                                                     │
│   Step 4: 实现节点函数(Command 控制路由)                     │
│       ↓                                                     │
│   Step 5: 连接成图(addEdge + compile)                      │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│                      错误处理策略                             │
│                                                             │
│   短暂错误 ──> retryPolicy(自动重试)                        │
│   LLM 错误 ──> 存进 State,让 AI 看到                        │
│   需要人工 ──> interrupt()(暂停等待)                        │
│   意外错误 ──> throw(开发者修复)                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

LangGraph 5步方法论总览


核心要点回顾

  1. 5 步方法论:画图 → 识别类型 → 设计 State → 实现节点 → 连接成图
  2. 节点原则:每个节点只做一件事,通过 Command 决定下一步
  3. 状态原则:只存原始数据,在节点内按需格式化
  4. 错误四象限:不同错误不同处理,让对的人/系统修对的错误
  5. 核心思想:分而治之,让复杂系统变得可控、可调试、可恢复

下一步学习

掌握了思维模式,接下来深入 API:


📅 更新时间:2026-02-22

读文档、看源码、写代码,理解 AI Agent 本质 🤖