基础图结构
构建你的第一个 LangGraph 应用,理解图、节点和边的核心概念
📚 学习目标
学完这篇文章后,你将能够:
- 理解 StateGraph 的核心架构
- 掌握如何使用 Annotation 定义图的状态
- 学会创建**节点(Node)**来处理逻辑
- 学会使用**边(Edge)**连接节点构建工作流
前置知识
在开始学习之前,你需要:
- 了解基础的 TypeScript 语法
- 已完成项目的环境配置(安装依赖等)
1️⃣ LangGraph 的核心概念
LangGraph 是基于图论(Graph Theory)构建的。一个典型的 LangGraph 应用包含以下三个核心要素:
- State(状态):在图的各个节点之间传递的数据结构。
- Node(节点):执行具体逻辑的函数(如处理输入、调用 LLM)。
- 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
}💡 练习题
- 修改代码:尝试添加一个新的节点
loggingNode,把它放在inputNode和validateOutputNode之间,用来打印当前的状态。 - 思考:如果在
inputNode中不返回step字段,最终结果里的step会是什么?(提示:这取决于是否设置了默认值,下一章我们将深入讲解状态管理)。
📚 参考资源
官方文档
项目代码
- 查看本节完整代码:quick-start/1.graph.ts
✅ 总结
核心要点:
- StateAnnotation 用于定义状态的形状。
- Nodes 是处理业务逻辑的函数,通过返回对象来更新状态。
- Edges (特别是
START和END) 定义了节点的执行顺序。 compile()将定义好的图转换为可执行的应用。
下一步:在下一篇文章《状态管理详解》中,我们将学习如何处理更复杂的状态更新逻辑,比如数组追加和数值累加。
登录以继续阅读
解锁完整文档、代码示例及更多高级功能。