771 lines
27 KiB
Markdown
771 lines
27 KiB
Markdown
# ISS-011 Chat 诊断 StateGraph 编排改造
|
||
|
||
**状态**:待实现
|
||
**严重程度**:高
|
||
**发现时间**:2026-07-16
|
||
**来源**:OnCall / Agent 编排模拟面试、当前 Chat 复杂诊断调用链复核
|
||
**预计实施周期**:2–3 个工作日
|
||
|
||
---
|
||
|
||
## 1. 背景
|
||
|
||
当前复杂 Chat 诊断在 `ChatService.executeChatComplex(...)` 中采用两层编排:
|
||
|
||
```text
|
||
SequentialAgent
|
||
-> Planner
|
||
-> Executor
|
||
-> Verifier
|
||
|
||
ChatService 外层循环
|
||
-> 解析 Verifier PASS / LOW_CONFID / REJECT
|
||
-> 决定 Composer、补证据或安全降级
|
||
```
|
||
|
||
这种实现已经具备 Planner、Executor、Gatekeeper、Verifier、Composer 的职责拆分,但流程控制分散在:
|
||
|
||
- `SequentialAgent` 固定顺序。
|
||
- `VerifierInputHook` 内的 Gatekeeper。
|
||
- `ChatService` 外层最多两轮循环。
|
||
- Composer 和固定降级逻辑。
|
||
|
||
随着 no-evidence、工具能力阻断、Executor 非法输出、Gatekeeper REJECT、Verifier LOW_CONFID 等状态增加,当前高层 Flow 抽象已经无法清晰表达阶段短路和定向重试。
|
||
|
||
---
|
||
|
||
## 2. 当前问题
|
||
|
||
### 2.1 Executor 语义失败后仍可能继续 Pipeline
|
||
|
||
如果 Executor 抛出异常,当前外层 `catch` 可以终止 Run;但如果 Executor 正常返回一段错误文本、非法结构或工具阻断结果,`SequentialAgent` 仍会继续调用 Verifier。
|
||
|
||
这会造成:
|
||
|
||
- Verifier 消费无效输入。
|
||
- 增加无意义模型调用和 Token。
|
||
- Trace 中难以区分执行失败与证据不足。
|
||
- 最终降级发生得过晚。
|
||
|
||
### 2.2 不能按失败阶段精确重试
|
||
|
||
当前 LOW_CONFID 重试会重新运行:
|
||
|
||
```text
|
||
Planner -> Executor -> Verifier
|
||
```
|
||
|
||
但真实需求可能是:
|
||
|
||
| 失败位置 | 期望恢复位置 |
|
||
|---|---|
|
||
| Planner 输出非法 | 重试 Planner |
|
||
| Executor 输出结构非法 | 保留计划,只重试 Executor |
|
||
| Gatekeeper 引用验真失败 | 直接进入固定安全降级 |
|
||
| Verifier LOW_CONFID | 将 missing evidence 返回 Planner 进行有限补证据 |
|
||
| 工具权限或能力阻断 | 不重试,直接降级 |
|
||
|
||
当前 `SequentialAgent + 外层 round` 无法自然表达这些回边。
|
||
|
||
### 2.3 Gatekeeper 藏在 Verifier Hook 中
|
||
|
||
当前链路是:
|
||
|
||
```text
|
||
Executor
|
||
-> VerifierInputHook
|
||
-> ExecutorGatekeeperService
|
||
-> Verifier
|
||
```
|
||
|
||
Hook 适合加工和拦截 Verifier 输入,但不适合根据 Gatekeeper 结果跳回 Executor。Gatekeeper 作为诊断质量门禁,应该成为显式编排节点。
|
||
|
||
### 2.4 编排逻辑已经形成隐式状态机
|
||
|
||
`ChatService` 当前同时负责:
|
||
|
||
- 构建 Agent。
|
||
- 执行 SequentialAgent。
|
||
- 控制 LOW_CONFID 轮次。
|
||
- 构造 retry context。
|
||
- 调用 Composer。
|
||
- 固定模板降级。
|
||
- 持久化 Run、self_evaluation 和汇总指标。
|
||
|
||
继续增加 `if/else` 会进一步扩大 `ChatService` 职责,降低流程可读性和可测试性。
|
||
|
||
---
|
||
|
||
## 3. 改造目标
|
||
|
||
使用 Spring AI Alibaba `StateGraph` 接管跨 Agent 的状态转换,现有 ReactAgent、Prompt、工具、证据协议和持久化能力继续复用。
|
||
|
||
目标职责:
|
||
|
||
```text
|
||
StateGraph
|
||
-> 控制顺序、条件边、重试、终止和降级
|
||
|
||
ReactAgent
|
||
-> 完成 Planner、Executor、Verifier、Composer 节点内部语义任务
|
||
|
||
Java Node
|
||
-> 完成 Gatekeeper、重试判断、固定降级等确定性任务
|
||
```
|
||
|
||
本次不使用 SupervisorAgent 替代固定诊断 Pipeline。SupervisorAgent 留给未来多个专科 SubAgent 之间的动态路由。
|
||
|
||
---
|
||
|
||
## 4. 目标流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start["START"] --> Planner["Planner"]
|
||
Planner -- "成功" --> Executor["Executor"]
|
||
Planner -- "失败" --> Fallback["Fallback"]
|
||
|
||
Executor -- "结构有效" --> Gatekeeper["Gatekeeper"]
|
||
Executor -- "失败或阻断" --> Fallback
|
||
|
||
Gatekeeper -- "PASS" --> Verifier["Verifier"]
|
||
Gatekeeper -- "LOW_CONFID 且存在已验真 binding" --> VerifiedInput["Build Verified Verifier Input"]
|
||
Gatekeeper -- "LOW_CONFID 且零条已验真 binding" --> Fallback
|
||
Gatekeeper -- "REJECT" --> Fallback
|
||
VerifiedInput --> Verifier
|
||
|
||
Verifier -- "PASS" --> Composer["Composer"]
|
||
Verifier -- "REJECT" --> Composer
|
||
Verifier -- "LOW_CONFID 且有预算" --> EvidenceRetry["Prepare Evidence Retry"]
|
||
Verifier -- "LOW_CONFID 且无预算" --> Composer
|
||
Verifier -- "执行失败" --> Fallback
|
||
EvidenceRetry --> Planner
|
||
|
||
Composer --> End["END"]
|
||
Fallback --> End
|
||
```
|
||
|
||
### 4.1 本期只保留 Verifier LOW_CONFID 补证据
|
||
|
||
Gatekeeper REJECT 本期不重试,直接进入 Fallback。
|
||
|
||
Verifier LOW_CONFID 保留当前有限补证据能力:
|
||
|
||
```text
|
||
目标:补充缺失证据
|
||
返回:Planner
|
||
默认上限:1 次
|
||
```
|
||
|
||
只有同时满足以下条件时才允许补证据:
|
||
|
||
- Verifier 提供了可执行的 missing evidence。
|
||
- LOW_CONFID 不是由 Gatekeeper verdict ceiling 导致。
|
||
- 所需工具存在且当前 Agent 有权限。
|
||
- 仍有 Run 级预算。
|
||
- 本 Run 尚未执行过补证据轮次。
|
||
|
||
Prepare Evidence Retry Node 由代码实现,负责把已确认事实、证据缺口、已调用工具、已执行 Query、当前 Skill 和剩余预算整理为受限 retry context,然后返回 Planner。
|
||
|
||
Planner 第二轮使用 `EVIDENCE_GAP_ONLY` 模式,只生成增量补证据计划,不允许重新开始完整诊断、扩大服务范围或重复已经成功执行的查询。
|
||
|
||
---
|
||
|
||
## 5. Gatekeeper REJECT 策略
|
||
|
||
**决策状态**:已确认,2026-07-16。
|
||
|
||
本期不增加 EvidenceRepairNode,也不让 Gatekeeper REJECT 返回 Executor 重试。任何 Gatekeeper REJECT 都直接进入固定安全降级。
|
||
|
||
原因:
|
||
|
||
- 第一版先验证显式 Graph 编排和阶段短路,不同时引入新的模型节点。
|
||
- 证据引用错误不一定可以安全修复,自动重新绑定可能制造第二次幻觉。
|
||
- 当前最重要的是保证不可信 Executor 输出不能进入 Verifier,而不是提高 REJECT 的自动恢复率。
|
||
- 直接 Fallback 的状态语义简单,便于先建立稳定的路由和测试基线。
|
||
|
||
处理流程:
|
||
|
||
```text
|
||
Executor
|
||
-> Gatekeeper
|
||
-> PASS / LOW_CONFID:进入 Verifier
|
||
-> REJECT:直接 Fallback
|
||
```
|
||
|
||
Fallback 最终表达只保留:
|
||
|
||
最终表达只保留:
|
||
|
||
- 已确认且能够独立验证的事实。
|
||
- 无法验证的证据引用问题。
|
||
- 当前诊断限制。
|
||
- 建议人工检查的下一步。
|
||
|
||
---
|
||
|
||
### 5.1 Executor INVALID_OUTPUT 策略
|
||
|
||
**决策状态**:已确认,2026-07-16。
|
||
|
||
`INVALID_OUTPUT` 定义为 Executor Agent 调用已经返回,但无法解析为最小 `executor_evidence_v2` 结构。它对应当前解析状态中的 `missing` 或 `malformed`,包括:
|
||
|
||
- 输出为空。
|
||
- 输出不是 JSON。
|
||
- JSON 被截断或语法非法。
|
||
- JSON 根节点不是对象。
|
||
- `claims` 不是数组。
|
||
|
||
以下情况不属于 `INVALID_OUTPUT`:
|
||
|
||
- 合法的空 claims 和 missing info。
|
||
- 合法 no-evidence。
|
||
- 结构可解析但 evidence binding 错误,此类进入 Gatekeeper。
|
||
- 引用真实但证据无法支持 claim,此类进入 Verifier。
|
||
|
||
本期处理方式:
|
||
|
||
```text
|
||
Executor INVALID_OUTPUT
|
||
-> 不重试 Executor
|
||
-> 不调用 Gatekeeper
|
||
-> 不调用 Verifier
|
||
-> 不调用模型 Composer
|
||
-> 固定安全 Fallback
|
||
```
|
||
|
||
原因:
|
||
|
||
- 当前没有可信结构化结果可供后续门禁消费。
|
||
- 重试有工具权限的 Executor 可能重复调用工具并产生第二套证据。
|
||
- 本期优先建立清晰、可验证的控制流,不同时引入格式修复模式。
|
||
|
||
Trace 至少记录:
|
||
|
||
- `executor_status = INVALID_OUTPUT`。
|
||
- missing / malformed 及解析错误摘要。
|
||
- 当前 Run 已发生的工具调用数量和成功情况。
|
||
- 跳转 Fallback 的原因。
|
||
- Gatekeeper、Verifier 未执行的原因。
|
||
|
||
Executor 原始输出只允许保留在受控审计中,不得直接作为用户答案。
|
||
|
||
---
|
||
|
||
### 5.2 Gatekeeper LOW_CONFID 策略
|
||
|
||
**决策状态**:已确认,2026-07-16。
|
||
|
||
Gatekeeper LOW_CONFID 表示 Executor 输出存在非致命结构或引用缺口,但不代表所有 evidence binding 都不可信。本期按已验真 binding 数量处理:
|
||
|
||
```text
|
||
Gatekeeper LOW_CONFID
|
||
-> 至少一条 checked binding 为 pass
|
||
-> 代码过滤失败 binding
|
||
-> 构造 verified executor output
|
||
-> Verifier
|
||
-> 最终 verdict 最高为 LOW_CONFID
|
||
|
||
-> 零条 checked binding 为 pass
|
||
-> 固定 Fallback
|
||
```
|
||
|
||
Verifier Input Builder 必须:
|
||
|
||
- 只保留 Gatekeeper `checked_bindings.status=pass` 对应的 evidence binding。
|
||
- 删除失败 binding。
|
||
- 没有有效 binding 的 claim 不得作为确认性 claim 进入 Verifier。
|
||
- 不向 Verifier 传递 Executor 未经验真的自由文本作为事实来源。
|
||
- 将 `verifier_verdict_ceiling` 设置为 `LOW_CONFID`。
|
||
|
||
即使模型 Verifier 返回 PASS,编排层也必须将有效 verdict 限制为 LOW_CONFID。
|
||
|
||
LOW_CONFID 进入 Verifier 的目标是保留部分真实证据,而不是让 Verifier 修复 Gatekeeper 失败。
|
||
|
||
---
|
||
|
||
## 6. Graph State 最小契约
|
||
|
||
Graph State 保存跨节点需要的结构化状态,不复制完整工具原文和模型思考过程。
|
||
|
||
| 状态 | 作用 | 策略 |
|
||
|---|---|---|
|
||
| `diagnosis_context` | 当前 Query、history、sessionId/runId 等统一上下文 | Replace |
|
||
| `planner_plan` | Planner 结构化计划 | Replace |
|
||
| `planner_status` | 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` | 只保留 Gatekeeper 通过 binding 的 Verifier 输入 | Replace |
|
||
| `verified_binding_count` | 当前可供 Verifier 使用的 binding 数量 | Replace |
|
||
| `verifier_verdict_ceiling` | PASS 或 LOW_CONFID | Replace |
|
||
| `verifier_output` | Verifier 结构化结果 | Replace |
|
||
| `verdict` | PASS / LOW_CONFID / REJECT / FAILED | Replace |
|
||
| `evidence_retry_count` | 补证据轮次 | Replace |
|
||
| `retry_context` | missing evidence 和补查约束 | Replace |
|
||
| `final_answer` | 最终用户表达 | Replace |
|
||
| `failure_reason` | 当前确定性失败原因 | Replace |
|
||
|
||
说明:
|
||
|
||
- `agent_step` 和 `tool_invocation` 继续作为完整 Trace 数据源。
|
||
- Graph State 只保存控制流程所需的最新状态。
|
||
- `no_evidence` 属于合法 Executor 输出,不等于 `FAILED`,仍然进入 Gatekeeper 和 Verifier。
|
||
|
||
---
|
||
|
||
## 7. 与当前代码的关系
|
||
|
||
### 7.1 继续复用
|
||
|
||
- Planner、Executor、Verifier、Composer Prompt。
|
||
- Skill Registry、Planner Skill metadata 和 Executor `read_skill`。
|
||
- `ExecutorGatekeeperService` 现有规则。
|
||
- `ToolTraceSummaryService`。
|
||
- Executor、Verifier、Composer 结构化解析逻辑。
|
||
- `diagnosis_run`、`agent_step`、`tool_invocation` 和 `self_evaluation`。
|
||
- Token、耗时和工具调用数回填。
|
||
- 当前 API 请求和响应协议。
|
||
|
||
### 7.2 需要调整
|
||
|
||
- `ChatService.executeChatComplex(...)` 不再创建 `SequentialAgent`。
|
||
- Gatekeeper 从 `VerifierInputHook` 的隐式执行迁为显式 Graph Node。
|
||
- LOW_CONFID 外层 `for round` 迁入 Graph 条件边。
|
||
- Composer 与固定 Fallback 成为独立节点。
|
||
- ChatService 只负责 Run 生命周期和调用 Graph,不继续承载细粒度状态机。
|
||
|
||
### 7.3 ReactAgent 接入策略
|
||
|
||
第一阶段使用适配 Node 显式调用当前 ReactAgent,不直接全面使用 `ReactAgent.asNode(...)`。
|
||
|
||
原因:
|
||
|
||
- 当前 Agent 根据 history 和 retry context 动态构造 Prompt。
|
||
- 当前使用自定义 outputKey 和解析逻辑。
|
||
- Hook、ThreadLocal 和父子 Graph `messages` 需要先验证。
|
||
|
||
Graph State 和 Agent 输入契约稳定后,再评估直接使用 `asNode(false, false)`。
|
||
|
||
### 7.4 已确认:父子状态使用输入白名单隔离
|
||
|
||
**决策状态**:已确认,2026-07-16。
|
||
|
||
外层 Graph 维护完整工作流状态,但每个 ReactAgent 不直接接收 `parentState.data()`。每个 Adapter Node 必须完成一次显式状态投影:
|
||
|
||
```text
|
||
父 Graph Shared State
|
||
-> Adapter Node 选择允许字段
|
||
-> Agent 专用 Input DTO
|
||
-> ReactAgent 私有执行上下文
|
||
-> Parser 提取标准输出
|
||
-> 只更新父 Graph 指定状态
|
||
```
|
||
|
||
各节点输入边界:
|
||
|
||
| 节点 | 允许读取 | 不允许直接读取 |
|
||
|---|---|---|
|
||
| Planner | query、history、retry context、Skill metadata | Executor、Gatekeeper、Verifier 的历史输出 |
|
||
| Executor | query、planner plan、selected skill、executor retry context | Verifier 结论、其他轮次未筛选 messages |
|
||
| Gatekeeper | executor structured output、当前 run 的 tool invocation | Planner 思考、其他 run 工具记录 |
|
||
| Verifier | query、executor structured output、gatekeeper result、verified tool trace | Planner 计划、Executor 思考、未经 Gatekeeper 验真的自由文本 |
|
||
| Composer | allowed claims、missing info、recommended actions | 原始工具结果、Executor 原始答案和未允许 claims |
|
||
|
||
实现约束:
|
||
|
||
- 第一阶段不使用 `asNode(true, true)`。
|
||
- `asNode(false, false)` 也不作为严格隔离手段,因为它主要减少 `messages` 传播,不能替代字段白名单。
|
||
- 每个 Adapter Node 使用专用 Input DTO,不复用一个包含所有字段的通用 AgentInput。
|
||
- ReactAgent 只向父 Graph 返回结构化 Node Output,不回传内部完整 `messages` 和推理过程。
|
||
- 子 Agent 的执行标识按 `runId + agentName + attempt` 隔离,避免不同 Agent 和重试轮次复用内部状态。
|
||
- 数据隔离由代码保证,Prompt 约束只作为补充。
|
||
|
||
### 7.5 已确认:编排审计使用独立 `orchestration_trace`
|
||
|
||
**决策状态**:已确认,2026-07-16。
|
||
|
||
Graph 路由记录不写入 `self_evaluation`。本期在 `diagnosis_run` 新增 nullable JSON 字段 `orchestration_trace`,用于保存当前 run 的紧凑编排摘要。
|
||
|
||
职责边界:
|
||
|
||
```text
|
||
self_evaluation
|
||
-> 结果质量、证据可信度以及 Gatekeeper / Verifier 等评估结果
|
||
|
||
orchestration_trace
|
||
-> 节点跳转、条件边原因、重试、降级和终止摘要
|
||
|
||
agent_step
|
||
-> 真实模型 Agent 调用
|
||
|
||
tool_invocation
|
||
-> 真实工具调用
|
||
```
|
||
|
||
最小结构:
|
||
|
||
```json
|
||
{
|
||
"version": "stategraph-v1",
|
||
"transitions": [
|
||
{
|
||
"from": "gatekeeper",
|
||
"to": "fallback",
|
||
"reason_code": "gatekeeper_reject",
|
||
"attempt": 1
|
||
}
|
||
],
|
||
"final_node": "fallback",
|
||
"termination_reason": "gatekeeper_reject",
|
||
"degraded": true,
|
||
"evidence_retry_count": 0
|
||
}
|
||
```
|
||
|
||
约束:
|
||
|
||
- 只写入 `diagnosis_run`,不写入会话级 `diagnosis_session`,因为 Graph 执行边界是 `runId`。
|
||
- 使用稳定的 `reason_code`,不保存完整 Prompt、模型思考、工具原文或 Graph State 快照。
|
||
- `transitions` 受 Graph 最大循环次数约束,不作为无限增长的事件日志。
|
||
- Trace API 将其作为与 `self_evaluation` 平级的可选字段返回;历史 run 可以为 `null`。
|
||
- 第一版不新增 orchestration 明细表,后续只有在需要跨 run 检索单次节点事件时再单独评估。
|
||
|
||
---
|
||
|
||
## 8. 分阶段实施计划
|
||
|
||
## 阶段 0:设计冻结
|
||
|
||
**预计时间**:1–2 小时
|
||
**目标**:完成讨论,不修改运行时实现。
|
||
|
||
任务:
|
||
|
||
- 确认 Graph State 最小契约。
|
||
- 确认所有条件边和最大重试次数。
|
||
- 确认 Fallback 用户表达。
|
||
- 确认旧 Sequential 测试的替换范围。
|
||
|
||
完成标准:
|
||
|
||
- 本 issue 中所有“待讨论决策”已有明确结论。
|
||
- 不存在未定义的循环和终止路径。
|
||
|
||
## 阶段 1:Graph 骨架和路由测试
|
||
|
||
**预计时间**:2–3 小时
|
||
**目标**:使用 Fake Node 验证 Graph API 和所有路径,不接真实模型。
|
||
|
||
任务:
|
||
|
||
- 创建诊断 Graph State 和状态常量。
|
||
- 创建 Graph 拓扑。
|
||
- 创建 Fake Planner、Executor、Gatekeeper、Verifier、Composer。
|
||
- 为所有条件边编写路由测试。
|
||
|
||
完成标准:
|
||
|
||
- Executor FAILED 后不调用 Gatekeeper、Verifier。
|
||
- Executor INVALID_OUTPUT 直接进入固定 Fallback,不触发任何模型重试。
|
||
- 任意 Gatekeeper REJECT 直接进入 Fallback,不调用 Verifier。
|
||
- LOW_CONFID 只允许一次 Planner 补证据。
|
||
- Graph 不存在无限循环。
|
||
|
||
## 阶段 2:接入真实节点
|
||
|
||
**预计时间**:3–4 小时
|
||
**目标**:将现有 Agent 和代码服务接入 Graph。
|
||
|
||
任务:
|
||
|
||
- 创建 Planner、Executor、Verifier、Composer Node Adapter。
|
||
- 创建显式 Gatekeeper Node。
|
||
- 创建 Verifier Input Builder Node,过滤未通过的 binding。
|
||
- 创建 Evidence Retry Prepare Node。
|
||
- 创建固定 Fallback Node。
|
||
- 保持现有 Prompt、工具和证据协议不变。
|
||
|
||
完成标准:
|
||
|
||
- Agent Hook 和 ToolCallback 正常工作。
|
||
- Gatekeeper 只执行一次,不再由 Verifier Hook 重复触发。
|
||
- no-evidence 继续进入 Gatekeeper 和 Verifier。
|
||
- Gatekeeper LOW_CONFID 只向 Verifier 提供已验真 binding,并限制 verdict 上限。
|
||
- Verifier LOW_CONFID 只有存在可执行缺口时才返回 Planner。
|
||
- 第二轮 Planner 只生成 `EVIDENCE_GAP_ONLY` 增量计划。
|
||
|
||
## 阶段 3:替换 ChatService 编排
|
||
|
||
**预计时间**:2–3 小时
|
||
**目标**:复杂 Chat 诊断正式调用 StateGraph。
|
||
|
||
任务:
|
||
|
||
- 将 `executeChatComplex(...)` 改为构造初始 Graph State 并执行 CompiledGraph。
|
||
- 使用 `runId` 作为 Graph `threadId`,`sessionId` 作为 metadata。
|
||
- 增加数据库迁移,为 `diagnosis_run` 添加 nullable JSON 字段 `orchestration_trace`。
|
||
- 将 Graph 的节点跳转、reason code、重试和终止摘要持久化到当前 run。
|
||
- 保留 Run 创建、状态更新、耗时、Token、工具数和 Eval 调用。
|
||
- 将 Graph 最终状态映射为现有 `ChatResult`。
|
||
|
||
完成标准:
|
||
|
||
- `/api/chat` 请求和响应协议不变。
|
||
- `diagnosis_run.agent_flow` 仍为 `CHAT`。
|
||
- Trace 明细继续归属于当前 runId。
|
||
- Trace API 将 `orchestration_trace` 作为与 `self_evaluation` 平级的可选字段返回。
|
||
- Executor 失败路径不产生 Verifier Agent step。
|
||
|
||
## 阶段 4:创建新测试体系
|
||
|
||
**预计时间**:3–4 小时
|
||
**目标**:以 Graph 路径和外部行为为中心创建测试,不迁移旧固定顺序断言。
|
||
|
||
新测试:
|
||
|
||
- `DiagnosisGraphWorkflowTest`:纯路由测试。
|
||
- `DiagnosisGraphNodeContractTest`:节点输入输出契约。
|
||
- `ChatServiceGraphIntegrationTest`:ChatService、Run、Trace、自评估集成。
|
||
|
||
必须覆盖:
|
||
|
||
- PASS 正常路径。
|
||
- Planner 失败。
|
||
- Executor FAILED / TOOL_BLOCKED / INVALID_OUTPUT。
|
||
- 合法 no-evidence。
|
||
- Gatekeeper REJECT 直接降级。
|
||
- Gatekeeper LOW_CONFID 且存在已验真 binding。
|
||
- Gatekeeper LOW_CONFID 且不存在已验真 binding。
|
||
- Verifier LOW_CONFID 补证据。
|
||
- Gatekeeper ceiling 导致的 LOW_CONFID 不触发补证据。
|
||
- LOW_CONFID 缺少可执行 missing evidence 时不触发补证据。
|
||
- 第二次 LOW_CONFID 不再补证据。
|
||
- Verifier REJECT 安全表达。
|
||
- Composer 失败固定降级。
|
||
- 同 session 多 run 隔离。
|
||
|
||
旧测试处理:
|
||
|
||
- `ChatServiceSequentialAgentTest` 不作为迁移约束,可以由新测试整体替换。
|
||
- `VerifierInputHookTest` 根据 Gatekeeper 迁移结果删除或改写。
|
||
- `ExecutorGatekeeperServiceTest`、Controller、Trace 和 Eval 契约测试继续保留。
|
||
|
||
## 阶段 5:回归、清理和文档
|
||
|
||
**预计时间**:1–2 小时
|
||
**目标**:完成行为确认并删除旧编排结构。
|
||
|
||
任务:
|
||
|
||
- 运行新的单元和集成测试。
|
||
- 运行相关 diagnosis eval baseline。
|
||
- 对比关键 Trace 路径。
|
||
- 删除 `SequentialAgent` 复杂诊断编排和旧外层 round 状态机。
|
||
- 删除不再需要的 Gatekeeper Hook 隐式执行逻辑。
|
||
- 更新架构文档和 issue 状态。
|
||
|
||
完成标准:
|
||
|
||
- 新测试全部通过。
|
||
- 关键 Eval 没有非预期退化。
|
||
- ChatService 不再维护隐式诊断状态机。
|
||
- 不存在新旧两套长期并行的重复实现。
|
||
|
||
---
|
||
|
||
## 9. 测试策略
|
||
|
||
本改造允许忽略并替换与 SequentialAgent 强绑定的历史测试,但不允许丢失已经建立的安全边界。
|
||
|
||
测试分层:
|
||
|
||
```text
|
||
Graph 路由测试
|
||
-> 不调用模型,验证条件边和循环上限
|
||
|
||
Node 契约测试
|
||
-> 验证 Agent / Java Node 的状态映射
|
||
|
||
Chat 集成测试
|
||
-> 验证外部协议、Run、Trace、orchestration_trace 和 self_evaluation
|
||
|
||
Eval baseline
|
||
-> 验证最终证据表达没有退化
|
||
```
|
||
|
||
不再把“所有 Agent 固定按顺序调用”作为正确性标准。正确性标准改为:
|
||
|
||
> 根据当前节点状态进入预期路径,并且所有安全门禁和外部协议保持成立。
|
||
|
||
---
|
||
|
||
## 10. 行为与协议影响
|
||
|
||
### 外部协议
|
||
|
||
保持不变:
|
||
|
||
- `/api/chat` 请求和响应结构。
|
||
- `sessionId/runId` 语义。
|
||
- `executor_evidence_v2`。
|
||
- Verifier 和 Composer 输出契约。
|
||
|
||
### Trace API 加法式变化
|
||
|
||
- Trace 聚合响应新增与 `self_evaluation` 平级的可选字段 `orchestration_trace`。
|
||
- 现有字段语义不变,历史 run 或未经过 StateGraph 的 run 返回 `null`。
|
||
- 这是有意的内部审计持久化和 Trace 查询协议扩展,不影响 `/api/chat` 消费方。
|
||
|
||
### 明确的内部行为变化
|
||
|
||
- Executor 失败后不再调用 Verifier。
|
||
- Executor INVALID_OUTPUT 不重试,直接进入固定 Fallback。
|
||
- Agent 调用顺序不再固定。
|
||
- Gatekeeper REJECT 直接安全降级,不进行自动修复和重试。
|
||
- Gatekeeper LOW_CONFID 只在存在已验真 binding 时进入 Verifier,且 verdict 最高为 LOW_CONFID。
|
||
- LOW_CONFID 根据 missing evidence 返回 Planner,而不是无差别完整重跑。
|
||
- 第二轮 Planner 使用增量补证据模式,不重新执行完整 Playbook。
|
||
- Agent step 数量、Token 和耗时可能减少。
|
||
- Trace 需要能解释条件边选择和终止原因。
|
||
|
||
这些是有意的编排行为变化,不是对外协议变化。
|
||
|
||
---
|
||
|
||
## 11. 验收标准
|
||
|
||
### 编排
|
||
|
||
- [ ] Executor FAILED / TOOL_BLOCKED 后不会执行 Gatekeeper 和 Verifier。
|
||
- [ ] Executor INVALID_OUTPUT 不重试,不执行 Gatekeeper、Verifier 和模型 Composer。
|
||
- [ ] Executor 合法 no-evidence 会继续执行 Gatekeeper 和 Verifier。
|
||
- [ ] Gatekeeper REJECT 直接进入 Fallback,不执行 Verifier。
|
||
- [ ] Gatekeeper LOW_CONFID 且零条已验真 binding 时直接进入 Fallback。
|
||
- [ ] Gatekeeper LOW_CONFID 且存在已验真 binding 时,Verifier 只接收通过校验的 binding。
|
||
- [ ] Gatekeeper LOW_CONFID 路径的最终 verdict 不得升级为 PASS。
|
||
- [ ] Verifier LOW_CONFID 最多触发一次 Planner 补证据。
|
||
- [ ] LOW_CONFID 补证据循环受次数和 Run 总预算限制。
|
||
- [ ] Gatekeeper verdict ceiling 导致的 LOW_CONFID 不触发补证据。
|
||
- [ ] 不存在可执行 missing evidence 时不触发补证据。
|
||
- [ ] 第二轮 Planner 只输出增量计划,不扩大诊断范围或重复成功查询。
|
||
- [ ] Composer 失败使用固定模板结束。
|
||
|
||
### 证据和安全
|
||
|
||
- [ ] Gatekeeper 规则语义不放宽。
|
||
- [ ] Verifier 只消费已验真证据。
|
||
- [ ] no-evidence 不得表达为已排除或问题不存在。
|
||
- [ ] REJECT 降级不泄漏 Executor 原始答案和未验证根因。
|
||
|
||
### 数据与审计
|
||
|
||
- [ ] Graph 使用 runId 作为 threadId。
|
||
- [ ] Agent step、tool invocation 和 self_evaluation 仍绑定正确 runId。
|
||
- [ ] `orchestration_trace` 只写入当前 diagnosis run,不污染其他 run 或 session 级数据。
|
||
- [ ] `orchestration_trace` 不包含 Prompt、模型思考、工具原文和 Graph State 快照。
|
||
- [ ] Trace 能展示实际节点路径、重试原因和终止原因。
|
||
- [ ] 历史 run 的 `orchestration_trace=null` 时 Trace API 仍能正常返回。
|
||
- [ ] Run 最终状态、答案、耗时、Token 和工具调用数正确回填。
|
||
|
||
### 工程质量
|
||
|
||
- [ ] 新 Graph 测试覆盖所有分支。
|
||
- [ ] `ChatServiceSequentialAgentTest` 已由新测试替换。
|
||
- [ ] 不保留长期重复的 Sequential 和 Graph 两套实现。
|
||
- [ ] 数据库 schema 仅新增 `diagnosis_run.orchestration_trace` nullable JSON 字段。
|
||
- [ ] `/api/chat` 和证据协议不变;Trace API 仅新增可选的 `orchestration_trace` 字段。
|
||
|
||
---
|
||
|
||
## 12. 风险与缓解
|
||
|
||
### ReactAgent 父子 Graph 状态污染
|
||
|
||
风险:直接使用 `asNode(...)` 可能导致 `messages`、outputKey 或 checkpoint 传播不符合预期。
|
||
|
||
缓解:第一阶段使用适配 Node 显式调用 Agent;完成契约测试后再考虑直接子图节点。
|
||
|
||
### Gatekeeper 重复执行
|
||
|
||
风险:显式 Gatekeeper Node 与现有 `VerifierInputHook` 同时执行。
|
||
|
||
缓解:迁移时明确 Gatekeeper 只有一个入口;Verifier Hook 只负责构造输入或被替换。
|
||
|
||
### LOW_CONFID 循环失控
|
||
|
||
风险:Verifier LOW_CONFID 持续返回 Planner,形成重复规划和工具调用。
|
||
|
||
缓解:保留当前最多一次补证据约束,并设置 Run 级总预算与 Graph recursion limit。
|
||
|
||
### Trace 与 Graph Checkpoint 语义混淆
|
||
|
||
风险:把当前数据库 Trace 当作 Graph 恢复检查点,或把 `MemorySaver` 当成持久化。
|
||
|
||
缓解:本期 Graph 只负责控制流程,不声明跨重启恢复;HITL 和持久 Checkpointer 单独立项。
|
||
|
||
---
|
||
|
||
## 13. Out of scope
|
||
|
||
本 issue 暂不包含:
|
||
|
||
- AIOps 迁移到公共 Graph。
|
||
- Chat 和 AIOps 入口统一。
|
||
- SupervisorAgent 和专科 SubAgent。
|
||
- 人工中断、审批和恢复。
|
||
- 持久化 Checkpointer。
|
||
- 并行工具或并行 Agent。
|
||
- EvidenceRepairNode 和 Gatekeeper REJECT 自动修复。
|
||
- Gatekeeper REJECT 返回 Executor 的重试回边。
|
||
- 修改 Prompt 业务语义。
|
||
- 修改 `executor_evidence_v2`、Verifier、Composer 协议。
|
||
- 除 `diagnosis_run.orchestration_trace` 外的其他数据库表或字段。
|
||
|
||
这些能力应在本 issue 完成后根据实际收益单独讨论。
|
||
|
||
---
|
||
|
||
## 14. 已冻结决策
|
||
|
||
以下决策均已确认,不再作为开放问题:
|
||
|
||
- 第一阶段保留现有 ReactAgent,通过 Adapter Node 调用。
|
||
- 父 Graph State 不直接传给 ReactAgent,使用每个 Agent 独立的 Input DTO 做白名单投影。
|
||
- 第一阶段不直接依赖 `ReactAgent.asNode(...)` 实现父子编排。
|
||
- Gatekeeper REJECT 本期不重试,直接进入 Fallback。
|
||
- 本期不增加 EvidenceRepairNode。
|
||
- Executor INVALID_OUTPUT 本期不重试,直接进入固定 Fallback。
|
||
- Gatekeeper LOW_CONFID 有已验真 binding 时进入 Verifier,零条时直接 Fallback。
|
||
- Gatekeeper LOW_CONFID 路径的最终 verdict 上限为 LOW_CONFID。
|
||
- Verifier LOW_CONFID 的补证据路径返回 Planner,并使用 `EVIDENCE_GAP_ONLY` 增量规划模式。
|
||
- Gatekeeper ceiling、无可执行缺口、无预算或已经补查时不触发 LOW_CONFID 重试。
|
||
- Graph 路由摘要写入独立的 `diagnosis_run.orchestration_trace`,不耦合进 `self_evaluation`。
|
||
- 不保留 Sequential / StateGraph 双链路配置开关;在专用 Git 分支完成实现和验收后,直接以 StateGraph 替换旧复杂诊断编排。
|
||
- 实现期间允许代码处于分支内的阶段性状态,但合并前必须删除旧 Sequential 编排和不再使用的迁移代码,不形成长期双轨维护。
|
||
|
||
---
|
||
|
||
## 15. 相关文件
|
||
|
||
- `src/main/java/com/superbiz/agent/service/ChatService.java`
|
||
- `src/main/java/com/superbiz/agent/service/ExecutorGatekeeperService.java`
|
||
- `src/main/java/com/superbiz/agent/hook/VerifierInputHook.java`
|
||
- `src/main/java/com/superbiz/agent/service/ToolTraceSummaryService.java`
|
||
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`
|
||
- `src/test/java/com/superbiz/agent/service/ChatServiceSequentialAgentTest.java`
|
||
- `src/test/java/com/superbiz/agent/service/ExecutorGatekeeperServiceTest.java`
|
||
- `src/test/java/com/superbiz/agent/hook/VerifierInputHookTest.java`
|
||
- `mvp/architecture/agent-orchestration.md`
|
||
- `mvp/architecture/harness-quality-gates.md`
|
||
- `knowledge_20260716_Spring_AI_Alibaba_Graph_诊断编排改造/`
|
||
|
||
## 16. 参考文档
|
||
|
||
- https://java2ai.com/docs/frameworks/graph-core/core/core-library
|
||
- https://java2ai.com/docs/frameworks/graph-core/quick-start
|
||
- 当前依赖:`spring-ai-alibaba-graph-core:1.1.2.0`
|
||
- 当前依赖:`spring-ai-alibaba-agent-framework:1.1.2.0`
|