跳转至

第 4 章 Agent 编排与状态机

本章学习目标 - 深入理解 LangGraph 的 StateGraph、条件边、Checkpointer、Store 等核心机制 - 掌握 TTD 的 20+ 节点图拓扑、7 条路由、AgenticBIState 状态机设计 - 深度对比 ReAct、Plan-and-Execute、Reflexion 三种 Agent 范式及其在 TTD 中的融合 - 理解修复循环、条件路由、SQL Cache 快速路径的实现原理 - 认清当前编排设计的工程权衡与改进方向

前置知识第 2 章 整体架构第 3 章 ADR 关联代码backend/app/agents/builder.pybackend/app/agents/state.pybackend/app/agents/sub_agents/router.py


4.1 背景与动机

4.1.1 为什么需要编排

一个 NL2SQL 查询远不止"调用一次 LLM 生成 SQL"那么简单。它涉及意图理解、检索、规划、生成、校验、执行、可视化、洞察——每一步都可能失败、需要重试或降级。如果把这些全塞进一个 prompt,LLM 既无法可靠执行,也无法审计。

Agent 编排要解决的核心问题是:如何把一个复杂任务拆解为可控的多步流程,让每步可观测、可纠错、可组合

4.1.2 编排范式的光谱

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
flowchart LR
    A["单次 LLM 调用<br/>最简但不可控"] --> B["ReAct 自主循环<br/>灵活但不可预测"]
    B --> C["Plan-and-Execute<br/>先规划再执行"]
    C --> D["确定性 DAG + 条件路由<br/>TTD 当前选择<br/>可控但不够灵活"]
    D --> E["自适应编排<br/>动态子图 + 中断点<br/>演进目标"]

    classDef bpProcess  fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
    classDef bpExternal fill:#f8f9fa,stroke:#dadce0,stroke-width:2px,color:#5f6368
    classDef bpInfo     fill:#f3e8fd,stroke:#9334e6,stroke-width:2px,color:#202124
    classDef bpSuccess  fill:#e6f4ea,stroke:#1e8e3e,stroke-width:2px,color:#202124

    class A,B,C bpExternal
    class D bpInfo
    class E bpSuccess

TTD 选择了 "确定性 DAG + 条件路由"(上图 D),这是工程上最可控的范式。代价是灵活性——无法处理预料之外的查询模式。演进目标是 自适应编排(上图 E),在保持可控性的前提下增加动态性。


4.2 设计原理

4.2.1 LangGraph 核心机制

AI Agent 理论关联:LangGraph 的编排模型

LangGraph 是 LangChain 团队推出的 Agent 编排框架,其核心抽象是 StateGraph——一个以状态为中心的有向图。理解 LangGraph 需要掌握几个关键概念:

  • State(状态):一个 TypedDict 或 dataclass,贯穿全图,所有节点共享。每个节点接收状态、返回状态的增量更新。LangGraph 通过 reducer(如 add_messages)定义字段如何合并(覆盖 vs 追加)。
  • Node(节点):一个函数 async def node(state) -> dict,接收当前状态,返回要更新的字段。节点内部可调用 LLM、工具、数据库。
  • Edge(边):节点间的转移。固定边(add_edge)是无条件跳转;条件边(add_conditional_edges)根据状态动态决定下一个节点。
  • Checkpointer(检查点):将每一步的状态快照持久化(如 AsyncPostgresSaver),实现会话恢复、时间旅行、断点续跑。这是多轮对话与容错的基础。
  • Store(长期存储):跨会话的 KV 存储(如 AsyncPostgresStore),支持按 namespace 隔离与语义搜索,用于长期记忆。
  • Command(goto=...):节点可通过返回 Command 对象显式指定跳转目标,比条件边更灵活。
  • Interrupt(中断):在指定节点暂停执行,等待外部输入(如人工确认)后恢复——这是 human-in-the-loop 的基础。

LangGraph 与纯 ReAct 的本质区别:ReAct 让 LLM 自主决定下一步,LangGraph 让开发者用图结构预定义下一步。前者灵活不可控,后者可控不灵活。生产系统倾向后者。

4.2.2 图拓扑总览

