Files

8.2 KiB
Raw Permalink Blame History

Context

阶段 0 已归档 StateGraph 设计基线,当前仓库仍没有 Graph 实现。阶段 1 只引入可编译、可用 Fake Node 执行的内部骨架,不连接 Spring Bean、ChatService、真实 Agent 或数据库。

锁定依赖 spring-ai-alibaba-graph-core:1.1.2.0 已通过本地 JAR 验证:

  • StateGraph.addNode(... AsyncNodeActionWithConfig)
  • StateGraph.addConditionalEdges(... AsyncEdgeActionWithConfig, mappings)
  • CompileConfig.builder().recursionLimit(...)
  • KeyStrategyFactoryBuilder、ReplaceStrategy、AppendStrategy
  • CompiledGraph.invoke(input, RunnableConfig)
  • RunnableConfig.builder().threadId(...)

阶段 2 将消费 Node action ports,阶段 3 将消费 compiled graph。阶段 1 自身没有生产调用方。

Goals / Non-Goals

Goals:

  • 建立明确的状态、状态枚举、节点、route 和 reason code 常量。
  • 建立 config-aware Node action ports 和可编译 Graph 工厂。
  • 以冻结计数和 guard 实现完整条件边。
  • 验证 AppendStrategy 和实际 CompiledGraph 行为。
  • 从有界 events 构造确定性的 orchestration trace。
  • 用 Fake Node 测试所有路由和终止边界。

Non-Goals:

  • 不接 ReactAgent、Gatekeeper Service、ToolTrace 或 Prompt。
  • 不修改 ChatService、Hook、ThreadLocal 或生产 Spring 配置。
  • 不持久化 trace,不修改 DB/DTO/API。
  • 不删除旧 Sequential 实现或测试。
  • 不运行 Maven E2E。

Decisions

1. Package and class boundaries

新代码位于 com.superbiz.agent.graph.diagnosis:

类型 职责
DiagnosisGraphState 26 个 state key、默认 Replace + events Append strategy、typed reads
DiagnosisGraphStatus Planner/Executor/Gatekeeper/Verifier/Composer status、Verdict、PlannerMode
DiagnosisGraphTopology Node id、route key、reason code 常量
DiagnosisGraphActions 八个 AsyncNodeActionWithConfig ports
DiagnosisGraphRouter 纯确定性 edge guard,不修改 state
DiagnosisGraphFactory 注册 Node/Edge、retry wrapper、evidence retry wrapper、recursion limit
OrchestrationEvent node/outcome/reasonCode/attempt
OrchestrationTransition from/to/reasonCode/attempt
DiagnosisOrchestrationTrace version/transitions/finalNode/terminationReason/degraded/evidenceRetryCount
DiagnosisOrchestrationTraceBuilder events → transitions/summary

Fake Node 和 script fixture 只存在于 test 源集。

替代方案:把 router 和状态读取放进 ChatService 或每个 Adapter。拒绝,因为会复制 guard 并阻碍 Fake Node 独立验证。

1.1 Direct dependency ownership

代码直接 import Graph Core API,因此 pom.xml 显式声明 com.alibaba.cloud.ai:spring-ai-alibaba-graph-core。版本继续由现有 Spring AI Alibaba BOM 管理为 1.1.2.0,不重复写版本。依赖 Agent Framework 的传递依赖虽可编译,但会让上游依赖图调整无意中破坏本模块,拒绝。

2. State strategy and typed reads

KeyStrategyFactoryBuilder.defaultStrategy(new ReplaceStrategy()),仅对 orchestration_events 使用 new AppendStrategy()。Node 每次返回 List.of(event),Graph 合并后保持有序列表。

typed reads 对 absent、null、错误类型和未知 enum 返回安全默认,不抛出边路由异常。未知 status/verdict 的路由默认 Fallback。

3. Config-aware action ports

所有 port 使用 AsyncNodeActionWithConfig,即使 Fake Node 当前只需要 state。原因是阶段 2 必须读取 RunnableConfig.threadId/metadata 并向 Agent 传递 run context;现在锁定接口可以避免随后重写 Graph topology。

DiagnosisGraphActions 构造时对八个 action 做 non-null 校验。

4. Retry counter ownership

