Files

170 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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
无。