TTD 用 LangGraph 的 StateGraph 编排了 20+ 节点的工作流。入口固定为 START → supervisor → query_understanding_agent → router,router 之后根据意图分流到 7 条预定义路由计划。

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
graph TD
    START([START]) --> supervisor
    supervisor --> query_understanding_agent
    query_understanding_agent --> router

    router -->|"kpi_lookup<br/>nl2sql_query"| data_retrieval_agent
    router -->|"deep_analysis_workflow"| planner
    router -->|"graph_reasoning"| graph_rag_agent
    router -->|"business_knowledge_qa"| data_retrieval_agent_kb
    router -->|"clarification_required"| data_retrieval_agent_cl

    subgraph SqlPipeline["SQL Pipeline"]
        data_retrieval_agent --> reranker
        reranker --> semantic_planner
        semantic_planner --> sql_generator
        sql_generator --> guardrails_agent
        guardrails_agent -->|"execute"| sql_executor
        guardrails_agent -->|"corrective_repair"| corrective_retrieval
        guardrails_agent -->|"reject"| END_REJECT([END])
        corrective_retrieval --> sql_generator
        sql_executor --> result_processor
        result_processor --> sql_explainer
    end

    sql_explainer --> visualization_agent
    visualization_agent --> insights_agent
    insights_agent --> suggest_followup_agent
    suggest_followup_agent --> END_OK([END])

    planner --> data_retrieval_agent
    graph_rag_agent --> END_GRAPH([END])
    data_retrieval_agent_kb --> knowledge_qa_agent
    knowledge_qa_agent --> END_KB([END])
    data_retrieval_agent_cl --> follow_up_agent
    follow_up_agent --> END_CL([END])

    classDef bpProcess  fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
    classDef bpData     fill:#e0f2f1,stroke:#0d7377,stroke-width:2px,color:#202124
    classDef bpDecision fill:#fef7e0,stroke:#f9ab00,stroke-width:2px,color:#202124
    classDef bpSuccess  fill:#e6f4ea,stroke:#1e8e3e,stroke-width:2px,color:#202124
    classDef bpError    fill:#fce8e6,stroke:#d93025,stroke-width:2px,color:#202124
    classDef bpInfo     fill:#f3e8fd,stroke:#9334e6,stroke-width:2px,color:#202124

    class supervisor,query_understanding_agent,router bpProcess
    class data_retrieval_agent,data_retrieval_agent_kb,data_retrieval_agent_cl,reranker bpData
    class semantic_planner,sql_generator,result_processor,sql_explainer bpProcess
    class guardrails_agent bpDecision
    class sql_executor bpProcess
    class corrective_retrieval bpInfo
    class visualization_agent,insights_agent,suggest_followup_agent bpProcess
    class planner,knowledge_qa_agent,follow_up_agent bpProcess
    class graph_rag_agent bpInfo
    class END_OK,END_GRAPH,END_KB,END_CL bpSuccess
    class END_REJECT bpError

图的编译在 main.py 启动时完成一次,注入 Checkpointer(AsyncPostgresSaver,会话持久化)和 Store(AsyncPostgresStore,长期记忆)。编译后的图是只读的,所有状态变化通过 Checkpointer 落盘。

4.2.3 七条路由

Router 根据 Query Understanding 的输出,用 _INTENT_TO_ROUTE 映射表(非 ML)决定路径:

Route 触发意图 执行路径
kpi_lookup KPI 直查 retrieval → reranker → sql_gen → guardrails → executor → explainer
nl2sql_query 趋势/对比/排名 完整管道 + viz + insights + followup
deep_analysis_workflow 根因分析/报告 planner + 全链路 + 三级评估器
analytical_workflow 归因/预测/分群 + analytical_agent (ML toolkit)
graph_reasoning 关系探索 graph_rag_agent (NL2Cypher),失败回退 SQL
business_knowledge_qa 政策/SOP 问答 retrieval → knowledge_qa_agent
clarification_required 模糊意图 retrieval → follow_up_agent

AI Agent 理论关联:ReAct / Plan-and-Execute / Reflexion 三范式融合

TTD 的编排混合了三种 Agent 范式,理解它们的差异是理解 TTD 设计的关键:

