LangGraph State 如何解决 Agent Tools 调用可用率?
最近在开发 Agent 场景中,有一个 Case 是要连续调用多个 tools: 有 A、B、C 三个 tool,分别执行不同的功能,且这三个 tools 有依赖关系:
A -> B -> C -> A
prompt 方案
最开始采用的方案是 prompt 约束 + few shot,prompt 如下:
**强制行动流程**:1. **第一步**: 调用 A 更新 website 字段 - 从用户输入中提取主要的公司网站URL - 如果有多个URL,选择最能代表公司的主网站2. **第二步**: 调用 B 添加到附件列表 - 使用与第一步相同的URL - 等待第一步成功后再调用3. **第三步**: 调用 C 提取公司信息 - 使用相同的URL从文档中提取公司详细信息 - 根据提取结果可能需要再次调用 A 更新其他业务字段
问题 - 不能保证 100% 可用率
prompt 方案带来最大的问题是执行流程不能保证 100% 执行,偶现个别 case 下 LLM 只调用了第一个 tool,然后就中断了流程。
更好的解决方案 - LangGraph State
State 的基本用法
1. 定义状态结构
from typing import TypedDictfrom langgraph.graph import StateGraph, ENDclass GraphState(TypedDict): input: str output: str step_count: int
2. 创建StateGraph实例
# 创建StateGraph,指定状态类型workflow = StateGraph(GraphState)
3. 定义节点函数
def node_1(state: GraphState) -> GraphState: """第一个节点的处理逻辑""" return { "input": state["input"], "output": f"处理了: {state['input']}", "step_count": state.get("step_count", 0) + 1 }def node_2(state: GraphState) -> GraphState: """第二个节点的处理逻辑""" return { "input": state["input"], "output": state["output"] + " -> 进一步处理", "step_count": state["step_count"] + 1 }
4. 添加节点
workflow.add_node("step1", node_1)workflow.add_node("step2", node_2)
5. 定义边连接
# 设置入口点workflow.set_entry_point("step1")# 添加边workflow.add_edge("step1", "step2")workflow.add_edge("step2", END)
6. 条件边的使用
def should_continue(state: GraphState) -> str: """决定下一步走向的条件函数""" if state["step_count"] < 3: return "continue" else: return "end"# 添加条件边workflow.add_conditional_edges( "step1", should_continue, { "continue": "step2", "end": END })
7. 编译并运行
# 编译图app = workflow.compile()# 运行图initial_state = { "input": "Hello World", "output": "", "step_count": 0}result = app.invoke(initial_state)print(result)
什么是 LangGraph State?
LangGraph 中的 State 是一个类型化的数据结构,用于在图的节点之间传递和维护信息。它类似于一个共享的内存空间,所有节点都可以读取和更新,其贯穿了Langgraph的整个生命周期。
使用 State 解决依赖关系
基本架构设计
from langgraph.graph import StateGraph, ENDfrom langchain.tools import Tool# 定义各个工具节点def search_node(state: AgentState) -> AgentState: """搜索节点"""def extract_node(state: AgentState) -> AgentState: """提取节点 - 依赖搜索结果"""def analyze_node(state: AgentState) -> AgentState: """分析节点 - 依赖提取数据"""def visualize_node(state: AgentState) -> AgentState: """可视化节点 - 依赖分析结果"""
构建依赖图
# 创建状态图workflow = StateGraph(AgentState)# 添加节点workflow.add_node("search", search_node)workflow.add_node("extract", extract_node)workflow.add_node("analyze", analyze_node)workflow.add_node("visualize", visualize_node)# 定义依赖关系(边)workflow.set_entry_point("search")workflow.add_edge("search", "extract")workflow.add_edge("extract", "analyze")workflow.add_edge("analyze", "visualize")workflow.add_edge("visualize", END)# 编译图app = workflow.compile()
条件路由处理
对于更复杂的场景,我们可以使用条件边来处理动态依赖:
def should_continue(state: AgentState) -> str: """根据状态决定下一步""" if state.get("errors"): return "error_handler" elif state.get("extracted_data"): # 根据数据类型选择不同的分析路径 if state["extracted_data"].get("type") == "numerical": return "statistical_analysis" else: return "text_analysis" return END# 添加条件边workflow.add_conditional_edges( "extract", should_continue, { "statistical_analysis": "statistical_node", "text_analysis": "text_node", "error_handler": "error_node", END: END })
高级特性
1. 并行执行无依赖工具
当多个工具之间没有数据依赖关系时,它们可以同时执行,而不需要等待彼此完成。
场景:收集多源数据
Task A: 从数据库查询用户信息
Task B: 从API获取天气数据
Task C: 从文件系统读取配置
这三个任务互不依赖,可以同时执行!
from langgraph.graph import START# 定义两个独立的搜索节点workflow.add_node("search_db", search_database_node)workflow.add_node("search_api", search_api_node)workflow.add_node("search_files", search_files_node)# 从起点并行执行workflow.add_edge(START, "search_db")workflow.add_edge(START, "search_api")workflow.add_edge(START, "search_files")# 汇聚到合并节点workflow.add_edge("search_db", "merge")workflow.add_edge("search_api", "merge")workflow.add_edge("search_files", "merge")
```
#### 2. 循环依赖处理
循环依赖(Loop/Cycle)指的是:工作流中某个节点的输出会再次回到之前的节点,形成一个循环,用于迭代优化、重试或渐进式改进结果。

循坏依赖通常用于需要评估生成结果的情况,比如生成结果不理想需要重试:

```plaintext
def refine_node(state: AgentState) -> AgentState: """迭代优化节点""" iteration = state.get("iteration", 0) result = refine_tool.run(state["current_result"]) return { **state, "current_result": result, "iteration": iteration + 1 }def should_refine(state: AgentState) -> str: """判断是否需要继续优化""" if state.get("iteration", 0) < 3: quality = evaluate_quality(state["current_result"]) if quality < 0.8: return "refine" return "finish"workflow.add_conditional_edges( "refine", should_refine, { "refine": "refine", # 循环回自己 "finish": "output" })
3. 状态持久化与恢复
状态持久化: 将工作流的执行状态保存到存储介质(内存、数据库、文件等)
状态恢复: 从保存的检查点恢复工作流,继续之前的执行
这就像游戏中的"存档"和"读档"功能!
from langgraph.checkpoint import MemorySaver# 使用检查点保存状态memory = MemorySaver()app = workflow.compile(checkpointer=memory)# 运行并保存状态config = {"configurable": {"thread_id": "task_123"}}result = app.invoke(initial_state, config=config)# 从检查点恢复并继续执行resumed_result = app.invoke(None, config=config)
最后
在完成通过 state 来处理依赖关系的改造后,tools 调用问题得以彻底解决,不再担心 LLM 只调用了其中某一个工具。