Spring AI Alibaba Graph:诊断编排改造

作者:叫我小杨同学的小码酱

StateGraphAgent 编排条件边故障诊断

0. 核心摘要

让 ReactAgent 继续负责做事,让 StateGraph 负责下一步去哪里。

生活类比:Planner、Executor、Verifier 是医院科室,Graph 是分诊和转诊制度。

官方核心模型是 State、Nodes、Edges。本地依赖 1.1.2.0 已确认支持 StateGraph、条件边、编译配置、中断和 threadId。

1. 概念破冰

状态记事实,节点做任务,边管下一步,检查点管恢复。

当前 ChatService 已经是半个状态机:SequentialAgent 运行 Planner、Executor、Verifier,外层 Java 再根据 PASS、LOW_CONFID、REJECT 决定 Composer 或重试。Graph 改造的价值,是把分散的控制权显式化。

当前:SequentialAgent + 外层 if/else
目标:StateGraph 条件边 + ReactAgent 语义节点

2. 深度解析

Supervisor 适合动态选择专科 Agent;Gatekeeper、Verifier 等强制门禁应由代码边控制。普通工具失败也不需要 interrupt,只有等待人工输入或审批时才暂停。

flowchart TD S["START"] --> P["Planner"] P --> E["Executor"] E -- "结构有效" --> G["Gatekeeper"] E -- "阻断或非法" --> F["Fallback"] G -- "允许" --> V["Verifier"] G -- "拒绝" --> F V -- "通过或拒绝" --> C["Composer"] V -- "低置信且有预算" --> R["Retry Guard"] R -- "补证据" --> P R -- "停止" --> C C --> X["END"] F --> X

状态设计

保存统一诊断上下文、计划、Executor 结构化输出、Gatekeeper 结果、Verifier verdict、重试轮次和最终结果。不要在 State 里复制所有原始日志或完整思考过程。

核心伪代码

StateGraph graph = new StateGraph("diagnosis_workflow", strategies)
  .addNode("planner", plannerNode)
  .addNode("executor", executorNode)
  .addNode("gatekeeper", gatekeeperNode)
  .addNode("verifier", verifierNode)
  .addNode("retry_guard", retryGuardNode)
  .addNode("composer", composerNode)
  .addNode("fallback", fallbackNode)
  .addEdge(START, "planner")
  .addEdge("planner", "executor")
  .addConditionalEdges("executor", routeAfterExecutor,
      Map.of("gatekeeper","gatekeeper",
             "retry_guard","retry_guard",
             "fallback","fallback"))
  .addConditionalEdges("gatekeeper", routeAfterGatekeeper,
      Map.of("verifier","verifier","fallback","fallback"))
  .addConditionalEdges("verifier", routeAfterVerifier,
      Map.of("retry_guard","retry_guard",
             "composer","composer",
             "fallback","fallback"))
  .addConditionalEdges("retry_guard", routeAfterRetry,
      Map.of("planner","planner","composer","composer"))
  .addEdge("composer", END)
  .addEdge("fallback", END);

运行边界

RunnableConfig config = RunnableConfig.builder()
  .threadId(runId)
  .addMetadata("sessionId", sessionId)
  .addMetadata("runId", runId)
  .build();

一个 diagnosis_run 使用一个 Graph thread,避免同一 session 下多个 run 共享检查点。MemorySaver 不是跨重启持久化。

ReactAgent 的接入

本地 ReactAgent 提供 asNode(boolean, boolean)。当前项目第一阶段更适合用适配节点调用已有 Agent,显式控制输入、outputKey 和解析;状态契约稳定后再评估直接 asNode。

3. 深度裂变

🔍 搜索内化:改造的是控制权,不是 Agent

Graph 的节点可以是 LLM,也可以是普通 Java 代码;ReactAgent 本身已经是子图。所谓“Multi-Agent 改 Graph”,实际上是把跨 Agent 状态转换交给父 Graph。

官方页面示例有 OverAllStaste 拼写错误,实际类型是 OverAllState。网站主分支可能领先于本地依赖,最终必须以项目 JAR 和编译测试为准。

4. 实战指南

  1. 先定义节点结果状态,不改 Prompt。
  2. 把现有 Planner、Executor、Verifier 包装为 Node。
  3. Gatekeeper 和固定降级做成 Java Node。
  4. 迁移现有两轮 LOW_CONFID 控制。
  5. 加入 Executor 阻断、非法结构和 Gatekeeper REJECT 条件边。
  6. 保留旧 Sequential 链路作为短期回退。
  7. 最后再增加 HITL、并行和专科 SubAgent。

避坑

5. 温故知新

FAQ

1. Graph 会替代 ReactAgent 吗?

不会,ReactAgent 可以作为子图节点继续使用。

2. 为什么不用 Supervisor 控制失败?

失败跳转是确定性规则,不需要增加一次模型决策。

3. no_evidence 是否直接 fallback?

不一定,合法 no-evidence 引用仍要经过 Gatekeeper 和 Verifier。

4. Composer 必须是 Agent 吗?

正常表达可以使用轻量 Agent,系统失败要保留固定模板。

5. threadId 用什么?

当前数据模型下优先使用 runId,sessionId 作为元数据。

6. 何时需要 Checkpointer?

需要暂停、恢复和检查 Graph 历史状态时。

7. 能直接使用 agent.asNode 吗?

可以,但要验证 outputKey、messages 和父子检查点。

8. AIOps 要单独 Graph 吗?

入口和输出策略独立,诊断核心可以共用。

自测题

  1. 为什么 Executor 工具阻断不应由 Verifier 决定重试?
  2. ReplaceStrategy 和 AppendStrategy 各适合什么状态?
  3. 为什么合法 no_evidence 仍然需要 Gatekeeper?
  4. Supervisor 与条件边的决策权有什么不同?
  5. 为什么 Graph threadId 更适合使用 runId?
  6. 什么情况下才应该配置 interruptBefore?