ReAct(Reasoning + Acting,2022) - 核心思想:LLM 交替进行"推理(Thought)"与"行动(Action)",在每一步根据观察结果(Observation)决定下一步。 - 循环:Thought → Action → Observation → Thought → ... 直到完成。 - 优势:灵活,能处理开放性任务。 - 劣势:不可预测(LLM 可能走偏)、难审计(需追踪完整 thought 链)、延迟不可控(循环次数不定)。 - 在 TTD 中:每个节点内部是 ReAct 的单步——LLM 推理后产出结构化结果,但"下一步做什么"由图决定而非 LLM。

Plan-and-Execute(2023) - 核心思想:先让 LLM 制定完整计划(Plan),再逐步执行(Execute),执行中可动态调整计划。 - 优势:有全局视野,避免 ReAct 的短视;适合多步复杂任务。 - 劣势:计划可能基于不完整信息;计划与执行的解耦增加复杂度。 - 在 TTD 中:deep_analysis_workflow 路由含独立的 planner 节点,先 LLM 生成多步执行计划,再逐步执行。这是典型的 Plan-and-Execute(arxiv.org/abs/2305.04091)。

Reflexion(2023) - 核心思想:在行动后引入"自我反思"——评估执行结果,基于反馈修正后续行为。 - 优势:能从失败中学习,自我纠错。 - 劣势:反思本身消耗 LLM 调用;反思质量依赖评估准确性。 - 在 TTD 中:deep_analysis_workflow 的三级评估器(retrieval/sql/answer evaluator)对结果打分,低分触发反思重试。这是 Reflexion(arxiv.org/abs/2303.11366)的简化版——评估但不基于反思重写计划。

TTD 的取舍:用确定性图保证安全可审计(不同于纯 ReAct),用节点内的 LLM 保证局部智能,用 Plan-and-Execute 处理复杂分析,用 Reflexion 做质量兜底。这是"范式融合"的工程实践。

4.2.4 全局状态 AgenticBIState

AgenticBIStatebackend/app/agents/state.py)是贯穿全图的 TypedDict(total=False),所有字段可选,节点只返回需要更新的字段(状态增量模式——LangGraph 的 reducer 会合并这些增量)。

类别 关键字段 说明
输入 question, language, user_context, session_id, options 用户请求
编排 routing_plan, current_agent, route_decision, execution_plan, plan_step_index 路由与计划
记忆 short_term_memory, memory_context 短期 + 长期记忆
生成 query_understanding, retrieval_results, graph_context, generated_sql, execution_result, visualization, insights 各阶段产出
评估 retrieval_quality, sql_quality, answer_quality 评估器打分
治理 tenant_id, governance_overlays, region 治理上下文
控制 status, errors, sql_cache_hit, repair_attempt, clarification_message 流程控制

4.3 实现详解

4.3.1 图的构建

图的编译在 main.py 启动时完成一次,注入 checkpointer(会话持久化)和 store(长期记忆):

# backend/app/agents/builder.py(简化)
def build_supervisor_graph(checkpointer, store, registry, pool):
    graph = StateGraph(AgenticBIState)

    # 注册 20+ 节点
    graph.add_node("supervisor", make_supervisor_node(registry))
    graph.add_node("query_understanding_agent", make_query_understanding_node(registry))
    graph.add_node("router", make_router_node(sql_cache))
    graph.add_node("data_retrieval_agent", make_data_retrieval_node(retriever))
    # ... 其余节点

    # 固定入口边
    graph.add_edge(START, "supervisor")
    graph.add_edge("supervisor", "query_understanding_agent")
    graph.add_edge("query_understanding_agent", "router")

    # 条件边:router → 7 路由
    graph.add_conditional_edges("router", _route_after_router, {...})

    # 条件边:guardrails → execute/repair/reject
    graph.add_conditional_edges("guardrails_agent", _route_after_validation, {...})

    return graph.compile(checkpointer=checkpointer, store=store)

thread_id=session_id 是 Checkpointer 的会话标识——同一会话的状态快照按 thread_id 隔离,实现多轮对话的上下文持久化。

4.3.2 条件路由函数

条件边是 TTD 编排的"控制流大脑"。每个条件函数根据当前状态决定下一个节点:

