【langgraph 从入门到精通graphApi 篇】LangGraphAPI 方式调用 - 初识与核心概念
文章目录
- 第 1 章:LangGraph 初识与核心概念
- 1.1 本章目标
- 1.2 核心概念
- LangGraph 是什么?
- LangGraph 在 AI 生态中的位置
- 第一个 Graph 的内部结构
- 1.3 实战:你的第一个 LangGraph 程序
- 1.4 API 速查
- 1.5 错误与避坑指南
- 坑 1:忘记导入 START 和 END
- 坑 2:节点函数返回 None 而非 dict
- 坑 3:返回的 key 不在 State 中
- 坑 4:混淆 invoke() 的参数
- 1.6 最佳实践总结
第 1 章:LangGraph 初识与核心概念
1.1 本章目标
学完本章你将能够:
- 理解 LangGraph 在 AI 开发生态中的定位
- 掌握 State、Node、Edge、Graph 四大核心概念
- 独立编写并运行第一个 LangGraph 程序
1.2 核心概念
LangGraph 是什么?
在计算机科学中,图(Graph)由节点(Node)和边(Edge)组成。节点是执行任务的单元,边是连接节点的线,决定了任务执行的先后顺序。就像地铁线路图——每个站点是节点,连接站点的轨道是边。
LangGraph 是一个有状态的多步骤 AI 应用编排框架。你可以把它想象成一个智能工厂的流水线:
| 概念 | 比喻(工厂流水线) | 技术定义 |
|---|---|---|
| Graph(图) | 整个工厂的布局图 | 定义了所有节点和边的有向图结构 |
| State(状态) | 在流水线上流转的零件 | 在节点间共享的数据结构,每个节点可以读取和修改 |
| Node(节点) | 每个工位 | 执行具体操作的函数(LLM 调用、工具执行、数据处理) |
| Edge(边) | 连接工位的传送带 | 定义节点间的执行顺序和条件 |
核心公式:Nodes 做工作,Edges 决定流程,State 是纽带
LangGraph 在 AI 生态中的位置
第一个 Graph 的内部结构
1.3 实战:你的第一个 LangGraph 程序
让我们从一个最简单的例子开始:输入一个人的名字,输出一句问候语。
# ============================================# 第 1 步:导入必要的模块# ============================================fromtypingimportTypedDictfromlanggraph.graphimportStateGraph,START,END# ============================================# 第 2 步:定义 State(状态)—— 图中流转的数据结构# ============================================classState(TypedDict):""" State 是图中所有节点共享的数据结构。 使用 TypedDict 定义,提供类型安全和 IDE 提示。 这里定义了两个字段: - name: 用户输入的名字 - greeting: 生成的问候语(初始为空) """name:strgreeting:str# TypedDict 是 Python 的类型提示工具,它定义了字典中每个键对应的值类型。# LangGraph 用 TypedDict 来声明 State 的结构,这样 IDE 可以自动补全字段名,# 也能在编写代码时检查类型错误。# ============================================# 第 3 步:定义 Node(节点)—— 执行具体操作的函数# ============================================defgreet(state:State)->dict:""" 节点函数签名规则: - 参数:接收当前 State 作为输入 - 返回值:返回一个 dict,包含要更新的 State 字段 注意:只需返回要更新的字段,不需要返回完整 State! LangGraph 会自动将返回值合并到当前 State 中。 """print(f" [greet 节点] 收到名字:{state['name']}")# 从 State 中读取 name,生成问候语,返回更新return{"greeting":f"你好,{state['name']}!"}# ============================================# 第 4 步:构建 Graph(图)—— 把节点和边组合起来# ============================================# 创建 StateGraph 构建器,传入 State 类型builder=StateGraph(State)# 注册节点:给 greet 函数起名为 "greet"builder.add_node("greet",greet)# 添加边(流程控制):# START → greet → END# 表示从图入口开始,执行 greet 节点,然后结束builder.add_edge(START,"greet")builder.add_edge("greet",END)# 编译图:将构建器"冻结"为可执行的图对象graph=builder.compile()# ============================================# 第 5 步:运行 Graph# ============================================print("=== 执行 Graph ===")# invoke() 方法传入初始状态,返回最终状态result=graph.invoke({"name":"小明"})print(f"=== 结果:{result['greeting']}")# ============================================# 运行输出:# === 执行 Graph ===# [greet 节点] 收到名字: 小明# === 结果: 你好, 小明!# ============================================代码执行流程解析:
graph.invoke({"name": "小明"})— 传入初始 State(只有name,greeting为默认值"")- 图从
START出发,找到第一条边START → greet - 执行
greet节点函数,传入当前 State,函数返回{"greeting": "你好, 小明!"} - 图将返回值合并到 State 中,State 变为
{"name": "小明", "greeting": "你好, 小明!"} - 找到下一条边
greet → END,图结束 invoke()返回最终的完整 State
1.4 API 速查
| API | 完整签名 | 入参说明 | 返回值 | 说明 |
|---|---|---|---|---|
StateGraph(state_schema) | StateGraph(state_schema: Type[StateT]) | state_schema: State 类型(TypedDict/dataclass/Pydantic) | StateGraph构建器对象 | 创建状态图构建器 |
.add_node(name, action) | add_node(node: str, action: Callable) | node: 节点名(str);action: 节点函数 | Self(支持链式调用) | 注册一个节点 |
.add_edge(start, end) | add_edge(start_key: str, end_key: str) | start_key: 源节点名;end_key: 目标节点名 | Self | 添加一条普通边 |
.compile() | compile(checkpointer, interrupt_before, interrupt_after, ...) | 可选参数见后续章节 | CompiledStateGraph | 编译图使之可执行 |
.invoke(input) | invoke(input: dict, config: dict = None) | input: 初始 State 字典;config: 运行配置(可选) | dict最终 State | 同步执行图 |
1.5 错误与避坑指南
坑 1:忘记导入 START 和 END
# ❌ 错误写法fromlanggraph.graphimportStateGraph# 只导入了 StateGraphbuilder=StateGraph(State)builder.add_edge(START,"my_node")# NameError: name 'START' is not defined# ✅ 正确写法fromlanggraph.graphimportStateGraph,START,END# 同时导入 START 和 END坑 2:节点函数返回 None 而非 dict
# ❌ 错误写法defbad_node(state:State):print("处理中...")# 忘记返回值,隐式返回 None# → LangGraph 收到 None,无法更新 State,可能报错或静默失败# ✅ 正确写法defgood_node(state:State)->dict:print("处理中...")return{"some_field":"new_value"}# 必须返回 dict坑 3:返回的 key 不在 State 中
classState(TypedDict):name:strgreeting:str# ❌ 错误写法defbad_node(state:State)->dict:return{"message":"hello"}# "message" 不在 State 中定义,运行时报错# ✅ 正确写法defgood_node(state:State)->dict:return{"greeting":"hello"}# "greeting" 在 State 中定义坑 4:混淆 invoke() 的参数
# ❌ 错误写法graph.invoke("hello")# 传入字符串而非 dict# ✅ 正确写法graph.invoke({"name":"小明"})# 传入 dict,key 对应 State 的字段1.6 最佳实践总结
- 使用 TypedDict 定义 State:类型安全,IDE 有完整提示,出错时容易定位问题
- 节点函数保持单一职责:一个节点只做一件事(如"搜索"、“生成回复”、“调用工具”),不要在一个节点里做太多事
- 始终从 START 到 END 形成完整路径:确保每个节点都有入口和出口,避免"死胡同"
- 节点返回值只包含变更字段:不需要返回完整 State,LangGraph 自动合并,减少冗余代码
- 先画图再写代码:复杂流程先用 Mermaid 画出图结构,再着手实现,思路更清晰
