前言

什么是 LangGraph?

深入了解 LangGraph 的定义、核心概念、设计理念以及它解决的核心问题

📚 学习目标

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

  • 理解 LangGraph 的定义和核心理念
  • 理解传统 LLM 应用面临的挑战
  • 掌握 LangGraph 的核心构建块(状态、节点、边、图)
  • 掌握 LangGraph 的核心优势(可控性、持久化等)
  • 对比 LangGraph 架构与传统链式架构的区别
  • 识别适合使用 LangGraph 的实际场景

前置知识

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

你需要了解:

  • LLM(大语言模型)的基本工作原理
  • 基本的编程逻辑和流程控制
  • 基本的 JavaScript/TypeScript 语法

1 LangGraph 的定义

引言

在构建智能应用的过程中,我们经常需要让 AI 系统能够自主决策、动态调整执行路径。传统的链式结构虽然可靠,但缺乏灵活性。LangGraph 正是为了解决这一问题而诞生的框架。

核心概念

LangGraph 是一个用于构建智能代理(Agent)应用的 JavaScript/TypeScript 框架。它将 LLM 应用的控制流程建模为图结构,其中:

  • 节点(Nodes) 代表不同的功能组件
  • 边(Edges) 代表信息流和控制流
  • 状态(State) 代表应用的当前快照

💡 核心理念

LangGraph 的核心理念是让 LLM 能够自主决定应用的执行路径,而不是按照预定义的固定步骤执行。

核心构建块

1. 状态(State)

状态是贯穿整个图执行过程的数据容器。它记录了:

  • 用户输入
  • 对话历史
  • 工具调用结果
  • 中间计算结果
// 定义状态结构
import { Annotation } from '@langchain/langgraph';

const StateAnnotation = Annotation.Root({
  messages: Annotation<string[]>({
    reducer: (prev, next) => [...prev, ...next],
  }),
  userQuery: Annotation<string>(),
  toolResults: Annotation<any[]>({
    reducer: (prev, next) => [...prev, ...next],
  }),
});

[!NOTE] 状态在整个图的执行过程中被持久化维护,这是实现多轮对话和复杂逻辑的关键。

2. 节点(Nodes)

节点是执行具体逻辑的函数单元。每个节点:

  • 接收当前状态作为输入
  • 执行特定逻辑(如调用 LLM、调用工具)
  • 返回状态更新
// 示例:分析用户查询的节点
async function analyzeQuery(state: typeof StateAnnotation.State) {
  const { userQuery } = state;

  // 调用 LLM 分析用户意图
  const analysis = await llm.invoke([
    { role: 'system', content: '分析用户查询的复杂度' },
    { role: 'user', content: userQuery },
  ]);

  // 返回状态更新
  return {
    messages: [analysis.content],
    complexity: analysis.metadata?.complexity || 'simple',
  };
}

// 示例:处理简单查询的节点
async function handleSimpleQuery(state: typeof StateAnnotation.State) {
  const { userQuery } = state;

  const response = await llm.invoke([{ role: 'user', content: userQuery }]);

  return {
    messages: [response.content],
  };
}

3. 边(Edges)

边定义了节点之间的连接关系,分为两种:

普通边(Normal Edges):固定的连接关系

graph.addEdge('nodeA', 'nodeB'); // nodeA 执行完后总是进入 nodeB

条件边(Conditional Edges):基于状态动态决定下一步

// 路由函数:根据复杂度决定下一个节点
function routeBasedOnComplexity(state: typeof StateAnnotation.State) {
  if (state.complexity === 'simple') {
    return 'simple_responder';
  } else if (state.complexity === 'tool_required') {
    return 'tool_caller';
  } else {
    return 'complex_reasoner';
  }
}

graph.addConditionalEdges('analyzer', routeBasedOnComplexity);

4. 图(Graph)

图是所有组件的容器,负责编排执行流程。

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

const graph = new StateGraph(StateAnnotation)
  // 添加节点
  .addNode('analyzer', analyzeQuery)
  .addNode('simple_responder', handleSimpleQuery)
  .addNode('tool_caller', callExternalTool)
  .addNode('complex_reasoner', handleComplexReasoning)

  // 定义边
  .addEdge(START, 'analyzer')
  .addConditionalEdges('analyzer', routeBasedOnComplexity)
  .addEdge('simple_responder', END)
  .addEdge('tool_caller', END)
  .addEdge('complex_reasoner', END)

  // 编译成可执行的应用
  .compile();

// 执行
const result = await graph.invoke({
  userQuery: '什么是 LangGraph?',
});

2 传统 LLM 应用的挑战

随着 LLM 技术的快速发展,开发者们发现传统的应用架构已经无法满足智能应用的复杂需求。

控制流固化问题

传统的 LLM 应用通常采用链式结构,执行路径是预先定义的:

问题表现:

  • 🔒 路径固定:无论用户输入什么,都按相同步骤执行
  • 🚫 缺乏适应性:无法根据上下文动态调整策略
  • 效率低下:即使简单问题也要走完整流程
  • 🔄 难以扩展:添加新功能需要重构整个流程

复杂任务处理困难

现实世界的任务往往需要多步骤协调:

传统方式的问题