函数 位置 可能返回值 决策依据
_route_after_router router 后 7 路由分支 QU 的 intent_type 映射
_route_after_retrieval data_retrieval 后 rerank, knowledge_qa, no_context, clarify 检索结果质量
_route_after_validation guardrails 后 execute, corrective_repair, repair, reject 校验失败类型
_route_after_execution executor 后 proceed, repair, fail 执行结果/超时
_route_after_result explainer 后 visualize, evaluate, insight, done 路由计划
_route_after_graph_rag graph_rag 后 done, fallback_sql Cypher 是否成功

4.3.3 修复循环

这是 TTD 编排的核心鲁棒性机制。Guardrails 校验失败时,不是直接拒绝,而是尝试修复——这是 Reflexion 范式的工程实现:

%%{init: {'theme':'base','themeVariables':{'primaryColor':'#e8f0fe','primaryTextColor':'#202124','primaryBorderColor':'#1a73e8','lineColor':'#5f6368','secondaryColor':'#e0f2f1','tertiaryColor':'#f8f9fa'}}}%%
flowchart LR
    GR["Guardrails<br/>五层校验"] -->|"通过"| EX[执行]
    GR -->|"列错误/术语违规<br/>可修复(最多2次)"| CR["Corrective Retrieval<br/>补偿检索"]
    CR --> SG["SQL Generator<br/>重试生成"]
    SG --> GR
    GR -->|"性能问题<br/>EXPLAIN cost 超阈值"| SG2["SQL Generator<br/>性能优化重试<br/>(最多1次)"]
    SG2 --> GR
    GR -->|"不可修复<br/>语法错误/策略违规"| REJ["拒绝执行<br/>返回用户友好错误"]

    classDef bpProcess  fill:#e8f0fe,stroke:#1a73e8,stroke-width:2px,color:#202124
    classDef bpDecision fill:#fef7e0,stroke:#f9ab00,stroke-width:2px,color:#202124
    classDef bpSuccess  fill:#e6f4ea,stroke:#1e8e3e,stroke-width:2px,color:#202124
    classDef bpError    fill:#fce8e6,stroke:#d93025,stroke-width:2px,color:#202124
    classDef bpInfo     fill:#f3e8fd,stroke:#9334e6,stroke-width:2px,color:#202124

    class GR bpDecision
    class EX bpSuccess
    class CR bpInfo
    class SG,SG2 bpProcess
    class REJ bpError

    linkStyle 0 stroke:#1e8e3e,stroke-width:2.5px
    linkStyle 1,2,4 stroke:#f9ab00,stroke-width:2px
    linkStyle 3 stroke:#1a73e8,stroke-width:2px
    linkStyle 5 stroke:#d93025,stroke-width:2px
  • 列引用错误sql_column_validator 检测到不存在的列 → corrective_retrieval 拉取正确列 → sql_generator 重试(最多 2 次)
  • 术语绑定违规:术语"价格"应绑定到 fact_transaction.price,但 SQL 写了 dim_article.price → corrective_retrieval 拉取正确表 → 重试
  • 性能问题:EXPLAIN 估算行数/cost 超阈值 → sql_generator 做性能优化重试(最多 1 次)

AI Agent 理论关联:Reflexion 与自愈

修复循环是 Reflexion 范式的工程实现:Agent 执行后获得反馈(校验失败信息),基于反馈调整行为(重新检索 + 重新生成)。

区别于学术 Reflexion 的是,TTD 的"反思"是确定性的(基于明确的错误类型触发对应的修复策略),而非让 LLM 自主反思。这保证了修复的可预测性,但限制了处理"未知错误"的能力。

与 Corrective RAG(CRAG)的关系:修复循环中的 corrective_retrieval 正是 CRAG 思想的体现——检索质量不够时不硬生成,而是补充检索后再试。详见 第 5 章

4.3.4 SQL Cache 快速路径

Router 在路由时检查 SQL 语义缓存:若问题 embedding 与缓存 SQL 的 embedding 相似度 ≥ 0.92,直接跳转 guardrails_agent,跳过检索与生成。这是用空间换时间的优化,详见 第 7 章

4.3.5 Graph RAG 降级

graph_reasoning 路由的 graph_rag_agent 若失败(如 Cypher 生成错误),自动回退到 SQL 流水线(_route_after_graph_rag → fallback_sql)。这是优雅降级的典型实现——任何子路径失败都有 fallback,不阻塞用户。

