基础图结构

构建你的第一个 LangGraph 应用,理解图、节点和边的核心概念

📚 学习目标

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

  • 理解 StateGraph 的核心架构
  • 掌握如何使用 Annotation 定义图的状态
  • 学会创建**节点(Node)**来处理逻辑
  • 学会使用**边(Edge)**连接节点构建工作流

前置知识

在开始学习之前,你需要:

  • 了解基础的 TypeScript 语法
  • 已完成项目的环境配置(安装依赖等)

1️⃣ LangGraph 的核心概念

LangGraph 是基于图论(Graph Theory)构建的。一个典型的 LangGraph 应用包含以下三个核心要素:

  1. State(状态):在图的各个节点之间传递的数据结构。
  2. Node(节点):执行具体逻辑的函数(如处理输入、调用 LLM)。
  3. Edge(边):定义节点之间的连接关系,决定控制流的走向。

想象一下,LangGraph 就像一个工厂流水线。State 是传送带上的货物,Node 是加工货物的工人,Edge 则是传送带的轨道。

2️⃣ 定义状态(State)

一切从定义状态开始。我们需要告诉 LangGraph,在这个工作流中流通的数据长什么样。

我们使用 Annotation.Root 来定义状态结构:

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

// 定义状态结构
const StateAnnotation = Annotation.Root({
    // 用户输入,类型为 string
    input: Annotation<string>(),
    
    // 处理结果,类型为 string
    output: Annotation<string>(),
    
    // 当前步骤,类型为 number
    step: Annotation<number>(),
    
    // 是否已处理,类型为 boolean
    isProcessed: Annotation<boolean>()
});

代码解析

  • Annotation<T>() 用于指定字段的类型。
  • 这里的定义非常直观,相当于定义了一个 TypeScript 接口,但 LangGraph 能够利用它在运行时管理数据流。

3️⃣ 创建节点(Node)

节点就是普通的 JavaScript/TypeScript 函数。它们接收当前的 State,并返回需要更新的部分状态。

LangGraph 会自动将节点返回的对象与当前状态进行合并(Shallow Merge)。

/**
 * 输入处理节点
 * 接收用户输入,进行初步处理
 */
const inputNode = (state: typeof StateAnnotation.State) => {
    console.log("正在处理输入:", state.input);
    
    // 返回要更新的字段
    return {
        step: 1,
        output: `处理后的数据:${state.input}`,
        isProcessed: true
    }
}

/**
 * 验证节点
 * 对处理结果进行验证
 */
const validateOutputNode = (state: typeof StateAnnotation.State) => {
    console.log("正在验证:", state.output);
    
    // 基于上一步的 output 进行再次处理
    return {
        step: state.step + 1,
        output: `${state.output}    [已验证]`
    }
}

4️⃣ 构建图(Graph)

定义好状态和节点后,我们就像搭积木一样把它们组装起来。

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

// 1. 创建图实例
const graph = new StateGraph(StateAnnotation)
    // 2. 添加节点
    .addNode('inputNode', inputNode)
    .addNode('validateOutputNode', validateOutputNode)

    // 3. 添加边(连接节点)
    // START 是图的入口
    .addEdge(START, 'inputNode')
    
    // 从 inputNode 流向 validateOutputNode
    .addEdge('inputNode', 'validateOutputNode')
    
    // validateOutputNode 完成后,流向 END(结束)
    .addEdge('validateOutputNode', END)

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

下面的 Mermaid 图展示了这个简单的工作流:

5️⃣ 运行图

最后,我们使用 invoke 方法来运行我们构建的图。我们需要传入初始状态。

async function runDemo() {
    // 传入初始状态,只需包含必要的字段(如 input)
    const res = await basicGraph.invoke({ input: '你好' });
    
    console.log("最终结果:", res);
}

runDemo();

运行结果可能如下所示:

正在处理输入: 你好
正在验证: 处理后的数据:你好
最终结果: {
  input: '你好',
  step: 2,
  output: '处理后的数据:你好    [已验证]',
  isProcessed: true
}

💡 练习题

  1. 修改代码:尝试添加一个新的节点 loggingNode,把它放在 inputNodevalidateOutputNode 之间,用来打印当前的状态。
  2. 思考:如果在 inputNode 中不返回 step 字段,最终结果里的 step 会是什么?(提示:这取决于是否设置了默认值,下一章我们将深入讲解状态管理)。

📚 参考资源

官方文档

项目代码


✅ 总结

核心要点

  • StateAnnotation 用于定义状态的形状。
  • Nodes 是处理业务逻辑的函数,通过返回对象来更新状态。
  • Edges (特别是 STARTEND) 定义了节点的执行顺序。
  • compile() 将定义好的图转换为可执行的应用。

下一步:在下一篇文章《状态管理详解》中,我们将学习如何处理更复杂的状态更新逻辑,比如数组追加和数值累加。

登录以继续阅读

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

立即登录

On this page