Edge 只选 route,不修改 state。Factory 用 wrapper 管理计数:

  • Planner 重入前,如果上次 planner_status 是 INVALID_OUTPUT/RETRYABLE_FAILED,count + 1。
  • Verifier/Composer 同理。
  • 第一次失败后的 state count 为 0,允许 self-loop;重入执行后 count 为 1,再失败则 Fallback。
  • Evidence Retry Node 完成时将 evidence_retry_count + 1、planner_retry_count=0、planner_mode=EVIDENCE_GAP_ONLY。
  • Verified Input Node 完成时重置 verifier_retry_count=0,因为它产生新的 verified input。
  • 技术重试不修改 evidence count。

替代方案:由每个 Fake/real action 自行维护计数。拒绝,因为遗漏会造成无限 self-loop,骨架必须拥有控制计数。

5. Conditional routing

Source Route keys
Planner executor / retry_planner / fallback
Executor gatekeeper / fallback
Gatekeeper verified_input / fallback
Verifier composer / retry_verifier / evidence_retry / fallback
Composer end / retry_composer / fallback

Verified Input 固定到 Verifier,Evidence Retry 固定到 Planner,Fallback 固定到 END。

Verifier evidence-retry guard 同时要求:

  • verifier_status=COMPLETED
  • effective_verdict=LOW_CONFID
  • verifier_verdict_ceiling=PASS
  • verifier_output.facts_checked 至少一项具有非空 fact 且 verification 为 no_evidence 或 indirect_support
  • evidence_retry_count < 1

否则 LOW_CONFID 到 Composer。router 只检查现有 Verifier 输出,不选择工具或构造 retry context;后者属于阶段 2 Evidence Retry Node。

6. Recursion limit

合法最坏路径低于 20 次 Node 执行;compile recursion limit 固定 32。测试断言 compiled graph 的 max iterations/compile config,并覆盖第二次技术失败和第二次 LOW_CONFID 均终止。

recursion limit 是最后保险,不替代业务 guard。

7. Event and trace contract

OrchestrationEvent 构造时拒绝 blank node/outcome/reason 或 attempt<1。每个 Fake/真实 Node attempt 返回一个 event;AppendStrategy 累积实际路径。

Builder:

  1. 要求 events 非空且类型正确。
  2. 相邻 events 生成 transition,transition reason/attempt 取 source event。
  3. 最后 event 决定 finalNode 和 terminationReason。
  4. final node 为 Fallback 时 degraded=true;其他质量由 effective verdict 表达。
  5. evidence retry count 从 state 读取。
  6. toMap() 使用冻结 snake_case 字段,transition 同样提供 map。

不从应用日志推导路径,也不在 state 维护第二份 transitions。

8. Test architecture

DiagnosisGraphRoutingTest 使用真实 CompiledGraph + scriptable Fake actions:

  • 每个 node 有 outcome 队列和调用计数。
  • Fake action 只输出本 node 的状态字段、必要 guard payload 和一个 event。
  • 每个用例使用唯一 RunnableConfig.threadId。
  • 断言 node sequence、调用次数、最终 state、events、trace transitions。
  • 参数化覆盖同类技术失败,独立用例覆盖 evidence retry/counter reset 和 unknown fail-closed。

DiagnosisOrchestrationTraceBuilderTest 覆盖空 events、非法 event、顺序、fallback degraded 和 map shape。

Interface Impact

  • 等级:L2 internal interface。
  • 新接口消费者:阶段 2 adapters、阶段 3 orchestrator、阶段 4 test suite。
  • 构建消费者:Maven 直接声明 Graph Core,版本仍由既有 BOM 统一管理。
  • 当前生产消费者:无。
  • 外部 API/DTO/数据库/状态:无变化。
  • 兼容策略:后续 actions 实现 ports;Graph State 不直接传给 Agent。
  • 回滚:revert 本阶段提交,无数据迁移。

Risks / Trade-offs

  • [Graph merge 行为与假设不同] → 使用真实 CompiledGraph 单元测试,不 mock StateGraph。
  • [计数 wrapper 与 action 更新冲突] → wrapper 最后写入控制计数,actions 不拥有 retry counters。
  • [Verifier gap 解析过早耦合] → router 只识别现有 facts_checked 最小字段,retry context 构造留到阶段 2。
  • [未接生产入口被误认为完成] → proposal/spec/acceptance 明确 skeleton-only,阶段 3 才切换。
  • [事件无限追加] → 所有业务循环有硬上限且 recursion limit=32。

Migration Plan

  1. 添加纯 Java 状态、router、actions、factory 和 trace types。
  2. 先用 Fake actions 编译和执行完整 Graph。
  3. 阶段 1 archive + commit 后,阶段 2 基于 ports 实现真实 nodes。
  4. 如需回滚,revert 阶段 1 commit;当前生产路径不受影响。

Open Questions

无。