4.3.6 模型分配

每个节点通过 registry.get_model(task) 获取模型,任务→模型映射见 ADR-7。模型分配由 ModelRegistry 统一管理,支持 Admin DB 在线覆盖与 Fallback 链降级。


4.4 方案选型对比

4.4.1 Agent 编排框架对比

维度 LangGraph AutoGen CrewAI 自建状态机
编排模型 显式状态图 对话式多 Agent 角色流水线 完全自定义
可控性 最高
状态持久化 内置 Checkpointer 需自建 需自建
HITL 中断 原生 interrupt 需自建 需自建
生态 LangChain 生态 微软生态 新兴
学习曲线
TTD 选择理由 显式图 + 持久化 + LangChain 集成最契合 NL2SQL 的可审计需求

4.4.2 DAG 编排 vs 自主 ReAct

维度 确定性 DAG(TTD) 自主 ReAct
可预测性 高(路径固定) 低(LLM 自主决定)
可审计性 高(每步显式) 低(需追踪 thought 链)
灵活性 低(路径预设) 高(可处理意外)
安全性 高(可控执行) 低(可能跑偏)
延迟 可预估 不可预估
适用场景 安全敏感、流程明确的任务 探索性、开放任务

性能与质量指标(设计目标)

以下为编排管道的设计目标值,TTD 尚未进行系统化实测

指标 设计目标 说明
Supervisor 延迟 < 100ms 嵌入计算 + 治理叠加层解析(无 LLM)
Query Understanding 延迟 0.5-1.5s 单次 LLM 调用(deepseek-v4-flash)
Router 延迟 < 5ms 纯确定性映射(_INTENT_TO_ROUTE
主路径端到端延迟(nl2sql_query) < 3s 不含 SQL 执行时间
deep_analysis 端到端延迟 < 10s 含三级评估器 + 多步分析
SQL Cache 命中跳过延迟 < 200ms 跳过检索与生成,仅护栏+执行

评估基础设施见 第 15 章,改进路线见 第 16 章

当前实现可改进之处

  1. 路由完全静态缺乏自学习:7 条路由是硬编码映射,当用户意图不在预设类别时只能 fallback。无法从历史查询中自动发现新模式。改进:增加路由效果反馈环,记录失败率,提示维护者扩展路由(详见 第 16 章)。
  2. 状态字段过多(~50 个)是"上帝对象"反模式:AgenticBIState 字段间有隐含依赖(如 visualization 依赖 execution_result),难以追踪。改进:用子状态分组(input/retrieval/generation/control)或引入 dataclass 收敛,强制声明字段依赖。
  3. 无 human-in-the-loop 中断点:LangGraph 原生支持 interrupt,但 TTD 只在可视化有 HITL,SQL 执行前无"高危查询人工确认"。改进:对 EXPLAIN 成本超阈值的查询加 interrupt,让用户确认后再执行。

改进方向

核心演进方向是自适应编排:保留确定性 DAG 的可审计骨架,在关键决策点引入动态子图与中断点,让系统在"可控"与"灵活"间取得更好平衡。这与多 Agent 辩论(multi-agent debate)、Self-Discover 等前沿方向呼应——让 Agent 在不确定时能"停下来想一想"或"找人确认",而非硬走预设路径。


4.5 小结与延伸阅读

本章要点

  1. TTD 用 LangGraph 编排 20+ 节点的确定性 DAG,7 条路由覆盖从 KPI 直查到深度分析的全场景。
  2. LangGraph 核心机制:StateGraph(状态中心图)、条件边(动态路由)、Checkpointer(状态持久化)、Store(长期记忆)、Interrupt(HITL)。
  3. AgenticBIState 是贯穿全图的状态机,节点采用状态增量模式。
  4. 修复循环(corrective_retrieval + 重试)是核心鲁棒性机制,基于 Reflexion 范式。
  5. 编排融合了 ReAct(节点内)、Plan-and-Execute(planner)、Reflexion(评估器)三种范式。

延伸阅读

下一章第 5 章 检索增强:R/V/G/D 四引擎 RAG——详解四引擎如何协作检索、Reranker 如何重排、补偿检索如何修复。