Files

227 lines
15 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
复杂 Chat 当前由 `ChatController -> ChatService.executeChatWithStrategy -> executeChatComplex` 驱动。`executeChatComplex` 同时负责 Run 生命周期、外层 LOW_CONFID round、`SequentialAgent` 构造、Verifier 解析、Composer、Fallback、持久化和评估;`VerifierInputHook` 又解析 Executor 输出、读取当前 Run 工具摘要、执行 `ExecutorGatekeeperService` 并通过 `VerifierContextHolder` 回传隐式状态。这些职责形成无法精确表达失败恢复位置、条件边和审计路径的隐式状态机。
阶段 0 不改变运行时,只冻结后续五个独立 change 必须遵守的架构契约。当前 change 的运行时影响为 L1;冻结目标最终涉及状态机语义、数据库与 Trace API,属于 L4。
| 区域 | 当前职责 | 冻结后的职责 |
|---|---|---|
| `ChatController` | 调用 ChatService | 请求/响应协议不变 |
| `ChatService` | Run 生命周期和细粒度隐式状态机 | 只维护 Run 生命周期并调用 Graph orchestrator |
| `SequentialAgent` | 固定跨 Agent 顺序 | 不再用于复杂 Chat 编排 |
| `VerifierInputHook` / `VerifierContextHolder` | 隐式 Gatekeeper、输入构造和跨层回传 | Gatekeeper/投影迁入显式 Node;旧隐式入口删除 |
| `ExecutorGatekeeperService` | 确定性 binding 校验 | 原规则复用,由显式 Gatekeeper Node 单次调用 |
| `DiagnosisRun` / `DiagnosisTraceService` | Run 与 self evaluation 聚合 | 增加 run-scoped orchestration trace |
## Goals / Non-Goals
**Goals:**
- 冻结最小 Graph State 的字段、所有权和更新策略。
- 冻结完整、有界且可终止的条件边与 retry 语义。
- 冻结 verified-input、Fallback、Run 状态与审计安全边界。
- 冻结旧测试替换范围和后续五个独立 change 的交付边界。
- 提供可被后续 OpenSpec Commit gate 机械对照的设计基线。
**Non-Goals:**
- 本 change 不实现或编译任何 Java/SQL/Prompt/配置变更。
- 不修改当前主运行时 specs 来宣称 StateGraph 已上线。
- 不运行 Maven E2E、日志或数据库验收。
- 不引入 SupervisorAgent、持久 Checkpointer、HITL、并行执行或 AIOps 公共 Graph。
- 不保留 Sequential/StateGraph 双轨开关。
## Decisions
### 1. StateGraph 只拥有跨节点控制状态
StateGraph 负责顺序、条件边、重试、终止和降级;现有 ReactAgent 继续完成语义任务;Gatekeeper、verified-input builder、evidence retry prepare 和固定 Fallback 使用确定性 Java Node。
替代方案:
- 继续在 ChatService 外层叠加 if/for:无法精确恢复失败节点和审计条件边,拒绝。
- 使用 SupervisorAgent:固定诊断 Pipeline 不需要动态选择专科 Agent,拒绝。
- 直接把父 State 交给 `ReactAgent.asNode(...)`:存在 messages/outputKey/私有状态泄漏风险,首版拒绝。
### 2. 最小 Graph State
默认 Replace;只有有界 `orchestration_events` 使用 Append。
| 字段 | 所有者/用途 | 策略 |
|---|---|---|
| `diagnosis_context` | query、history、sessionId、runId | Replace |
| `planner_plan` | Planner 结构化计划 | Replace |
| `planner_status` | COMPLETED / INVALID_OUTPUT / RETRYABLE_FAILED / NON_RETRYABLE_FAILED | Replace |
| `planner_retry_count` | 当前 Planner 阶段技术重试次数 | Replace |
| `planner_mode` | NORMAL / EVIDENCE_GAP_ONLY | Replace |
| `executor_output` | 完整 `executor_evidence_v2` | Replace |
| `executor_status` | COMPLETED / INVALID_OUTPUT / TOOL_BLOCKED / FAILED | Replace |
| `gatekeeper_result` | 原始确定性校验结果 | Replace |
| `gatekeeper_status` | PASS / LOW_CONFID / REJECT | Replace |
| `verified_executor_output` | 只保留通过 binding 的 claim 投影 | Replace |
| `verified_evidence` | 从通过 binding 的 `matched_text` 构造 | Replace |
| `verified_binding_count` | 当前可信 binding 数 | Replace |
| `verifier_verdict_ceiling` | PASS 或 LOW_CONFID | Replace |
| `verifier_output` | Verifier 结构化结果 | Replace |
| `verifier_status` | COMPLETED / INVALID_OUTPUT / RETRYABLE_FAILED / NON_RETRYABLE_FAILED | Replace |
| `verifier_retry_count` | 固定 verified input 技术重试次数 | Replace |
| `verifier_model_verdict` | 模型 PASS / LOW_CONFID / REJECT | Replace |
| `effective_verdict` | 应用 Gatekeeper ceiling 后的 verdict | Replace |
| `composer_output` | Composer 结构化输出 | Replace |
| `composer_status` | COMPLETED / INVALID_OUTPUT / RETRYABLE_FAILED / NON_RETRYABLE_FAILED | Replace |
| `composer_retry_count` | 固定安全输入技术重试次数 | Replace |
| `evidence_retry_count` | 诊断补证据轮次 | Replace |
| `retry_context` | evidence gaps、prior verified data、completed queries、约束 | Replace |
| `orchestration_events` | 每个 node attempt 的有界终态事件 | Append |
| `final_answer` | 最终安全用户表达 | Replace |
| `failure_reason` | 确定性失败 reason code | Replace |
不保存 Prompt、模型思考、完整工具原文、完整 Graph State 快照或其他 Run 数据。
### 3. 完整路由矩阵
| From | Outcome / Guard | To | 计数与约束 |
|---|---|---|---|
| START | always | Planner | Planner 阶段 retry count=0 |
| Planner | COMPLETED | Executor | 不增加 retry |
| Planner | INVALID_OUTPUT / RETRYABLE_FAILED 且 count=0 | Planner | 同业务输入重试一次,count=1 |
| Planner | NON_RETRYABLE_FAILED 或技术重试耗尽 | Fallback | 不执行后续 Agent |
| Executor | COMPLETED | Gatekeeper | 合法 no-evidence 也属于 COMPLETED |
| Executor | INVALID_OUTPUT / TOOL_BLOCKED / FAILED | Fallback | Executor 永不重试 |
| Gatekeeper | PASS | Verified Input Builder | ceiling=PASS |
| Gatekeeper | LOW_CONFID 且 verified binding > 0 | Verified Input Builder | ceiling=LOW_CONFID |
| Gatekeeper | REJECT、未知状态或 LOW_CONFID 且 binding=0 | Fallback | 不执行 Verifier |
| Verified Input Builder | completed | Verifier | 只投影通过 binding |
| Verifier | INVALID_OUTPUT / RETRYABLE_FAILED 且 count=0 | Verifier | 相同 verified input 重试一次 |
| Verifier | NON_RETRYABLE_FAILED 或技术重试耗尽 | Fallback | 不输出 Executor claim |
| Verifier | PASS / REJECT | Composer | 使用 effective verdict |
| Verifier | LOW_CONFID,非 ceiling 导致,存在有效 gaps,evidence count=0 | Prepare Evidence Retry | evidence count 增加一次 |
| Verifier | LOW_CONFID 且任一补查条件不满足 | Composer | 不补查 |
| Prepare Evidence Retry | completed | Planner | mode=EVIDENCE_GAP_ONLY;新 Planner 阶段 retry count 重置 |
| Composer | COMPLETED | END | 返回 Composer 安全表达 |
| Composer | INVALID_OUTPUT / RETRYABLE_FAILED 且 count=0 | Composer | 相同 allowed material 重试一次 |
| Composer | NON_RETRYABLE_FAILED 或技术重试耗尽 | Fallback | 可使用 Verifier 已允许材料 |
| Fallback | deterministic answer produced | END | degraded=true |
| 未处理异常/持久化失败/无法生成安全答案 | failure | outer failure handling | Run=FAILED,best-effort 保存已有 events |
Graph compile 必须设置 recursion limit 作为最终保险;业务循环仍由独立计数显式限制。
### 4. 四类计数互相独立
- `planner_retry_count`:每次进入 Planner 阶段最多一次;evidence retry 重新进入时重置。
- `verifier_retry_count`:同一 verified input 最多一次。
- `composer_retry_count`:同一 allowed material 最多一次。
- `evidence_retry_count`:整个 Run 最多一次。
技术重试不增加 evidence retry,也不得重新执行前序节点或工具。
### 5. Executor 状态按输出契约定义
合法 `executor_evidence_v2`(包括 no-evidence、空查询结果或工具限制说明)均为 COMPLETED。只有工具层明确禁止且没有合法结构时为 TOOL_BLOCKED;空/非法结构为 INVALID_OUTPUT;其他未形成合法结构的异常为 FAILED。只有 COMPLETED 进入 Gatekeeper,其余直接 Fallback 且不重试。
补证据轮只执行增量查询,但输出包含应保留 prior verified claims 的完整快照;Java 不做 claim 文本语义合并,完整快照重新经过 Gatekeeper。
### 6. Gatekeeper 与 Verifier 输入边界
Gatekeeper 保留原始结果并 fail-closed 标准化为 PASS / LOW_CONFID / REJECT;未知、缺失或无法识别结果映射为 REJECT。
PASS 与可继续 LOW_CONFID 都经过 Verified Input Builder。Builder 复用 `checked_bindings`,仅从通过项投影 `claim_id`、`source_invocation_id`、`tool_name`、`raw_path`、`matched_text`;不得传递完整 `tool_trace_summary`、失败 binding 或 Executor 自由文本。LOW_CONFID ceiling 不得被模型 PASS 提升。
### 7. 两类安全 Fallback
**前置验证失败:** Planner/Executor/Verifier 无法形成可信材料,或 Gatekeeper REJECT/零可信 binding。固定表达只包含校验状态、工具执行概况、诊断限制和人工查看 Trace 建议,不含任何 Executor claim。
**Composer 后置降级:** 已有 Verifier 允许材料,但 Composer 技术重试耗尽。确定性模板可以使用 allowed claims/missing info/recommended actions,仍不得读取 raw output。
成功生成安全答案时 Run=SUCCESS,并用 verdict 或 `orchestrationTrace.degraded=true` 表达质量;只有未处理异常、持久化失败或无法生成安全答案时为 FAILED,不新增 DEGRADED 状态。
### 8. Run-scoped 编排审计
每个 Node attempt 最多追加一个 `{node,outcome,reason_code,attempt}` 终态 event。按事件顺序压缩为 version、transitions、final_node、termination_reason、degraded、evidence_retry_count。
只持久化到当前 `diagnosis_run.orchestration_trace`;`RunnableConfig.threadId=runId`。Trace API 只在 `run.orchestrationTrace` 返回解析对象,不复制到顶层/session/raw 字段。它不替代 self evaluation、AgentStep、ToolInvocation 或 Graph checkpoint。
### 9. 测试替换边界
| 测试 | 处理 |
|---|---|
| `ChatServiceSequentialAgentTest` | 用 Graph 路由、Node 契约和 Chat 集成测试替换;删除固定顺序断言 |
| `VerifierInputHookTest` | 删除或改写为显式 Gatekeeper/Input Builder 契约测试 |
| `ExecutorGatekeeperServiceTest` | 保留并扩展 checked binding 与未知状态 fail-closed |
| `ChatControllerTest` | 保留,证明 `/api/chat` 兼容 |
| `DiagnosisTraceServiceTest` / Repository tests | 保留并扩展 run-scoped orchestration trace |
| Eval/Composer 安全测试 | 保留,证明 allowed-material、no-evidence 和 REJECT 不退化 |
阶段 0 无运行时行为,不新增单元测试。阶段 1–4 按风险建立上述测试;阶段 5 统一执行 Maven E2E、日志和数据库验收。
### 10. 六个独立 OpenSpec change
| 阶段 | Change | 唯一交付边界 |
|---|---|---|
| 0 | `chat-diagnosis-stategraph-design-freeze` | 冻结本设计,不改运行时 |
| 1 | `chat-diagnosis-stategraph-routing-skeleton` | Graph State、拓扑、Fake Node 路由与 trace builder |
| 2 | `chat-diagnosis-stategraph-real-nodes` | Agent Adapter、Gatekeeper、verified input、retry prepare、Fallback |
| 3 | `chat-diagnosis-stategraph-chatservice-cutover` | ChatService 生产入口、DB migration、Run/Trace API |
| 4 | `chat-diagnosis-stategraph-test-suite` | 新测试体系与旧测试替换 |
| 5 | `chat-diagnosis-stategraph-cleanup-docs` | 旧编排清理、最终回归、Maven E2E、日志/DB、文档 |
后续 change 必须先读取阶段 0 archive;若发现设计不准,必须在当阶段 OpenSpec 中显式记录和解决。
## Interface Impact
### Classification
- 当前阶段 0 change:L1。只交付设计、术语和决策档案,不改变运行时。
- 最终冻结目标:L4。状态机语义和 Run 终态判断变化,Trace API 与数据库契约扩展,旧内部调用路径将被删除。
### Changed contracts and consumers
| 契约 | 目标变化 | 消费者 |
|---|---|---|
| `/api/chat` | 请求/响应结构保持不变,内部路径改由 Graph 驱动 | ChatController、前端/demo 客户端 |
| Agent 输出协议 | `executor_evidence_v2`、Verifier、Composer 输出保持不变 | Agent adapters、Eval |
| Verifier 输入 | 改为 `verified_executor_output + verified_evidence`,不再提供完整 tool trace | Verifier adapter、Prompt binding |
| Run 状态 | 安全 Fallback 为 SUCCESS + degraded;只有无法安全响应的未处理失败为 FAILED | Trace、Feedback、Eval、运维审计 |
| Trace API | 仅 `run.orchestrationTrace` 新增解析对象 | Trace DTO/Service、demo 脚本、Trace UI |
| 数据库 | 仅新增 nullable JSON `diagnosis_run.orchestration_trace` | Flyway、DiagnosisRun repository |
| 内部编排 | 删除复杂 Chat Sequential、外层 round、Gatekeeper-in-Hook/ThreadLocal 入口 | ChatService、Hook、测试 |
### Compatibility, migration, and rollback
- 兼容消费者不需要修改 `/api/chat` 调用;Trace 消费者按加法字段处理。
- 新 StateGraph Chat Run 必须写非空 orchestration trace;历史 Run 不回填、不增加兼容读取。
- 数据库迁移先加 nullable 列,再切换代码;nullable 只服务于安全部署,不降低新 Run 应用契约。
- 每阶段可 Git revert;阶段 3 后回滚代码时允许保留无害 nullable 列。
- 不以 feature flag 或配置恢复长期双轨;若切换失败,回滚完整阶段提交。
### Interface acceptance
- Controller 契约测试证明 `/api/chat` 不变。
- Node/集成测试证明 Verifier 输入与安全 Fallback 边界。
- Repository/Trace 测试证明 run ownership 和唯一 API 投影。
- 阶段 5 Maven E2E、`logs/` 和数据库查询证明跨层最终行为。
## Risks / Trade-offs
- [阶段性 spec 与运行时差异] 阶段 0 只新增设计基线 capability,不修改运行时 specs。
- [六个 change 漂移] 每个 Discover/Commit gate 强制引用阶段 0 archive。
- [Graph API 漂移] 后续只使用本地 `1.1.2.0` JAR 已验证签名,并由阶段 1 编译测试锁定。
- [Gatekeeper 双执行] 阶段 2 迁移显式 Node,阶段 5 删除旧 Hook/ThreadLocal,不形成长期双轨。
- [安全降级泄漏] Fallback 输入类型分离并用 Node/集成测试证明。
- [Trace 无限增长或泄密] event 每 attempt 一条,受业务次数与 recursion limit 限制,字段白名单禁原文。
## Migration Plan
1. 阶段 0 archive 本设计基线并提交。
2. 阶段 1 引入未接生产入口的 Graph 骨架和路由测试。
3. 阶段 2 接入真实节点但不切换 ChatService。
4. 阶段 3 切换 ChatService,增加 nullable JSON 列和 run Trace 投影。
5. 阶段 4 用新测试体系覆盖路由和安全契约。
6. 阶段 5 删除旧编排并执行最终 Maven E2E、`logs/` 与数据库验收。
回滚按阶段 Git revert。阶段 3 后回滚运行时代码时允许保留 nullable 列;不通过配置重新启用长期双轨。历史 Run 不回填。
## Open Questions
无。若后续发现本设计与锁定 API 或安全契约冲突,必须在当阶段 sm-flow 中分类并按门禁处理。