核心组件详解

图结构详解

深入了解 StateGraph 和 MessageGraph,掌握图的创建、编译和可视化流程

📚 学习目标

学完这篇文章后,你将能够:

  • 深刻理解 StateGraph 的核心作用
  • 掌握图的编译过程及其重要性
  • 学会使用 Mermaid 可视化你的图结构
  • 了解不同类型图结构的适用场景

前置知识

在开始学习之前,建议先阅读:

你需要了解:

  • JavaScript/TypeScript 基础
  • 基本的数据结构(图、节点、边)

引言

在 LangGraphJS 中,图(Graph) 是整个框架的核心概念。如果你熟悉前端开发中的状态管理(如 Redux)或者组件树结构(如 React),那么理解 LangGraph 的图结构会相对容易。

图结构本质上是一个有向图,它定义了你的 AI 应用的执行流程。与传统的链式结构不同,图结构允许 LLM 动态决定下一步的执行路径,这为构建智能代理提供了强大的灵活性。

💡 与前端开发的类比

  • 图结构 ≈ React 应用的组件树 + 路由系统
  • 状态管理 ≈ Redux Store 或 React Context
  • 编译过程 ≈ Webpack/Vite 的构建过程

1 图(Graph)的核心地位

在 LangGraph 应用中,是核心容器,它将状态、节点和边组织在一起,形成一个可执行的单元。

类比理解

前端概念LangGraph 概念说明
Component TreeGraph应用的整体结构
Redux StoreState全局数据存储
ComponentNode逻辑单元
RouterEdge导航控制

2 主要图类

StateGraph(推荐)

StateGraph 是最通用的图类,允许你定义强类型的状态结构。

import { StateGraph, Annotation } from '@langchain/langgraph';

// 1. 定义状态
const StateAnnotation = Annotation.Root({
  count: Annotation<number>(),
  history: Annotation<string[]>(),
});

// 2. 创建图
const graph = new StateGraph(StateAnnotation);

特点

  • ✅ 类型安全
  • ✅ 高度灵活
  • ✅ 支持复杂状态逻辑

MessageGraph

MessageGraphStateGraph 的特化版本,状态固定为消息数组。

import { MessageGraph } from '@langchain/langgraph';

const graph = new MessageGraph();

适用场景

  • 🤖 简单的聊天机器人
  • 💬 仅需传递消息的链式调用
  • 🚀 快速原型开发

ℹ️ 选择建议

对于大多数应用场景,推荐使用 StateGraph,因为它提供了更大的灵活性和扩展性。


3 编译过程(Compile)

图必须经过编译才能变为可执行的 Runnable

const app = graph.compile();

编译做了什么?

  1. 结构验证:检查是否有孤立节点、死循环(非预期)等。
  2. 状态绑定:将 StateAnnotation 绑定到每个节点。
  3. 运行时配置:注入 CheckpointSaver(用于持久化)等。
  4. 类型检查:确保状态和节点的类型一致性。
  5. 优化处理:为执行做准备。

编译选项

const app = graph.compile({
  checkpointer: new MemorySaver(), // 启用记忆功能
  interruptBefore: ['human_review'], // 在特定节点前暂停
  interruptAfter: ['critical_decision'], // 在特定节点后暂停
});

📝 代码示例

让我们通过一个完整的示例来理解图结构的创建和使用:

import { StateGraph, Annotation, START, END } from '@langchain/langgraph';

const StateAnnotation = Annotation.Root({
  input: Annotation<string>(),
  output: Annotation<string>(),
  step: Annotation<number>(),
  isProcessed: Annotation<boolean>(),
});

const inputNode = (state: typeof StateAnnotation.State) => {
  console.log('%c Line:12 🍭 state', 'color:#6ec1c2', state.input);
  return {
    step: 1,
    output: `处理后的数据:${state.input}`,
    isProcessed: true,
  };
};

const validateOutputNode = (state: typeof StateAnnotation.State) => {
  console.log('%c Line:22 🧀 state', 'color:#f5ce50', state);
  return {
    step: state.step + 1,
    output: `${state.output}    [已验证]`,
  };
};

const graph = new StateGraph(StateAnnotation)
  .addNode('inputNode', inputNode)
  .addNode('validateOutputNode', validateOutputNode)
  .addEdge(START, 'inputNode')
  .addEdge('inputNode', 'validateOutputNode')
  .addEdge('validateOutputNode', END)
  .compile();

graph.invoke({ input: '你好' }).then((res) => {
  console.log('%c Line:39 🥤 res', 'color:#42b983', res);
});

4 可视化与调试

LangGraph 提供了生成 Mermaid 图表的能力,帮助你直观地理解图结构。

代码生成图表

import { StateGraph } from '@langchain/langgraph';

// ... 构建图的代码 ...

const app = graph.compile();

// 获取 Mermaid 源码
const mermaidSource = app.getGraph().drawMermaid();
console.log(mermaidSource);

典型结构可视化

线性结构

分支结构

循环结构(Agent)


🎨 实践指导

1. 创建你的第一个图

import { StateGraph, Annotation, START, END } from '@langchain/langgraph';

