AI Agent工作流编排实战:LangGraph多节点状态机设计与生产部署

AI Agent工作流编排的核心问题

构建AI智能体时,单次LLM调用无法处理复杂业务逻辑。Agent需要根据中间结果决定下一步动作——调用工具、切换分支还是终止流程。LangGraph通过有向图状态机模型解决这个问题,每个节点是一个处理单元,边定义转移条件和数据流向。

LangGraph状态图设计原理

LangGraph的核心抽象是StateGraph。定义一个TypedDict作为全局状态容器,所有节点共享读写这个状态对象。图的构建分三步:初始化StateGraph、添加节点函数、添加条件边或固定边。

状态定义示例:

from typing import TypedDict, Annotated, List
from langgraph.graph import StateGraph, END
import operator

class AgentState(TypedDict):
    messages: Annotated[list, operator.add]
    next_action: str
    tool_results: dict
    iteration: int
    max_iterations: int

每个节点的函数签名统一为def node_fn(state: AgentState) -> dict,返回部分状态更新。LangGraph自动合并返回值到全局状态。

多节点条件分支实现

实际业务中Agent需要根据推理结果选择不同路径。条件边通过add_conditional_edges实现,接收一个映射函数和路径字典。

def router(state: AgentState) -> str:
    if state['iteration'] >= state['max_iterations']:
        return 'end'
    if state['next_action'] == 'tool_call':
        return 'tool_node'
    elif state['next_action'] == 'reflect':
        return 'reflect_node'
    else:
        return 'end'

graph = StateGraph(AgentState)
graph.add_node('planner', planner_fn)
graph.add_node('tool_node', tool_fn)
graph.add_node('reflect_node', reflect_fn)
graph.add_node('finalizer', finalizer_fn)

graph.set_entry_point('planner')
graph.add_conditional_edges('planner', router, {
    'tool_node': 'tool_node',
    'reflect_node': 'reflect_node',
    'end': 'finalizer'
})
graph.add_edge('tool_node', 'planner')
graph.add_edge('reflect_node', 'planner')
graph.add_edge('finalizer', END)

app = graph.compile()

执行时调用app.invoke(initial_state),图引擎自动完成状态传递和节点调度。

工具调用节点的生产级写法

工具节点不应直接执行外部API调用,而是封装为异步函数,加入超时控制和重试逻辑:

import httpx
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(3), wait=wait_exponential(min=1, max=10))
async def call_search_api(query: str, timeout: float = 15.0) -> dict:
    async with httpx.AsyncClient(timeout=timeout) as client:
        resp = await client.get(
            'https://api.search.example/v1/search',
            params={'q': query, 'limit': 5}
        )
        resp.raise_for_status()
        return resp.json()

在节点函数中调用异步工具时,使用asyncio.run或直接将图编译为异步模式。

循环与迭代终止策略

Agent容易陷入无限循环——规划节点持续调用工具节点,工具节点返回结果又触发新一轮规划。三种终止策略必须同时配置:

1. 硬性迭代次数上限(max_iterations)

2. 状态收敛检测:连续两次状态差异小于阈值时终止

3. 超时兆底:整个图执行超过限定时间强制退出

def convergence_check(state: AgentState) -> bool:
    msgs = state.get('messages', [])
    if len(msgs) < 2:
        return False
    last_two = msgs[-2:]
    similarity = compute_similarity(last_two[0], last_two[1])
    return similarity > 0.95

持久化与断点恢复

长时间运行的Agent需要支持断点恢复。LangGraph集成checkpoint机制,使用SQLite或PostgreSQL作为后端:

from langgraph.checkpoint.sqlite import SqliteSaver

memory = SqliteSaver.from_conn_string('./agent_checkpoints.db')
app = graph.compile(checkpointer=memory)

config = {'configurable': {'thread_id': 'session_001'}}
result = app.invoke(initial_state, config)

# 恢复执行:用相同thread_id重新调用
resumed = app.invoke(None, config)

每次节点执行完毕,状态自动写入数据库。进程崩溃后用相同thread_id恢复,从最后一个完成的节点继续执行。

生产环境部署要点

部署LangGraph Agent到生产环境需要关注三个维度:

并发控制:图引擎本身无并发限制,需要在外层加入信号量或工作队列。推荐使用Redis队列加Worker模式,每个Worker运行独立图实例。

可观测性:通过langchain.callbacks集成LangSmith或自建OpenTelemetry追踪。关键指标包括单节点执行耗时、整体图执行时间、工具调用成功率和状态体积变化。

from langchain.callbacks import LangChainTracer

tracer = LangChainTracer(project_name='agent-prod')
result = app.invoke(
    initial_state,
    config={'callbacks': [tracer], 'configurable': {'thread_id': tid}}
)

成本控制:LLM调用是主要成本来源。在节点函数中缓存重复查询结果,对工具返回值做摘要压缩再写回状态,减少下游节点的token消耗。

实际生产中一个中等复杂度的Agent(5-8节点、3轮平均迭代)单次执行成本在0.02-0.15美元之间,日均处理1000次请求的月token成本约600-4500美元。合理的缓存和摘要策略可以将成本压缩到原始的30%-50%。

原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/aiagent-gong-zuo-liu-bian-pai-shi-zhan-langgraph-duo-jie/

(0)
小编小编
上一篇 10小时前
下一篇 10小时前

相关推荐