// 传统链式处理复杂任务的问题
async function traditionalApproach(userQuery: string) {
  // 步骤1:总是先调用 LLM
  const analysis = await llm.invoke(userQuery);

  // 步骤2:总是尝试工具调用(即使不需要)
  const toolResult = await callTool(analysis);

  // 步骤3:总是进行最终处理
  const finalResult = await llm.invoke(`${analysis} ${toolResult}`);

  return finalResult;
}

问题:

  • 浪费资源在不必要的步骤上
  • 无法处理需要多轮交互的复杂任务
  • 错误处理困难

LangGraph 的解决方案

// LangGraph 动态处理复杂任务
const smartAgent = new StateGraph(StateAnnotation)
  .addNode('analyzer', analyzeQuery)
  .addNode('simple_responder', handleSimpleQuery)
  .addNode('tool_caller', callExternalTool)
  .addNode('complex_reasoner', handleComplexReasoning)
  .addConditionalEdges('analyzer', routeBasedOnComplexity)
  .compile();

优势:

  • 根据任务复杂度选择合适路径
  • 支持多轮交互和状态维护
  • 优雅的错误处理和恢复

状态管理缺失

传统应用难以维护对话历史和上下文,容易导致“状态丢失”,使得多轮对话变得困难,且无法准确基于之前的交互进行推理。


3 LangGraph 的核心优势

1. 可控性(Controllability)

LangGraph 让开发者能够精确控制应用流程:

关键特性:

  • 🎛️ 精确控制:开发者定义每个节点的行为
  • 🔀 灵活路由:基于状态和条件的动态路径选择
  • 🛡️ 错误处理:内置的异常处理和恢复机制

2. 持久化(Persistence)

支持状态保存和恢复,实现真正的记忆能力。

[!NOTE] 想象一个客服机器人,它能记住用户的历史问题、偏好以及当前的上下文,这就是持久化带来的威力!

(代码示例省略,请在后续章节查看详细实现)

3. 人机交互(Human-in-the-Loop)

支持在关键决策点暂停,等待人工干预。这对于敏感操作或需要人工确认的场景至关重要。

4. 流式处理(Streaming)

实时输出和响应,提升用户体验,避免用户长时间等待完整响应。


4 执行流程可视化

下面的序列图展示了 LangGraph 应用的典型执行流程:

关键点:

  • 状态在整个执行过程中被维护和传递
  • LLM 可以在决策节点决定执行路径
  • 循环和分支都是自然支持的

5 架构对比分析

传统架构 vs LangGraph 架构

特性传统链式架构LangGraph 架构
控制流固定、线性动态、图状
决策能力预定义逻辑LLM 自主决策
状态管理无状态或简单状态复杂状态管理
错误处理基础异常处理智能错误恢复
扩展性难以扩展高度可扩展
调试能力有限强大的可视化调试

6 实际应用场景与实践指导

典型场景

  • 智能客服系统:处理复杂多变的用户请求,支持多轮对话和状态记忆。
  • 代码生成助手:理解需求、生成代码、自我审查和优化。

何时选择 LangGraph?

适合使用 LangGraph 的场景:

  • ✅ 需要动态决策的应用
  • ✅ 复杂的多步骤任务
  • ✅ 需要状态管理的对话系统
  • ✅ 人机协作的工作流
  • ✅ 需要工具调用的智能代理

继续使用传统方式的场景:

  • ✅ 简单的单步处理任务
  • ✅ 高度可预测的业务流程
  • ✅ 对性能要求极高的场景

💡 练习题

  1. 选择题:LangGraph 中的节点函数通常返回什么?

    • A. 完整的全新状态对象
    • B. 部分状态更新对象
    • C. 布尔值
    • D. 空值
    点击查看答案

    正确答案是 B. 部分状态更新对象。 节点通常返回增量更新,再由 reducer 合并进全局状态。

  2. 选择题:LangGraph 相比传统链式架构的优势不包括:

    • A. 动态控制流
    • B. 内置的 AI 模型训练功能
    • C. 状态持久化
    • D. 人机交互支持
    点击查看答案

    正确答案是 B. 内置的 AI 模型训练功能。 LangGraph 关注编排与执行,不负责训练基础模型。

  3. 思考题:如果你的应用只是简单地将用户输入发送给 LLM 并直接返回结果,是否需要使用 LangGraph?为什么?

    点击查看答案

    通常不需要。单轮问答用直接 LLM 调用更轻量。 当你需要多步骤流程、状态管理、重试/中断/持久化时,再引入 LangGraph 更合适。

  4. 分析题:在上面的"执行流程可视化"流程图中,状态是在哪里被维护的?这与无状态的 API 调用有什么本质区别?

    点击查看答案

    状态由 Graph 的 State + reducer 维护,并可跨节点、跨轮次持续存在。 无状态 API 每次请求互相独立,不会天然继承上一次执行上下文。


📚 参考资源

官方文档

示例代码


✅ 总结

本章要点

  • LangGraph 的核心概念:将应用流程建模为图结构(状态、节点、边、图),提供了比传统链式结构更高的灵活性。
  • 传统架构的挑战:控制流固化、状态管理缺失、复杂任务处理困难。
  • LangGraph 的核心优势:可控性、持久化、人机交互和流式处理。
  • 架构对比:灵活性 vs 可预测性,动态控制流 vs 固定路径。
  • 技术选型:选择架构时应根据任务的复杂度和需求进行权衡。

下一步:在下一篇文章中,我们将详细拆解《核心概念》,深入每个组件的具体用法。

登录以继续阅读

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

立即登录

On this page