// 1. 定义状态结构
const StateAnnotation = Annotation.Root({
  input: Annotation<string>(),
  output: Annotation<string>(),
  step: Annotation<number>({
    default: () => 0,
  }),
});

// 2. 创建图构建器
const graphBuilder = new StateGraph(StateAnnotation);

// 3. 添加节点和边
graphBuilder
  .addNode('process', processNode)
  .addEdge(START, 'process')
  .addEdge('process', END);

// 4. 编译图
const graph = graphBuilder.compile();

2. 状态设计最佳实践

// ✅ 好的状态设计
const StateAnnotation = Annotation.Root({
  // 基础数据
  messages: Annotation<BaseMessage[]>({
    reducer: messagesStateReducer,
    default: () => [],
  }),

  // 业务状态
  userInfo: Annotation<UserInfo>(),
  currentStep: Annotation<string>(),

  // 控制标志
  isComplete: Annotation<boolean>({
    default: () => false,
  }),
});

// ❌ 避免的状态设计
const BadStateAnnotation = Annotation.Root({
  // 避免嵌套过深的对象
  complexNestedData: Annotation<{
    level1: { level2: { level3: any } };
  }>(),

  // 避免存储函数或不可序列化的对象
  callback: Annotation<Function>(),
});

3. 图结构模式

线性流程

// 适用于:数据处理管道、简单工作流
graph
  .addEdge(START, 'step1')
  .addEdge('step1', 'step2')
  .addEdge('step2', 'step3')
  .addEdge('step3', END);

条件分支

// 适用于:智能路由、决策系统
graph.addConditionalEdges('decision', routingFunction, {
  path_a: 'nodeA',
  path_b: 'nodeB',
  end: END,
});

循环结构

// 适用于:迭代优化、多轮对话
graph
  .addConditionalEdges('check', shouldContinue, {
    continue: 'process',
    finish: END,
  })
  .addEdge('process', 'check');

4. 编译时配置

// 基础编译
const graph = graphBuilder.compile();

// 带检查点的编译(支持持久化)
import { MemorySaver } from '@langchain/langgraph';

const graph = graphBuilder.compile({
  checkpointer: new MemorySaver(),
});

// 带断点的编译(调试用)
const graph = graphBuilder.compile({
  breakpoints: ['nodeA', 'nodeB'],
});

🚀 高级特性

1. 多图组合

// 子图作为节点
const subGraph = subGraphBuilder.compile();

const mainGraph = new StateGraph(StateAnnotation)
  .addNode('subProcess', subGraph)
  .compile();

2. 动态图构建

// 根据配置动态添加节点
const buildGraph = (config: GraphConfig) => {
  const builder = new StateGraph(StateAnnotation);

  config.nodes.forEach((nodeConfig) => {
    builder.addNode(nodeConfig.name, nodeConfig.handler);
  });

  config.edges.forEach((edgeConfig) => {
    builder.addEdge(edgeConfig.from, edgeConfig.to);
  });

  return builder.compile();
};

❓ 常见问题解答

Q: StateGraph 和 MessageGraph 的主要区别是什么?

A: 主要区别在于状态结构的复杂度:

  • StateGraph:支持复杂的自定义状态结构,适用于大多数应用场景
  • MessageGraph:状态仅为消息数组,适用于简单的聊天场景

Q: 为什么必须编译图才能使用?

A: 编译过程执行以下重要任务:

  • 验证图结构的完整性和正确性
  • 进行类型检查和优化
  • 应用运行时配置(检查点、断点等)
  • 为执行做准备和优化

Q: 如何处理图执行中的错误?

A: 可以通过以下方式处理错误:

try {
  const result = await graph.invoke(input);
} catch (error) {
  if (error instanceof GraphRecursionError) {
    // 处理递归限制错误
  } else {
    // 处理其他错误
  }
}

💡 练习题

  1. 思考题:为什么 StateGraphMessageGraph 更适合复杂的企业级应用?

    点击查看答案

    StateGraph 可定义多字段结构化状态和自定义 reducer,适合复杂业务数据流。 MessageGraph 更偏消息序列场景,扩展复杂业务字段时约束较多。

  2. 操作题:使用 getGraph().drawMermaid() 方法,尝试打印出上一章“环境搭建”中示例代码的图结构。

    点击查看答案

    在 compile 后执行 console.log(app.getGraph().drawMermaid()) 即可得到图源码。 你应至少看到 START -> llmNode -> END 的主干结构。


✅ 总结

本章要点

  • 图是将业务逻辑组织成可执行流的容器
  • StateGraph 是主要的图类,支持复杂状态管理
  • compile() 是图从定义到运行的必经之路
  • 可视化是调试和沟通 LangGraph 架构的最佳工具

实践建议

  • 优先使用 StateGraph 而非 MessageGraph
  • 合理设计状态结构,保持简洁和类型安全
  • 充分利用编译时配置来增强功能(checkpointer、interruptBefore/After)
  • 使用 drawMermaid() 方法可视化图结构,便于调试和团队沟通

下一步:了解了图的骨架,我们需要填充血肉——状态管理

登录以继续阅读

解锁完整文档、代码示例及更多高级功能。

立即登录

On this page