python
#!/usr/bin/env python3
"""
Task 3: StateGraph Demo - Shopping Cart
Shows how state persists and accumulates across nodes
"""
from typing import TypedDict, List
from langgraph.graph import StateGraph, START, END
print("\n🛒 STATEGRAPH DEMO - Shopping Cart")
print("=" * 40)
# Define state structure
class CartState(TypedDict):
items: List[str]
total: float
status: str
def add_apple(state: CartState):
"""Add apple to cart - shows state accumulation"""
print("\nStep 1: Adding apple ($5) to cart...")
new_items = state["items"] + ["apple"]
new_total = state["total"] + 5
print(f" → State: items={new_items}, total=${new_total}")
return {
"items": new_items,
"total": new_total
}
def add_banana(state: CartState):
"""Add banana to cart - shows accumulation continues"""
print("\nStep 2: Adding banana ($3) to cart...")
new_items = state["items"] + ["banana"]
new_total = state["total"] + 3
print(f" → State: items={new_items}, total=${new_total}")
return {
"items": new_items,
"total": new_total
}
def checkout(state: CartState):
"""Complete purchase - shows state persistence"""
print("\nStep 3: Processing checkout...")
print(f" → Final items: {state['items']}")
print(f" → Final total: ${state['total']}")
return {
"status": "paid"
}
# Build the graph
print("\nBuilding StateGraph workflow...")
workflow = StateGraph(CartState)
# Add nodes
workflow.add_node("add_apple", add_apple)
workflow.add_node("add_banana", add_banana)
workflow.add_node("checkout", checkout)
# Define flow
workflow.set_entry_point("add_apple")
workflow.add_edge("add_apple", "add_banana")
workflow.add_edge("add_banana", "checkout")
workflow.add_edge("checkout", END)
# Compile and run
app = workflow.compile()
# Initial state
initial_state = {
"items": [],
"total": 0.0,
"status": "pending"
}
print(f"\nInitial State: {initial_state}")
print("\nExecuting workflow...")
# Run the workflow
result = app.invoke(initial_state)
# Show final state
print("\n" + "=" * 40)
print("✅ FINAL STATE:")
print(f" Items: {result['items']}")
print(f" Total: ${result['total']}")
print(f" Status: {result['status']}")
print("\n💡 Key Insights:")
print(" • State persisted across all nodes")
print(" • Each node added to the state")
print(" • Previous values were preserved")
# Save completion marker
try:
with open('/root/stategraph_complete.txt', 'w') as f:
f.write('StateGraph implementation complete\n')
f.write(f'Final state: {result}\n')
except:
pass # Local testing
LangGraph Shopping Cart 示例完整逐行解读
这份代码是 LangGraph StateGraph 最基础核心演示:状态在节点间持续传递、增量更新,非常适合入门理解 LangGraph 状态流转机制。
核心知识点:
StateGraph、TypedDict状态定义、节点函数、边 (Edge)、工作流编译、状态合并规则。
一、头部模块
#!/usr/bin/env python3
"""
Task 3: StateGraph Demo - Shopping Cart
Shows how state persists and accumulates across nodes
"""
from typing import TypedDict, List
from langgraph.graph import StateGraph, START, END
-
#!/usr/bin/env python3:Linux 脚本声明,指定用 python3 执行 -
文档字符串:说明演示目标 ------展示状态在多个节点之间持久保存、累积更新
-
TypedDict:给状态做类型约束(推荐,IDE 智能提示) -
StateGraph:LangGraph 核心类,用于构建有状态图工作流 -
START / END:LangGraph 内置常量,代表图的起点、终点print("\n🛒 STATEGRAPH DEMO - Shopping Cart")
print("=" * 40)
控制台打印分隔标题。
二、状态定义 CartState
class CartState(TypedDict):
items: List[str]
total: float
status: str
✅ LangGraph 状态载体定义
TypedDict:只定义结构,不实例化类;描述字典里有哪些 key 和对应类型- 整个工作流全程共享同一个状态字典 :
items:购物车内商品列表total:总价status:订单状态pending/paid
⚠️ 重要规则(LangGraph 默认): 节点返回部分状态字典 ,LangGraph 会执行合并更新,不会覆盖整个 state ! 没有返回的字段,保留原有值。
三、各个 Node 节点函数
节点函数统一签名:def func(state: CartState) -> dict 入参:当前最新状态;返回:想要更新的状态片段
1. add_apple 节点
def add_apple(state: CartState):
print("\nStep 1: Adding apple ($5) to cart...")
new_items = state["items"] + ["apple"]
new_total = state["total"] + 5
print(f" → State: items={new_items}, total=${new_total}")
return {
"items": new_items,
"total": new_total
}
逻辑:
- 读取传入 state 里当前
items和total - 新建列表(不原地修改原始 state!函数式风格)追加 apple,总价 + 5
- 只返回要修改的两个 key
status没有返回 → LangGraph 保持原来的值不变
最佳实践:不要直接
state["items"].append()修改入参对象,容易产生副作用。优先构造新值返回。
2. add_banana 节点
def add_banana(state: CartState):
print("\nStep 2: Adding banana ($3) to cart...")
new_items = state["items"] + ["banana"]
new_total = state["total"] + 3
print(f" → State: items={new_items}, total=${new_total}")
return {
"items": new_items,
"total": new_total
}
承接上一个节点输出的状态,继续追加商品,总价累加。
3. checkout 结算节点
def checkout(state: CartState):
print("\nStep 3: Processing checkout...")
print(f" → Final items: {state['items']}")
print(f" → Final total: ${state['total']}")
return {
"status": "paid"
}
重点: 只返回 status,items、total 完全不改动 LangGraph 自动保留已经累加好的商品和总价,仅更新 status。
四、构建 StateGraph 工作流
print("\nBuilding StateGraph workflow...")
workflow = StateGraph(CartState)
实例化图,并绑定状态类型 CartState,告诉图:整个流程流转的数据结构是什么。
# Add nodes
workflow.add_node("add_apple", add_apple)
workflow.add_node("add_banana", add_banana)
workflow.add_node("checkout", checkout)
-
add_node(节点名称字符串, 函数) -
第一个参数是图内唯一节点标识,用于定义边;第二个是执行函数
Define flow
workflow.set_entry_point("add_apple")
workflow.add_edge("add_apple", "add_banana")
workflow.add_edge("add_banana", "checkout")
workflow.add_edge("checkout", END) -
set_entry_point:图执行起点 -
add_edge(A,B):A 执行完成后,无条件流向 B -
checkout → END:到达终点,图运行结束
当前流程图: START → add_apple → add_banana → checkout → END
app = workflow.compile()
compile():编译图,生成可执行运行时对象 app,之后才能调用 .invoke()
五、初始化状态 & 执行工作流
initial_state = {
"items": [],
"total": 0.0,
"status": "pending"
}
初始状态字典,必须完整满足 CartState 结构,作为图执行的起点数据。
result = app.invoke(initial_state)
核心执行入口: app.invoke(初始状态)
- 将 initial_state 传入图
- 按照定义的边顺序依次执行节点
- 每个节点执行后,自动合并返回字典更新全局状态
- 抵达 END 后,返回最终完整状态
result
六、输出最终状态
print("\n" + "=" * 40)
print("✅ FINAL STATE:")
print(f" Items: {result['items']}")
print(f" Total: ${result['total']}")
print(f" Status: {result['status']}")
result = 图跑完之后完整的最终 CartState。
七、最后的文件写入(可选)
try:
with open('/root/stategraph_complete.txt', 'w') as f:
f.write('StateGraph implementation complete\n')
f.write(f'Final state: {result}\n')
except:
pass # Local testing
异常捕获写法,服务器环境写入标记文件,本地运行路径不存在不会崩溃。
运行输出预期
🛒 STATEGRAPH DEMO - Shopping Cart
========================================
Building StateGraph workflow...
Initial State: {'items': [], 'total': 0.0, 'status': 'pending'}
Executing workflow...
Step 1: Adding apple ($5) to cart...
→ State: items=['apple'], total=$5.0
Step 2: Adding banana ($3) to cart...
→ State: items=['apple', 'banana'], total=$8.0
Step 3: Processing checkout...
→ Final items: ['apple', 'banana']
→ Final total: $8.0
========================================
✅ FINAL STATE:
Items: ['apple', 'banana']
Total: $8.0
Status: paid
核心底层原理总结(重点!)
- 全局单一状态容器 整个图共享一份状态字典,节点之间依靠这份字典传递信息。
- 状态合并规则(默认 StateGraph) 节点返回
{key: value}→ 增量更新,没有返回的键维持原值,不会清空状态。
对比传统 Chain:Chain 经常需要手动在每一步传递所有变量,LangGraph 自动维护。
- 节点无副作用范式 推荐不修改入参 state 对象,构造新数据返回;避免并发 / 分支场景出现数据错乱。
- 此示例是线性 DAG 顺序执行;在此基础上你可以扩展:
- 条件分支
add_conditional_edges - 循环(Agent 思考循环)
- 并行节点
拓展思考题
你可以试着修改代码验证机制:
- 在 checkout 节点只返回
status,items/total 为什么不会消失? - 如果某节点返回空字典
{},状态会发生什么? - 如果在节点内部
state["items"].append("xxx")直接原地修改,和构造新列表有什么区别?