refactor(trace): enforce run-only diagnosis model

This commit is contained in:
zhuyongxin
2026-07-20 14:11:34 +08:00
parent 190013c901
commit 4b9cf7c5cc
63 changed files with 583 additions and 909 deletions
@@ -0,0 +1,199 @@
# Chat StateGraph 运行时架构
**更新日期**:2026-07-20
**状态**:当前复杂 Chat 诊断的权威运行时架构
**适用范围**:`POST /api/chat` 的复杂诊断路径;简单 Chat 和 AIOps 使用各自链路
## 1. 架构定位
复杂 Chat 已单轨切换为 Spring AI Alibaba bounded `StateGraph`。`ChatService` 负责 Run 生命周期和持久化,`ChatDiagnosisGraphRuntime` 负责执行 Graph,`DiagnosisGraphFactory` 负责声明 Node 与条件边,Agent/Java Node 负责各自的语义任务或确定性校验。
```mermaid
flowchart LR
API["POST /api/chat"] --> Chat["ChatService.executeChatComplex"]
Chat --> Session["chat_session"]
Chat --> Run["diagnosis_run: RUNNING"]
Chat --> Actions["DiagnosisRealGraphActionsFactory"]
Actions --> Runtime["ChatDiagnosisGraphRuntime"]
Runtime --> Factory["DiagnosisGraphFactory"]
Factory --> Graph["Compiled StateGraph"]
Graph --> Planner["PlannerNodeAdapter"]
Graph --> Executor["ExecutorNodeAdapter"]
Graph --> Gatekeeper["GatekeeperNode"]
Graph --> Projection["VerifiedInputNode"]
Graph --> Verifier["VerifierNodeAdapter"]
Graph --> Retry["EvidenceRetryPrepareNode"]
Graph --> Composer["ComposerNodeAdapter"]
Graph --> Fallback["FallbackNode"]
Executor --> Tools["lookup_knowledge / logs / metrics"]
Tools --> Invocations["tool_invocation"]
Planner --> Steps["agent_step"]
Executor --> Steps
Verifier --> Steps
Composer --> Steps
Graph --> Mapper["DiagnosisGraphResultMapper"]
Graph --> TraceBuilder["DiagnosisOrchestrationTraceBuilder"]
Mapper --> SelfEval["diagnosis_run.self_evaluation"]
TraceBuilder --> RouteTrace["diagnosis_run.orchestration_trace"]
Chat --> RunDone["diagnosis_run: SUCCESS / FAILED"]
RunDone --> TraceAPI["exact Run Trace API"]
SelfEval --> TraceAPI
RouteTrace --> TraceAPI
Steps --> TraceAPI
Invocations --> TraceAPI
```
## 2. 运行生命周期
一次复杂 Chat 运行按以下顺序执行:
1. `ChatService` 解析或创建 `sessionId`,生成唯一 `runId`。
2. 确保 `chat_session` 元数据存在,并创建 `diagnosis_run`,初始状态为 `RUNNING`、`agent_flow=CHAT`。
3. 构建 Planner、Executor、Verifier、Composer 四个 `ReactAgent`,再由 `DiagnosisRealGraphActionsFactory` 组合 Java Nodes。
4. `ChatDiagnosisGraphRuntime` 以 `runId` 作为 Graph `threadId`,将 `sessionId/runId` 放入 `RunnableConfig.metadata`。
5. `DiagnosisGraphFactory` 编译 StateGraph 并执行,Graph recursion limit 固定为 32。
6. Graph 返回非空 `final_answer` 后,`DiagnosisGraphResultMapper` 生成 verifier evaluation,`DiagnosisOrchestrationTraceBuilder` 压缩路由摘要。
7. `ChatService` 保存答案、耗时、步骤数、工具数、自评估和编排摘要,将 Run 标记为 `SUCCESS`。
8. 未处理异常会尽力保存 partial state/partial trace,再将 Run 标记为 `FAILED`;能够生成安全 Fallback 的路径仍是 `SUCCESS`,并通过 `degraded=true` 表达质量降级。
9. `finally` 清理本轮检索追踪和 session/run ThreadLocal,避免跨 Run 污染。
## 3. Graph 拓扑
```mermaid
flowchart TD
Start([START]) --> Planner[Planner]
Planner -->|COMPLETED| Executor[Executor]
Planner -->|technical retry once| Planner
Planner -->|non-retryable / exhausted| Fallback[Fallback]
Executor -->|COMPLETED| Gatekeeper[Gatekeeper]
Executor -->|INVALID_OUTPUT / TOOL_BLOCKED / FAILED| Fallback
Gatekeeper -->|PASS| VerifiedInput[Verified Input]
Gatekeeper -->|LOW_CONFID + verified bindings| VerifiedInput
Gatekeeper -->|REJECT / no verified binding| Fallback
VerifiedInput --> Verifier[Verifier]
Verifier -->|technical retry once| Verifier
Verifier -->|LOW_CONFID + critical gap + retry allowed| EvidenceRetry[Evidence Retry]
EvidenceRetry -->|EVIDENCE_GAP_ONLY| Planner
Verifier -->|completed and no retry| Composer[Composer]
Verifier -->|non-retryable / exhausted| Fallback
Composer -->|COMPLETED| End([END])
Composer -->|technical retry once| Composer
Composer -->|non-retryable / exhausted| Fallback
Fallback --> End
```
路由规则:
| 节点 | 继续条件 | 重试 | 安全终止 |
|---|---|---|---|
| Planner | `COMPLETED` 进入 Executor | `INVALID_OUTPUT` / `RETRYABLE_FAILED` 最多一次技术重试 | `NON_RETRYABLE_FAILED` 或重试耗尽进入 Fallback |
| Executor | 只有 `COMPLETED` 进入 Gatekeeper | 不做 Graph 技术重试 | 非法输出、工具阻断或执行失败进入 Fallback |
| Gatekeeper | `PASS`,或 `LOW_CONFID` 且至少一个 verified binding | 不重试 | `REJECT` 或零 verified binding 进入 Fallback |
| Verifier | 完成后由 `effective_verdict` 决定 Composer 或补证据 | 技术失败最多一次;证据补查最多一次 | 不可重试失败或技术重试耗尽进入 Fallback |
| Composer | `COMPLETED` 结束 | 技术失败最多一次 | 不可重试失败或重试耗尽进入 Fallback |
| Fallback | 生成非空确定性安全答复 | 不重试 | 直接结束并标记 `degraded=true` |
Evidence retry 只有同时满足以下条件才发生:
- `evidence_retry_count < 1`。
- Gatekeeper 给出的 verifier verdict ceiling 仍允许 `PASS`。
- Verifier 输出包含可提取的 critical evidence gap。
补证据时 Planner 进入 `EVIDENCE_GAP_ONLY`,`planner_retry_count` 重置;Executor 只执行增量查询,但重新输出完整 `executor_evidence_v2` 快照。
## 4. 状态与执行边界
### Graph State
Graph State 只保存跨 Node 的控制信息和结构化结果:
- `diagnosis_context`、`planner_plan`、`executor_output`。
- `gatekeeper_result`、`verified_executor_output`、`verified_evidence`。
- `verifier_output`、`composer_output`、`final_answer`。
- Planner/Verifier/Composer 技术重试计数和 `evidence_retry_count`。
- `orchestration_events` 有界追加事件。
默认状态键使用 replace strategy,只有 `orchestration_events` 使用 append strategy。事件在 Graph 边界存为 classloader-neutral Map:`node/outcome/reason_code/attempt`,避免 DevTools restart classloader 造成 record 类型身份不一致。
### RunnableConfig
外层 Graph config 使用:
- `threadId = runId`。
- metadata 包含 `sessionId` 和 `runId`。
调用 nested `ReactAgent` 时,`ReactAgentDiagnosisInvoker` 创建独立 config,只保留业务身份与 store,不向子 Agent 传播外层 Graph 的 human-feedback、state-update、checkpoint/resume 控制 metadata,避免父 Graph 恢复语义污染子 Graph。
## 5. 证据信任边界
```text
Executor output
-> source_invocation_id + raw_path + evidence_excerpt
-> GatekeeperNode / ExecutorGatekeeperService
-> 按当前 runId 读取 tool_invocation
-> 验证 invocation ownership、raw_path、excerpt
-> VerifiedInputNode
-> 只投影通过的 claims/bindings/evidence
-> VerifierNodeAdapter
-> 只判断已验真证据是否支持 claim
-> ComposerNodeAdapter
-> 只表达允许输出的结论、限制和建议
```
Verifier 不读取完整工具 Trace,不执行新检索,也不读取 Skill 正文。当前版本不生成或读取 `tool_trace_summary`。
## 6. Run 级审计模型
| 审计层 | 存储/API | 回答的问题 |
|---|---|---|
| 执行明细 | `agent_step`、`tool_invocation` | 模型和工具实际做了什么? |
| 证据与答案质量 | `diagnosis_run.self_evaluation` | 引用是否真实、claim 是否可推导、Prompt/Gatekeeper 版本是什么? |
| Graph 路由 | `diagnosis_run.orchestration_trace` / `run.orchestrationTrace` | 走了哪些 Node、为何重试或降级、在哪里结束? |
`orchestration_trace` 当前结构:
```json
{
"version": "stategraph-v1",
"transitions": [
{"from": "planner", "to": "executor", "reason_code": "completed", "attempt": 1}
],
"final_node": "composer",
"termination_reason": "composer_completed",
"degraded": false,
"evidence_retry_count": 0
}
```
该字段只属于 exact Run 投影,响应不提供兼容 `session` 投影;非 StateGraph Run 可以为空。
## 7. 验收层次
| 测试层 | 权威测试 | 覆盖 |
|---|---|---|
| Workflow | `DiagnosisGraphWorkflowTest` | 全部分支、有限重试、补证据和 Fallback |
| Node Contract | `DiagnosisGraphNodeContractTest` | 真实 Node 的输入投影、输出状态和证据边界 |
| Runtime | `ChatDiagnosisGraphRuntimeTest` | config、最终状态、partial failure/trace |
| Chat Integration | `ChatServiceGraphIntegrationTest` | Run 生命周期、答案、自评估、编排摘要和失败持久化 |
| Trace Contract | `DiagnosisTraceServiceTest` | exact run ownership 和 `run.orchestrationTrace` 投影 |
| Demo Contract | `InterviewDemoScriptContractTest` | exact runId、Graph 字段和 summary 输出 |
## 8. 关键代码
- `src/main/java/com/superbiz/agent/service/ChatService.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/ChatDiagnosisGraphRuntime.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisGraphFactory.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisGraphRouter.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisGraphState.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisRealGraphActionsFactory.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/ReactAgentDiagnosisInvoker.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisGraphResultMapper.java`
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisOrchestrationTraceBuilder.java`
- `src/main/java/com/superbiz/agent/service/DiagnosisTraceService.java`