Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b9cf7c5cc | ||
|
|
190013c901 | ||
|
|
208a231113 | ||
|
|
99e490f227 | ||
|
|
1460dd1e99 | ||
|
|
42ba204532 | ||
|
|
581daffdad | ||
|
|
a36fe72639 |
@@ -148,7 +148,7 @@ openspec/changes/phase-1-infrastructure/
|
||||
|
||||
## 敏感信息(已编辑)
|
||||
|
||||
- MySQL 密码:已从仓库移除,使用环境变量注入
|
||||
- MySQL 密码:已配置在 application.yml(`!Fucker123..`)
|
||||
- Redis:无密码
|
||||
|
||||
---
|
||||
|
||||
@@ -97,7 +97,7 @@ spring:
|
||||
redis:
|
||||
host: 119.29.78.52
|
||||
port: 6379
|
||||
password: ${SUPERBIZ_REDIS_PASSWORD}
|
||||
password: '!Fucker123..'
|
||||
database: 0
|
||||
timeout: 3000
|
||||
```
|
||||
|
||||
@@ -140,7 +140,7 @@ Error Code: 1049
|
||||
datasource:
|
||||
url: jdbc:mysql://119.29.78.52:33306/superbiz_agent?...
|
||||
username: root
|
||||
password: ${SUPERBIZ_MYSQL_PASSWORD}
|
||||
password: '!Fucker123..'
|
||||
```
|
||||
|
||||
**Redis 配置**:
|
||||
@@ -149,7 +149,7 @@ data:
|
||||
redis:
|
||||
host: 119.29.78.52
|
||||
port: 6379
|
||||
password: ${SUPERBIZ_REDIS_PASSWORD}
|
||||
password: '!Fucker123..'
|
||||
```
|
||||
|
||||
**Flyway 配置**:
|
||||
|
||||
@@ -44,13 +44,6 @@ build/
|
||||
app.log
|
||||
logs/
|
||||
|
||||
### Local Secrets ###
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
application-local.yml
|
||||
application-*.local.yml
|
||||
|
||||
### Upload Files ###
|
||||
uploads/
|
||||
|
||||
|
||||
@@ -103,6 +103,11 @@
|
||||
- 使用场景:Trace API、Trace UI、Verifier 审计、评测 fixture 和人工排查。
|
||||
- 边界:Diagnosis Trace 是聚合视图,不要求单独的 trace 主表;当前 trace 明细由 `agent_step` 和 `tool_invocation` 表承载。
|
||||
|
||||
### Diagnosis Orchestration Trace
|
||||
- 定义:一次 Diagnosis Run 的紧凑编排审计摘要,记录实际节点路径、条件边原因、技术重试、降级和终止原因。
|
||||
- 使用场景:解释诊断编排为何进入某个节点、为何重试或为何提前终止,并支撑路由验收和人工审计。
|
||||
- 边界:它是 Diagnosis Trace 的编排维度,不是完整事件日志、自评估结果或持久恢复检查点;不保存 Prompt、模型思考、工具原文和完整编排上下文快照。
|
||||
|
||||
### Flyway
|
||||
- 定义:数据库版本迁移工具,管理 SQL 脚本的版本化执行
|
||||
- 配置:spring.flyway.enabled=true, baseline-on-migrate=true
|
||||
@@ -155,55 +160,15 @@
|
||||
- 使用场景:Executor 按 skill workflow 调用 evidence tools 收集事实,`tool_invocation` 记录这些事实证据。
|
||||
- 边界:最终诊断结论必须被 evidence tools 支撑,不能仅由 skill 正文支撑。
|
||||
|
||||
### Diagnosis Harness
|
||||
- 定义:围绕 Diagnosis Agent 提供确定性运行控制的边界,负责 Run、预算、取消、重试装配、Tool 调用记录、证据验真和最终释放,不承担业务诊断推理。
|
||||
- 边界:Harness 不是工作流引擎,不实现 Planner/Executor/Composer 节点或自行编写 ReAct 循环。
|
||||
|
||||
### Diagnosis Agent
|
||||
- 定义:诊断链路中唯一拥有 ReAct 工具循环并生成 `DiagnosisDraft` 的 Agent,负责规划证据查询、判断证据充分性和撰写完整诊断草稿。
|
||||
- 边界:不负责意图路由、Run/Session 生命周期、证据物理验真、独立语义审查或最终发布;证据不足时必须明确停止并保留限制。
|
||||
|
||||
### EvidenceGuard
|
||||
- 定义:Harness 内部的确定性证据验真能力,校验 Draft 引用、当前 Run 所有权、Tool 调用状态和有界 Agent 投影。
|
||||
- 边界:EvidenceGuard 不调用 LLM,也不判断证据是否足以推出业务结论。
|
||||
|
||||
### SemanticGuard
|
||||
- 定义:使用隔离上下文对完整诊断 Draft 与已验真证据做报告级语义审查的单轮 Agent。
|
||||
- 边界:无工具、无记忆、无 ReAct 循环,不访问 Redis,不生成或改写用户报告。
|
||||
|
||||
### Invocation Status
|
||||
- 定义:Tool 调用及结果投影的生命周期状态,固定为 `PROJECTING`、`READY`、`ERROR`。
|
||||
- 边界:它只说明调用记录是否完成,不说明结果是否包含证据。
|
||||
|
||||
### Evidence Status
|
||||
- 定义:证据 Tool 的结果语义,固定为 `EVIDENCE_FOUND`、`NO_EVIDENCE`、`ERROR`。
|
||||
- 边界:`NO_EVIDENCE` 只表示当前查询范围内没有匹配结果,不能解释为问题不存在、根因被排除或系统健康。
|
||||
|
||||
### RunContext
|
||||
- 定义:一次 Diagnosis Run 的显式执行上下文,结构不可变地携带 `sessionId`、`runId`、deadline,以及该 Run 独占的取消、预算、重试策略和生命周期状态句柄。
|
||||
- 边界:RunContext 通过方法参数或框架受控 context 显式传播,不依赖 ThreadLocal;结构不可变不等于内部计数和取消状态不能变化,这些变化由线程安全句柄管理。
|
||||
|
||||
### Run Lifecycle
|
||||
- 定义:Diagnosis Harness 对单次 Run 执行状态的内存控制,采用 first-terminal-wins 规则保证成功、失败、取消、超时和预算耗尽只能产生一个最终终态。
|
||||
- 边界:Run Lifecycle 不直接等同于数据库实体写入;应用用例负责把最终状态映射到 `diagnosis_run` 持久化。
|
||||
|
||||
### Run Budget
|
||||
- 定义:单次 Run 的模型调用、Tool 调用、单 Tool 调用、输入/输出/总 Token 和 canonical invocation 字节容量的线程安全消耗计数与门禁。
|
||||
- 边界:预算上限由 Harness 配置显式提供;实际 Token 在模型响应后记录,超限后保留真实消耗并阻止后续执行。
|
||||
|
||||
### Harness Retry Policy
|
||||
- 定义:Harness 对同一技术操作 attempt 数和可重试失败类型的显式策略。
|
||||
- 边界:Router 与 SemanticGuard 的技术失败最多两次 attempt;Diagnosis Agent、Tool 和 Evidence repair 只有一次 attempt。Agent 正常 ReAct 轮次不是 retry,`NO_EVIDENCE`、业务拒绝、取消和预算耗尽不可重试。
|
||||
|
||||
### Verifier Skill Isolation
|
||||
- 定义:Chat Verifier 与 skill 系统隔离,只校验 Executor 答案和 `tool_trace_summary`。
|
||||
- 定义:Chat Verifier 与 skill 系统隔离,只校验 Gatekeeper 投影后的 `verified_executor_output` 和 `verified_evidence`。
|
||||
- 使用场景:防止 Verifier 把 playbook 指令当作事实证据;Verifier 只判断已有证据是否支持结论。
|
||||
- 边界:Verifier 不接收 `skill_catalog`,不暴露 `read_skill`,不读取 `SKILL.md`。
|
||||
- 边界:Verifier 不接收 `skill_catalog`,不暴露 `read_skill`,不读取 `SKILL.md`、完整 `tool_trace_summary` 或未经验真的 Executor 自由文本。
|
||||
|
||||
## Diagnosis Playbook Business Rules
|
||||
|
||||
- Planner 只看 skill metadata,输出 `selected_skill`、`selection_reason` 和 plan。
|
||||
- Executor 才能调用 `read_skill(selected_skill)`,并且读取 skill 后仍必须调用 evidence tools。
|
||||
- Skill 正文不得替代 `lookup_knowledge`、日志、指标或告警数据。
|
||||
- Verifier 只基于 `tool_trace_summary` 校验事实,不基于 skill 正文校验事实。
|
||||
- Verifier 只基于 Gatekeeper 通过的 `verified_executor_output` 和 `verified_evidence` 校验事实,不基于 skill 正文、完整工具 Trace 或未验真输出校验事实。
|
||||
- 当前阶段保留单 active skill 白名单:`diagnose-mysql-connection-pool`。
|
||||
|
||||
+6
-8
@@ -4,10 +4,12 @@
|
||||
|
||||
| 日期 | slug | 说明 | 领域 | 关键词 | 关联 OpenSpec | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 2026-07-21 | single-react-tool-invocation-store | 建立统一 ToolBoundary 与 Redis canonical invocation store,集中生命周期、证据状态、TTL、容量和 Run 所有权。 | Harness/Tool boundary/Canonical store | ISS-014, ToolBoundary, canonical invocation, PROJECTING, READY, ERROR, TTL, RESULT_TOO_LARGE | openspec/changes/archive/2026-07-21-single-react-tool-invocation-store | archived |
|
||||
| 2026-07-21 | single-react-harness-run-context | 建立显式 RunContext、Harness Core、预算、取消、类型化重试和 Tool Store 基础。 | Harness/Run lifecycle/Budget | ISS-014, RunContext, deadline, cancellation, budget, retry, ToolCallKey | openspec/changes/archive/2026-07-21-single-react-harness-run-context | archived |
|
||||
| 2026-07-21 | single-react-aci-tool-contracts | 冻结 RAG、日志和 MySQL evidence Tool 的 Agent-facing ACI Schema、状态、框架调用引用和描述边界。 | Harness/Agent Tool contract | ISS-014, ACI, tool_call_id, evidence_status, RAG, query_logs, query_mysql, MOCK | openspec/changes/archive/2026-07-21-single-react-aci-tool-contracts | archived |
|
||||
| 2026-07-21 | single-react-design-freeze | 冻结单体 Diagnosis Agent、Harness、Guard、工具证据与阶段门禁契约。 | Chat/Harness/Agent contract | ISS-014, single ReactAgent, Harness, EvidenceGuard, SemanticGuard, tool_call_id, evidence_status | openspec/changes/archive/2026-07-21-single-react-design-freeze | archived |
|
||||
| 2026-07-17 | chat-diagnosis-stategraph-cleanup-docs | 清理旧诊断编排闭包,对齐当前文档与 demo contract,并完成 ISS-011 最终 live、日志和数据库验收。 | Chat diagnosis orchestration/cleanup | legacy closure, current docs, orchestration trace, Maven E2E, MySQL ownership | openspec/changes/archive/2026-07-20-chat-diagnosis-stategraph-cleanup-docs | archived |
|
||||
| 2026-07-17 | chat-diagnosis-stategraph-test-suite | 建立 Workflow、Node Contract、Chat Integration 三层权威测试体系并退役旧 Hook implementation tests。 | Chat diagnosis orchestration/testing | workflow test, node contract, Chat integration, coverage matrix, Hook test retirement | openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-test-suite | archived |
|
||||
| 2026-07-17 | chat-diagnosis-stategraph-chatservice-cutover | 将复杂 Chat 单轨切换到 Diagnosis StateGraph,并增加 Run 级 orchestration trace 和 verified-only Verifier 输入。 | Chat diagnosis orchestration/production cutover | ChatService, CompiledGraph stream, runId metadata, orchestration trace, verified-only prompt, V012 | openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-chatservice-cutover | archived |
|
||||
| 2026-07-17 | chat-diagnosis-stategraph-real-nodes | 接入真实 Agent/Java Nodes、显式 Gatekeeper、可信输入投影、关键证据补查与安全 Fallback,暂不切换生产入口。 | Chat diagnosis orchestration/nodes | ReactAgent adapter, Gatekeeper node, verified input, evidence retry, safe fallback, CompiledGraph | openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-real-nodes | archived |
|
||||
| 2026-07-17 | chat-diagnosis-stategraph-routing-skeleton | 实现未接生产入口的 Diagnosis StateGraph 骨架、有限路由和 Fake Node 测试。 | Chat diagnosis orchestration/graph | StateGraph, fake node, conditional edge, retry counter, orchestration events, trace builder | openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-routing-skeleton | archived |
|
||||
| 2026-07-17 | chat-diagnosis-stategraph-design-freeze | 冻结 ISS-011 的 Graph State、条件边、有限重试、安全降级、审计和测试迁移边界。 | Chat diagnosis orchestration/design | StateGraph, runId, Gatekeeper, verified evidence, fallback, orchestration trace, test migration | openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-design-freeze | archived |
|
||||
| 2026-07-10 | session-run-trace-isolation | 拆分会话态和运行态,引入 runId 隔离 Trace、Feedback、AIOps 和 demo 链路。 | Trace/session/run isolation | chat_session, diagnosis_run, runId, trace exact run, feedback fallback, AIOps SSE metadata, baseline drift | openspec/changes/archive/2026-07-10-session-run-trace-isolation | archived |
|
||||
| 2026-07-09 | interview-demo-quality-audit | 增加面试演示前置质量审计,覆盖 prompt、Gatekeeper 和评测基线。 | Agent eval/demo/Prompt audit | interview demo preflight, prompt_audit, gatekeeper rules, diagnosis baseline, 12 fixtures | openspec/changes/archive/2026-07-09-interview-demo-quality-audit | archived |
|
||||
| 2026-07-08 | executor-composer-final-answer | 引入 Composer 生成最终回答,只使用 Verifier 允许的结论材料。 | Chat quality gate/evidence attribution | chat_composer, final answer, allowed_claims, allowed_hypotheses, safe fallback, composer_output | openspec/changes/archive/2026-07-08-executor-composer-final-answer | archived |
|
||||
@@ -37,7 +39,3 @@
|
||||
| 2026-06-24 | lookup-knowledge-integration | 接入知识库检索,支持 L0 精确匹配和 L1 语义检索。 | 知识库检索 | L0精确匹配, L1语义检索, frontmatter, 混合检索 | - | archived |
|
||||
| 2026-06-23 | phase1-infrastructure | 搭建第一阶段基础设施,包括 MySQL、Redis、Milvus、Flyway 和 JPA。 | 基础设施/文档管理 | MySQL, Redis, Milvus, Flyway, JPA, 向量检索, 类别过滤 | - | archived |
|
||||
| 2026-05-29 | chatmodel-abstraction | 抽象 ChatModel 和 EmbeddingModel,支持多模型路由。 | 解耦/多模型路由 | ChatModel, EmbeddingModel, DeepSeek, BGE-M3, SiliconFlow, Spring AI | - | archived |
|
||||
| 2026-07-21 | single-react-rag-log-projections | RAG/log projection adapters through ToolBoundary | Harness/Tool projection | ISS-014, RAG, query_logs, projection, scope, redaction, MOCK, NO_EVIDENCE | openspec/changes/archive/2026-07-21-single-react-rag-log-projections | archived |
|
||||
| 2026-07-21 | single-react-mysql-readonly-tool | Fail-closed read-only MySQL evidence Tool with AST allowlist, JDBC controls and bounded projection | Harness/MySQL security | ISS-014, MySQL, JSqlParser, allowlist, PreparedStatement, timeout, projection | openspec/changes/archive/2026-07-21-single-react-mysql-readonly-tool | archived |
|
||||
| 2026-07-21 | single-react-diagnosis-agent | Single internal Diagnosis ReactAgent with Harness-controlled model/tool loop, bounded context and typed Draft | Harness/Diagnosis Agent/ReAct | ISS-014, ReactAgent, DiagnosisDraft, PreviousTurn, ToolInterceptor, ModelInterceptor, budget | openspec/changes/archive/2026-07-21-single-react-diagnosis-agent | archived |
|
||||
| 2026-07-21 | single-react-evidence-semantic-guards | Deterministic evidence validation, isolated semantic review and fail-closed diagnosis release | Harness/EvidenceGuard/SemanticGuard/Release | ISS-014, EvidenceGuard, verified snapshot, SemanticGuard, repair, fallback, release policy | openspec/changes/archive/2026-07-21-single-react-evidence-semantic-guards | archived |
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
# Chat Diagnosis StateGraph ChatService Cutover 验收
|
||||
|
||||
## 结果
|
||||
|
||||
已接受。OpenSpec tasks 26/26 完成,阶段 3 可归档。
|
||||
|
||||
## 验证
|
||||
|
||||
### 静态验证
|
||||
|
||||
- `git diff --check`:通过。
|
||||
- source/reference isolation:cutover 核心文件中的 `SequentialAgent`、`VerifierContextHolder`、`VerifierInputHook`、`tool_trace_summary` 命中 0;核心 TODO/FIXME/placeholder 命中 0。
|
||||
- schema whitelist:V012 为 1 个 ALTER TABLE、1 个 ADD COLUMN、0 CREATE、0 DROP,目标仅 `diagnosis_run.orchestration_trace JSON NULL`。
|
||||
- `openspec validate chat-diagnosis-stategraph-chatservice-cutover --strict`:通过。
|
||||
- `openspec validate --specs --strict`:14 passed,0 failed。
|
||||
|
||||
### 脚本验证
|
||||
|
||||
- focused Maven regression:Graph runtime/result mapper/real nodes、ChatService cutover、Trace、Controller、Repository、Gatekeeper、Composer、Eval,共 27 suites / 119 tests;0 failures、0 errors、0 skipped。
|
||||
- `mvn -q -DskipTests test-compile`:通过。
|
||||
- `ChatServiceGraphIntegrationTest` 覆盖 SUCCESS、handled Fallback、unhandled failure、blank answer/partial trace 和同 session 多 Run 隔离。
|
||||
|
||||
### 浏览器/人工验证
|
||||
|
||||
- 未运行。阶段 3 的公开协议由 Controller/service tests 覆盖,完整人工/live 验收按用户规则保留到阶段 5。
|
||||
|
||||
### 未验证
|
||||
|
||||
- 未使用 Maven 启动应用做 live E2E。
|
||||
- 未检查 `logs/` 运行日志。
|
||||
- 未执行 `scripts/query_mysql.py` 查询真实数据库。
|
||||
- 原因:用户明确要求只有阶段 5 全部完成后统一执行端到端、日志和数据库验收;阶段 3 只做风险相关自动化验证。
|
||||
- 剩余风险:真实模型/工具调用下的 Prompt 行为、Flyway 在真实 MySQL 的应用结果和最终 Trace 数据须由阶段 5 E2E 证明。
|
||||
|
||||
## 已完成范围
|
||||
|
||||
- 复杂 Chat 唯一生产编排切换到 Diagnosis StateGraph,公开 ChatResult 保持兼容。
|
||||
- Run 生命周期、metrics、Eval、finally cleanup 与 runId 隔离保持;handled Fallback=SUCCESS,未处理/空答案=FAILED。
|
||||
- 新增 Run 级 compact orchestration trace,并只在 Trace run 对象暴露解析结果。
|
||||
- Verifier Prompt/self-evaluation 使用 verified-only 数据,不伪造未发生 verdict/event。
|
||||
- 移除冲突的 Sequential 实现测试并以 Graph/public contract tests 替代。
|
||||
|
||||
## Bug 修复和诊断
|
||||
|
||||
- 替代测试错误引用 `com.superbiz.agent.tool.ToolInvocationRecorder`:通过定义/引用搜索确认类型位于同一 `service` 包,删除错误 import。
|
||||
- no-answer 新测试错误期待 inner cause:分类为测试断言偏差,改为公开 wrapper error,同时保留 FAILED 与真实 partial trace 核心断言。
|
||||
|
||||
## 交接
|
||||
|
||||
- OpenSpec archive:已同步 5 份 delta specs,并归档到 `openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-chatservice-cutover/`。
|
||||
- 下一步:审查精确 Git diff 并完成阶段 3 独立提交,之后才启动阶段 4。
|
||||
- OpenSpec 归档确认:用户已明确授权后续阶段直接实现/归档;归档已完成。
|
||||
@@ -0,0 +1,21 @@
|
||||
# Chat Diagnosis StateGraph ChatService Cutover Brief
|
||||
|
||||
## 背景
|
||||
|
||||
- 用户目标:将 ISS-011 阶段 3 作为独立 sm-flow,正式切换复杂 Chat 生产编排并增加 Run 级 orchestration trace。
|
||||
- 当前问题:真实 Diagnosis Graph Nodes 已存在,但生产入口仍依赖 SequentialAgent、外层重试和 ThreadLocal/Hook 隐式状态。
|
||||
- 关联 OpenSpec:`openspec/changes/chat-diagnosis-stategraph-chatservice-cutover/`
|
||||
- devflow 分档:complex。
|
||||
|
||||
## 范围
|
||||
|
||||
- 本次要做:复杂 Chat 单轨 Graph cutover;复用四类 Agent builder;Graph result/self-evaluation 映射;V012 Run JSON 字段;Trace run-only 投影;verified-only Verifier Prompt;必要回归测试。
|
||||
- 本次不做:不改 `/api/chat` 请求/响应,不做历史 trace 回填,不删除仍供历史代码/测试使用的 Hook/ThreadLocal 类型,不完成阶段 4 测试体系全面收敛,不运行 live E2E/log/DB 验收。
|
||||
- 影响区域:ChatService、Diagnosis Graph runtime/result mapper、DiagnosisRun/Flyway、Trace DTO/service、Verifier Prompt、Graph/Service/Trace tests。
|
||||
|
||||
## OpenSpec 对齐
|
||||
|
||||
- proposal 覆盖状态:已覆盖。
|
||||
- design 覆盖状态:已覆盖。
|
||||
- specs 覆盖状态:已覆盖,5 个 delta capabilities。
|
||||
- tasks 覆盖状态:26/26 已完成。
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
# Chat Diagnosis StateGraph ChatService Cutover Decisions
|
||||
|
||||
## Entry Summary
|
||||
|
||||
- 问题:复杂 Chat 仍使用 SequentialAgent + ThreadLocal/Hook 隐式状态机,真实 Graph 尚未成为生产入口,也没有 Run 级 orchestration trace 持久化和 API 投影。
|
||||
- 期望:阶段 3 独立完成生产 cutover、Run/Trace 映射和必要测试,归档并提交后才进入阶段 4。
|
||||
- 分档:complex。
|
||||
- Change:`chat-diagnosis-stategraph-chatservice-cutover`。
|
||||
- 授权:用户已要求后续阶段直接实现,不再逐 checkpoint 等待;阶段门禁、独立 archive/commit 与阶段 5 才 E2E 约束不变。
|
||||
|
||||
## Context Sources
|
||||
|
||||
- `mvp/issues/active/ISS-011-chat-diagnosis-stategraph-orchestration.md` 阶段 3、协议影响、Run 状态和验收章节。
|
||||
- 阶段 0–2 OpenSpec archives、devflow acceptance/decisions 与当前四份 Graph 主 specs。
|
||||
- `devflow/glossary/CONTEXT.md` 中 Chat Session、Diagnosis Run、Diagnosis Trace、Diagnosis Orchestration Trace 的边界。
|
||||
- `ChatService` 生产调用链、四个 Agent builder、Run persistence/self-evaluation/metrics 逻辑。
|
||||
- `DiagnosisRun`、V011 migration、`DiagnosisTraceResponse`、`DiagnosisTraceService` 与相关 tests。
|
||||
- `DiagnosisGraphFactory`、真实 action factory、Node adapters、final trace builder 和本地 CompiledGraph API。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 术语 | orchestration trace 是否属于 self-evaluation 或完整 Trace event log? | evidence-driven | 已解决 |
|
||||
| Q2 | 边界 | 阶段 3 是否改变 `/api/chat`,以及 Trace 字段出现在哪一层? | user-interview(既有冻结决策) | 已确认 |
|
||||
| Q3 | 生命周期 | LOW_CONFID/REJECT/Fallback 是否应使用 FAILED 或新增 DEGRADED? | user-interview(既有冻结决策) | 已确认 |
|
||||
| Q4 | 错误处理 | Graph 异常时如何 best-effort 保存已有编排事实而不伪造 event? | evidence-driven | 已解决 |
|
||||
| Q5 | 技术实现 | 是否复用现有 Agent factory/Hook/ToolCallback 与真实 Node assembly? | evidence-driven | 已解决 |
|
||||
| Q6 | 安全 | Graph Verifier Prompt/self-evaluation 是否可继续使用 raw Executor 和完整 tool trace? | evidence-driven | 已解决 |
|
||||
| Q7 | 验收 | 阶段 3 是否需要新增测试,是否现在运行 live E2E? | user-interview(用户最新规则) | 已确认 |
|
||||
|
||||
## Evidence-driven Findings
|
||||
|
||||
- Q1:glossary 与阶段 0 spec 已定义 orchestration trace 为 Run 级紧凑编排摘要,与 self-evaluation、AgentStep/ToolInvocation 和 checkpoint 分离;无需新增术语或 ADR。
|
||||
- Q4:所有已定义 Agent/Java 失败应由 Graph 路由到 handled Fallback 并返回 final state;只有真实可取得的 final/partial state 才可构造 trace。无法取得 state 的未处理异常标记 Run FAILED,不得生成虚假 transition。
|
||||
- Q5:`DiagnosisRealGraphActionsFactory` 已提供真实 Node assembly;ChatService 现有四个 builder、AgentLoggingHook、Skills hooks、method tools 和 ToolCallbacks 可直接构造 ReactAgent,再通过 `ReactAgentDiagnosisInvoker` 注入,不得复制 Prompt/Agent factory。
|
||||
- Q6:阶段 2 spec 已禁止 Graph Verifier 使用 raw Executor/full tool trace;当前 `chat-verifier-prompt.md` 仍描述旧 Hook payload,是阶段 3 必须同步的明确 gap。self-evaluation 可保存 Graph 的 verified output、Gatekeeper audit 和 Composer audit,但不能重新引入 raw 输入。
|
||||
|
||||
## User-interview Confirmations
|
||||
|
||||
| 问题 | 用户原话/既有确认 | 确认状态 | OpenSpec 回写 |
|
||||
|---|---|---|---|
|
||||
| Q2 外部协议与 Trace 层级 | ISS-011 已冻结 `/api/chat` 不变,Trace 只在 `run.orchestrationTrace` 增解析对象 | 已确认 | proposal |
|
||||
| Q3 Run 生命周期 | ISS-011 已冻结安全 Fallback 为 SUCCESS,不新增 DEGRADED;只有无法生成安全响应的未处理失败为 FAILED | 已确认 | proposal |
|
||||
| Q7 验收节奏 | “端到端只在最后阶段全部完成后才验证;每个阶段如果有必要添加单元测试验收的话,就加” | 已确认 | proposal |
|
||||
|
||||
## Interface Impact
|
||||
|
||||
- 等级:L4。
|
||||
- 原因:复杂 Chat 内部状态机正式切换;DiagnosisRun 增加数据库 JSON 契约;Trace run 对象新增字段;旧固定顺序消费者/测试不再成立。
|
||||
- 保持兼容:`/api/chat` request/response、sessionId/runId、Executor/Verifier/Composer 输出契约不变。
|
||||
- 加法变化:只新增 `diagnosis_run.orchestration_trace` 和 `run.orchestrationTrace`。
|
||||
- 回滚:revert 阶段 3 代码/Prompt/spec,数据库列可保留 nullable;不保留运行时双轨开关。
|
||||
|
||||
## Discover Status
|
||||
|
||||
- `devflow/index.md`:命中阶段 0–2 archives 和 Run/Trace 历史项目。
|
||||
- Glossary:相关术语已存在且无冲突,不需更新。
|
||||
- ADR:阶段 0 已记录难以逆转的状态机/Trace 决策,本阶段没有新的三条件 ADR。
|
||||
- 未解决问题:0。
|
||||
- Draft 产物:当前只创建 proposal + decisions;design/specs/tasks 留到 Commit checkpoint。
|
||||
|
||||
## Grill-with-docs Review
|
||||
|
||||
### Domain model stress test
|
||||
|
||||
- 同一 session 连续两个复杂 Chat run:每次编译/执行使用自己的 runId threadId 和 metadata;orchestration trace 只写各自 DiagnosisRun,session 投影不复制,符合 Session/Run/Trace 领域边界。
|
||||
- Gatekeeper REJECT 或 Planner/Executor 技术失败:Graph 进入确定性 Fallback,返回安全非空答案;Run 为 SUCCESS,trace `degraded=true`,不会把诊断质量塞进 Run status。
|
||||
- Composer 成功但 verdict=LOW_CONFID/REJECT:Run 仍为 SUCCESS;self-evaluation 保存 effective verdict,orchestration trace 保存实际路径,两者职责不混合。
|
||||
- Graph 未处理异常:使用流式 NodeOutput 捕获最后一个真实 state,只有其中已有 events 时才 best-effort 构造 partial trace;没有 event 时不伪造 transition,Run 标记 FAILED。
|
||||
- 历史/AI_OPS run:新增列 nullable,Trace DTO 对旧 run 可返回 null;不增加历史回填或跨 flow 假数据。
|
||||
|
||||
### Design tree conclusions
|
||||
|
||||
- 生产切换采用单轨,不增加 feature flag 或保留 Sequential/Graph 双运行;回滚依靠 Git revert,nullable 列可保留。
|
||||
- ChatService 负责 Run 生命周期和调用一个专用 Graph runtime/orchestrator;复杂 Agent 构造从旧 Sequential 私有流程中搬移或封装复用,不复制第二套 builder。
|
||||
- Graph 执行优先使用可观察的 `CompiledGraph.stream(..., config)` 收集最后真实 state,以支持异常时 best-effort trace;正常终止仍以 END state 的 `final_answer` 为唯一答案来源。
|
||||
- Graph result mapping 形成独立组件:final answer、Verifier evaluation、Composer audit、Gatekeeper audit、trace JSON 均从显式 final state读取,不再访问 VerifierContextHolder。
|
||||
- Verifier Prompt 必须更新为 `diagnosis_context`、`verified_executor_output`、`verified_evidence`、`gatekeeper_audit`、`verdict_ceiling` 和可选 retry context;删除 raw Executor/full tool trace/Hook Gatekeeper 说明。
|
||||
- 阶段 3 必须有 production cutover 与 Trace DTO/Service tests;阶段 4 再做测试体系全面改名、夹具收敛和旧测试删除。
|
||||
|
||||
### Documentation result
|
||||
|
||||
- 术语与 `devflow/glossary/CONTEXT.md` 完全一致,无需修改 glossary。
|
||||
- 状态机、Run status 和 orchestration trace 隔离均来自阶段 0 已归档 ADR/规格,不创建重复 ADR。
|
||||
- proposal 已反映单轨切换、L4 接口影响、流式 partial-state 处理、Prompt 安全边界和阶段 5 E2E 延期。
|
||||
- Grill question pool 全部关闭;无需要再次询问用户的产品取舍。
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
### Module and caller map
|
||||
|
||||
`ChatController` 的 normal/SSE 两个入口都调用 `ChatService.executeChatWithStrategy`,复杂分支进入 `executeChatComplex`;对外仍只消费 `ChatResult(answer, sessionId, runId)`。阶段 3 将内部链路变为 `ChatService Run lifecycle -> complex Chat Graph runtime/Agent assembly -> real Diagnosis Nodes -> Graph result mapper -> DiagnosisRun persistence -> DiagnosisTraceService`。Trace UI/Eval 当前读取兼容 `session.selfEvaluation`,它仍由 Run self-evaluation 投影;新增 orchestration trace 只属于 `run`。AIOps、Feedback、CaseLibrary 和 Run list 继续使用 DiagnosisRun 既有字段,不消费新增 orchestration trace。
|
||||
|
||||
| 模块 | 所有权 | 允许的依赖/影响 |
|
||||
|---|---|---|
|
||||
| ChatController | `/api/chat` normal/SSE 协议 | 继续只依赖 ChatResult;无字段变化 |
|
||||
| ChatService | Chat Session/Diagnosis Run 生命周期、成功/失败保存、metrics、Eval、finally cleanup | 调用一个 Graph runtime/result mapper;不再拥有条件边/重试/Gatekeeper/Composer 路由 |
|
||||
| Complex Chat Graph runtime | 每请求 Agent assembly、initial state、RunnableConfig、CompiledGraph stream | 复用现有 Prompt/tool/skill/logging;不持久化跨 Run 状态 |
|
||||
| Diagnosis Graph | Node status、verified material、events、final answer | 保持阶段 1/2 路由和 counter 所有权 |
|
||||
| Graph result mapper | final/partial state 到安全 evaluation/trace DTO | 不读 ThreadLocal,不查询其他 run,不持久化 raw material |
|
||||
| DiagnosisRun/Flyway | 当前 Run 的 orchestration JSON | 仅一个 nullable JSON 列;历史/AIOps 可为 null |
|
||||
| DiagnosisTraceService/DTO | exact/latest Run 查询和 API 投影 | 只在 RunTrace 加 parsed map;session/top-level/run-list 不重复 |
|
||||
|
||||
### Lifecycle and coupling audit
|
||||
|
||||
ReactAgent 与 CompiledGraph 都按请求构造,因为 Planner/Executor system Prompt 含本次 history/knowledge map;Graph State 和 runtime last-state holder 也是 invocation-scoped,不进入 singleton 可变字段。SessionContextHolder 仍只包围当前请求并在 finally 清理;Graph Node config 以 runId threadId + metadata 绑定 AgentStep、ToolInvocation 和 Gatekeeper。success persistence 在 Eval 之前完成,EvaluationService 再按 runId 合并 rule channel;handled Fallback 与 Composer 使用同一 SUCCESS 路径。Trace JSON 与 self-evaluation 分栏,避免把路线、质量和完整 Agent/tool 明细耦合到一个容器。
|
||||
|
||||
### Consumer impact audit
|
||||
|
||||
- ChatController normal/SSE:ChatResult 协议不变,L4 内部切换不要求调用方迁移。
|
||||
- Trace UI/demo:继续读取兼容 `session.selfEvaluation`;新的 `run.orchestrationTrace` 是加法字段,最终脚本断言留到阶段 5。
|
||||
- DiagnosisTraceEvaluator:现有 fixtures 不变;工具覆盖仍可从 `toolInvocations` 读取,兼容 `executor_structured_output` 保存 verified projection。pre-verification Fallback 质量未来应以 trace degraded 而非伪 verdict 判断,属于阶段 4 测试体系/阶段 5文档收尾。
|
||||
- AIOps/Feedback/CaseLibrary/Run list:实体新增 nullable 字段不改变 builder call sites或查询语义。
|
||||
- 数据库:Hibernate validate 要求 V012 与 entity 同批;回滚代码可忽略保留列。
|
||||
|
||||
### Cross-artifact alignment
|
||||
|
||||
| 对齐链 | 结果 | 证据 |
|
||||
|---|---|---|
|
||||
| brief/proposal 目标、范围、非目标 → proposal | 已对齐 | 单轨 cutover、Run/Trace、Prompt、阶段边界与 E2E 延期均明确 |
|
||||
| proposal 承诺与约束 → design | 已对齐 | 10 项决策覆盖 runtime、state、config、partial state、result、persistence、DB/API/Prompt/tests |
|
||||
| design 架构/接口结论 → specs/tasks | 已对齐 | L4、单轨、Run status、verified-only、Trace 唯一投影和 schema whitelist 均有 requirement/task |
|
||||
| specs 可观察行为 → tasks 可执行切片 | 已对齐 | 6 组 26 个切片覆盖数据、runtime、Prompt、cutover、tests、handoff |
|
||||
|
||||
### Audit result
|
||||
|
||||
未发现与阶段 0–2、Run/Trace ADR 或 glossary 冲突。审计确认不能把 Agent factory 复制进 Node,也不能把 pre-verification Fallback 伪装为 Verifier verdict;两项已在 design/specs/tasks 固定。唯一跨阶段依赖是阶段 4 让测试/Eval 以 orchestration degraded 理解无 Verifier verdict 的安全 Fallback,已记录但不阻塞阶段 3 production correctness。架构风险可接受,cross-artifact gap=0,无未解决接口消费者。
|
||||
|
||||
## Commit Gate
|
||||
|
||||
- schema:spec-driven;proposal/design/specs/tasks 全部 done,applyRequires=`tasks` 已满足。
|
||||
- OpenSpec:当前 change strict validation 通过;14 个主 specs 全部 strict pass。
|
||||
- 规格结构:5 个 delta capabilities、23 条 requirements、72 个 scenarios;tasks 26 个可执行 checkbox。
|
||||
- Cross-artifact:4/4 已对齐,gap=0。
|
||||
- Interface impact:L4;design 已独立记录消费者、加法 DB/Trace 协议、单轨迁移和 Git revert 回滚。
|
||||
- Question pool:所有 evidence-driven 已查证;所有 user-interview 已由 ISS-011/用户原话确认;无未决项。
|
||||
- Preflight:`git diff --check` 通过;Commit checkpoint 尚未修改 Java、SQL、Prompt 或测试。
|
||||
- 结论:Draft OpenSpec 已达到可执行状态,创建 `.committed`,阶段 3 Apply 只能以这些产物为依据。
|
||||
|
||||
## Apply Authorization
|
||||
|
||||
- 用户原话:“直接实现吧,不用找我授权了”。
|
||||
- 本阶段在 Commit gate 后直接进入 Apply;不扩大到阶段 4 全面测试迁移或阶段 5 live E2E。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### Reference implementations read
|
||||
|
||||
- `ChatService.executeChatComplex`、四个 complex Agent builders、Run start/save、metrics、Prompt audit、self-evaluation merge:迁移源实现和外部兼容基线。
|
||||
- `DiagnosisGraphFactory`、`DiagnosisRealGraphActionsFactory`、四个 Agent adapters、Gatekeeper/VerifiedInput/Fallback、`DiagnosisOrchestrationTraceBuilder`:Graph 路由/计数/安全材料唯一真理源。
|
||||
- `DiagnosisRun`、V011 migration、`DiagnosisTraceResponse`、`DiagnosisTraceService`、`DiagnosisTraceServiceTest`:Run JSON 字段和 exact/latest Trace 映射标准。
|
||||
- `ChatController` normal/SSE、`DiagnosisTraceController`:公开协议调用者与响应包装边界。
|
||||
- `SelfEvaluationMergeService`、`EvaluationService`、`DiagnosisTraceEvaluator`:evaluation container、异步 rule merge 和兼容消费者。
|
||||
- 本地 graph-core 1.1.2.0 `javap`:CompiledGraph `stream/invoke/state`、NodeOutput `state()`、RunnableConfig `threadId/metadata` 的真实 API。
|
||||
- `chat-*-prompt.md`:现有 Prompt 组装与 Verifier 旧 Hook payload gap。
|
||||
|
||||
### Technology inventory
|
||||
|
||||
| 类别 | 项目标准 / 本阶段使用 |
|
||||
|---|---|
|
||||
| Graph execution | `CompiledGraph.stream(initial, config)` + NodeOutput.state,当前请求线程阻塞消费 |
|
||||
| Run context | SessionContextHolder + RunnableConfig threadId/metadata;runId 是唯一执行边界 |
|
||||
| Agent assembly | ReactAgent builder、AgentLoggingHook、PlannerSkillMetadataHook/SkillsAgentHook、现有 tools/callbacks |
|
||||
| JSON persistence | Jackson map serialization;实体 String + `@JdbcTypeCode(SqlTypes.JSON)`;Flyway JSON column |
|
||||
| Trace API | Lombok DTO builder + DiagnosisTraceService parsed Map;exact/latest Run 查询 |
|
||||
| Evaluation | SelfEvaluationMergeService container;EvaluationService 按 runId 异步合并 rule channel |
|
||||
| Tests | JUnit 5,通过 public service/runtime/Trace API;只 mock repository/model/tool 外部边界 |
|
||||
| MQ/Consumer | 不涉及 |
|
||||
|
||||
### New infrastructure and reuse
|
||||
|
||||
- 新增一个深接口的 complex Chat Graph runtime/result mapper;复用既有 Graph/Node/Agent builders,不增加新依赖或第二套路由。
|
||||
- 新增 V012、DiagnosisRun 字段和 RunTrace parsed map;不新增表、repository method 或历史 backfill。
|
||||
- TDD tracer bullet 从 Trace DTO/Service 的唯一 Run 投影开始,再进入 runtime final-state mapping,最后切换 ChatService。
|
||||
- 研究未发现 devflow/OpenSpec 冲突,技术清单足以开始实现。
|
||||
|
||||
## Apply Progress
|
||||
|
||||
- TDD Trace slice RED:DiagnosisTraceServiceTest 明确缺少 DiagnosisRun builder 字段和 RunTrace getter。
|
||||
- GREEN:V012、DiagnosisRun JSON 字段、RunTrace parsed map、DiagnosisTraceService mapping 完成;10 个 Trace service tests 通过。
|
||||
- 失败分类:首次 GREEN 运行仅测试夹具用裸 ObjectMapper 无法序列化 LocalDateTime,属于 test harness 偏差;改为项目可用的 `findAndRegisterModules()` 后原始 focused loop 通过,未改业务协议。
|
||||
- Trace API JSON 断言证明顶层/session 无重复字段、run 为解析对象、无 raw 字段;null/invalid JSON fail closed。
|
||||
|
||||
## Apply Completion
|
||||
|
||||
- 复杂 Chat 已单轨切换到 `ChatDiagnosisGraphRuntime`;生产 `ChatService` 不再创建 `SequentialAgent`,不再读取 `VerifierContextHolder`,Graph Verifier 只保留 `AgentLoggingHook`。
|
||||
- runtime 使用 query-only initial state、`threadId=runId` 和 sessionId/runId metadata,流式保留最后真实 state;异常只保存真实 partial state/trace。
|
||||
- `DiagnosisGraphResultMapper` 只从 verified projection 构造兼容 self-evaluation;Verifier 未完成时不伪造 verdict,不持久化 full tool trace/raw Executor。
|
||||
- Verifier Prompt 与 runtime payload 已统一为 verified-only,Prompt audit 更新为 `chat-prompts-v2` / `chat-verifier-v3`。
|
||||
- 旧 `ChatServiceSequentialAgentTest` 因绑定已删除的固定顺序/ThreadLocal/score retry 实现而移除,由 public service/runtime/route tests 替代。
|
||||
- V012 schema 白名单测试确认只新增 `diagnosis_run.orchestration_trace JSON NULL`,无其他 schema object。
|
||||
|
||||
## Verification Summary
|
||||
|
||||
- focused regression:27 suites / 119 tests,0 failures、0 errors、0 skipped。
|
||||
- Maven test compilation:通过。
|
||||
- OpenSpec:当前 change strict pass;主 specs 14/14 strict pass。
|
||||
- 静态门禁:`git diff --check` 通过;cutover 禁用引用 0;核心 TODO/placeholder 0;schema whitelist 为 1 ALTER / 1 ADD COLUMN / 0 CREATE / 0 DROP。
|
||||
- 实现期唯一失败分类:no-answer service test 曾错误期待 inner cause 文本,属于测试断言偏差;按公开 wrapper error + FAILED/partial trace 契约修正后通过,OpenSpec 与生产代码无需变更。
|
||||
- 按阶段门禁未运行 Maven live E2E、未检查 `logs/`、未执行 `scripts/query_mysql.py`;统一保留到阶段 5。
|
||||
|
||||
## Archive Result
|
||||
|
||||
- 5 份 delta specs 已同步:新增 9、修改 13、删除 1 条 requirements。
|
||||
- OpenSpec 已归档到 `openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-chatservice-cutover/`。
|
||||
- CLI 对 proposal 结构给出非阻塞建议(大 change/delta 拆分与 SHALL/scenario 启发式);tasks 26/26、delta specs 和 strict validation 均通过,未形成验收阻塞。
|
||||
@@ -0,0 +1,21 @@
|
||||
# Chat Diagnosis StateGraph ChatService Cutover Evidence
|
||||
|
||||
## 证据
|
||||
|
||||
| 来源 | 证据 | 结论 | 是否已汇报 |
|
||||
|---|---|---|---|
|
||||
| `ChatService` + source isolation search | 复杂路径只有一次 Graph runtime 调用,无 SequentialAgent、VerifierContextHolder、VerifierInputHook 或 score retry | 单轨 cutover 完成,简单 Chat 路径未改 | 是 |
|
||||
| `ChatDiagnosisGraphRuntimeTest` / `DiagnosisRealGraphIntegrationTest` | query-only state、runId thread/metadata、Composer/Fallback、empty stream、blank answer、partial trace、Gatekeeper once/twice | Graph identity、路由和真实 partial-state 边界可观察 | 是 |
|
||||
| `DiagnosisGraphResultMapperTest` / `ChatVerifierPromptContractTest` | verified projection、effective verdict 兼容、pre-verification 无伪 verdict、禁用 raw/full trace 字段 | self-evaluation 与 Prompt 安全边界一致 | 是 |
|
||||
| `ChatServiceGraphIntegrationTest` | ChatResult、agent_flow、SUCCESS/Fallback/FAILED、metrics/Eval、partial trace、多 Run 隔离 | 生产生命周期与兼容返回满足阶段 3 规格 | 是 |
|
||||
| `DiagnosisTraceServiceTest` | `run.orchestrationTrace` 解析对象、top/session 无重复、invalid/null fail closed | Trace 字段所有权保持 Run 隔离 | 是 |
|
||||
| `DiagnosisRunSchemaContractTest` | V012 executable SQL 与唯一允许语句精确相等 | schema 仅增加一个 nullable JSON 列 | 是 |
|
||||
| focused Maven suite | 27 suites / 119 tests,0 failures/errors/skipped | Graph、Controller、Repository、Gatekeeper、Composer、Eval 回归通过 | 是 |
|
||||
| OpenSpec/static gates | change strict、14/14 主 specs、test compile、diff check、禁用引用/占位/schema whitelist 全通过 | 规格、编译和源级隔离闭环 | 是 |
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- orchestration trace 必须独立于 self-evaluation 和详细 Agent/tool Trace;V012 与 RunTrace 的实现保持这一边界。
|
||||
- handled Fallback 表示安全降级答案,Run 仍为 SUCCESS;未处理、空答案或 invariant 失败才是 FAILED。
|
||||
- Verifier/Gatekeeper 只以显式 Graph state 传递可信材料;继续使用 Hook/ThreadLocal 会形成双 Gatekeeper 和不安全输入,因此生产路径已彻底移除该依赖。
|
||||
- 旧 Sequential 测试验证的是已废止内部机制,替换为 public service + runtime + route contract tests 才能保持真实回归价值。
|
||||
@@ -0,0 +1,49 @@
|
||||
# Acceptance
|
||||
|
||||
## 静态验证
|
||||
|
||||
- 旧闭包路径不存在,executable legacy refs=0。
|
||||
- current-doc stale architecture refs=0;历史兼容引用有明确限定。
|
||||
- `git diff --check` 通过;无新增 migration/schema 变更;临时调试标记=0。
|
||||
- 当前 change strict 和 16 个 main specs strict 全部通过。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
- `mvn -q -DskipTests test-compile`:通过。
|
||||
- 39-suite authoritative/focused Maven command:157 tests,0 failure/error/skipped。
|
||||
- 归档前 `mvn clean` + test compilation + 43-suite deterministic command:189 tests,0 failure/error/skipped。
|
||||
- `DiagnosisTraceEvaluatorTest` + `DiagnosisEvalBaselineDiffTest`:12/12 baseline,same diff=0。
|
||||
- PowerShell parser + `InterviewDemoScriptContractTest`:通过。
|
||||
- `run-interview-demo-check.ps1 -SessionId iss-011-stage5-20260720015557 -OutputDir target/iss-011-stage5-output-current`:exit 0。
|
||||
- `scripts/query_mysql.py` exact queries:V012、Run JSON、AgentStep/ToolInvocation ownership 全部通过。
|
||||
- `openspec validate --all --strict --no-interactive`:17/17 passed;`git diff --check`、current-doc、schema、debug source、port/temp scope checks 通过。
|
||||
|
||||
## Live E2E
|
||||
|
||||
| 项目 | 结果 |
|
||||
|---|---|
|
||||
| Maven profile | `mvp-demo` |
|
||||
| sessionId | `iss-011-stage5-20260720015557` |
|
||||
| runId | `run-808ac38f-3ad0-4462-a6d0-ed50d8686473` |
|
||||
| Run | `CHAT/SUCCESS` |
|
||||
| answer / metrics | 109 chars / 75964ms / 111802 tokens / 8 steps / 12 tools |
|
||||
| Graph | `stategraph-v1`, `fallback`, `fallback_completed`, degraded=true, 3 transitions, retry=0 |
|
||||
| evaluation / feedback | non-empty / useful |
|
||||
| new ERROR | 0 |
|
||||
| DB ownership | wrong owner=0,wrong-session rows=0 |
|
||||
| process cleanup | owned PIDs stopped,9900 released |
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
- 不适用。本阶段验收入口是 API/PowerShell executable contract,无 UI 改动。
|
||||
|
||||
## 未验证
|
||||
|
||||
- 无 OpenSpec 必需项未验证。
|
||||
|
||||
## 归档状态
|
||||
|
||||
- ISS-011 已归档至 `mvp/issues/archived/ISS-011-chat-diagnosis-stategraph-orchestration.md`。
|
||||
- OpenSpec 归档路径:`openspec/changes/archive/2026-07-20-chat-diagnosis-stategraph-cleanup-docs`。
|
||||
- OpenSpec CLI 已同步主 specs:新增 `chat-diagnosis-stategraph-cleanup-docs`,更新 `mvp-demo-trace-acceptance` 3 项 requirement。
|
||||
- 不 push。
|
||||
@@ -0,0 +1,32 @@
|
||||
# Chat Diagnosis StateGraph Cleanup And Final Acceptance
|
||||
|
||||
## 背景
|
||||
|
||||
ISS-011 阶段 0-4 已完成 StateGraph 设计冻结、路由骨架、真实 Nodes、ChatService 单轨切换和三层权威测试。阶段 5 负责删除旧 Hook/ThreadLocal/full-trace service 闭包、对齐当前文档与 demo executable contract,并以唯一 Run 完成最终 Maven、日志和数据库验收。
|
||||
|
||||
## 目标
|
||||
|
||||
- 只保留 bounded StateGraph 复杂 Chat 编排和 verified-only Verifier 输入。
|
||||
- 让 current architecture/eval/demo 文档与 Run-owned orchestration trace 一致。
|
||||
- 先通过确定性回归,再用 Maven `mvp-demo` 证明 exact Chat/Trace/feedback、日志和数据库 ownership。
|
||||
- 所有门禁通过后关闭 ISS-011,并归档阶段 5 OpenSpec。
|
||||
|
||||
## 范围
|
||||
|
||||
- 删除 `VerifierInputHook`、`VerifierContextHolder`、`ToolTraceSummaryService` 及其 focused test。
|
||||
- 更新 current architecture/eval/demo 文档和 interview demo check。
|
||||
- 修复 live 暴露的 Graph event classloader 边界与 nested ReactAgent resume config 问题。
|
||||
- 完成 Graph/Chat/Trace/Eval 回归、Maven live E2E、日志/MySQL 核验、进程清理和 Issue 生命周期收口。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不修改公开 Chat/feedback API、Executor/Verifier/Composer 业务协议或数据库 schema。
|
||||
- 不重写 archived issues、历史 design notes 和 legacy fixtures。
|
||||
- 不删除旧 Trace/fixture 对 `tool_trace_summary` 的只读兼容。
|
||||
- 不 push,不删除失败尝试的审计数据。
|
||||
|
||||
## 元数据
|
||||
|
||||
- 分档:complex
|
||||
- OpenSpec:`chat-diagnosis-stategraph-cleanup-docs`
|
||||
- 接口影响:L2 内部类型/状态表示修复;外部 API/DTO/schema 不变
|
||||
@@ -0,0 +1,159 @@
|
||||
# Chat Diagnosis StateGraph Cleanup, Final Acceptance And Documentation Decisions
|
||||
|
||||
## Entry Summary
|
||||
|
||||
- 问题:ISS-011 运行时已切换且测试体系已收敛,但旧 Hook/ThreadLocal/service死代码、当前架构文档和最终 live 证据尚未闭环。
|
||||
- 期望:阶段 5完成清理、文档、自动化回归、eval、Maven E2E、日志/DB 验收、Issue 归档和独立提交。
|
||||
- 分档:complex;接口影响 L2 内部删除 + 文档/demo 验收增强,外部 API/DB 协议不变。
|
||||
- Change:`chat-diagnosis-stategraph-cleanup-docs`。
|
||||
- 授权:用户已明确要求直接实现;本阶段按此前规则执行唯一最终 E2E。
|
||||
|
||||
## Context Sources
|
||||
|
||||
- ISS-011 阶段 5、测试策略、协议影响、验收标准和冻结决策。
|
||||
- 阶段 0–4 OpenSpec archives、devflow acceptance 与提交 `581daff`、`42ba204`、`1460dd1`、`99e490f`、`208a231`。
|
||||
- 全仓 `VerifierInputHook`/`VerifierContextHolder`/`ToolTraceSummaryService` 定义与引用搜索。
|
||||
- `mvp/architecture/README.md` 列出的 current docs、`mvp/eval/README.md`、`mvp/demo/` scripts/checklist。
|
||||
- `mvp-demo` profile、payment-timeout request、`scripts/query_mysql.py` 和 logs/ 现有布局。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 清理 | 旧 Hook/ThreadLocal/trace summary service 是否还有生产消费者? | evidence-driven | 已解决 |
|
||||
| Q2 | 文档 | 哪些旧引用应更新,哪些历史材料应保留? | evidence-driven | 已解决 |
|
||||
| Q3 | E2E | 最终 live 场景如何绑定唯一 session/run 并证明 Graph 路径? | evidence-driven | 已解决 |
|
||||
| Q4 | 日志/DB | 如何避免用旧日志/latest DB 记录冒充当前证据? | evidence-driven | 已解决 |
|
||||
| Q5 | 验收 | 何时允许启动 Maven、是否需要日志和 DB 查询? | user-interview(用户最新规则) | 已确认 |
|
||||
| Q6 | 关闭 | 何时把 ISS-011 从 active 移到 archived? | evidence-driven | 已解决 |
|
||||
|
||||
## Evidence-driven Findings
|
||||
|
||||
- Q1:旧闭包只有 `VerifierInputHook -> VerifierContextHolder + ToolTraceSummaryService`,以及 `ToolTraceSummaryServiceTest`;ChatService/Graph/Trace/Eval 均无引用,可整体删除。
|
||||
- 实现前规格校正:`ChatVerifierPromptContractTest` 和 `DiagnosisGraphTestSuiteStructureTest` 必须保留旧类型名称的负向字符串断言;这不构成 executable reference。OpenSpec 已收紧为无定义/import/实例化/type-use,允许负向 guard literal。
|
||||
- Q2:current architecture index 仍列 `agent-orchestration.md` 等为当前真理源,因此必须更新;`mvp/issues/design-notes`、archived issues、历史 eval fixtures 保留时间点/兼容语义,不做大规模重写。
|
||||
- Q3:`run-interview-demo-check.ps1` 已用 Chat response runId 查询 exact Trace/feedback,最适合扩展 `run.orchestrationTrace` fail-fast 和 summary,不另建重复脚本。
|
||||
- Q4:E2E 使用唯一 timestamp sessionId;日志记录启动前 byte/time 边界并按 session/run 搜索;DB 所有核心查询带 exact sessionId/runId,另查询错误 ownership count。
|
||||
- Q6:只有实现、回归、eval、live E2E、日志、DB 和 OpenSpec门禁全部通过后,Issue checkbox 才可完成并移动到 archived。
|
||||
|
||||
## User-interview Confirmation
|
||||
|
||||
| 问题 | 用户原话 | 状态 | OpenSpec 回写 |
|
||||
|---|---|---|---|
|
||||
| Q5 最终验收节奏 | “端到端只在最后阶段全部完成后才验证……日志在log文件夹,项目库有查询数据库的py工具” | 已确认 | proposal |
|
||||
|
||||
## Grill-with-docs Result
|
||||
|
||||
- Session/Run/Trace 术语保持不变;新增强调 `orchestration_trace` 是 Run 路由摘要,不属于 self-evaluation 或日志。
|
||||
- StateGraph、Workflow/Node Contract/Chat Integration 属于实现/测试架构术语,不修改业务 glossary。
|
||||
- 当前文档必须使用 explicit Gatekeeper Node、verified-only Verifier 和 bounded evidence retry;历史设计笔记仍可描述当时 Hook 架构。
|
||||
- 删除旧闭包是阶段 0 已冻结单轨迁移的自然收尾,不形成新的难逆转权衡,无需 ADR。
|
||||
|
||||
## Discover Status
|
||||
|
||||
- `devflow/index.md`:命中阶段 0–4 archives。
|
||||
- 接口影响:L2 内部类型删除;外部 API/DTO/DB/Prompt/状态语义无变化。
|
||||
- E2E 入口/脚本/日志/DB 工具已定位;真实执行留到 Apply 最后。
|
||||
- 未解决问题:0。
|
||||
- Draft 产物:proposal + decisions;尚未生成 design/spec/tasks,尚未删除代码或启动应用。
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
### Module and evidence map
|
||||
|
||||
`ChatController -> ChatService -> ChatDiagnosisGraphRuntime -> DiagnosisRealGraphActionsFactory -> explicit Nodes -> DiagnosisGraphResultMapper -> DiagnosisRun/Trace` 是唯一当前 Chat链。旧 `VerifierInputHook -> ToolTraceSummaryService/VerifierContextHolder` 已从主链断开,删除不改变输入/输出或持久化。阶段 5新增的 demo script assertion只消费 exact Trace `run.orchestrationTrace`,DB/log检查是验收消费者,不成为运行时业务依赖。
|
||||
|
||||
| 模块 | 所有权 | 阶段 5动作 |
|
||||
|---|---|---|
|
||||
| Graph/Chat runtime | 路由、Node、Run 生命周期 | 不改行为,仅回归 |
|
||||
| Legacy Hook closure | 旧 Sequential Verifier payload | 整体删除 |
|
||||
| Current architecture docs | 当前实现真理源 | 更新 StateGraph/verified-only/trace |
|
||||
| Historical docs/fixtures | 时间点/兼容记录 | 保留,不冒充当前实现 |
|
||||
| Demo check | live Chat/Trace/feedback executable contract | 增加 exact orchestration trace fail-fast |
|
||||
| logs/MySQL | live运行证据 | 只读本次 session/run |
|
||||
| ISS/OpenSpec/devflow | 生命周期与交接 | 所有门禁通过后归档 |
|
||||
|
||||
### Lifecycle and failure ownership
|
||||
|
||||
- 自动化门禁失败:不启动 live Maven,修复代码/测试/规格后重跑。
|
||||
- live startup失败:应用未 ready,不执行 demo/DB成功声明,先读启动输出和新日志诊断。
|
||||
- Chat/Trace/feedback失败:保留 exact response/run证据,ISS保持 active。
|
||||
- log ERROR:逐条分类;未解释 ERROR阻塞验收。
|
||||
- DB不一致:以 exact run为准,不能用 API成功掩盖 persistence偏差。
|
||||
- finally:无论成功失败都停止本轮进程并确认端口,不扩大到未知已有进程。
|
||||
|
||||
### Consumer and compatibility audit
|
||||
|
||||
- 外部 API/DTO/DB consumer无迁移;demo summary仅加字段。
|
||||
- Trace UI/eval 对历史 `tool_trace_summary` 的读取保留,旧 fixture不批量迁移。
|
||||
- current docs消费者将看到新 StateGraph架构;历史链接仍可追溯 old Hook设计。
|
||||
- Issue move只改变文档位置/index,代码/运行时不依赖该路径。
|
||||
|
||||
### Cross-artifact alignment
|
||||
|
||||
| 上游 → 下游 | 检查内容 | 状态 |
|
||||
|---|---|---|
|
||||
| brief/proposal → proposal | cleanup、current docs、demo、regression、live/log/DB、Issue closure | 已对齐 |
|
||||
| proposal → design | 删除闭包、current/history边界、顺序、identity、日志/DB、cleanup | 已对齐 |
|
||||
| design → specs/tasks | 负向 literal例外、E2E字段、exact evidence、进程清理、Issue gate | 已对齐 |
|
||||
| specs → tasks | 每条 requirement有可执行 cleanup/docs/test/live/log/DB/closure slice | 已对齐 |
|
||||
|
||||
### Audit result
|
||||
|
||||
审计确认阶段 5不需要新运行时抽象或 DB migration;主要风险来自外部 live状态和证据归属,已通过 unique session/run、log boundary、exact DB queries和process ownership缓解。规格误把负向名称 literal 当 executable reference 的 gap 已修正。接口影响 L2,cross-artifact gap=0,无新 ADR。
|
||||
|
||||
## Commit Gate
|
||||
|
||||
- schema:spec-driven;proposal/design/2 delta specs/tasks 全部 done,applyRequires=`tasks` 已满足。
|
||||
- OpenSpec:当前 change strict pass;16 个主 specs strict pass。
|
||||
- Cross-artifact:4/4 已对齐,gap=0;负向 guard literal例外已写入 proposal/design/spec/tasks。
|
||||
- Question pool:5 个 evidence-driven 已解决,1 个 user-interview 已由用户原话确认,无未决项。
|
||||
- Interface impact:L2 internal type removal + demo/docs enhancement;外部协议/DB无变化。
|
||||
- Preflight:`git diff --check` 通过;尚未删除代码、修改 current docs/script或启动应用。
|
||||
- 结论:Draft OpenSpec 达到可执行状态,创建 `.committed` 后进入 Apply。
|
||||
|
||||
## Apply Progress
|
||||
|
||||
### Legacy closure removal
|
||||
|
||||
- 已删除 `VerifierInputHook`、`VerifierContextHolder`、`ToolTraceSummaryService` 和 `ToolTraceSummaryServiceTest`,四个路径均不存在。
|
||||
- `rg` 对 `src/main`、`src/test` 的旧类型扫描仅命中 `ChatVerifierPromptContractTest` 和 `DiagnosisGraphTestSuiteStructureTest` 中的负向守卫字符串;无定义、import、实例化、继承或类型依赖。
|
||||
- 删除后 focused 回归覆盖 Executor parser、Gatekeeper service/node、VerifiedInput、Verifier、Composer、Fallback、Workflow、Node Contract、Chat integration、Trace、result mapper 和结构契约:14 suites / 82 tests,0 failure、0 error、0 skipped。
|
||||
- `mvn -q -DskipTests test-compile` 通过;Graph/shared protocol 真理源保留,Spring 当前链路所需类型可完整编译。
|
||||
|
||||
### Current docs and demo contract
|
||||
|
||||
- architecture index、编排、session/trace、current MVP、evidence pipeline、quality gates、feedback、retrieval 和 eval 文档已切换为 bounded StateGraph、显式 Gatekeeper/Verified Input、verified-only Verifier、有限重试/Fallback 和 Run-owned `orchestration_trace`。
|
||||
- current-doc scan 对 `SequentialAgent`、旧 Hook/ThreadLocal/service 及旧测试类名为 0 命中;`tool_trace_summary` 仅剩 4 处,均明确标注为旧 Run/fixture 只读兼容,不是当前 Verifier 输入。
|
||||
- interview demo check 绑定 Chat 返回的 exact runId,校验 Chat/Trace ownership、Run CHAT/SUCCESS、Agent/tool/self-evaluation、Graph trace 六个字段和 feedback success;summary 新增 orchestration version、final node、termination reason、degraded、transition count 和 evidence retry count。
|
||||
- PowerShell parser 语法检查通过;`InterviewDemoScriptContractTest` 2 tests 通过,覆盖 exact runId URL/response、orchestration fail-fast 和 summary 字段。
|
||||
|
||||
### Final deterministic gates
|
||||
|
||||
- authoritative/focused regression:39 suites / 157 tests,0 failure、0 error、0 skipped;覆盖三层 Graph、全部 Graph Node/router/trace builder、Chat/Trace/Gatekeeper/Composer、Controller、Repository、schema、feedback/tool recorder 和 demo contract。
|
||||
- fixed diagnosis eval:12/12 passed,verdict distribution 为 PASS=5、LOW_CONFID=6、REJECT=1;same-baseline diff 无 regression、0 items。
|
||||
- `mvn -q -DskipTests test-compile` 通过;当前 change strict 通过,16 个主 specs strict 全部通过。
|
||||
- `git diff --check`、legacy executable refs、current-doc stale refs 和 unexpected schema change 检查全部通过。
|
||||
- focused 回归日志中的 Graph ERROR/exception stack trace 来自 `ChatServiceGraphIntegrationTest` 对 FAILED/no-answer/unhandled failure 的显式契约用例,Maven exit 0,不是未解释的 live ERROR。
|
||||
|
||||
### Live failure diagnosis and correction
|
||||
|
||||
- 首次 live identity:sessionId=`iss-011-stage5-20260717140450`,runId=`run-6db680f8-f764-49d1-995f-0e55a4b05a06`。demo contract 在 exact Trace `run.orchestrationTrace=null` 处 fail-fast,未提交 feedback;Run 为 `CHAT/FAILED`,步骤/工具均为 0。
|
||||
- 新日志根因:`DiagnosisOrchestrationTraceBuilder` 收到类名相同但 classloader identity 不同的 `OrchestrationEvent`,`instanceof` 失败并抛出 `orchestration events contain unsupported value`。这是 Spring Boot DevTools live classloader 才暴露的 Graph state 表示缺陷,单元 JVM 未复现。
|
||||
- 冲突分类:代码偏离/运行时兼容 bug,OpenSpec 对 non-empty orchestration trace 和 live Maven startup 的要求正确,不修改验收口径。
|
||||
- RED:新增 portable event map builder 回归,修复前 1 test error;GREEN:Graph state 的 production/test actions 改存 classloader-neutral Map,builder兼容 local record/Map,Node/Workflow assertions 改读 Map。
|
||||
- 修复后先运行 5-suite Graph/Node/Runtime/Chat integration focused gate,再运行完整 39 suites / 157 tests,全部 0 failure/error/skipped;首次 Maven 进程链已按 ownership 停止,9900 已释放。
|
||||
|
||||
- 第二个 live blocker 为外层 Graph `RunnableConfig` 的 resume metadata 被原样传给内层 ReactAgent,触发 `Resume request without a configured checkpoint saver`。回归先证明 nested config 与 outer config 同一且含 `HUMAN_FEEDBACK`,再改为保留 sessionId/runId、剔除 resume/state-update/checkpoint 控制信息的独立配置;5 suites / 50 tests 和随后完整 39 suites / 157 tests 通过,临时 `[DEBUG-ISS011-NODE]` 探针已删除且源码扫描为 0。
|
||||
- 2026-07-17 的一次长请求在工具执行期间遭遇外部 MySQL 瞬时 `Connection is closed`,留下精确 `RUNNING` 失败尝试;仓库查询工具随后证明数据库恢复且 server `wait_timeout=28800`。该失败未被当作验收通过,失败 Run 保留为真实审计记录。
|
||||
|
||||
### Accepted live E2E
|
||||
|
||||
- 启动:`mvn spring-boot:run "-Dspring-boot.run.profiles=mvp-demo"`;启动前 9900 空闲,隐藏进程链为 cmd `25080` -> Maven Java `17860` -> app Java `10732`,readiness 后执行固定 payment-timeout demo。
|
||||
- identity:sessionId=`iss-011-stage5-20260720015557`,runId=`run-808ac38f-3ad0-4462-a6d0-ed50d8686473`;Chat/Trace exact identity 一致,answer 长度 109,feedback request success。
|
||||
- Trace:Run=`CHAT/SUCCESS`,8 AgentSteps、12 ToolInvocations,self-evaluation 非空;`stategraph-v1`,final node=`fallback`,termination=`fallback_completed`,degraded=`true`,3 transitions,evidence retry count=0。
|
||||
- Fallback 原因是 Gatekeeper LOW_CONFID 且本轮模型输出缺少 `source_invocation_id`;这是按冻结契约执行的安全降级,answer 非空且未绕过 Gatekeeper,日志/DB 均可审计。
|
||||
- 最终日志发生跨日 rollover:7 月 20 日 active `application.log`/`chat.log` 全部属于本轮;`application-error.log` 最后写入仍为 7 月 17 日。本轮 `rg " ERROR "` 对 application/chat 为 0,新增 error-file bytes 为 0;session/run、Graph 75964ms、evaluation、exact Trace 和 useful feedback 均有关联日志。
|
||||
- MySQL:V012 `orchestration_trace` 为 nullable JSON;exact Run answer=109、duration=75964、token=111802、steps=8、tools=12、evaluation len=8822、trace len=438、feedback=useful;JSON 路由与 Trace 完全一致。
|
||||
- ownership:AgentStep 8、ToolInvocation 12,各自 distinct session/run=1、wrong owner=0;唯一 session 下 wrong run/step/tool 均为 0。
|
||||
- cleanup:只停止 PID `10732/17860/25080`,最终 9900 已释放,无剩余 owned process。
|
||||
@@ -0,0 +1,38 @@
|
||||
# Evidence
|
||||
|
||||
## Source And Dependency Evidence
|
||||
|
||||
- 旧闭包四个文件已删除;`src/main`/`src/test` 旧类型扫描仅剩两个测试中的负向名称守卫,无 definition/import/instantiation/type dependency。
|
||||
- 当前真理源保留 `ExecutorEvidenceParser`、`ExecutorGatekeeperService`、`GatekeeperNode`、`VerifiedInputNode`、`VerifierNodeAdapter` 和 `DiagnosisGraphResultMapper`。
|
||||
- current docs 不再描述 SequentialAgent、Hook Gatekeeper 或 full-trace Verifier;4 处 `tool_trace_summary` 均明确为历史只读兼容。
|
||||
|
||||
## Deterministic Evidence
|
||||
|
||||
- 删除后 focused:14 suites / 82 tests,0 failure/error/skipped。
|
||||
- 最终 authoritative/focused:39 suites / 157 tests,0 failure/error/skipped。
|
||||
- 归档前 `mvn clean` 后重建验证:43 suites / 189 tests,0 failure/error/skipped;额外覆盖 4 个无需外部服务的现存测试类。
|
||||
- diagnosis eval:12/12 passed;PASS=5、LOW_CONFID=6、REJECT=1;same-baseline diff=0。
|
||||
- `mvn -q -DskipTests test-compile`、PowerShell parser、OpenSpec current strict、16 main specs strict、`git diff --check`、legacy/current-doc/schema scans 均通过。
|
||||
|
||||
## Diagnose Evidence
|
||||
|
||||
- DevTools live classloader 使 record `instanceof` 边界失效;portable event map regression 先 RED,Node state 改用 Map 且 builder 兼容 record/Map 后 GREEN。
|
||||
- outer Graph resume metadata 污染 nested ReactAgent;nested config isolation regression 先 RED,保留 session/run metadata并剔除 resume/state-update/checkpoint 控制信息后 GREEN。
|
||||
- 两次修复后均重跑 focused 和完整 deterministic gate;临时调试探针为 0。
|
||||
|
||||
## Accepted Live Evidence
|
||||
|
||||
- sessionId:`iss-011-stage5-20260720015557`
|
||||
- runId:`run-808ac38f-3ad0-4462-a6d0-ed50d8686473`
|
||||
- Maven profile:`mvp-demo`;Chat/Trace/feedback script exit 0。
|
||||
- Run:CHAT/SUCCESS;answer=109 chars;8 steps;12 tools;self-evaluation 非空;feedback=useful。
|
||||
- Graph:stategraph-v1;planner -> executor -> gatekeeper -> fallback;termination=fallback_completed;degraded=true;evidence retries=0。
|
||||
- Logs:本轮 active application/chat 中 ERROR=0,error appender 无新写入;session/run、evaluation、Trace、feedback 可关联。
|
||||
- DB:V012 JSON column 存在;Run fields/JSON 与 API 一致;step/tool wrong owner=0;unique-session wrong rows=0。
|
||||
- Cleanup:owned process chain 已停止,9900 已释放。
|
||||
- Archive preflight:临时 `target/iss-011-stage5*` 目录为 0,OpenSpec strict 17/17,current-doc stale=0,schema diff=0,`git diff --check` 通过。
|
||||
|
||||
## Known Limits
|
||||
|
||||
- 本次真实模型遗漏 `source_invocation_id`,Gatekeeper 按契约降为 LOW_CONFID 并进入安全 Fallback;这是成功且可审计的 degraded Run,不是完整 Composer 正常路径。
|
||||
- 2026-07-17 外部 MySQL 瞬时断连留下一个 RUNNING 失败尝试;它未计入验收且保留审计,不影响 2026-07-20 exact accepted Run。
|
||||
@@ -0,0 +1,70 @@
|
||||
# Chat Diagnosis StateGraph Design Freeze Acceptance
|
||||
|
||||
## 结果
|
||||
|
||||
已接受。阶段 0 完成设计冻结,没有修改运行时实现。
|
||||
|
||||
## 验证
|
||||
|
||||
### 静态验证
|
||||
|
||||
- 命令:`git diff --check`
|
||||
- 结果:passed
|
||||
- 备注:仅有现有 LF/CRLF 提示,无 whitespace error。
|
||||
|
||||
- 检查:Git changed/untracked 路径运行时拒绝列表。
|
||||
- 结果:passed,12 个路径,`src/`、Maven、运行配置、脚本、数据库迁移命中 0。
|
||||
- 备注:阶段 0 只包含 Issue、glossary、OpenSpec/devflow 和执行记录。
|
||||
|
||||
- 检查:proposal → design → specs → tasks 四向对齐。
|
||||
- 结果:passed,gap=0。
|
||||
- 备注:状态、路由、Fallback、审计、测试迁移和六阶段边界均闭环。
|
||||
|
||||
### 脚本验证
|
||||
|
||||
- 命令:`openspec validate chat-diagnosis-stategraph-design-freeze --type change --strict --json`
|
||||
- 结果:passed,1/1。
|
||||
- 备注:当前 change 无结构或场景格式问题。
|
||||
|
||||
- 命令:`openspec validate --specs --strict --json`
|
||||
- 结果:passed,11/11。
|
||||
- 备注:归档前主规格基线未回归。
|
||||
|
||||
### 浏览器/人工验证
|
||||
|
||||
- 结果:not run。
|
||||
- 原因:阶段 0 无 UI 或运行行为。
|
||||
|
||||
### 未验证
|
||||
|
||||
- 单元测试:not run。阶段 0 无代码行为,新增或运行单元测试没有新的验收价值。
|
||||
- Maven E2E:not run。用户明确要求仅阶段 5 在全部实现完成后统一执行。
|
||||
- `logs/`:not inspected for stage acceptance;保留到阶段 5。
|
||||
- 数据库:not queried for stage acceptance;保留到阶段 5。
|
||||
- 备注:此前改造前 live baseline 仅为 research,不计入本阶段验收。
|
||||
|
||||
## 已完成范围
|
||||
|
||||
- 冻结最小 Graph State、所有条件边、四类独立计数和终止路径。
|
||||
- 冻结 verified-input、两类 Fallback、Run 状态与 orchestration trace 边界。
|
||||
- 冻结 L4 消费者、兼容、迁移、回滚和测试替换策略。
|
||||
- 创建 ADR-001,并规定阶段 1–5 引用本阶段 archive。
|
||||
- OpenSpec apply tasks 7/7 完成。
|
||||
|
||||
## 已知限制
|
||||
|
||||
- 运行时仍为旧 Sequential 编排,这是阶段 0 的有意状态。
|
||||
- 新设计尚未经过 Graph 编译、Node 单测、Chat 集成或最终 E2E;后续阶段逐项证明。
|
||||
- 主运行时 specs 暂时仍描述旧行为,只新增设计基线 capability。
|
||||
|
||||
## Bug 修复和诊断
|
||||
|
||||
- 更正此前错误流程模型:删除未提交的总 change,改为六个独立 sm-flow/change。
|
||||
- 更正此前错误 E2E 门禁:阶段 0–4 不做 E2E,阶段 5 统一验证。
|
||||
|
||||
## 交接
|
||||
|
||||
- 下一步:阶段 0 Git commit;提交完成后才能创建阶段 1 change。
|
||||
- Delta sync:新增 `chat-diagnosis-stategraph-design-freeze` 主 spec,共 6 个 requirements,无现有 spec 修改/删除。
|
||||
- OpenSpec 归档确认:用户已在目标中明确要求每阶段 archive,并在后续澄清中再次确认,视为已授权。
|
||||
- OpenSpec 归档结果:已同步主 spec,并归档到 `openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-design-freeze/`。
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
# ADR-001: StateGraph owns run-scoped diagnosis control
|
||||
|
||||
**状态**:已接受
|
||||
**日期**:2026-07-17
|
||||
|
||||
复杂 Chat 使用 Spring AI Alibaba StateGraph 管理一次 Diagnosis Run 内的顺序、条件边、有限重试、终止和降级;ReactAgent 只执行 Planner、Executor、Verifier、Composer 的语义任务,Gatekeeper、verified-input builder、evidence retry prepare 和固定 Fallback 使用确定性 Java Node。这样可以精确恢复失败位置并形成可审计路径,同时继续复用现有 Agent、工具和证据协议。
|
||||
|
||||
Gatekeeper 从 `VerifierInputHook` 的隐式执行迁为显式且唯一的 Graph Node。Verifier 只能消费 Gatekeeper passed checked bindings 投影出的 `verified_executor_output` 和 `verified_evidence`;前置验证失败的 Fallback 不得输出 Executor claim。
|
||||
|
||||
编排审计只属于当前 `runId`:有界 `orchestration_events` 压缩后写入 `diagnosis_run.orchestration_trace`,Trace API 只在 `run.orchestrationTrace` 暴露解析对象。它不替代 self evaluation、AgentStep、ToolInvocation 或持久 Graph checkpoint,也不新增 trace 明细表。
|
||||
|
||||
## Considered Options
|
||||
|
||||
- 继续在 `ChatService` 外层叠加 `for/if`:拒绝,失败恢复位置、循环上限和路由原因仍然隐式。
|
||||
- 使用 SupervisorAgent:拒绝,当前是固定诊断 Pipeline,不需要动态选择专科 Agent。
|
||||
- 直接将父 Graph State 交给 `ReactAgent.asNode(...)`:首版拒绝,无法证明 messages、outputKey 和私有执行上下文隔离。
|
||||
- 长期保留 Sequential/StateGraph feature flag 双轨:拒绝,会形成两个编排真理源并增加安全规则漂移。
|
||||
|
||||
## Compatibility And Migration
|
||||
|
||||
`/api/chat`、`executor_evidence_v2`、Verifier 和 Composer 输出协议保持不变。Trace API 只增加 run-scoped 字段;数据库只增加 nullable JSON 列,历史 Run 不回填。
|
||||
|
||||
实施必须按六个独立 sm-flow/change 依次完成:设计冻结、路由骨架、真实节点、ChatService/Trace 切换、测试体系、清理与最终验收。阶段 1–5 必须读取阶段 0 archive,偏离本 ADR 时通过当阶段 OpenSpec 显式修正。
|
||||
|
||||
## Rollback
|
||||
|
||||
每阶段使用独立 Git commit,可整体 revert 当前阶段。生产切换后回滚代码时允许保留 nullable `orchestration_trace` 列;不得用配置重新形成长期双轨。
|
||||
@@ -0,0 +1,20 @@
|
||||
# Chat Diagnosis StateGraph Design Freeze Brief
|
||||
|
||||
## 背景
|
||||
|
||||
- 用户目标:将 ISS-011 阶段 0–5 分别作为独立 sm-flow,前一阶段 archive 并 Git commit 后才进入下一阶段。
|
||||
- 当前问题:复杂 Chat 的跨 Agent 状态机分散在 ChatService、SequentialAgent、VerifierInputHook 和 ThreadLocal 中;实现前需先冻结统一设计。
|
||||
- 关联 OpenSpec:`openspec/changes/chat-diagnosis-stategraph-design-freeze/`
|
||||
- devflow 分档:complex
|
||||
|
||||
## 范围
|
||||
|
||||
- 本次要做:冻结最小 Graph State、完整路由、有限重试、安全 Fallback、run-scoped 审计、L4 接口影响和测试替换边界。
|
||||
- 本次不做:任何 Java、SQL、Prompt、配置、运行时 spec 或运行行为修改;不运行 Maven E2E。
|
||||
- 影响区域:ISS-011、glossary、OpenSpec 设计基线、阶段 0 ADR 和后续五阶段交接契约。
|
||||
|
||||
## OpenSpec 对齐
|
||||
|
||||
- proposal 覆盖状态:已覆盖阶段 0 目标、范围、非目标、验收和风险。
|
||||
- specs 覆盖状态:新增设计基线 capability,不提前修改运行时 capabilities。
|
||||
- tasks 覆盖状态:7/7 完成,且仅包含文档、ADR 和静态验证。
|
||||
@@ -0,0 +1,120 @@
|
||||
# Chat Diagnosis StateGraph Design Freeze Decisions
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 术语 | Diagnosis Orchestration Trace 与 Diagnosis Trace、self evaluation、Graph checkpoint 的边界是什么? | evidence-driven | 已解决 |
|
||||
| Q2 | 边界 | ISS-011 是一个总 sm-flow,还是阶段 0–5 各自独立 sm-flow? | user-interview | 已解决 |
|
||||
| Q3 | 验收 | Maven E2E 在每阶段执行还是只在最终阶段执行? | user-interview | 已解决 |
|
||||
| Q4 | 验收 | 每阶段是否强制新增并运行单元测试? | user-interview | 已解决 |
|
||||
| Q5 | 技术 | 锁定的 StateGraph 版本是否提供条件边、config-aware Node/Edge、recursion limit 和 threadId? | evidence-driven | 已解决 |
|
||||
| Q6 | 架构 | Gatekeeper、Verifier 输入与 Composer 的可信材料边界应复用什么现有契约? | evidence-driven | 已解决 |
|
||||
| Q7 | 接口 | 阶段 0 本身和最终设计分别属于什么接口影响等级? | evidence-driven | 已解决 |
|
||||
| Q8 | 归档 | 每阶段是否应在进入下一阶段前独立 archive 和 Git commit? | user-interview | 已解决 |
|
||||
|
||||
## Evidence-driven
|
||||
|
||||
| 结论 | 证据来源 | 是否已汇报用户 |
|
||||
|---|---|---|
|
||||
| Orchestration Trace 是 run 级紧凑编排摘要,不是事件日志、自评估或 Graph checkpoint | `devflow/glossary/CONTEXT.md`、ISS-011 §7.5、session-run-trace-isolation decisions | 已汇报 |
|
||||
| Gatekeeper 从 Hook 迁为显式 Node 是有意替换旧内部架构,不允许双入口 | executor-gatekeeper-hook decisions、ISS-011 §2.3/§7.2/§14 | 已汇报 |
|
||||
| Verifier verified evidence 必须来自 Gatekeeper 通过的 checked bindings;Composer 不得读取 raw Executor/tool output | verifier-evidence-reference-fidelity、executor-composer-final-answer 历史档案、ISS-011 §7.4 | 已汇报 |
|
||||
| 本地 1.1.2.0 API 支持条件边、config-aware Node/Edge、recursion limit、RunnableConfig.threadId 和 ReactAgent.call(input, config) | Maven dependency tree 与本地 JAR `javap` 研究记录 | 已汇报 |
|
||||
| 阶段 0 是文档/规格交付,无运行时接口变化;其冻结的最终目标涉及状态机、DB 和 Trace API,属于 L4 | sm-flow operating-rules、ISS-011 §10/§14 | 已汇报 |
|
||||
| 主 OpenSpec 的外层 groundedness round、Hook Gatekeeper 和完整 tool_trace_summary 输入与冻结设计冲突 | `openspec/specs/chat-verifier-agent/spec.md` 等主规格 | 已汇报 |
|
||||
|
||||
## User-interview
|
||||
|
||||
| 问题原文 | 用户原话 | 确认状态 | OpenSpec 回写 |
|
||||
|---|---|---|---|
|
||||
| ISS-011 的阶段关系如何映射 sm-flow? | “iss-011里每个阶段,都是一个sm-flow,而不是将一整个iss-011打包进一个sm-flow中” | 已确认 | 已回写 proposal 范围与非目标 |
|
||||
| Maven E2E 何时执行? | “端到端只在最后阶段全部完成后才验证” | 已确认 | 已回写 acceptance 与 out of scope |
|
||||
| 阶段单元测试是否强制? | “每个阶段如果有必要添加单元测试验收的话,就加,没有必要的话就跳过单元测试” | 已确认 | 已回写 acceptance |
|
||||
| 每阶段如何进入下一阶段? | “每个阶段需要归档完并提交才能进入下一个阶段” | 已确认 | 已回写阶段门禁 |
|
||||
|
||||
## OpenSpec Input Context
|
||||
|
||||
### devflow index
|
||||
|
||||
已命中并读取:
|
||||
|
||||
- `session-run-trace-isolation`
|
||||
- `executor-gatekeeper-hook`
|
||||
- `verifier-evidence-reference-fidelity`
|
||||
- `executor-evidence-output-contract`
|
||||
- `executor-v2-output-contract`
|
||||
- `executor-verifier-claim-checks`
|
||||
- `executor-composer-final-answer`
|
||||
- `mvp-demo-trace-acceptance`
|
||||
|
||||
### Historical constraints entering OpenSpec
|
||||
|
||||
- `runId` 是运行态和 Trace 的所有权边界。
|
||||
- AgentStep、ToolInvocation 与 self evaluation 的既有 run 绑定必须保留。
|
||||
- checked binding 是 verified evidence 的复用来源。
|
||||
- Composer 的 allowed-material 安全边界不得削弱。
|
||||
- 旧 Gatekeeper-in-Hook 决策在本设计中被显式废止,不能保留并行入口。
|
||||
- 主 OpenSpec 的旧运行时要求只能在对应实现阶段修改,阶段 0 不提前宣称代码已切换。
|
||||
|
||||
## Key Decisions
|
||||
|
||||
### 六个独立交付单元
|
||||
|
||||
阶段 0–5 分别使用独立 slug、OpenSpec change、devflow 项目、Archive 和 Git commit。前一 change 归档并提交后才创建下一 change。
|
||||
|
||||
### 阶段 0 不承载后续实现
|
||||
|
||||
阶段 0 只冻结设计并归档长期上下文。阶段 1–5 的代码、数据库、测试和清理任务不进入本 change 的 tasks。
|
||||
|
||||
### 验收分层
|
||||
|
||||
阶段 0 没有运行时行为变化,不新增或运行单元测试,也不运行 Maven E2E。验收使用 OpenSpec strict validation、结构检查和文档一致性检查。Maven E2E、`logs/` 与数据库只在阶段 5 统一执行。
|
||||
|
||||
### 接口影响
|
||||
|
||||
- 当前 change:L1 文档/设计交付,不改变调用方可观察行为。
|
||||
- 冻结目标:L4,涉及内部状态机语义、Trace API 加字段、数据库契约、迁移和回滚。
|
||||
- 兼容:保持 `/api/chat` 和 Agent 输出协议;Trace API 为加法式 run 字段。
|
||||
- 回滚:后续运行时代码可按阶段 Git revert;nullable DB 列可保留,不引入双轨配置。
|
||||
- 消费者:ChatController/ChatService、Trace DTO/Service/UI/demo、数据库迁移、评测与运维审计。
|
||||
|
||||
## Risks Accepted
|
||||
|
||||
- 阶段 0 archive 后,冻结设计已完成但运行时仍为旧 Sequential;这是有意的阶段性状态。
|
||||
- 六个 changes 的一致性由后续每次 context/commit gate 读取并审计本档案保证。
|
||||
- 不为阶段 0 的纯设计变更新增无行为价值的单元测试。
|
||||
|
||||
## Cross-Artifact 对齐检查
|
||||
|
||||
| 上游 → 下游 | 检查内容 | 状态 |
|
||||
|---|---|---|
|
||||
| brief/prd → proposal | Issue 的阶段 0 目标、范围、非目标和验收已进入 proposal | 已对齐 |
|
||||
| proposal → 设计产物 | 状态、路由、重试、Fallback、审计、测试迁移和六阶段边界均进入 design | 已对齐 |
|
||||
| 设计产物 → specs/tasks | L4 影响、安全边界、终止规则和阶段 0 文档工作均进入 spec 或 tasks | 已对齐 |
|
||||
| specs → tasks | 设计基线、源文档、ADR、严格验证和无运行时变更检查均有可执行任务 | 已对齐 |
|
||||
|
||||
Gap:无。
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
输入链为 `ChatController -> ChatService`,目标处理链为 Run 生命周期 → Graph orchestrator → 白名单 Agent/Java Nodes,输出仍为 `ChatResult + DiagnosisRun + exact RunTrace`。Graph State 只属于当前 run,verified evidence 只来自当前 run 的 passed checked bindings,编排摘要只写当前 Diagnosis Run。旧“Gatekeeper stays in VerifierInputHook”决策被 ISS-011 的显式 Node 有意替代,但旧 Gatekeeper 规则本身继续复用;旧“不新增 trace 主表”和 run ownership 决策保持成立。主要耦合风险是 Hook/Node 双执行、阶段性主 spec 漂移和 Trace 投影重复,design 已分别通过单入口迁移、按阶段修改运行时 specs、唯一 `run.orchestrationTrace` 投影缓解。架构风险已由用户确认的 ISS-011 冻结决策和六阶段交付口径接受,无需返回 grill。
|
||||
|
||||
## Commit Preflight
|
||||
|
||||
- proposal、design、specs、tasks 完整:通过。
|
||||
- 所有 user-interview 已确认:通过。
|
||||
- 未汇报 evidence-driven 结论:无。
|
||||
- L4 接口影响、消费者、兼容、迁移和回滚:已在 design 独立章节记录。
|
||||
- OpenSpec strict validation:change 1/1 通过,主 specs 11/11 通过。
|
||||
- Apply 授权:用户启动目标时要求分阶段完整执行、archive 和 Git commit,后续又确认六个独立 sm-flow;视为当前阶段连续执行授权。
|
||||
|
||||
## Apply Evidence
|
||||
|
||||
- Task 1.1:ISS-011 §3–14 与 committed design 的 State 字段、条件边、四类计数、Fallback、安全审计和测试迁移语义一致;未发现需回写 OpenSpec 的 drift,未修改运行时代码。
|
||||
- Task 1.2:将 glossary 中新 Orchestration Trace 的具体 StateGraph/Graph State 表述收敛为“诊断编排/编排上下文快照”;Verifier 的 verified-output/evidence 名称作为跨节点协议保留。
|
||||
- Task 2.1:创建 ADR-001,记录 StateGraph 控制边界、显式 Gatekeeper、run-scoped trace、替代方案、兼容、迁移和回滚。
|
||||
- Task 2.2:六个独立 change 的唯一边界已写入 design、design-baseline spec、ADR 和根计划;阶段 1–5 必须引用阶段 0 archive。
|
||||
- Task 3.1:最终 strict validation 为 change 1/1、主 specs 11/11;proposal/design/spec/tasks 对状态、Fallback、审计、运行时非目标和测试迁移均形成闭环,cross-artifact gap 为 0。
|
||||
- Task 3.2:Git 枚举 12 个 changed/untracked 路径,运行时拒绝列表命中 0;无 `src/`、Maven、运行配置、脚本或数据库迁移变更。
|
||||
- Task 3.3:单元测试未运行,因为阶段 0 无代码行为;Maven E2E、`logs/` 和数据库核验未运行,因为用户明确要求只在阶段 5 全部实现后统一执行。改造前 research baseline 不计入阶段验收。
|
||||
@@ -0,0 +1,30 @@
|
||||
# Chat Diagnosis StateGraph Design Freeze Evidence
|
||||
|
||||
## 证据
|
||||
|
||||
| 来源 | 证据 | 结论 | 是否已汇报 |
|
||||
|---|---|---|---|
|
||||
| ISS-011 §3–14 | 已定义目标流程、26 个 State 字段、有限回边、Fallback、Trace 和测试策略 | 可形成无开放分支的阶段 0 设计基线 | 是 |
|
||||
| `ChatService` / Controller 引用核查 | 生产链为 Controller → ChatService → SequentialAgent,细粒度状态散布在 ChatService | StateGraph 应只接管 Run 内控制,ChatService 保留生命周期 | 是 |
|
||||
| `VerifierInputHook` / `VerifierContextHolder` 引用核查 | Gatekeeper、工具摘要和解析结果通过 Hook/ThreadLocal 隐式传播 | Gatekeeper 与 verified-input 必须迁为显式 Node,不能保留双入口 | 是 |
|
||||
| executor-gatekeeper-hook 历史 decisions | 旧阶段曾决定 Gatekeeper 留在 Hook 且不重试 | 本设计有意替换入口,但继续复用确定性规则 | 是 |
|
||||
| session-run-trace-isolation 历史 decisions | runId 是执行/Trace 所有权边界,AgentStep/ToolInvocation 已承载明细 | orchestration trace 只附着当前 Run,不新增明细主表 | 是 |
|
||||
| Verifier/Composer 历史档案 | checked bindings 和 allowed material 是可信边界 | Builder 不重复验真,Fallback 不泄漏 raw claim | 是 |
|
||||
| 本地 Graph Core 1.1.2.0 JAR | 已验证条件边、config-aware Node/Edge、recursion limit、threadId 与 Agent call API | 阶段 1 可基于锁定签名实现,不采用网上漂移示例 | 是 |
|
||||
| 主 OpenSpec 核查 | 旧 spec 仍描述 Hook Gatekeeper、完整 tool trace 和外层 groundedness round | 阶段 0 不提前改运行时 spec,后续对应实现阶段再修改 | 是 |
|
||||
| 用户原话 | 六个独立 sm-flow;仅阶段 5 E2E;单测按必要性 | 阶段门禁与测试口径已固定 | 是 |
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- 结论:阶段 0 运行时影响为 L1,但冻结目标为 L4。
|
||||
- 证据:本阶段 changed paths 无 `src/`/SQL/配置;最终目标改变状态机、Trace API 和 DB。
|
||||
- 风险:设计完成不等于运行时完成。
|
||||
- 用户确认:已确认分阶段交付。
|
||||
- 结论:旧 Gatekeeper-in-Hook 决策应被显式 Node 有意替代。
|
||||
- 证据:当前 Hook 引用与 ISS-011 条件边要求冲突。
|
||||
- 风险:迁移期双执行。
|
||||
- 用户确认:ISS-011 冻结决策已确认。
|
||||
- 结论:阶段 0 不需要单元测试或 E2E。
|
||||
- 证据:Git 运行时拒绝列表命中 0,OpenSpec strict 和文档一致性已覆盖本阶段可观察产物。
|
||||
- 风险:运行时正确性仍未证明,将由阶段 1–5 测试和最终 E2E 证明。
|
||||
- 用户确认:已确认。
|
||||
@@ -0,0 +1,42 @@
|
||||
# Chat Diagnosis StateGraph Real Nodes 验收
|
||||
|
||||
## 结果
|
||||
|
||||
已接受。OpenSpec tasks 27/27 完成;真实 Nodes 可构造和测试,旧生产 Sequential 路径保持可用,阶段 2 未切换生产入口。
|
||||
|
||||
## 静态验证
|
||||
|
||||
- `openspec validate chat-diagnosis-stategraph-real-nodes --strict`:通过。
|
||||
- `openspec validate --specs --strict`:13 passed,0 failed。
|
||||
- `git diff --check`:通过;只有 LF/CRLF 转换提示,无 whitespace error。
|
||||
- 源码/引用检查:`ChatService` Graph 引用 0;新增源码 forbidden refs 0;protocol 反向依赖 0;DB/Trace/Prompt diff 0。
|
||||
- 装配对齐:无核心 TODO/FIXME/placeholder;Graph factory 继续拥有所有 retry counter 与 Planner reset。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
- 新 protocol/Node/CompiledGraph/Router/Trace focused suite:通过。
|
||||
- `mvn -q "-Dtest=ChatServiceSequentialAgentTest,VerifierInputHookTest,ExecutorGatekeeperServiceTest" test`:通过。
|
||||
- 两组测试合计:100 tests,0 failures,0 errors,0 skipped。
|
||||
- `mvn -q -DskipTests test-compile`:通过。
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
- 未运行。阶段 2 不改变用户入口或 UI,没有独立人工验收价值。
|
||||
|
||||
## 未验证
|
||||
|
||||
- Maven live E2E、`logs/` 日志和 `scripts/query_mysql.py` 数据库核验未运行。
|
||||
- 原因:用户明确要求只在阶段 5 全部实现后统一做最终 E2E;阶段 2 尚未切换生产入口。
|
||||
- 风险:当前验收只证明组件/Graph 契约与旧路径回归,不证明真实生产装配、模型、DB 和 Trace 全链路。
|
||||
|
||||
## 已完成范围
|
||||
|
||||
- 中立共享 protocol 与旧路径行为保持型委托。
|
||||
- 四个 Agent adapters、显式 Gatekeeper、可信投影、关键证据补查、Composer 与两类 Fallback。
|
||||
- 真实 CompiledGraph 装配、critical gap 路由修复和完整 focused test 证据。
|
||||
|
||||
## 交接
|
||||
|
||||
- 下一步:归档本 change、独立提交阶段 2,然后启动阶段 3 `chat-diagnosis-stategraph-chatservice-cutover`。
|
||||
- OpenSpec 归档:已同步主 specs,并归档到 `openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-real-nodes/`。
|
||||
- 归档授权:用户已明确“直接实现吧,不用找我授权了”,授权后续阶段在门禁通过后直接归档和提交。
|
||||
@@ -0,0 +1,21 @@
|
||||
# Chat Diagnosis StateGraph Real Nodes Brief
|
||||
|
||||
## 背景
|
||||
|
||||
- 用户目标:将 ISS-011 阶段 2 作为独立 sm-flow,接入真实 Agent/Java Nodes,并在归档、验收和独立 Git 提交后才进入阶段 3。
|
||||
- 当前问题:阶段 1 只有 Fake Node 路由骨架;Executor/Verifier/Composer 协议逻辑分散在 Hook 与 ChatService,真实 Graph 尚不能安全调用 Agent、Gatekeeper 或投影可信材料。
|
||||
- 关联 OpenSpec:`openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-real-nodes/`
|
||||
- devflow 分档:complex
|
||||
|
||||
## 范围
|
||||
|
||||
- 本次要做:共享无状态 protocol 组件;Planner/Executor/Verifier/Composer adapters;显式 Gatekeeper、Verified Input、Evidence Retry、Fallback Nodes;真实 CompiledGraph 装配和 focused tests。
|
||||
- 本次不做:不切换 ChatService 生产入口,不修改 DB、Trace API、Prompt 契约,不删除旧 Sequential/Hook,不运行 live E2E。
|
||||
- 影响区域:`diagnosis.protocol`、`graph.diagnosis`、`VerifierInputHook`、`ChatService` 共享逻辑委托及对应测试。
|
||||
|
||||
## OpenSpec 对齐
|
||||
|
||||
- proposal 覆盖状态:已覆盖。
|
||||
- design 覆盖状态:已覆盖;接口影响为 L2,生产切换明确延期到阶段 3。
|
||||
- specs 覆盖状态:已覆盖真实 Nodes 安全边界,并修正 critical evidence gap 路由条件。
|
||||
- tasks 覆盖状态:27/27 完成。
|
||||
@@ -0,0 +1,218 @@
|
||||
# Chat Diagnosis StateGraph Real Nodes Decisions
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 边界 | 阶段 2 是否切换 ChatService/DB/Trace? | user-interview(六阶段已确认) | 已解决 |
|
||||
| Q2 | 复用 | 新 Nodes 如何避免复制 Hook/ChatService 解析与安全渲染? | evidence-driven | 已解决 |
|
||||
| Q3 | Agent | Adapter 如何调用真实 ReactAgent 并保留 Hook/ToolCallback/run config? | evidence-driven | 已解决 |
|
||||
| Q4 | Gatekeeper | 显式 Node 如何保证当前 run、单次调用和 fail-closed 标准化? | evidence-driven | 已解决 |
|
||||
| Q5 | 安全 | passed checked bindings 如何投影为 verified output/evidence? | evidence-driven | 已解决 |
|
||||
| Q6 | 补证据 | 哪些 facts 可触发 evidence retry,completed queries 如何表达? | evidence-driven | 已解决 |
|
||||
| Q7 | Fallback | 前置验证失败与 Composer 后置失败可分别使用哪些材料? | evidence-driven | 已解决 |
|
||||
| Q8 | Prompt | 阶段 2 是否立即修改共享 Verifier Prompt? | evidence-driven | 已解决 |
|
||||
| Q9 | 验收 | 阶段 2 是否需要单元/集成测试与 E2E? | evidence-driven + user rule | 已解决 |
|
||||
|
||||
## Evidence-driven
|
||||
|
||||
| 结论 | 证据来源 | 是否已汇报用户 |
|
||||
|---|---|---|
|
||||
| ReactAgent.call(input, config) 返回 AssistantMessage,现有 AgentLoggingHook 从 config metadata 读取 sessionId/runId | 本地 1.1.2.0 javap、AgentLoggingHook | 已汇报 |
|
||||
| Executor parser 当前在 VerifierInputHook,Verifier/Composer parser 与 renderer 当前在 ChatService | 定向源码阅读和 references | 已汇报 |
|
||||
| checked_bindings 提供 claim_id/tool_name/source_invocation_id/raw_path/matched_text/status | ExecutorGatekeeperService | 已汇报 |
|
||||
| Gatekeeper.validateRun 使用 run-scoped ToolInvocation repository | ExecutorGatekeeperService tests/code | 已汇报 |
|
||||
| Graph path不能注册旧 VerifierInputHook,否则 Gatekeeper 会双执行且输入包含 full tool trace | 阶段 0 ADR、Hook 源码 | 已汇报 |
|
||||
| evidence retry 只允许 critical no_evidence/indirect_support | 阶段 0 design/ISS-011 | 已汇报 |
|
||||
| 阶段 1 router 未检查 is_critical,属于实现偏离 | Router 源码与阶段 0 baseline 对照 | 已汇报 |
|
||||
| 共享 Prompt 暂时仍服务旧 Sequential path,本阶段直接修改会提前破坏生产 payload | ChatService agent builder + VerifierInputHook + prompt | 已汇报 |
|
||||
| Node 输入/安全边界新增且旧解析会重构,单元和 focused regression 必要;E2E 不必要 | 阶段边界和用户规则 | 已汇报 |
|
||||
|
||||
## User-interview
|
||||
|
||||
| 问题原文 | 用户原话 | 确认状态 | OpenSpec 回写 |
|
||||
|---|---|---|---|
|
||||
| 阶段 2 是否独立 sm-flow? | “iss-011里每个阶段,都是一个sm-flow” | 已确认 | 独立 change |
|
||||
| 是否可提前切生产入口? | “每个阶段需要归档完并提交才能进入下一个阶段” | 已确认不可提前阶段 3 | Out of Scope |
|
||||
| 阶段 2 是否执行 E2E? | “端到端只在最后阶段全部完成后才验证” | 已确认不执行 | Acceptance |
|
||||
| 是否添加单元测试? | “如果有必要添加单元测试验收的话,就加” | 已确认规则;本阶段判定必要 | Acceptance |
|
||||
|
||||
## Context And Handoff
|
||||
|
||||
- 阶段 0 archive/commit:design baseline / `581daff`
|
||||
- 阶段 1 archive/commit:routing skeleton / `42ba204`
|
||||
- 当前 change:`chat-diagnosis-stategraph-real-nodes`
|
||||
- 后续 change:`chat-diagnosis-stategraph-chatservice-cutover`,只能在本阶段 archive + commit 后创建。
|
||||
|
||||
## Technical Decisions
|
||||
|
||||
### Shared protocol components
|
||||
|
||||
- 抽取 Executor、Verifier、Composer 解析器,旧 Hook/ChatService 委托新组件。
|
||||
- 抽取 Composer safe input builder / renderer,旧 ChatService 保持相同输出。
|
||||
- JSON sanitization 只存在一份共享实现,不在每个 Node copy。
|
||||
- 抽取过程是行为保持 refactor;现有 focused tests 是回归门禁。
|
||||
|
||||
### Agent adapter boundary
|
||||
|
||||
- `DiagnosisAgentInvoker` 是最小 port:`invoke(String, RunnableConfig) -> String`。
|
||||
- `ReactAgentDiagnosisInvoker` 只包装 `ReactAgent.call(...).getText()`。
|
||||
- Planner/Executor/Verifier/Composer adapters 各自拥有白名单 input projector、parser 和 status event。
|
||||
- tests 使用 fake invoker,另有 ReactAgent wrapper test。
|
||||
|
||||
### Legacy Hook coexistence
|
||||
|
||||
- 旧 Sequential path 在阶段 3 前仍通过 VerifierInputHook 执行 Gatekeeper。
|
||||
- Graph Verifier Agent 不注册该 Hook;显式 Gatekeeper Node 是 Graph 中唯一 validation 入口。
|
||||
- Parser/enricher 可共享,但 Hook 的 legacy payload/prompt 暂不改变。
|
||||
- 阶段 3 切换生产入口并同步 Verifier Prompt;阶段 5 删除旧隐式结构。
|
||||
|
||||
### Gatekeeper normalization
|
||||
|
||||
- raw pass → PASS。
|
||||
- raw fail + severity low_confid → LOW_CONFID。
|
||||
- raw fail + severity reject → REJECT。
|
||||
- 缺失、unknown、异常或不一致 → REJECT。
|
||||
- verified_binding_count 只统计 checked_bindings.status=pass。
|
||||
|
||||
### Verified projection
|
||||
|
||||
- 通过项按 claim_id + source_invocation_id + tool_name + raw_path 与原 binding 精确匹配。
|
||||
- verified_executor_output 只包含 answer_version 与至少一条 passed binding 的 filtered claims;合法零 claim 保持空列表。
|
||||
- verified_evidence 只含 claim_id/source_invocation_id/tool_name/raw_path/matched_text。
|
||||
- hypotheses、失败 binding、未引用 ToolInvocation、raw Executor output 不投影。
|
||||
|
||||
### Evidence retry
|
||||
|
||||
- extractor 要求 `is_critical=true` 且 verification 为 no_evidence/indirect_support。
|
||||
- gap 字段:claim_id(从 `claim-id: text` 提取或空)、fact、verification、reason。
|
||||
- completed queries 由 verified evidence 的 tool/invocation/path 去重生成。
|
||||
- prior verified output/evidence 原样只读进入 retry_context。
|
||||
- 约束固定:max_retry=1、do_not_repeat_successful_queries、only_execute_incremental_queries、preserve_prior_verified_claims。
|
||||
- Executor 输入声明“增量执行、完整输出”,Java 不合并 claims。
|
||||
|
||||
### Interface impact
|
||||
|
||||
- 等级:L2 internal interface;共享 parser 委托保持旧行为。
|
||||
- 新消费者:阶段 3 Graph orchestrator/Agent factory。
|
||||
- 当前外部 API/DB/生产路由:无变化。
|
||||
- 回滚:revert 本阶段提交;旧 Sequential path仍完整。
|
||||
- 有意修正:Router 只允许 critical gap,属于对冻结基线的代码修复。
|
||||
|
||||
## Risks Accepted
|
||||
|
||||
- 真实模型尚未执行;Node contract 通过 fake invoker/real service tests证明,阶段 5 才 E2E。
|
||||
- Prompt 输入说明与 Graph input 的最终同步推迟到阶段 3,避免当前旧生产 Hook 提前不兼容。
|
||||
- 旧 Hook 暂时仍存在,但不进入 Graph action graph;阶段 5 必须删除。
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
### Module and ownership map
|
||||
|
||||
`Diagnosis Context + RunnableConfig` → Agent adapters / deterministic Nodes → owned Graph State fields → `DiagnosisGraphRouter` → next Node or END → `final_answer + orchestration_events`。阶段 2 只提供这条可构造链,阶段 3 才由 `ChatService` 创建 Run、构造 Agent 实例并调用 Graph。
|
||||
|
||||
| 模块 | 数据所有权 | 允许依赖 |
|
||||
|---|---|---|
|
||||
| `diagnosis.protocol` | JSON contract、纯解析结果、安全 input/rendering | Jackson 与纯 DTO;不依赖 Graph/Hook/ChatService/ThreadLocal |
|
||||
| `graph.diagnosis` Agent adapters | 白名单输入、Agent attempt status/event | protocol、注入的 invoker、Graph API |
|
||||
| Gatekeeper Node | raw Gatekeeper result、normalized status/count | ExecutorGatekeeperService、当前 run config |
|
||||
| Verified Input / Retry Prepare | verified projection、critical gaps、retry context | raw result 的只读投影与 protocol DTO |
|
||||
| Router / Factory | 条件边、有限计数、调用次序 | Graph State;不解析 Agent raw output |
|
||||
| legacy Hook / ChatService | 阶段 3 前的生产 Sequential 流程 | 只委托 protocol;不得消费真实 Graph action set |
|
||||
|
||||
### Lifecycle and coupling audit
|
||||
|
||||
Graph State 和 events 都是 invocation-scoped,runId 只从当前 RunnableConfig 获取,Nodes 不持有跨 Run 可变状态。旧路径与 Graph 路径阶段性共享的只有无状态 protocol 组件和 Gatekeeper service,不共享 ThreadLocal 或 Agent output。ReactAgent/invoker 必须构造注入,阶段 2 不复制 ChatService Prompt/Agent factory。唯一有意的阶段性耦合是 legacy consumers 改为委托 protocol,这由旧 focused tests 和完整 revert 保护。阶段 3 前生产入口、DB、Trace、Prompt 均保持隔离。
|
||||
|
||||
### Cross-artifact alignment
|
||||
|
||||
| 对齐链 | 结果 | 证据 |
|
||||
|---|---|---|
|
||||
| brief/proposal 目标、范围、非目标 → proposal | 已对齐 | 独立阶段边界、真实 Nodes、无生产切换均明确 |
|
||||
| proposal 承诺与约束 → design | 已对齐 | invoker、共享组件、Gatekeeper、投影、retry、Fallback、L2 均有决策 |
|
||||
| design 架构/接口结论 → specs/tasks | 已对齐 | 中立 protocol 包、构造注入、fail-closed 和生产隔离均有任务/行为 |
|
||||
| specs 可观察行为 → tasks 可执行切片 | 已对齐 | 每个 requirement 至少由一个实现任务和一个测试/验收任务覆盖 |
|
||||
|
||||
### Audit result
|
||||
|
||||
审计发现共享协议组件包所有权与 Agent 实例装配边界需要显式化,已回写 design/tasks。未发现状态字段、路由计数、run 生命周期或阶段边界的新冲突。接口影响维持 L2,消费者都在本 change 与下一阶段明确范围内。剩余风险是共享抽取的旧行为漂移和 binding 投影泄漏,均有 focused regression 与 mixed-binding tests。架构风险可接受,无未解决问题。
|
||||
|
||||
## Commit Gate
|
||||
|
||||
- proposal/design/specs/tasks:全部存在,OpenSpec status `isComplete=true`。
|
||||
- 当前 change strict validation:通过。
|
||||
- 主 specs strict validation:13 passed,0 failed。
|
||||
- 规格结构:9 requirements、22 scenarios;tasks:27 个 checkbox 切片。
|
||||
- Cross-artifact:4/4 已对齐,gap=0。
|
||||
- 接口影响:L2,已在 design 独立章节记录消费者、兼容和回滚。
|
||||
- Question pool:所有 evidence-driven 已汇报;所有 user-interview 已确认;无未决项。
|
||||
- Preflight scope:`git diff --check` 通过;Commit checkpoint 未修改业务代码。
|
||||
- 结论:Draft OpenSpec 达到可执行状态,创建 `.committed`。
|
||||
|
||||
## Apply Authorization
|
||||
|
||||
- 用户原话:“直接实现吧,不用找我授权了”。
|
||||
- 解释:阶段 2–5 后续 checkpoint 可在前置门禁通过后直接继续,不再因 Apply 或 Archive 授权暂停。
|
||||
- 不扩大范围:每阶段仍须独立 OpenSpec、验收归档、Git commit;阶段 0–4 不做 E2E,阶段 5 才统一执行。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### Reference implementations read
|
||||
|
||||
- `src/main/java/com/superbiz/agent/hook/VerifierInputHook.java`:Executor JSON sanitization、parse status、tool-name normalization、唯一 invocation 回填与 legacy Gatekeeper payload。
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`:Verifier claim/fact parser、Gatekeeper ceiling、Composer allowed-material builder、Composer parser/safe renderer、旧 retry context。
|
||||
- `src/main/java/com/superbiz/agent/service/ExecutorGatekeeperService.java`:`validateRun`、severity normalization source、checked binding 与 matched_text 结构。
|
||||
- `src/main/java/com/superbiz/agent/graph/diagnosis/DiagnosisGraphFactory.java`:config-aware action ports、technical retry/evidence retry counter 所有权和 recursion limit。
|
||||
- `src/main/java/com/superbiz/agent/graph/diagnosis/OrchestrationEvent.java` 与 `src/test/java/com/superbiz/agent/graph/diagnosis/ScriptedDiagnosisGraphActions.java`:每 attempt 单 event 形态。
|
||||
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`:RunnableConfig metadata 中 sessionId/runId 的审计读取方式。
|
||||
- `src/test/java/com/superbiz/agent/hook/VerifierInputHookTest.java`、`ChatServiceSequentialAgentTest.java`、`DiagnosisGraphRoutingTest.java`:JUnit 5、Mockito 边界替身和 CompiledGraph observable behavior 测试风格。
|
||||
- 本地 `1.1.2.0` JAR `javap`:`ReactAgent.call(String,RunnableConfig)` 与 `RunnableConfig.threadId/metadata` 公共 API。
|
||||
|
||||
### Technology inventory
|
||||
|
||||
| 类别 | 项目标准 / 本阶段使用 |
|
||||
|---|---|
|
||||
| JSON contract | Jackson `ObjectMapper`、`LinkedHashMap` 保持稳定字段顺序;共享 sanitization 只存在一份 |
|
||||
| Graph Node | `AsyncNodeActionWithConfig` 返回 `CompletableFuture<Map<String,Object>>`;state 默认 Replace、events Append |
|
||||
| Agent boundary | 构造注入的 `DiagnosisAgentInvoker`;ReactAgent wrapper 透传同一个 RunnableConfig |
|
||||
| Run scope | `config.metadata("runId")` 为 Gatekeeper 唯一运行边界;缺失即 fail closed |
|
||||
| Error handling | 合法 contract/invalid output/temporary/permanent 分离;unknown exception 不推断为可重试 |
|
||||
| Tests | JUnit 5;只在 ReactAgent、repository 等系统边界使用 fake/mock;Node/CompiledGraph 走公开 action/graph 接口 |
|
||||
| Request/response | 本阶段不改 Controller/DTO/API,不适用 |
|
||||
| MQ/Consumer | 本阶段不涉及,不适用 |
|
||||
| DB/Trace/Prompt | 本阶段禁止修改,阶段 3 处理 |
|
||||
|
||||
### Reuse and new infrastructure
|
||||
|
||||
- 新建中立 `com.superbiz.agent.diagnosis.protocol`:`JsonPayloadSupport`、Executor/Verifier/Composer protocol、safe input/rendering、`EvidenceGapExtractor`;不得依赖 Graph/Hook/ChatService/ThreadLocal。
|
||||
- 新建 `graph.diagnosis` Node 层:invoker wrapper、failure classifier、四个 Agent adapters、Gatekeeper、Verified Input、Retry Prepare、Fallback 和 action assembly。
|
||||
- 不新建 Prompt/Agent factory;阶段 3 通过构造注入已有 ReactAgent 实例。
|
||||
- 不新增 Maven dependency、数据库迁移、配置项或生产 consumer。
|
||||
|
||||
### Pre-apply conclusion
|
||||
|
||||
参考实现、API 签名、异常和测试标准已足以指导实现;未发现 devflow/OpenSpec 冲突。进入 TDD tracer bullet,先锁定共享 Executor parser 的合法 no-evidence 与 malformed 行为。
|
||||
|
||||
## Apply Completion And Verification
|
||||
|
||||
### Assembly alignment
|
||||
|
||||
- 首个共享 protocol 模块与最终真实 Graph action assembly 均逐项对照 design/specs:invoker 显式透传 RunnableConfig,Gatekeeper 单次 fail-closed,Verified Input 精确投影,Verifier/Composer 固定输入重试,critical evidence retry 与两类 Fallback 边界全部落地。
|
||||
- `DiagnosisGraphFactory` 继续独占技术重试计数、evidence retry 计数和 Planner mode/reset;Node 不重复拥有编排计数。
|
||||
- 新增源码中无 `ThreadLocal`、`VerifierInputHook`、`tool_trace_summary`、`raw_executor`、TODO 或 FIXME;protocol 包无 Graph/Hook/ChatService 反向依赖。
|
||||
- `ChatService` 无 Diagnosis Graph/CompiledGraph 引用,生产切换保持在阶段 3;DB migration、Trace DTO/entity/repository 和 prompts 均无 diff。
|
||||
|
||||
### Automated verification
|
||||
|
||||
- 新 protocol/Node/真实 CompiledGraph/Router/Trace focused suite:通过。
|
||||
- 旧 `ChatServiceSequentialAgentTest`、`VerifierInputHookTest`、`ExecutorGatekeeperServiceTest` 回归:通过。
|
||||
- 合计 100 tests,0 failures,0 errors,0 skipped。
|
||||
- `mvn -q -DskipTests test-compile`:通过。
|
||||
- `openspec validate chat-diagnosis-stategraph-real-nodes --strict`:通过。
|
||||
- `openspec validate --specs --strict`:13 passed,0 failed。
|
||||
- `git diff --check`:通过;仅报告 Git 既有 LF/CRLF 转换提示,无 whitespace error。
|
||||
|
||||
### Deferred final verification
|
||||
|
||||
- 阶段 2 按用户确认不运行 Maven live E2E,不启动应用,不检查 `logs/`,不查询数据库。
|
||||
- 上述端到端、日志和 `scripts/query_mysql.py` 数据库核验统一保留到阶段 5 全部实现完成后执行。
|
||||
@@ -0,0 +1,25 @@
|
||||
# Chat Diagnosis StateGraph Real Nodes Evidence
|
||||
|
||||
## 证据
|
||||
|
||||
| 来源 | 证据 | 结论 | 是否已汇报 |
|
||||
|---|---|---|---|
|
||||
| `VerifierInputHook.java`、`ChatService.java` | Executor/Verifier/Composer 解析与安全渲染原实现 | 抽取到中立 protocol 并让旧路径委托,避免双真理源 | 是 |
|
||||
| `ExecutorGatekeeperService.java` | `validateRun` 与 checked binding/matched_text 契约 | Graph Gatekeeper 必须按当前 runId 单次调用并 fail closed | 是 |
|
||||
| 本地 Graph/ReactAgent 1.1.2.0 API | `ReactAgent.call(String,RunnableConfig)` 与 config-aware Graph action | 最小 invoker 可精确透传输入和当前 Run metadata | 是 |
|
||||
| 阶段 0/1 OpenSpec archives | 路由、计数、状态与安全边界冻结 | 阶段 2 不改变 Graph counter 所有权或生产入口 | 是 |
|
||||
| 新 protocol/Node/CompiledGraph tests | PASS、REJECT、LOW_CONFID、critical retry、固定输入重试和安全 fallback | 真实 Nodes 的可观察路径和材料边界已覆盖 | 是 |
|
||||
| 旧 Sequential/Hook/Gatekeeper tests | 共享抽取后的旧路径回归 | 阶段 2 未破坏当前生产控制流 | 是 |
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- Graph Verifier 不得注册旧 `VerifierInputHook`,否则会双执行 Gatekeeper 并泄漏完整 tool trace。
|
||||
- Verified Input 必须用 claim/invocation/tool/path 精确关联 passed binding;不能复刻 Gatekeeper 判断或读取未引用工具结果。
|
||||
- Router 与 Retry Prepare 必须共用 critical-gap 提取规则:仅 `is_critical=true` 的 `no_evidence`/`indirect_support`。
|
||||
- 技术重试输入必须字节一致,且不得重跑前序 Node;计数仍由 Graph factory 统一拥有。
|
||||
- 当前 ChatService 无 Graph 引用,DB/Trace/Prompt 无 diff,满足阶段 2 的生产隔离要求。
|
||||
|
||||
## 风险与后续证据
|
||||
|
||||
- 本阶段使用 fake invoker 和 focused tests,不证明真实模型/外部基础设施联通;阶段 5 最终 E2E 统一补证。
|
||||
- Prompt 输入说明、生产装配、Run/Trace 持久化属于阶段 3,不能提前从阶段 2 证据推断已完成。
|
||||
@@ -0,0 +1,69 @@
|
||||
# Chat Diagnosis StateGraph Routing Skeleton Acceptance
|
||||
|
||||
## 结果
|
||||
|
||||
已接受。阶段 1 完成未接生产入口的 Graph 骨架和 Fake Node 路由体系。
|
||||
|
||||
## 验证
|
||||
|
||||
### 静态验证
|
||||
|
||||
- 命令:`git diff --check`
|
||||
- 结果:passed。
|
||||
- 检查:production refs、forbidden deps、23 changed paths 白名单。
|
||||
- 结果:passed,outside refs=0,forbidden refs=0,out-of-scope=0。
|
||||
|
||||
### 脚本验证
|
||||
|
||||
- 命令:`mvn -q "-Dtest=DiagnosisGraphRoutingTest,DiagnosisOrchestrationTraceBuilderTest" test`
|
||||
- 结果:passed,35 tests(29 routing + 6 trace),0 failure/error。
|
||||
- 覆盖:正常、三类技术 retry、Executor 不重试、Gatekeeper、evidence retry、Composer、unknown fail-closed、threadId、Append events 和 trace。
|
||||
|
||||
- 命令:`mvn -q "-DskipTests" test`
|
||||
- 结果:passed。
|
||||
- 覆盖:main/test compilation。
|
||||
|
||||
- 命令:`openspec validate chat-diagnosis-stategraph-routing-skeleton --type change --strict --json`
|
||||
- 结果:passed,1/1。
|
||||
|
||||
- 命令:`openspec validate --specs --strict --json`
|
||||
- 结果:passed,12/12(归档前)。
|
||||
|
||||
### 浏览器/人工验证
|
||||
|
||||
- 结果:not run。
|
||||
- 原因:无 UI 或生产入口变化。
|
||||
|
||||
### 未验证
|
||||
|
||||
- Maven E2E:not run,用户要求仅阶段 5 全部实现后统一执行。
|
||||
- `logs/`:not inspected,保留到阶段 5。
|
||||
- 数据库:not queried,保留到阶段 5。
|
||||
- 真实模型/Agent:not invoked,属于阶段 2。
|
||||
|
||||
## 已完成范围
|
||||
|
||||
- 显式 Graph Core direct dependency。
|
||||
- 26 state keys、typed status、topology/route/reason constants。
|
||||
- 八个 config-aware action ports 和真实 CompiledGraph factory。
|
||||
- Planner/Verifier/Composer 技术计数、一次 evidence retry、recursion limit 32。
|
||||
- fail-closed router、events Append 和 trace builder。
|
||||
- 35 个 Fake Node/trace tests。
|
||||
|
||||
## 已知限制
|
||||
|
||||
- Skeleton 没有生产消费者,阶段 3 才切换 ChatService。
|
||||
- Fake Node 只证明控制流,不证明真实 Agent JSON、Gatekeeper 或安全输入映射。
|
||||
- orchestration trace 尚未持久化或通过 API 暴露。
|
||||
|
||||
## Bug 修复和诊断
|
||||
|
||||
- 架构审计发现并修正 Graph Core 传递依赖所有权,改为 BOM 管理的直接依赖。
|
||||
- 自查补齐全部正常节点 threadId、Verifier REJECT 和缺失 effective verdict 场景。
|
||||
|
||||
## 交接
|
||||
|
||||
- 下一步:阶段 1 Git commit;完成后才能创建阶段 2 change。
|
||||
- Delta sync:新增 `chat-diagnosis-stategraph-routing-skeleton` 主 spec,共 6 requirements。
|
||||
- OpenSpec 归档确认:用户已要求每阶段 archive,授权已存在。
|
||||
- OpenSpec 归档结果:已同步主 spec,并归档到 `openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-routing-skeleton/`。
|
||||
@@ -0,0 +1,21 @@
|
||||
# Chat Diagnosis StateGraph Routing Skeleton Brief
|
||||
|
||||
## 背景
|
||||
|
||||
- 用户目标:ISS-011 阶段 1 独立完成 Graph 骨架和 Fake Node 路由测试,archive/commit 后才能进入真实 Node 阶段。
|
||||
- 当前问题:阶段 0 只有设计基线,仓库此前没有可编译 StateGraph 或条件边验证。
|
||||
- 关联 OpenSpec:`openspec/changes/chat-diagnosis-stategraph-routing-skeleton/`
|
||||
- devflow 分档:complex
|
||||
- 前置基线:`openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-design-freeze/`
|
||||
|
||||
## 范围
|
||||
|
||||
- 本次要做:Graph Core 直接依赖、状态/枚举、config-aware action ports、deterministic router、Graph factory、有限计数、events/trace builder、Fake Node tests。
|
||||
- 本次不做:真实 Agent/Gatekeeper、ChatService、Hook、DB、Trace API、旧实现清理、Maven E2E。
|
||||
- 影响区域:`pom.xml`、`com.superbiz.agent.graph.diagnosis`、对应 test 包。
|
||||
|
||||
## OpenSpec 对齐
|
||||
|
||||
- proposal 覆盖状态:已覆盖 skeleton-only 目标、L2 边界、测试与 E2E 非目标。
|
||||
- specs 覆盖状态:6 个 requirements 覆盖编译、Planner、Executor/Gatekeeper、Verifier、Composer、trace。
|
||||
- tasks 覆盖状态:12/12 完成。
|
||||
@@ -0,0 +1,112 @@
|
||||
# Chat Diagnosis StateGraph Routing Skeleton Decisions
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 术语 | 阶段 1 的 Graph State、event、trace 含义从哪里继承? | evidence-driven | 已解决 |
|
||||
| Q2 | 边界 | 阶段 1 是否接入 ChatService 或真实 Agent/Service? | evidence-driven | 已解决 |
|
||||
| Q3 | 技术 | 锁定 1.1.2.0 是否支持所需 Node/Edge、策略和 recursion limit? | evidence-driven | 已解决 |
|
||||
| Q4 | 技术 | Node action port 是否需要 RunnableConfig? | evidence-driven | 已解决 |
|
||||
| Q5 | 验收 | 阶段 1 是否有必要添加单元测试? | evidence-driven + user rule | 已解决 |
|
||||
| Q6 | 接口 | 新骨架的接口影响等级与消费者是什么? | evidence-driven | 已解决 |
|
||||
| Q7 | 循环 | recursion limit 应取多少,是否替代业务计数? | evidence-driven | 已解决 |
|
||||
| Q8 | 阶段 | 是否在本 change 实现真实 nodes、DB、Trace API 或旧代码清理? | user-interview(已由六阶段口径确认) | 已解决 |
|
||||
|
||||
## Evidence-driven
|
||||
|
||||
| 结论 | 证据来源 | 是否已汇报用户 |
|
||||
|---|---|---|
|
||||
| 阶段 1 必须完整继承阶段 0 baseline | archived design/spec/ADR | 已汇报 |
|
||||
| 本阶段只做 Fake Node 骨架,不接真实模型 | ISS-011 阶段 1/2 边界 | 已汇报 |
|
||||
| 1.1.2.0 支持 AsyncNodeActionWithConfig、AsyncEdgeActionWithConfig、conditional edges、Replace/Append、recursionLimit 和 threadId | 本地 JAR `javap` / `javap -c` | 已汇报 |
|
||||
| AppendStrategy 将 list/collection 追加为有序列表,可用于 node terminal events | 本地 AppendStrategy bytecode | 已汇报 |
|
||||
| 路由是新增行为且分支多,单元测试有必要 | 阶段 1 完成标准与用户“必要则加”规则 | 已汇报 |
|
||||
| 最坏合法路径少于 20 次 Node 执行,limit 32 有安全余量 | 冻结路由矩阵的路径计数 | 已汇报 |
|
||||
| 当前仓库没有 Graph 包或实现 | `rg` / package 目录核查 | 已汇报 |
|
||||
| 生产代码将直接 import Graph Core,必须从传递依赖提升为 BOM 管理的直接依赖 | pom 与 dependency tree / 架构审计 | 已汇报 |
|
||||
|
||||
## User-interview
|
||||
|
||||
| 问题原文 | 用户原话 | 确认状态 | OpenSpec 回写 |
|
||||
|---|---|---|---|
|
||||
| 阶段 1 是否应独立执行 sm-flow? | “iss-011里每个阶段,都是一个sm-flow” | 已确认 | 本 change 独立边界 |
|
||||
| 阶段 1 是否执行 E2E? | “端到端只在最后阶段全部完成后才验证” | 已确认 | Out of Scope / Acceptance |
|
||||
| 阶段 1 是否添加单元测试? | “如果有必要添加单元测试验收的话,就加” | 已确认规则;本阶段判定必要 | Acceptance |
|
||||
| 是否可提前实现阶段 2–5? | “每个阶段需要归档完并提交才能进入下一个阶段” | 已确认不可提前 | Out of Scope |
|
||||
|
||||
## Context And Handoff
|
||||
|
||||
- 前置 archive:`openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-design-freeze/`
|
||||
- 前置 commit:`581daff`
|
||||
- 当前 change:`chat-diagnosis-stategraph-routing-skeleton`
|
||||
- 后续 change:`chat-diagnosis-stategraph-real-nodes`,只能在本阶段 archive + commit 后创建。
|
||||
|
||||
## Technical Decisions
|
||||
|
||||
### Package and API
|
||||
|
||||
- 新包:`com.superbiz.agent.graph.diagnosis`。
|
||||
- `pom.xml` 显式声明 Graph Core,版本继续由现有 BOM 管理。
|
||||
- Graph 工厂接收 config-aware Node action ports,不依赖 Spring Bean 或真实 Agent。
|
||||
- Fake actions 只放 `src/test`。
|
||||
- 状态读取集中在 typed helper/router,避免各 edge 复制字符串解析。
|
||||
|
||||
### Retry ownership
|
||||
|
||||
- Planner/Verifier/Composer Node wrapper 根据进入节点前的上次技术失败状态增加各自 retry count。
|
||||
- 第一次失败时 count=0,允许 self-loop;重入后 count=1,第二次失败直接 Fallback。
|
||||
- Evidence Retry Node 将 run-level evidence count 增加一次并重置 planner retry count。
|
||||
- Edge 只选择 route,不隐式修改状态。
|
||||
|
||||
### Event and trace
|
||||
|
||||
- 每个 Fake/后续真实 Node 返回一个 event list,AppendStrategy 负责累积。
|
||||
- event 包含 node/outcome/reasonCode/attempt,不包含 payload。
|
||||
- trace builder 由相邻 events 生成 transition;final node/reason 来自最后 event。
|
||||
- events 为空时拒绝构造 trace,避免伪造路径。
|
||||
|
||||
### Interface impact
|
||||
|
||||
- 等级:L2 internal interface。
|
||||
- 新消费者:阶段 2 Node adapters、阶段 3 ChatService orchestrator、阶段 4 tests。
|
||||
- 外部 API/DB/运行路径:无变化。
|
||||
- 回滚:revert 本阶段提交即可;因为未接生产入口,没有数据迁移。
|
||||
- 兼容:后续 action adapters 必须实现已冻结 ports,不得传递父 State 全量数据。
|
||||
|
||||
## Risks Accepted
|
||||
- Stage 1 skeleton 会暂时存在但未被生产调用,这是阶段边界要求,不是死代码最终状态。
|
||||
- 真实 Agent 状态映射尚未验证,由阶段 2 独立 change 负责。
|
||||
- Maven E2E 不运行,生产路径完全未改变。
|
||||
|
||||
## Apply Evidence
|
||||
|
||||
- Task 1.1:显式声明 BOM 管理的 Graph Core;新增 26 个 state keys、状态枚举、拓扑/route/reason 常量、默认 Replace + events Append 策略和安全 typed reads。
|
||||
- Task 1.2:新增不可变 event/transition/trace records,构造期拒绝空 routing metadata 和非法计数,map 输出只有冻结字段。
|
||||
- Task 2.1:新增八个 non-null config-aware action ports,Fake/真实 Node 共用同一 Graph 接入面。
|
||||
- Task 2.2:新增纯 router;所有未知/缺失状态 fail closed,LOW_CONFID guard 只读 facts_checked,不构造 retry context。
|
||||
- Task 2.3:Graph Factory 注册八节点和全部条件边;wrapper 独占 retry/evidence control state,compile recursion limit=32。
|
||||
- 首模块 Maven compile:passed(31s),锁定 1.1.2.0 API 假设成立。
|
||||
- Task 3.1:trace builder 从 event 单向派生 transitions/final reason/degraded/evidence count,空或异类 events 显式失败。
|
||||
- Task 4.1:新增严格 FIFO Fake Node fixture,记录 sequence/calls/threadId,每 attempt 只追加一个 terminal event,意外调用立即失败。
|
||||
- Task 4.2:真实 CompiledGraph normal/Planner/Executor/Gatekeeper focused tests 首轮通过(Maven exit 0,约 67s)。
|
||||
- Task 4.3:Verifier/evidence/Composer 路由与独立计数测试通过(Maven exit 0,约 12s)。
|
||||
- Task 4.4:routing + trace focused suite 通过(Maven exit 0,约 28s),覆盖事件顺序、degraded、map 白名单、不可变性和非法输入。
|
||||
- Task 5.1:35 tests(29 routing + 6 trace)全通过;Maven test compilation、change strict 1/1、主 specs 12/12、diff check 均通过。
|
||||
- Task 5.2:现有 production refs=0,新 Graph 对真实 Service/DB/Trace refs=0,23 个 changed paths 全部命中阶段白名单;Maven E2E/log/DB 按用户口径保留到阶段 5。
|
||||
- Review:补齐所有正常节点 threadId 传播、Verifier REJECT→Composer 和 completed-without-verdict fail-closed 用例;增强后 focused suite exit 0。
|
||||
|
||||
## Cross-Artifact 对齐检查
|
||||
|
||||
| 上游 → 下游 | 检查内容 | 状态 |
|
||||
|---|---|---|
|
||||
| brief/prd → proposal | 阶段 1 目标、Fake Node 边界、测试口径和 E2E 非目标 | 已对齐 |
|
||||
| proposal → 设计产物 | direct dependency、状态、ports、router、counter、trace、测试架构 | 已对齐 |
|
||||
| 设计产物 → specs/tasks | 所有可观察路由、终止、安全默认和实现模块 | 已对齐 |
|
||||
| specs → tasks | 编译、全路由、trace、focused tests、生产隔离检查 | 已对齐 |
|
||||
|
||||
Gap:无。
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
输入是 run-scoped 初始 state 与 `RunnableConfig`,处理链是 CompiledGraph → config-aware action ports → deterministic router/counters,输出是最终 state 与纯路由 trace;阶段 1 没有 Controller/Service/DB 消费者。Graph State 由单次 invoke 所有,events 只由 Node append,transitions 只由 builder 派生,避免双写。阶段 2 只实现 action ports,阶段 3 才将 orchestrator 交给 ChatService,因此当前未接生产入口是刻意生命周期边界。审计发现的唯一缺口是 Graph Core 直接依赖所有权,已回写 proposal/design/tasks。与阶段 0 archive 无冲突,L2 风险可由 Fake Node CompiledGraph tests 和 revert 单提交控制。
|
||||
@@ -0,0 +1,31 @@
|
||||
# Chat Diagnosis StateGraph Routing Skeleton Evidence
|
||||
|
||||
## 证据
|
||||
|
||||
| 来源 | 证据 | 结论 | 是否已汇报 |
|
||||
|---|---|---|---|
|
||||
| 阶段 0 archive/ADR | 冻结 26 个 state keys、完整路由、四类计数、run audit | 阶段 1 实现未偏离基线 | 是 |
|
||||
| 本地 Graph Core 1.1.2.0 `javap` | config-aware Node/Edge、conditional edge、recursion limit、threadId 存在 | 使用公共锁定 API 可编译 | 是 |
|
||||
| AppendStrategy bytecode | list/collection 按顺序追加 | 每 Node 返回单 event list 可形成实际路径 | 是 |
|
||||
| Maven compile | `mvn -q "-DskipTests" compile` exit 0 | direct dependency 和 Factory API 编译成立 | 是 |
|
||||
| Fake Node CompiledGraph tests | 29 routing tests,0 failure/error | 全条件边、retry、threadId、unknown fail-closed 成立 | 是 |
|
||||
| Trace tests | 6 tests,0 failure/error | transitions、degraded、map 白名单、不可变和非法输入成立 | 是 |
|
||||
| Test compilation | `mvn -q "-DskipTests" test` exit 0 | 全测试源可编译 | 是 |
|
||||
| OpenSpec validation | change 1/1、主 specs 12/12 strict | artifacts 与既有规格无回归 | 是 |
|
||||
| 生产隔离检查 | outside Graph refs=0,Graph 对真实 Service/DB/Trace refs=0 | 阶段 1 未接生产入口 | 是 |
|
||||
| Git 路径白名单 | 23 changed paths,out-of-scope=0 | 无跨阶段文件混入 | 是 |
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- 结论:直接声明 Graph Core 是正确依赖所有权。
|
||||
- 证据:生产代码直接 import Graph Core;依赖原先仅由 Agent Framework 传递。
|
||||
- 风险:BOM 升级仍需重新跑真实 Graph tests。
|
||||
- 用户确认:不需要,属于构建稳健性。
|
||||
- 结论:recursion limit 32 足够且没有替代业务计数。
|
||||
- 证据:最坏合法路径低于 20;第二次技术失败和第二次 LOW_CONFID tests 均终止。
|
||||
- 风险:未来新增循环必须重算。
|
||||
- 用户确认:不需要,冻结业务上限未变。
|
||||
- 结论:单元测试必要,E2E 不必要。
|
||||
- 证据:阶段新增条件边行为但未接生产入口;35 tests 直接验证 Graph。
|
||||
- 风险:真实 Agent 映射仍留给阶段 2。
|
||||
- 用户确认:符合用户按必要性和最终阶段 E2E 规则。
|
||||
@@ -0,0 +1,50 @@
|
||||
# Chat Diagnosis StateGraph Test Suite 验收
|
||||
|
||||
## 结果
|
||||
|
||||
已接受。OpenSpec tasks 21/21 完成,阶段 4为 test-only,无生产行为变更。
|
||||
|
||||
## 验证
|
||||
|
||||
### 静态验证
|
||||
|
||||
- `git diff --check`:通过。
|
||||
- `git diff --name-only HEAD -- src/main`:0 个文件。
|
||||
- test inventory:三个权威类均存在;`ChatServiceSequentialAgentTest`/`VerifierInputHookTest` 均不存在;`ScriptedDiagnosisGraphActions` 定义 1 处。
|
||||
- `openspec validate chat-diagnosis-stategraph-test-suite --strict`:通过。
|
||||
- `openspec validate --specs --strict`:15 passed,0 failed。
|
||||
|
||||
### 脚本验证
|
||||
|
||||
- 三层权威 suite:4 suites / 43 tests,0 failures/errors/skipped。
|
||||
- 完整保留安全回归:31 suites / 126 tests,0 failures/errors/skipped。
|
||||
- `mvn -q -DskipTests test-compile`:通过。
|
||||
|
||||
### 浏览器/人工验证
|
||||
|
||||
- 未运行;阶段 4仅重构自动化测试,且用户要求最终人工/live 验收到阶段 5统一执行。
|
||||
|
||||
### 未验证
|
||||
|
||||
- 未使用 Maven 启动应用做 live E2E。
|
||||
- 未检查 `logs/`。
|
||||
- 未执行 `scripts/query_mysql.py`。
|
||||
- 剩余风险:真实模型、工具、Flyway/MySQL 和最终 Trace 内容仍需阶段 5 E2E/log/DB 证据。
|
||||
|
||||
## 已完成范围
|
||||
|
||||
- 建立 Workflow、Node Contract、Chat Integration 三层权威测试体系。
|
||||
- 补齐 ceiling/second LOW_CONFID、tool-failure legal snapshot、partial-pass REJECT 和 Verifier invalid status 边界。
|
||||
- 删除旧 Hook implementation test,并保留 parser/Gatekeeper/projection/Composer 等安全回归。
|
||||
- 用结构测试和 source gate 防止旧 Sequential/Hook 测试回归。
|
||||
|
||||
## 已知限制
|
||||
|
||||
- 生产 `VerifierInputHook`/`VerifierContextHolder` 类型仍存在但已无生产/权威测试消费者;阶段 5清理。
|
||||
- component tests 与权威层存在有意的分层 overlap,详见 `evidence.md`。
|
||||
|
||||
## 交接
|
||||
|
||||
- OpenSpec archive:已同步 2 份 delta specs,并归档到 `openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-test-suite/`。
|
||||
- 下一步:审查精确 Git diff并完成阶段 4独立提交,之后启动阶段 5。
|
||||
- OpenSpec 归档确认:用户已授权直接执行后续归档;归档已完成。
|
||||
@@ -0,0 +1,20 @@
|
||||
# Chat Diagnosis StateGraph Test Suite Brief
|
||||
|
||||
## 背景
|
||||
|
||||
- 用户目标:将 ISS-011 阶段 4作为独立 sm-flow,建立以 Graph 路径和外部行为为中心的新测试体系。
|
||||
- 当前问题:阶段 1–3 覆盖充分但组织分散,旧 Hook payload test 仍会约束已退出生产的隐式状态机。
|
||||
- 关联 OpenSpec:`openspec/changes/chat-diagnosis-stategraph-test-suite/`
|
||||
- devflow 分档:complex;接口影响 L1 test-only。
|
||||
|
||||
## 范围
|
||||
|
||||
- 本次要做:Workflow/Node Contract/Chat Integration 三层权威入口、Issue 路径矩阵补齐、旧 Hook test 退役、保留安全回归。
|
||||
- 本次不做:不改生产源码,不删除生产 Hook/ThreadLocal 类型,不运行 live E2E/log/DB 验收。
|
||||
- 影响区域:Diagnosis Graph tests、ChatService integration test、OpenSpec/devflow。
|
||||
|
||||
## OpenSpec 对齐
|
||||
|
||||
- proposal/design/specs:已覆盖,2 个 delta capabilities。
|
||||
- tasks:21/21 已完成。
|
||||
- 生产行为:无变化,`src/main` diff=0。
|
||||
@@ -0,0 +1,121 @@
|
||||
# Chat Diagnosis StateGraph Test Suite Decisions
|
||||
|
||||
## Entry Summary
|
||||
|
||||
- 问题:阶段 1–3 的安全覆盖已充足,但测试命名/组织仍是逐步实现产物,尚未形成 ISS-011 指定的 Workflow、Node Contract、Chat Integration 三层权威体系。
|
||||
- 期望:阶段 4只重构测试结构并补齐矩阵,不改变生产行为;归档并提交后才进入阶段 5。
|
||||
- 分档:complex(路径矩阵广、涉及旧安全测试退役,但接口影响为 L1 test-only)。
|
||||
- Change:`chat-diagnosis-stategraph-test-suite`。
|
||||
- 授权:用户已要求直接实现,阶段门禁与阶段 5 才 live E2E 的约束不变。
|
||||
|
||||
## Context Sources
|
||||
|
||||
- ISS-011 阶段 4、测试策略和验收标准。
|
||||
- `chat-diagnosis-stategraph-design-freeze` 的 test migration requirement。
|
||||
- 阶段 1–3 archive/acceptance 和当前 119-test focused baseline。
|
||||
- `DiagnosisGraphRoutingTest`、各 Node tests、`DiagnosisRealGraphIntegrationTest`、`ChatDiagnosisGraphRuntimeTest`、`ChatServiceGraphIntegrationTest`。
|
||||
- `VerifierInputHookTest`、protocol parser tests、`ExecutorGatekeeperServiceTest` 与 Trace/Controller/Repository/Eval tests。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 术语 | Workflow、Node Contract、Chat Integration 的职责边界是什么? | evidence-driven | 已解决 |
|
||||
| Q2 | 边界 | 是否把所有现有 Graph unit tests 合并成三个巨型类? | evidence-driven | 已解决 |
|
||||
| Q3 | 旧测试 | `VerifierInputHookTest` 在显式 Graph Gatekeeper 后应保留、改写还是删除? | evidence-driven | 已解决 |
|
||||
| Q4 | 验收 | 如何证明阶段 4矩阵完整且没有恢复固定 Sequential 顺序? | evidence-driven | 已解决 |
|
||||
| Q5 | 阶段 | 是否允许为测试可测性改生产代码或执行 live E2E? | user-interview(既有冻结规则) | 已确认 |
|
||||
|
||||
## Evidence-driven Findings
|
||||
|
||||
- Q1:Issue 已明确三类测试;现有 `DiagnosisGraphRoutingTest` 对应 Workflow,分散 Node/Protocol tests 对应 Node Contract,`ChatServiceGraphIntegrationTest` 对应外部生命周期。
|
||||
- Q2:现有细粒度测试失败定位清晰,全部合并会制造大文件;应保留专用 unit tests,同时新增/重命名三层权威入口并共享夹具。
|
||||
- Q3:生产 Graph Verifier 已不注册 Hook,Hook test 仍验证 raw/full-trace/ThreadLocal payload,与 verified-only 生产协议冲突;parser/Gatekeeper/投影行为已有独立 tests,故阶段 4删除 Hook test,生产类型留到阶段 5。
|
||||
- Q4:以 Issue 必需路径清单建立 requirement-to-test matrix;source check 禁止 `SequentialAgent`/`VerifierInputHookTest` 成为新 suite 依赖,并运行保留安全回归。
|
||||
|
||||
## User-interview Confirmation
|
||||
|
||||
| 问题 | 用户原话/既有确认 | 状态 | OpenSpec 回写 |
|
||||
|---|---|---|---|
|
||||
| Q5 阶段边界 | “端到端只在最后阶段全部完成后才验证;每个阶段如果有必要添加单元测试验收的话,就加” | 已确认 | proposal |
|
||||
|
||||
## Grill-with-docs Result
|
||||
|
||||
- 术语不进入业务 glossary:Workflow/Node Contract/Integration 是测试架构术语,不改变 Session、Run、Trace、Gatekeeper 或 evidence gap 领域定义。
|
||||
- 具体场景压力测试:同 session 多 run 属于 Chat Integration;Gatekeeper REJECT/LOW_CONFID 与 retry exhaustion 属于 Workflow;failed binding 过滤与 verified-only payload 属于 Node Contract。
|
||||
- 旧 Hook test 的有效行为已分别迁移到 `ExecutorEvidenceParserTest`、`ExecutorGatekeeperServiceTest`、`GatekeeperNodeTest` 和 `VerifiedInputNodeTest`;删除不会丢失安全真理源。
|
||||
- 没有难以逆转的新架构取舍,不创建 ADR;测试组织可以在保持行为矩阵的前提下继续演进。
|
||||
|
||||
## Discover Status
|
||||
|
||||
- `devflow/index.md`:命中阶段 0–3 archive。
|
||||
- 生产调用链:阶段 3 已冻结且测试阶段默认不修改。
|
||||
- 接口影响:L1 test-only;无 API/DTO/DB/Prompt/运行时消费者变化。
|
||||
- 未解决问题:0。
|
||||
- Draft 产物:proposal + decisions;尚未生成 design/spec/tasks,尚未修改测试代码。
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
### Test ownership map
|
||||
|
||||
`ISS-011 path matrix -> DiagnosisGraphWorkflowTest -> ScriptedDiagnosisGraphActions -> real DiagnosisGraphFactory` 负责控制流;`Node/protocol contracts -> DiagnosisGraphNodeContractTest + focused component tests -> real Node actions/parsers/Gatekeeper` 负责安全投影;`public lifecycle -> ChatServiceGraphIntegrationTest -> Run repositories/Eval/Trace mapping` 负责外部行为。Controller、Repository、Trace、Eval 和 protocol tests 是三层体系的下游安全消费者,不应被重写成 Graph 内部顺序断言。
|
||||
|
||||
### Data and lifecycle ownership
|
||||
|
||||
- Workflow fixtures 只拥有脚本状态、调用计数和 events,不创建 Session/Run。
|
||||
- Node Contract fixtures 只拥有 invoker input/output 和 mock Gatekeeper current-run result,不持久化生产实体。
|
||||
- Chat Integration fixtures 只观察 ChatService public result 和 current Run persistence,不推断内部 Node 次序。
|
||||
- `VerifierInputHookTest` 删除后不产生数据契约缺口:Executor parser、Gatekeeper、passed-binding projection 各自已有单一测试所有者。
|
||||
|
||||
### Coupling risks
|
||||
|
||||
- 最大风险是 Workflow 与 Node Contract 都断言完整路径而重复;设计将 Fake route matrix 与 real-node input/security matrix分开。
|
||||
- `ScriptedDiagnosisGraphActions` 是唯一 Fake topology fixture;不新增第二套 Graph builder。
|
||||
- 测试-only阶段禁止 `src/main` diff,避免为测试便利扩大 production API。
|
||||
- 类重命名使用 Git rename,旧名称仅允许出现在 OpenSpec/devflow迁移说明中。
|
||||
|
||||
### Cross-artifact alignment
|
||||
|
||||
| 上游 → 下游 | 检查内容 | 状态 |
|
||||
|---|---|---|
|
||||
| brief/proposal → proposal | 三层体系、旧 Hook test退役、保留安全回归、阶段 5 E2E 延期 | 已对齐 |
|
||||
| proposal → design | rename-not-copy、职责归属、production diff=0、rollback | 已对齐 |
|
||||
| design → specs/tasks | Workflow/Node/Integration矩阵、Hook test删除、source inventory和验证门禁 | 已对齐 |
|
||||
| specs → tasks | 每类 scenario 均有 rename、补缺、回归或静态验收任务 | 已对齐 |
|
||||
|
||||
### Audit result
|
||||
|
||||
架构审计未发现业务 glossary、阶段 0–3 specs 或生产行为冲突。新 capability 只描述测试验证系统,modified design-freeze requirement 完整保留并细化旧测试替换边界。接口影响保持 L1,cross-artifact gap=0,无需回写生产 spec 或创建 ADR。
|
||||
|
||||
## Commit Gate
|
||||
|
||||
- schema:spec-driven;proposal/design/2 delta specs/tasks 全部 done,applyRequires=`tasks` 已满足。
|
||||
- OpenSpec:当前 change strict pass;15 个主 specs strict pass。
|
||||
- Cross-artifact:4/4 已对齐,gap=0。
|
||||
- Question pool:4 个 evidence-driven 已查证,1 个 user-interview 由用户既有原话确认,无未决项。
|
||||
- Interface impact:L1 test-only;design 有独立影响/回滚章节,默认 `src/main` diff=0。
|
||||
- Preflight:`git diff --check` 通过,当前仅 Draft OpenSpec/devflow 与根目录计划文件,无测试/生产代码修改。
|
||||
- 结论:Draft OpenSpec 达到可执行状态,创建 `.committed` 后进入 Apply。
|
||||
|
||||
## Apply Completion
|
||||
|
||||
- `DiagnosisGraphRoutingTest` 已以 Git rename 演进为 `DiagnosisGraphWorkflowTest`;所有 scripted run 统一断言 events 与真实 sequence 完全一致。
|
||||
- `DiagnosisRealGraphIntegrationTest` 已演进为 `DiagnosisGraphNodeContractTest`;补齐合法工具失败限制、partial-pass REJECT 和 Verifier invalid 无伪 verdict。
|
||||
- Workflow 显式断言 Gatekeeper ceiling 将模型 PASS 限制为 LOW_CONFID 且不触发 evidence retry,以及第二次 LOW_CONFID 不再补证据。
|
||||
- `ChatServiceGraphIntegrationTest` 增加 SessionContextHolder finally cleanup 断言;public Run/Trace/Eval/multi-run 覆盖保持。
|
||||
- `VerifierInputHookTest` 已删除;生产 Hook/ThreadLocal 类型未修改,留待阶段 5清理。
|
||||
- 新增 `DiagnosisGraphTestSuiteStructureTest`,保证三个权威类存在、Sequential/Hook实现测试不存在且权威测试不引用旧实现。
|
||||
|
||||
## Verification Summary
|
||||
|
||||
- 新权威层:4 suites / 43 tests,0 failures/errors/skipped。
|
||||
- 完整保留安全回归:31 suites / 126 tests,0 failures/errors/skipped。
|
||||
- Maven test compilation:通过。
|
||||
- OpenSpec:当前 change strict pass;主 specs 15/15 strict pass。
|
||||
- 静态门禁:`git diff --check` 通过;required authoritative classes=3;legacy tests=0;scripted fixture definitions=1;`src/main` diff=0。
|
||||
- 按阶段门禁未运行 Maven live E2E、未检查 `logs/`、未执行 `scripts/query_mysql.py`;统一保留到阶段 5。
|
||||
|
||||
## Archive Result
|
||||
|
||||
- 2 份 delta specs 已同步:新增 test-suite capability 6 条 requirements,修改 design-freeze test migration requirement 1 条。
|
||||
- OpenSpec 已归档到 `openspec/changes/archive/2026-07-17-chat-diagnosis-stategraph-test-suite/`。
|
||||
@@ -0,0 +1,42 @@
|
||||
# Chat Diagnosis StateGraph Test Suite Evidence
|
||||
|
||||
## Requirement-to-test Matrix
|
||||
|
||||
| ISS-011 路径/边界 | 权威测试 | 辅助证据 |
|
||||
|---|---|---|
|
||||
| PASS 与精确 event/transition | `DiagnosisGraphWorkflowTest.normalPassPathUsesCompiledGraphAndPreservesEventOrder` | `DiagnosisGraphNodeContractTest.compiledRealNodeGraphCompletesPassPathInExactOrder` |
|
||||
| Planner 一次技术重试/耗尽/非重试失败 | `DiagnosisGraphWorkflowTest.planner*` | Planner adapter focused test |
|
||||
| Executor FAILED/TOOL_BLOCKED/INVALID/no-evidence | `DiagnosisGraphWorkflowTest.executor*` | `DiagnosisGraphNodeContractTest.legalSnapshotAfterToolFailureRemainsCompletedAndReachesGatekeeper` |
|
||||
| Gatekeeper PASS/LOW/REJECT/unknown | `DiagnosisGraphWorkflowTest.gatekeeper*` | Gatekeeper Node/service tests |
|
||||
| partial-pass REJECT 不泄漏 claim | Workflow unsafe route | `DiagnosisGraphNodeContractTest.gatekeeperRejectSkipsVerifierAndUsesPreVerificationFallback` |
|
||||
| verified-only passed-binding projection | Workflow VerifiedInput route | `VerifiedInputNodeTest` + Verifier adapter test |
|
||||
| Verifier 技术重试/耗尽/非重试失败 | `DiagnosisGraphWorkflowTest.verifier*` | `DiagnosisGraphNodeContractTest.verifierInvalidOutputSetsExecutionStatusWithoutFabricatedVerdict` |
|
||||
| critical evidence retry、无 gap、non-critical、ceiling、第二次 LOW | `DiagnosisGraphWorkflowTest.*LowConfidence*` / `secondLowConfidence*` | EvidenceRetryPrepareNodeTest + real full-snapshot integration |
|
||||
| 第二轮完整 snapshot 再验真 | Workflow evidence retry | `DiagnosisGraphNodeContractTest.criticalGapPerformsOneIncrementalRoundAndRevalidatesCompleteSnapshot` |
|
||||
| Verifier REJECT 安全表达 | `DiagnosisGraphWorkflowTest.verifierRejectStillRunsComposerWithSafeMaterial` | ComposerSafeInputBuilderTest |
|
||||
| Composer retry/耗尽/非重试/安全 Fallback | `DiagnosisGraphWorkflowTest.composer*` | ComposerNodeAdapterTest + FallbackNodeTest |
|
||||
| ChatResult/Run/Trace/evaluation/cleanup | `ChatServiceGraphIntegrationTest` | Controller/Trace/Repository/Eval tests |
|
||||
| 同 session 多 run 隔离 | `ChatServiceGraphIntegrationTest.sameSessionCreatesDistinctRunIdsAndKeepsTracePerRun` | Run repository/Trace exact-run tests |
|
||||
| 三层结构与旧实现测试退役 | `DiagnosisGraphTestSuiteStructureTest` | source inventory command |
|
||||
|
||||
## 旧 Hook test 安全映射
|
||||
|
||||
| 旧行为 | 新真理源 |
|
||||
|---|---|
|
||||
| fenced/prefixed/malformed Executor JSON | `ExecutorEvidenceParserTest` |
|
||||
| invocation/raw_path/evidence excerpt真实性 | `ExecutorGatekeeperServiceTest` |
|
||||
| Gatekeeper status/severity/audit | `GatekeeperNodeTest` |
|
||||
| passed binding 精确投影 | `VerifiedInputNodeTest` |
|
||||
| Verifier verified-only payload | `VerifierNodeAdapterTest` + `ChatVerifierPromptContractTest` |
|
||||
|
||||
## 验证证据
|
||||
|
||||
- 31 suites / 126 tests:0 failures、0 errors、0 skipped。
|
||||
- test compilation、当前 change strict、主 specs 15/15、diff check 全通过。
|
||||
- `src/main` diff=0;三个权威类存在;旧 Sequential/Hook tests不存在;Scripted fixture 定义唯一。
|
||||
|
||||
## Intentional overlap and limits
|
||||
|
||||
- Workflow 与 Node Contract 都覆盖 PASS/REJECT,但前者验证 route/event,后者验证真实输入/安全材料;这是分层证据,不是复制 fixture。
|
||||
- 细粒度 component tests 保留以定位失败,不要求全部搬进三个权威类。
|
||||
- 真实模型/工具、日志和数据库行为未在阶段 4验证,统一由阶段 5 live E2E承担。
|
||||
@@ -1,44 +0,0 @@
|
||||
# Acceptance: single-react-aci-tool-contracts
|
||||
|
||||
## 实现结果
|
||||
|
||||
- RAG Contract:最小 query Request、bounded document evidence Result。
|
||||
- Log Contract:逻辑 Topic/Lookback Request、Mock provenance、Scope/Pattern/Event Result。
|
||||
- MySQL Contract:逻辑 data source、参数化 SQL Request、bounded structured rows Result。
|
||||
- 共享 Contract:snake_case Tool 名称、ACI 描述、不可变集合 helper,复用阶段 0 两套状态枚举。
|
||||
- 旧 Tool、Chat/AIOps、Controller、持久化、数据源和公开协议未修改。
|
||||
|
||||
## 静态验证
|
||||
|
||||
- `openspec validate single-react-aci-tool-contracts --strict`:通过。
|
||||
- `openspec instructions apply --change single-react-aci-tool-contracts --json`:12/12 tasks complete。
|
||||
- `rg` 引用检查:新 contract 生产包未接入旧运行链路。
|
||||
- 受保护文件 diff scope:旧 Tool、Chat/AIOps、Controller、Repository、resources 均为空。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
- `mvn -q -DskipTests compile`:通过。
|
||||
- `mvn -q '-Dtest=RagToolContractTest,QueryLogsToolContractTest,MysqlToolContractTest' test`:通过。
|
||||
- `mvn -q '-Dtest=HarnessContractTest,LookupKnowledgeToolTest,QueryLogsToolsTest' test`:通过。
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
- 不适用。本阶段无 UI、Controller、SSE 或公开运行行为变化。
|
||||
|
||||
## 未验证
|
||||
|
||||
- 未执行 live LLM/Redis/CLS/MySQL E2E;本阶段没有接入这些运行路径,最终 live E2E 按 ISS-014 门禁留到阶段 7。
|
||||
- 未验证 ToolInterceptor 的真实 ID 传播;阶段 2/3A 必须以 `ToolCallRequest.getToolCallId()` 添加集成测试。
|
||||
- 未验证真实日志 adapter 的 `SourceKind` 扩展;本 Issue 首版明确只使用 Mock。
|
||||
- Provider 侧旧凭据轮换仍需凭据所有者完成,仓库只能证明明文已移除。
|
||||
|
||||
## 剩余风险与后续门禁
|
||||
|
||||
- 新旧 Contract 短期并存,阶段 3B/3C 接入前不得声称旧 Tool 已符合新 ACI 输出。
|
||||
- 下一阶段只能在本 change OpenSpec Archive 和 Git commit 完成后开始。
|
||||
|
||||
## 状态
|
||||
|
||||
- Stage acceptance: accepted
|
||||
- OpenSpec archive: archived at `openspec/changes/archive/2026-07-21-single-react-aci-tool-contracts`
|
||||
- Main spec sync: `openspec/specs/aci-evidence-tool-contracts/spec.md`(7 added requirements)
|
||||
@@ -1,32 +0,0 @@
|
||||
# Brief: single-react-aci-tool-contracts
|
||||
|
||||
## 背景
|
||||
|
||||
旧 RAG 和日志 Tool 暴露检索/基础设施细节与不一致状态,MySQL Tool 尚无 Agent-facing 类型。Harness 实现前需要先冻结三类最小 ACI 契约。
|
||||
|
||||
## 目标
|
||||
|
||||
- 冻结 RAG、日志、MySQL 的 Request/Result JSON Schema。
|
||||
- 统一 `evidence_status`,并保持其与 invocation lifecycle 独立。
|
||||
- 统一使用框架 `tool_call_id`,禁止模型传入或 Harness 生成第二套 ID。
|
||||
- 冻结简短 Tool 名称/描述和 Mock 日志来源边界。
|
||||
- 用三个独立契约测试锁定行为。
|
||||
|
||||
## 范围
|
||||
|
||||
- 新增 `com.superbiz.agent.harness.tool.contract` 值对象、枚举和描述常量。
|
||||
- 复用阶段 0 的 `InvocationStatus` 与 `EvidenceStatus`。
|
||||
- 验证 JSON、不可变集合、描述泄漏和新旧边界。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不切换旧 RAG/日志运行方法或 Chat/AIOps 注册。
|
||||
- 不实现投影、Redis store、真实日志适配器或 MySQL 执行。
|
||||
- 不修改 Controller/SSE 或公开协议。
|
||||
|
||||
## 元数据
|
||||
|
||||
- 分档:standard
|
||||
- 接口影响:L2 前置内部契约;当前运行行为无变化
|
||||
- 关联 Issue:ISS-014 阶段 1
|
||||
- 关联 OpenSpec:`openspec/changes/single-react-aci-tool-contracts`
|
||||
@@ -1,116 +0,0 @@
|
||||
# Decisions: single-react-aci-tool-contracts
|
||||
|
||||
## 规模与入口
|
||||
|
||||
- 分档:standard。
|
||||
- 入口:ISS-014 阶段 1,前置 `single-react-design-freeze` 已 Archive 并由 Git commit `58c3910` 固化。
|
||||
- 目标:冻结三类 evidence Tool 的 Agent-facing ACI 契约,不接入新运行链路。
|
||||
|
||||
## Context
|
||||
|
||||
- `devflow/index.md` 命中 `single-react-design-freeze`、`modular-rag-pipeline` 和 `evidence-trace-hardening`。
|
||||
- `devflow/glossary/CONTEXT.md` 已定义 Diagnosis Harness、Invocation Status、Evidence Status 与 Evidence Tools。
|
||||
- 阶段 0 已确认 `tool_call_id` 使用框架 ID、两套状态语义分离、阶段串行门禁和阶段 6B 才公开切换。
|
||||
- 未发现根目录旧 `CONTEXT.md` 与 glossary 冲突。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| 维度 | 问题 | 模式 | 证据与结论 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| 术语 | invocation lifecycle 与 evidence result 是否使用同一状态? | evidence-driven | ISS-014 5.2、阶段 0 contract 明确分离;分别复用 `InvocationStatus` 与 `EvidenceStatus`。 | 已解决并汇报 |
|
||||
| 术语 | `tool_call_id` 由谁生成、从哪里取得? | evidence-driven | Spring AI `AssistantMessage.ToolCall.id()` 与 Alibaba `ToolCallRequest.getToolCallId()` 提供框架 ID;普通 `ToolContext` 不自动加入该 ID。Harness 不生成第二套 ID。 | 已解决并汇报 |
|
||||
| 边界 | 阶段 1 是否直接改旧 RAG/日志执行签名与返回值? | evidence-driven | ISS-014 阶段 1 只冻结 Contract,投影在阶段 3B、公开切换在阶段 6B;本阶段只新增契约代码和测试。 | 已解决并汇报 |
|
||||
| 边界 | 日志阶段是否实现真实 CLS/MCP 或保留 Topic discovery? | evidence-driven | ISS-014 8.1 明确继续 Mock、删除 Agent 侧 discovery、真实适配器不在本 Issue 提前设计。 | 已解决并汇报 |
|
||||
| 验收 | 如何证明契约已冻结且有界? | evidence-driven | 对三类独立 DTO 做精确 JSON、不可变集合、状态和描述泄漏测试;不以旧 Tool 集成测试代替。 | 已解决并汇报 |
|
||||
| 技术 | 框架 ID 能否在后续 Harness 边界取得? | evidence-driven | 本地依赖 Spring AI Alibaba 1.1.2.0 暴露 `ToolInterceptor.interceptToolCall(ToolCallRequest, ToolCallHandler)`,request 含 `toolCallId`。 | 已解决并汇报 |
|
||||
|
||||
## Grill 结论
|
||||
|
||||
- 术语、边界、验收三类问题均已由代码、依赖 API、阶段 0 档案和 ISS-014 证明。
|
||||
- 没有需要新增用户偏好或风险取舍的 `user-interview` 问题;不代理确认任何新方向。
|
||||
- `grill-with-docs` 要求的代码可证问题已先查证;结论已向用户汇报。
|
||||
- Proposal 已回写框架 ID 接入点、旧运行链路不切换、Mock 边界和 L2 接口影响。
|
||||
|
||||
## 已确认决策
|
||||
|
||||
- DTO 放在 Harness 的 Tool Contract 边界,复用阶段 0 的共享状态枚举,不在旧 `dto` 包继续堆叠协议。
|
||||
- 三类结果只携带 `evidence_status`,canonical invocation 的 `status` 保持独立;阶段 1 通过测试冻结枚举,不提前定义存储实现。
|
||||
- Tool description 使用代码常量冻结,后续 Tool adapter 注册时复用;旧 `@Tool` 注解本阶段不改,避免提前改变运行行为。
|
||||
- RAG 输入仅保留 `query`;日志输入仅保留逻辑 `topic/query/lookback_minutes`;MySQL 输入仅保留逻辑 `data_source/sql/params`。
|
||||
- 日志 `source_kind` 首版固定支持 `MOCK` 契约值,但保留 enum 扩展位置给后续真实适配器 change 审查。
|
||||
|
||||
## 能力与工具限制
|
||||
|
||||
- Discover 能力来源:`sm-flow` + `grill-with-docs`。
|
||||
- 仓库要求的 `codebase-retrieval` 和 LSP 工具在当前工具集中不可用;已用 `rg` 引用搜索、源码阅读和本地依赖 `javap` 补足事实核对。该限制不改变契约方向,但后续 Apply 仍需通过编译和引用测试验证。
|
||||
|
||||
## Cross-artifact 对齐
|
||||
|
||||
| 链路 | 状态 | 结论 |
|
||||
|---|---|---|
|
||||
| brief 目标/范围/非目标 -> proposal | 已对齐 | 三类 DTO、状态、框架 ID、短描述和不切旧运行链路均有对应。 |
|
||||
| proposal 范围/约束/承诺 -> design | 已对齐 | 包边界、ID 来源、record/defensive copy、三类 Schema 和迁移顺序均已设计。 |
|
||||
| design 决策/接口影响/风险 -> specs/tasks | 已对齐 | L2 边界、字段、状态、描述、Mock provenance 和运行不切换均有可验证 requirement 与任务。 |
|
||||
| specs 可观察行为 -> tasks | 已对齐 | 每类 Contract 都有实现与独立测试,另有状态、回归和 diff scope 验证。 |
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
- 能力来源:`zoom-out`,以项目 glossary 的 Diagnosis Harness、Evidence Tools、Invocation Status 和 Evidence Status 术语审计。
|
||||
- 当前输入到输出链路仍为 `ChatController/ChatService` 或 `AiOpsService -> ReactAgent -> LookupKnowledgeTool/QueryLogsTools -> 旧结果`,新契约没有运行消费者。
|
||||
- 未来链路为 `Diagnosis Agent -> Alibaba ToolInterceptor/Harness -> typed Request -> adapter/store/projector -> bounded Result -> Agent observation`,阶段 1 只占有 typed contract 边界。
|
||||
- 数据所有权保持明确:框架拥有 `tool_call_id`,canonical invocation 拥有生命周期,Tool-specific result 拥有证据语义与有界内容。
|
||||
- 主要耦合风险是新旧契约短期并存被误当成已迁移;通过独立包、无旧调用方修改和后续阶段门禁控制,无 ADR 冲突。
|
||||
|
||||
## Commit Gate Preflight
|
||||
|
||||
- proposal、design、specs、tasks 文件完整,OpenSpec CLI 状态为 complete。
|
||||
- strict validation:`openspec validate single-react-aci-tool-contracts --strict` 通过。
|
||||
- question pool 中没有未汇报的 evidence-driven 结论或未确认的 user-interview 问题。
|
||||
- 接口影响为 L2,当前运行消费者零变更;阶段 6B 的 L4 切换保持独立。
|
||||
- cross-artifact 四段对齐无 gap,架构审计未发现需要回写的新实现约束。
|
||||
- Apply 已由用户对 ISS-014 全阶段的持续授权覆盖;仍严格限制在本 Committed OpenSpec tasks 内。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### 参考实现
|
||||
|
||||
- `src/main/java/com/superbiz/agent/tool/LookupKnowledgeTool.java`:确认旧 RAG 暴露 `LookupResult`、ContextPack 和检索 Trace,本阶段不改。
|
||||
- `src/main/java/com/superbiz/agent/agent/tool/QueryLogsTools.java`:确认旧日志输入包含 region/logTopic/limit、存在 Topic discovery 和 mutable nested DTO,本阶段不改。
|
||||
- `src/test/java/com/superbiz/agent/tool/LookupKnowledgeToolTest.java`:现有 RAG 行为回归基线。
|
||||
- `src/test/java/com/superbiz/agent/agent/tool/QueryLogsToolsTest.java`:现有 Mock 日志行为回归基线。
|
||||
- `src/main/java/com/superbiz/agent/harness/contract/*.java`:Java 17 record、Jackson snake_case 和共享状态枚举风格。
|
||||
|
||||
### 技术栈清单
|
||||
|
||||
- 请求/响应标准:Java 17 record + Jackson `@JsonProperty`,集合构造时 defensive copy。
|
||||
- Tool 定义:当前使用 Spring AI `@Tool`,新名称/描述先以常量冻结,后续 adapter 注册复用。
|
||||
- 框架调用 ID:Spring AI Alibaba `ToolCallRequest.getToolCallId()`;普通 `ToolContext` 不作为 ID 来源。
|
||||
- 异常与校验:本阶段只冻结结构;Schema、ID、权限、范围和状态组合错误由后续 Pre-Tool/Projector 显式返回安全 `ERROR`。
|
||||
- MQ/Consumer/加密验签:本 change 不涉及。
|
||||
|
||||
### 新建类型
|
||||
|
||||
- `AgentToolContracts` 与 contract defensive-copy helper。
|
||||
- RAG Request/Result/Evidence。
|
||||
- Log Topic/SourceKind/Request/Result/Scope/Pattern/Event。
|
||||
- MySQL Request/Result。
|
||||
- 三个独立 contract test classes。
|
||||
|
||||
### 影响半径
|
||||
|
||||
- 新增包当前应无生产调用方;旧 Chat/AIOps、Tool、Controller、Repository 和配置文件均不修改。
|
||||
- 通过 focused compile/tests 和 `rg`/diff scope 证明边界。
|
||||
|
||||
## Apply 结果
|
||||
|
||||
- 冲突分类:未发现 OpenSpec 遗漏、代码偏离或方向不确定项。
|
||||
- 新增共享 ACI Tool 名称/描述、defensive-copy helper 和三类 typed Request/Result records。
|
||||
- 新增三个独立契约测试,覆盖精确 JSON、状态分离、框架 ID 原样保留、不可变集合、Mock provenance 和基础设施字段排除。
|
||||
- 首模块对齐:共享/RAG/日志/MySQL contract 与 design/tasks 全部完成;旧 runtime 接入保持 TODO,归属后续 3B/3C/6B changes。
|
||||
|
||||
## Apply 验证
|
||||
|
||||
- 编译:`mvn -q -DskipTests compile` 通过。
|
||||
- 新契约:`mvn -q '-Dtest=RagToolContractTest,QueryLogsToolContractTest,MysqlToolContractTest' test` 通过。
|
||||
- 旧行为回归:`mvn -q '-Dtest=HarnessContractTest,LookupKnowledgeToolTest,QueryLogsToolsTest' test` 通过。
|
||||
- 静态 scope:新 contract 生产类型当前无旧运行消费者;受保护的 Tool、Chat/AIOps、Controller、Repository 和配置文件 diff 为空。
|
||||
@@ -1,27 +0,0 @@
|
||||
# Evidence: single-react-aci-tool-contracts
|
||||
|
||||
## 文档证据
|
||||
|
||||
- ISS-014 5.2/5.3 冻结 `evidence_status` 与框架 `tool_call_id`;6-9 节冻结 RAG、日志和 MySQL Agent-facing Schema。
|
||||
- ISS-014 阶段 1 明确只冻结 ACI Contract,不实现 Agent 架构切换、真实 CLS/MCP 或 MySQL 执行。
|
||||
- 阶段 0 OpenSpec 与 devflow 已冻结 `InvocationStatus`、`EvidenceStatus`、框架 ID 真理源和阶段 6B 才公开切换。
|
||||
|
||||
## 代码证据
|
||||
|
||||
- `LookupKnowledgeTool` 仍返回包含 ContextPack/Trace 的旧 `LookupResult`,证明需要新的 bounded RAG Contract,也证明本阶段未提前切换。
|
||||
- `QueryLogsTools` 仍暴露 region/logTopic/limit、Topic discovery 和旧 mutable DTO,证明逻辑 Topic/Scope/Mock provenance 契约的必要性。
|
||||
- `ChatService` 与 `AiOpsService` 仍引用旧 `LookupKnowledgeTool`/`QueryLogsTools`,新 contract 生产包当前没有旧运行消费者。
|
||||
- 本地 Spring AI 1.1.7 `AssistantMessage.ToolCall` 提供 `id()`;Spring AI Alibaba 1.1.2.0 `ToolCallRequest` 提供 `getToolCallId()` 与 `ToolInterceptor` 边界。
|
||||
- Spring AI 1.1.7 普通 `ToolContext` 只传递调用方 context/history,不自动提供当前 Tool Call ID,因此后续必须从 Alibaba interceptor request 接入。
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- lifecycle 与 evidence result 必须保持两套正交状态;已汇报并进入 OpenSpec/代码测试。
|
||||
- `tool_call_id` 可以从当前框架 API 取得,Harness 无需也不得生成第二套 ID;已汇报并进入 OpenSpec。
|
||||
- 阶段 1 不改旧运行签名/返回;已通过引用和 diff scope 验证。
|
||||
- 日志首版保留 Mock 数据源但必须显式 `source_kind=MOCK`,不实现真实适配器;已进入 Log Contract。
|
||||
- 三类 Contract 的可验证口径是精确 JSON、不可变结果、短描述和基础设施字段排除;三个独立测试均通过。
|
||||
|
||||
## 工具限制
|
||||
|
||||
- 当前会话未提供 `codebase-retrieval` 或 LSP;使用 `rg` 引用搜索、源码阅读、本地依赖 `javap`、Maven 编译和 focused tests 完成等价核对。
|
||||
@@ -1,36 +0,0 @@
|
||||
# Acceptance: single-react-design-freeze
|
||||
|
||||
## 实现结果
|
||||
|
||||
- 新增类型化 Harness contracts 和序列化契约测试。
|
||||
- ISS-014 已调整为 11 个串行 changes,并补齐 Tool ID、双状态、previous turn 和安全切换决策。
|
||||
- Python 查询脚本和 Spring 主配置改为环境变量 Secret。
|
||||
- 集成测试和历史 handoff 中的旧 Secret 副本已删除或脱敏。
|
||||
- devflow glossary 新增 Harness、EvidenceGuard、SemanticGuard、Invocation Status 和 Evidence Status。
|
||||
|
||||
## 静态验证
|
||||
|
||||
- OpenSpec strict validation:通过。
|
||||
- Secret 扫描:通过,已知真实 Secret 模式零匹配。
|
||||
- Diff whitespace 检查:通过。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
- 4 个 contract tests:通过。
|
||||
- ToolInvocationRecorder、ExecutorGatekeeperService、ChatController focused baseline:通过。
|
||||
- 查询脚本缺失密码环境变量时 fail fast:通过。
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
- 不适用;阶段 0 未切换任何公开 UI/API。
|
||||
|
||||
## 未验证与后续门禁
|
||||
|
||||
- Provider 侧旧凭据轮换待凭据所有者完成。
|
||||
- Live E2E 留到阶段 7。
|
||||
- 阶段 1 只有在本 change Archive 和 Git commit 后才能开始。
|
||||
|
||||
## 状态
|
||||
|
||||
- Stage acceptance: accepted
|
||||
- OpenSpec archive: authorized by standing user instruction
|
||||
@@ -1,31 +0,0 @@
|
||||
# Brief: single-react-design-freeze
|
||||
|
||||
## 背景
|
||||
|
||||
ISS-014 将 Chat 诊断从多 Agent、Hook、ThreadLocal 和外层重试编排收敛为单体 Diagnosis ReAct Agent、确定性 Harness 和隔离 SemanticGuard。阶段 0 先冻结后续实施共同依赖的契约和安全边界。
|
||||
|
||||
## 目标
|
||||
|
||||
- 提供可复用的 Diagnosis Draft、Knowledge Answer、Fallback、published result 和 previous turn 类型。
|
||||
- 固定 framework Tool Call ID、调用生命周期和证据结果双状态。
|
||||
- 固定取消、重试、no-evidence、阶段门禁和安全凭据策略。
|
||||
- 保持当前公开 Chat 运行行为不变。
|
||||
|
||||
## 范围
|
||||
|
||||
- `com.superbiz.agent.harness.contract` 类型层和 focused tests。
|
||||
- ISS-014 的 11 个串行 OpenSpec changes 台账。
|
||||
- 主配置、查询脚本和集成测试中的明文 Secret 清理。
|
||||
- OpenSpec、devflow glossary 和阶段验收基线。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不接入新 Harness、Agent 或 Guards。
|
||||
- 不切换 `/api/chat`,不删除旧运行链。
|
||||
- 不执行 live E2E。
|
||||
|
||||
## 元数据
|
||||
|
||||
- Scale: complex
|
||||
- Parent issue: `ISS-014`
|
||||
- OpenSpec: `openspec/changes/single-react-design-freeze`
|
||||
@@ -1,20 +0,0 @@
|
||||
# Decisions: single-react-design-freeze
|
||||
|
||||
## 已确认决策
|
||||
|
||||
- ISS-014 保留为总 Issue,实施拆成 11 个独立、串行 sm-flow changes。
|
||||
- 每个 change 必须完成 Apply、阶段验收、OpenSpec Archive 和 Git commit 后才能进入下一项。
|
||||
- Apply、Archive 和阶段 Git commit 已获得用户对整个目标的持续授权;仅方向性决策需要暂停。
|
||||
- `tool_call_id` 使用框架协议 ID,Harness 不生成第二套 ID。
|
||||
- `status=PROJECTING/READY/ERROR` 表示 invocation lifecycle;`evidence_status=EVIDENCE_FOUND/NO_EVIDENCE/ERROR` 表示结果语义。
|
||||
- `NO_EVIDENCE` 只能支持限定范围的 `NEGATIVE_OBSERVATION`。
|
||||
- KNOWLEDGE_QUERY 使用 answer items 绑定 `tool_call_id + document_id`,首版不进入 SemanticGuard。
|
||||
- `diagnosis_run` 是 previous turn 的持久化真理源;只有最近的 `DIAGNOSIS + SUCCESS` 安全发布结果可用。
|
||||
- 取消采用分层、可观测语义;同步模型调用不承诺无法证明的立即硬取消。
|
||||
- 底层重试压为一次 attempt,Router/SemanticGuard 的允许重试只由 Harness 执行。
|
||||
- 阶段 4 和 6A 不接管公开入口,阶段 6B 才执行原子 SSE 切换。
|
||||
|
||||
## 权衡
|
||||
|
||||
- contract types 提前落地会增加少量文件,但后续 output type、validator、持久化和 SSE 可以复用,避免多阶段字符串协议漂移。
|
||||
- Provider 侧凭据轮换是外部前置,阶段 0 只证明工作树已清理,不伪造外部完成状态。
|
||||
@@ -1,25 +0,0 @@
|
||||
# Evidence: single-react-design-freeze
|
||||
|
||||
## 代码与框架证据
|
||||
|
||||
- `ChatController` 当前直接管理会话、模型、工具、执行和伪流式 SSE,证明公开切换必须延后到阶段 6B。
|
||||
- `ChatService` 当前构建 Planner/Executor/Verifier/Composer 并依赖 ThreadLocal,证明阶段 0 只能创建无运行依赖的 contract types。
|
||||
- Spring AI Alibaba `Builder` 提供 ToolInterceptor、output type、tool timeout 和调用限制扩展点;`ReactAgent` 提供 interrupt。
|
||||
- Spring AI 1.1.7 `SpringAiRetryProperties` 构造器默认 `maxAttempts=10`,与 Harness 单一重试所有权冲突,阶段 2 必须压为一次底层 attempt。
|
||||
- `DiagnosisRun` 当前只有通用 status 和文本 answer,不足以确定性恢复安全 previous turn,因此确认后续保存 `intent/release_outcome/published_result`。
|
||||
- 历史 ISS-009 和 verifier evidence 归档证明 `NO_EVIDENCE` 只能表达限定范围内无匹配结果。
|
||||
|
||||
## 验证证据
|
||||
|
||||
- `mvn -q '-Dtest=HarnessContractTest' test`:通过。
|
||||
- `mvn -q '-Dtest=ToolInvocationRecorderTest,ExecutorGatekeeperServiceTest,ChatControllerTest' test`:通过。
|
||||
- `mvn -q '-Dtest=HarnessContractTest,ToolInvocationRecorderTest,ExecutorGatekeeperServiceTest,ChatControllerTest' test`:通过。
|
||||
- `openspec validate single-react-design-freeze --strict`:通过。
|
||||
- `git diff --check`:通过,仅有 Windows line-ending warning。
|
||||
- 已知旧 Secret 模式扫描:零匹配。
|
||||
- 缺少 `SUPERBIZ_MYSQL_PASSWORD` 时运行查询脚本:在连接前 fail fast,符合预期。
|
||||
|
||||
## 未验证
|
||||
|
||||
- 未运行模型、Redis、MySQL 或 Milvus live E2E;按阶段门禁留到阶段 7。
|
||||
- Provider 侧旧凭据是否已经轮换无法由仓库证明,必须由凭据所有者完成,并在阶段 3C/7 前核验。
|
||||
@@ -1,65 +0,0 @@
|
||||
# Single React Diagnosis Agent Acceptance
|
||||
|
||||
## 结果
|
||||
|
||||
已接受。阶段 4 Committed OpenSpec 的 11 项任务全部完成,新链路仅通过内部 Java/test 入口运行,公开 Chat 未切换。
|
||||
|
||||
## 验证
|
||||
|
||||
### 静态验证
|
||||
|
||||
- 检查:新 `harness.agent` 包与 Prompt 搜索 `ThreadLocal|SessionContextHolder|while|SequentialAgent|SupervisorAgent|StateGraph|Planner|Composer|Verifier|raw_response`。
|
||||
- 结果:通过,无匹配。
|
||||
- 检查:`git diff --name-only` 限定 Controller、ChatService、AiOpsService。
|
||||
- 结果:通过,无 diff。
|
||||
- 检查:OpenSpec artifact status、cross-artifact、L2 interface impact、`.committed`、`.archive-ready`。
|
||||
- 结果:通过。
|
||||
|
||||
### 脚本验证
|
||||
|
||||
- 命令:`mvn -q -DskipTests compile`
|
||||
- 结果:通过。
|
||||
- 命令:`mvn -q '-Dtest=HarnessToolInterceptorTest,DiagnosisAgentUseCaseTest' test`
|
||||
- 结果:通过,14 tests。
|
||||
- 命令:`mvn -q '-Dtest=DiagnosisAgentUseCaseTest,HarnessToolInterceptorTest,DiagnosisHarnessCoreTest,ToolBoundaryTest,ToolAdapterTest,MysqlToolAdapterTest,CanonicalInvocationStoreTest,HarnessContractTest,RagToolContractTest,QueryLogsToolContractTest,MysqlToolContractTest' test`
|
||||
- 结果:通过。
|
||||
- 命令:`openspec validate single-react-diagnosis-agent --strict`
|
||||
- 结果:通过。
|
||||
- 命令:归档后 `openspec validate single-react-diagnosis-agent --type spec --strict`
|
||||
- 结果:通过;仓库级 `openspec validate --specs --strict` 另发现前序 `mysql-readonly-tool`、`rag-log-projections` 主规格仍使用旧 scenario 格式,本阶段不跨归档边界修改。
|
||||
|
||||
### 浏览器/人工验证
|
||||
|
||||
- 不适用。本阶段无 UI、HTTP 或 SSE 行为变化。
|
||||
|
||||
### 未验证
|
||||
|
||||
- 未启动 Maven 应用、外部模型、MySQL、Redis、Milvus 或日志服务;按 ISS-014 门禁统一留到阶段 7 live E2E。
|
||||
- 未验证 provider 生产响应始终携带 Token Usage;缺失 Usage 时模型调用次数仍强制,实际 Token 只能在 provider 返回时记录。
|
||||
|
||||
## 已完成范围
|
||||
|
||||
- 单一 Diagnosis ReactAgent、单 Prompt 和固定 Query/PreviousTurn 输入。
|
||||
- 框架原生 tool loop、exact Tool Call ID 和三类 Harness adapter bridge。
|
||||
- 模型/Token/Tool/上下文/Draft 预算与无自动 retry。
|
||||
- 严格 DiagnosisDraft 输出和无证据停止规则。
|
||||
- 显式 sessionId/runId audit metadata、可注入 AgentStep Hook、canonical Tool invocation。
|
||||
- 公开 Chat/AiOps 与旧多 Agent 路径保持不变。
|
||||
|
||||
## 已知限制
|
||||
|
||||
- Draft 尚未经过 EvidenceGuard/SemanticGuard,不能公开发布;阶段 5 负责释放门禁。
|
||||
- previous turn 由调用方传入,阶段 6A 才实现同 Session 安全 Run 选择和确定性组装。
|
||||
- 真实业务 adapter/Spring Bean 装配和公开入口切换分别留给阶段 6A/6B。
|
||||
- 仓库级全规格 strict validation 仍受阶段 3B/3C 主规格 scenario 标题格式阻塞,建议阶段 7 文档清理时统一修正并复验。
|
||||
|
||||
## Bug 修复和诊断
|
||||
|
||||
- 编译发现框架 `Interceptor.getName()` 必须实现,已补充稳定名称并回归。
|
||||
- 首次测试修正了两个测试假设:callback 异常包装类型,以及 ToolResponseMessage 在 Prompt instructions 中的实际位置;生产规格与实现方向未变。
|
||||
- 提交前自审发现默认 BeanOutputConverter schema 不允许 `conclusion=null`,与冻结的无证据契约冲突;已增加 schema post-process 和 focused regression,未放宽其他 Draft 字段。
|
||||
|
||||
## 交接
|
||||
|
||||
- 下一步:提交独立阶段 4 commit,再进入阶段 5。
|
||||
- OpenSpec 归档确认:用户已对 ISS-014 每阶段 Apply、Archive 和 Git commit 提供持续授权;已归档至 `openspec/changes/archive/2026-07-21-single-react-diagnosis-agent`,主规格已同步至 `openspec/specs/single-react-diagnosis-agent/spec.md`。
|
||||
@@ -1,21 +0,0 @@
|
||||
# Single React Diagnosis Agent Brief
|
||||
|
||||
## 背景
|
||||
|
||||
- 用户目标:按 ISS-014 阶段 4 建立唯一的 Diagnosis ReAct Agent,并完成独立 sm-flow 归档与提交。
|
||||
- 当前问题:Harness Core 和三类 evidence Tool 已就绪,但没有一个内部诊断执行链消费它们;公开 Chat 仍依赖旧的简单/多 Agent 路径。
|
||||
- 关联 OpenSpec:`openspec/changes/archive/2026-07-21-single-react-diagnosis-agent/`
|
||||
- devflow 分档:complex
|
||||
- 需求真理源:`mvp/issues/active/ISS-014-single-react-agent-harness-aci-ptk-refactor.md`,不重复创建独立 PRD。
|
||||
|
||||
## 范围
|
||||
|
||||
- 本次要做:单 Prompt、单 Diagnosis ReactAgent、固定 Query/PreviousTurn 输入、Harness Model/Tool interceptors、三类 Tool 注册、严格 DiagnosisDraft 解析、上下文/模型/Tool/Token 预算和内部审计注入。
|
||||
- 本次不做:公开 Chat 切换、旧链路删除、EvidenceGuard、SemanticGuard、previous turn 选择、DiagnosisRun 持久化和 live E2E。
|
||||
- 影响区域:`com.superbiz.agent.harness.agent`、`src/main/resources/prompts`、focused tests、OpenSpec/devflow/ISS-014 状态。
|
||||
|
||||
## OpenSpec 对齐
|
||||
|
||||
- proposal 覆盖状态:已覆盖
|
||||
- specs 覆盖状态:已覆盖
|
||||
- tasks 覆盖状态:已覆盖
|
||||
@@ -1,156 +0,0 @@
|
||||
# Decisions: single-react-diagnosis-agent
|
||||
|
||||
## Discover status
|
||||
|
||||
- Checkpoint: Discover
|
||||
- Capability source: `sm-flow`,使用 `grill-with-docs` 进行代码可证问题澄清,并使用 GitNexus、源码、依赖 sources jar 与 `javap` 核对调用链和框架 API。
|
||||
- Scale: complex。变更新增内部 Agent/use case,跨越模型、Tool、预算、结构化输出和审计边界,但不切换公开协议。
|
||||
- `devflow/index.md` 命中 design freeze、RunContext、ACI contracts、canonical store、RAG/log projection 和 MySQL Tool;没有与 OpenSpec 冲突的 ADR。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 术语 | 单体 Diagnosis Agent 是否包含外层 Graph 或多个报告作者? | evidence-driven | 已解决 |
|
||||
| Q2 | 边界 | 阶段 4 是否切换公开 Chat 或删除旧多 Agent 链路? | evidence-driven | 已解决 |
|
||||
| Q3 | 验收 | 如何证明 ReAct 正常轮次不是 Harness retry? | evidence-driven | 已解决 |
|
||||
| Q4 | 技术 | 如何取得并保留框架原始 tool_call_id? | evidence-driven | 已解决 |
|
||||
| Q5 | 技术 | 如何在每个模型和 Tool 边界强制 Run 预算? | evidence-driven | 已解决 |
|
||||
| Q6 | 输出 | 框架生成的 DiagnosisDraft schema 是否与可空 conclusion 契约一致,并会直接返回 DiagnosisDraft? | evidence-driven | 已解决 |
|
||||
| Q7 | 上下文 | previous_turn 如何进入模型且保持固定 Schema 和有界? | evidence-driven | 已解决 |
|
||||
| Q8 | 审计 | 如何保留 Run/AgentStep/ToolInvocation 而不引入 ThreadLocal? | evidence-driven | 已解决 |
|
||||
| Q9 | 验收 | 无证据结果如何停止而不补造根因? | evidence-driven | 已解决 |
|
||||
|
||||
## Evidence-driven
|
||||
|
||||
| 结论 | 证据来源 | 是否已汇报用户 |
|
||||
|---|---|---|
|
||||
| 只新增一个拥有 tool loop 的 `ReactAgent`,无 SequentialAgent、SupervisorAgent 或业务 StateGraph。 | ISS-014 阶段 4;`ChatService` 旧链路反例;Spring AI Alibaba `ReactAgent` API | 已汇报 |
|
||||
| 阶段 4 只提供内部用例,公开入口保持旧实现,接口影响 L2。 | ISS-014 1174-1197、阶段 0 design freeze、GitNexus `createReactAgent` 引用 | 已汇报 |
|
||||
| `ToolCallRequest.getToolCallId()` 精确暴露 `AssistantMessage.ToolCall.id()`;ToolInterceptor 可在回调执行前取得该 ID。 | framework sources `ToolCallRequest`、`AgentToolNode` | 已汇报 |
|
||||
| `ModelInterceptor` 包围每次真实模型调用,适合调用 `beforeModelCall` 并记录响应 Usage;ToolBoundary 已负责 Tool 预算,不能重复计数。 | framework `AgentLlmNode`/`InterceptorChain`;`ToolBoundary` | 已汇报 |
|
||||
| BeanOutputConverter 可从 DiagnosisDraft 生成格式说明,但默认 schema 不允许冻结契约的 `conclusion=null`;必须 post-process nullable conclusion,且 `ReactAgent.call` 仍返回 AssistantMessage,需要 Harness 严格解析 JSON。 | framework `DefaultBuilder`、`ReactAgent`、本地生成 schema | 已汇报 |
|
||||
| RunContext 可放入 `RunnableConfig` metadata,由框架控制地传播到 ToolInterceptor;不需要 ThreadLocal。 | `RunnableConfig.addMetadata(String,Object)`、`AgentToolNode` | 已汇报 |
|
||||
| 现有 `AgentLoggingHook` 优先读取 config metadata 的 sessionId/runId,可作为可选审计 Hook 复用;ToolBoundary 保持 canonical Tool invocation。 | `AgentLoggingHook`、`ToolBoundary` | 已汇报 |
|
||||
| 原始 Query 不截断;超限 fail closed。PreviousTurn 先按固定 record 序列化并受独立/总上下文字节限制。 | ISS-014 极简上下文与预算规则 | 已汇报 |
|
||||
| `NO_EVIDENCE` 不是错误,只能形成限定范围的 NEGATIVE_OBSERVATION;Prompt 必须要求 conclusion=null、记录 missing_info 并停止。 | glossary、ACI spec、DiagnosisDraft contract | 已汇报 |
|
||||
|
||||
## User-interview
|
||||
|
||||
- 本阶段没有新增 user-interview 问题。方向、范围、阶段串行规则、框架 ID、状态语义以及 routine Apply/Archive/Commit 持续授权均已由用户在 ISS-014 评审与前序阶段确认。
|
||||
|
||||
## 关键取舍
|
||||
|
||||
- 决策:使用框架 `ToolInterceptor` 直接桥接已注册的 Tool 定义与 Harness adapter。
|
||||
- 原因:Spring AI `ToolCallback` 的调用参数不包含 Tool Call ID,而 Alibaba interceptor 明确提供原始 ID 和运行 metadata。
|
||||
- 影响:ToolCallback 负责模型可见定义,interceptor 负责受控执行;未知 Tool 仍交给框架 handler 并最终失败,不伪造结果。
|
||||
- 决策:模型预算由 `ModelInterceptor` 执行,Tool 预算继续由 `ToolBoundary` 执行。
|
||||
- 原因:避免在 Agent 层和 Tool boundary 双重 reserve。
|
||||
- 决策:阶段 4 只严格反序列化 `DiagnosisDraft`,不提前实现 EvidenceGuard。
|
||||
- 原因:字段引用真实性、唯一性和语义支持属于阶段 5;本阶段只验证 Agent 能生成冻结结构并携带框架 IDs。
|
||||
- 决策:复用现有 Agent Hook 注入点,不复制 AgentStep 持久化实现。
|
||||
- 原因:阶段 4 不接公开运行态,阶段 6A 再装配真实 Repository 和 Run 持久化。
|
||||
|
||||
## OpenSpec 回写
|
||||
|
||||
- 需进入 proposal/design/spec/tasks:单 Agent、内部入口、ToolInterceptor 原始 ID、ModelInterceptor 模型预算、ToolBoundary 单点 Tool 预算、严格 JSON 解析、上下文字节限制、审计 Hook 注入、无证据停止、不切换公开入口。
|
||||
- 不创建 ADR:这些是 ISS-014 已冻结方向和当前阶段可逆的内部装配,不满足新的难逆转架构决策条件。
|
||||
|
||||
## Cross-artifact 对齐
|
||||
|
||||
| 上游 -> 下游 | 检查内容 | 状态 |
|
||||
|---|---|---|
|
||||
| brief/ISS-014 -> proposal | 单 Agent、内部入口、极简上下文、预算、审计、非目标和验收预期 | 已对齐 |
|
||||
| proposal -> design | Tool/Model interceptor、严格 Draft、无重试、审计注入和公开隔离 | 已对齐 |
|
||||
| design -> specs/tasks | ID 传播、预算单点、输入输出限制、生命周期所有权和风险缓解 | 已对齐 |
|
||||
| specs -> tasks | 7 组可观察要求均有输入/Prompt、Tool bridge、Agent use case 和 focused test 切片 | 已对齐 |
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
- 能力来源:`zoom-out`,使用 glossary 的 Diagnosis Agent、Diagnosis Harness、RunContext、Evidence Status 和 Invocation Status 术语。
|
||||
- 链路为 `DiagnosisAgentInput + RunContext -> internal use case -> one ReactAgent -> model/tool interceptors -> ChatModel/ToolBoundary -> strict DiagnosisDraft`,没有外层业务 Graph。
|
||||
- RunContext 拥有预算/取消/生命周期,ToolBoundary/store 拥有 canonical invocation,use case 拥有输入和 Draft 解析,Agent 只拥有诊断语义;数据所有权不重叠。
|
||||
- 最大耦合风险是 Spring AI Alibaba interceptor/output schema API;设计通过本地 1.1.2.0 sources jar 和实际 schema 生成结果证实,并以 focused framework-loop/schema tests 固定。
|
||||
- 最大阶段风险是 Draft 在 Guards 前被误用;类名、文档和零 Controller 消费者共同保持 internal/draft 边界,阶段 5 前不得发布。
|
||||
|
||||
## 接口影响
|
||||
|
||||
- 级别:L2 内部接口。
|
||||
- 变更对象:新增内部 Java use case/factory/input/limits/interceptors/registry,不修改既有方法签名。
|
||||
- 消费者:本阶段只有 focused tests;阶段 6A 将成为首个生产消费者。
|
||||
- 兼容性:公开 HTTP/SSE、Controller DTO、数据库和旧 Chat/AiOps 路径不变,无迁移或回滚要求。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### 参考实现与框架源码
|
||||
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`:`createReactAgent`、`buildChatExecutorAgent` 和旧多 Agent 反例;只复用 Builder 形态,不复用运行职责。
|
||||
- `src/test/java/com/superbiz/agent/service/ChatServiceSequentialAgentTest.java`:scripted `ChatModel` 测试模式。
|
||||
- `src/main/java/com/superbiz/agent/harness/core/DiagnosisHarnessCore.java`:模型/Tool/Token/容量边界。
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/boundary/ToolBoundary.java`:Tool budget 和 canonical record 单点。
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/adapter/RagToolAdapter.java`、`QueryLogsToolAdapter.java`、`MysqlToolAdapter.java`:阶段 4 唯一允许的 evidence Tool 执行入口。
|
||||
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`:可注入 AgentStep audit,优先读取 RunnableConfig metadata。
|
||||
- Spring AI Alibaba 1.1.2.0 sources:`ReactAgent`、`DefaultBuilder`、`AgentLlmNode`、`AgentToolNode`、`ToolCallRequest`、`InterceptorChain`。
|
||||
|
||||
### 技术栈清单
|
||||
|
||||
- `ReactAgent.builder()` + 从 `DiagnosisDraft` 生成并修正 nullable conclusion 的 `.outputSchema(...)`,不新建 Graph/SequentialAgent。
|
||||
- `RunnableConfig.addMetadata(String,Object)` 显式携带 sessionId/runId/RunContext,并设置 `_stream_=false`。
|
||||
- `ModelInterceptor` 对每次模型调用执行 Core budget;读取 `ChatResponseMetadata.Usage`。
|
||||
- `ToolInterceptor` 读取 exact framework ID,调用 adapter bridge;`ToolBoundary` 保留唯一 Tool reserve/store 边界。
|
||||
- Spring `FunctionToolCallback` 仅定义模型可见 Tool Schema/description;直接 callback 执行 fail closed。
|
||||
- Jackson `ObjectMapper` 负责固定输入 JSON 和严格 DiagnosisDraft 反序列化;UTF-8 字节按 `StandardCharsets.UTF_8` 计算。
|
||||
- 框架 Hook 列表作为 AgentStep audit 扩展点;阶段 4 不新增 JPA/Redis/Flyway。
|
||||
|
||||
### 新建基础设施
|
||||
|
||||
- `harness.agent`:Input、Limits、Tool registry/interceptor、Model interceptor、Factory、UseCase 和异常类型。
|
||||
- `prompts/diagnosis-agent-prompt.md`:唯一 Diagnosis Agent Prompt。
|
||||
- focused scripted model/tool-loop tests;无需新 Maven 依赖。
|
||||
|
||||
### ISS-014 PRD 复用
|
||||
|
||||
- 阶段 4 不新建独立 `prd.md`:ISS-014 已完整覆盖问题、用户价值、数据流、Draft Schema、预算、重试、阶段边界和验收;`brief.md` 只索引本切片,不复制总 Issue。
|
||||
|
||||
## Commit Gate Preflight
|
||||
|
||||
- proposal、design、specs、tasks 完整,`openspec status` 为 complete,`openspec validate single-react-diagnosis-agent --strict` 通过。
|
||||
- question pool 全部为已汇报的 evidence-driven 结论;无未确认 user-interview、接口等级或风险接受问题。
|
||||
- Cross-artifact 四段对齐无 gap;架构审计的数据所有权、阶段边界和框架耦合缓解已进入 design/spec/tasks。
|
||||
- 接口影响为 L2,仅新增内部 Java API;公开 Controller/SSE/JPA/旧 ChatService 保持不变。
|
||||
- Apply、Archive 和阶段 Git commit 使用用户对 ISS-014 各阶段的持续授权;实现必须严格限制为 Committed OpenSpec。
|
||||
- `.committed` 已创建,Committed OpenSpec 可进入 Apply。
|
||||
|
||||
## Apply Progress
|
||||
|
||||
- 首模块对齐:Input/Limits/Prompt/Tool registry/Tool interceptor 已落地,任务 1.2、2.1、2.2 完成;1.1 等待 focused test 后完成。
|
||||
- 编译首次发现 `ToolInterceptor` 必须实现 `Interceptor.getName()`;分类为代码偏离,已补充稳定名称并复编译通过,无需修改 OpenSpec。
|
||||
- 单 Agent use case、Model interceptor、strict Draft parser 和 audit Hook 注入已完成;scripted ChatModel 真实执行框架 `model -> Tool -> model` loop。
|
||||
- 首次测试的两处失败均为测试假设偏差:Spring 会将 callback 异常包装为 `ToolExecutionException`,Tool observation 位于 `Prompt.instructions` 的 `ToolResponseMessage` 而非 `Prompt.getContents()`;已按框架真实 API 修正测试,生产设计未变。
|
||||
- 阶段 4 focused tests 共 14 个通过,任务 1.1-4.2 完成;剩余任务 4.3 为综合回归、静态范围和 OpenSpec 验证。
|
||||
|
||||
## Apply Result
|
||||
|
||||
- 新增一个且仅一个 `diagnosis_agent` Factory 和内部 `DiagnosisAgentUseCase`;没有外层业务 Graph、SequentialAgent、SupervisorAgent 或手写 ReAct loop。
|
||||
- 新增单一 Prompt、固定 `DiagnosisAgentInput(query, previous_turn)`、可配置 UTF-8 限制和严格 `DiagnosisDraft` 解析;不接受完整历史,不执行结构修复或 Agent retry。
|
||||
- 新增 `HarnessModelInterceptor`,对每个非流式模型轮次执行 Core model/Token budget,并在 late result 返回后复查 Run active 状态。
|
||||
- 新增 `HarnessEvidenceTools` 和 `HarnessToolInterceptor`,注册三类冻结 Tool,精确传播框架 Tool Call ID,并通过阶段 3B/3C adapter/ToolBoundary 返回有界结果。
|
||||
- AgentStep 使用可注入框架 Hook 保留,RunnableConfig 显式传播 sessionId/runId;Run 和 Tool canonical invocation 继续由既有 Harness 边界拥有。
|
||||
- 公开 Controller、ChatService、AiOpsService 无 diff;旧多 Agent 主链路继续保留。
|
||||
|
||||
## Apply Verification
|
||||
|
||||
- 编译:`mvn -q -DskipTests compile` 通过。
|
||||
- 阶段 4 focused:`mvn -q '-Dtest=HarnessToolInterceptorTest,DiagnosisAgentUseCaseTest' test`,14 tests 通过。
|
||||
- 综合回归:`mvn -q '-Dtest=DiagnosisAgentUseCaseTest,HarnessToolInterceptorTest,DiagnosisHarnessCoreTest,ToolBoundaryTest,ToolAdapterTest,MysqlToolAdapterTest,CanonicalInvocationStoreTest,HarnessContractTest,RagToolContractTest,QueryLogsToolContractTest,MysqlToolContractTest' test` 通过。
|
||||
- OpenSpec:`openspec validate single-react-diagnosis-agent --strict` 通过。
|
||||
- 静态范围:新 Agent 包无 ThreadLocal、手写 while、外层 Graph、多 Agent 类型或 raw response;Controller/ChatService/AiOpsService diff 为空。
|
||||
- 未执行 live E2E:按 ISS-014 阶段门禁统一留到阶段 7。
|
||||
|
||||
## Archive Result
|
||||
|
||||
- 11/11 OpenSpec tasks 完成,`.archive-ready` 已创建。
|
||||
- 主规格已同步至 `openspec/specs/single-react-diagnosis-agent/spec.md`。
|
||||
- Change 已归档至 `openspec/changes/archive/2026-07-21-single-react-diagnosis-agent`。
|
||||
- `devflow/index.md` 和 ISS-014 阶段表已更新为阶段 0-4 archived,下一阶段为 5。
|
||||
- 提交前 schema 自审发现框架默认 BeanOutputConverter 将 `conclusion` 限为 object,与冻结的无证据 `null` 语义冲突;分类为实现设计遗漏,已回写 archived design,新增 nullable schema post-process 与回归测试,规格行为未改变。
|
||||
@@ -1,29 +0,0 @@
|
||||
# Single React Diagnosis Agent Evidence
|
||||
|
||||
## 代码与文档证据
|
||||
|
||||
| 来源 | 证据 | 结论 | 是否已汇报 |
|
||||
|---|---|---|---|
|
||||
| `mvp/issues/active/ISS-014-single-react-agent-harness-aci-ptk-refactor.md` | 阶段 4 明确单 Agent、内部入口、极简上下文、结构化 Draft、无重试和预算验收 | 本 change 不得切换公开入口或删除旧链路 | 是 |
|
||||
| `ChatService.java` + GitNexus references | `createReactAgent` 被旧策略入口调用;复杂路径仍创建 Planner/Executor/Verifier/Composer | 新实现必须是独立内部 use case,不能复用旧 Service 运行职责 | 是 |
|
||||
| Spring AI Alibaba 1.1.2.0 `ReactAgent`/`AgentLlmNode` sources | 框架自带 ReAct loop;非流式 `ModelResponse` 保留 `ChatResponse` Usage | 不手写循环,使用 ModelInterceptor 强制模型/Token 预算 | 是 |
|
||||
| Spring AI Alibaba `ToolCallRequest`/`AgentToolNode` sources | `ToolCallRequest.getToolCallId()` 来自 `AssistantMessage.ToolCall.id()`,Tool interceptor 在 callback 前执行 | 可以精确传播框架 ID,不生成第二套 ID | 是 |
|
||||
| Spring AI Alibaba `DefaultBuilder` + 本地 BeanOutputConverter 输出 | 默认 schema 只允许 object conclusion,但冻结契约允许无证据时 conclusion=null | 生成 schema 必须 post-process nullable conclusion,UseCase 仍严格反序列化 DiagnosisDraft | 是 |
|
||||
| `DiagnosisHarnessCore.java` / `ToolBoundary.java` | Core 提供 model/Token/capacity;ToolBoundary 已负责 Tool reserve/store | Agent 层只 reserve model/context,禁止双扣 Tool budget | 是 |
|
||||
| 阶段 3B/3C adapters | RAG/log/MySQL 都以 `RunContext + ToolCallRequestEnvelope` 进入 ToolBoundary | Tool registry 可直接桥接既有 adapter,不复制投影或安全策略 | 是 |
|
||||
| `AgentLoggingHook.java` | 优先从 RunnableConfig metadata 读取 sessionId/runId | Factory 可复用现有 Hook 注入点,不依赖 ThreadLocal | 是 |
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- 单 Agent 的可验证边界是一个 `ReactAgent.call`,内部允许正常模型/Tool轮次,但外部没有 Agent retry 或第二个报告作者。
|
||||
- ToolCallback 不直接提供 Tool Call ID,必须使用 Alibaba `ToolInterceptor`;已由真实 scripted framework loop 证明 ID 进入 ToolResponseMessage。
|
||||
- `PreviousTurn` 只作为固定上下文,当前 Draft 只允许引用当前 Run Tool result 中的 ID。
|
||||
- `NO_EVIDENCE` 必须以 `conclusion=null`、限定范围的负向观察和 missing info 结束,不能推导健康或排除根因。
|
||||
- 阶段 4 的 L2 内部 API 不影响公开消费者;阶段 5/6A/6B 前 Draft 不可发布。
|
||||
|
||||
## 实现证据
|
||||
|
||||
- 新包 `com.superbiz.agent.harness.agent` 包含 Input/Limits、Prompt loader、Tool registry/interceptor、Model interceptor、Factory 和 UseCase。
|
||||
- `diagnosis-agent-prompt.md` 是唯一新 Diagnosis Agent Prompt,包含 Tool、证据绑定、停止和精确 JSON 规则。
|
||||
- 14 个阶段 4 tests 覆盖框架 model -> Tool -> model、ID、错误、未知 Tool、PreviousTurn、审计 metadata、nullable conclusion schema、no-evidence、解析和预算。
|
||||
- 综合回归同时覆盖 Harness Core、ToolBoundary、3B/3C adapter、canonical store 和冻结 contracts。
|
||||
@@ -1,44 +0,0 @@
|
||||
# Acceptance: single-react-evidence-semantic-guards
|
||||
|
||||
## Result
|
||||
|
||||
- Status: archived
|
||||
- OpenSpec tasks: 14/14 complete
|
||||
- Interface impact: L2 internal
|
||||
- Public protocol: unchanged
|
||||
|
||||
## Static Verification
|
||||
|
||||
- `git diff --check`:阶段文件无 whitespace error;工作区用户已有 `AGENTS.md`/`CLAUDE.md` 仅报告 line-ending warning,未纳入阶段范围。
|
||||
- 公开 `controller`、`ChatService.java`、`AiOpsService.java` diff 为空。
|
||||
- SemanticGuard 包和 prompt 不含 Tool Call ID、raw response、ReactAgent、StateGraph、ThreadLocal 或手写 while。
|
||||
- 新 guard/release 包不包含业务 Agent loop。
|
||||
|
||||
## Script Verification
|
||||
|
||||
- `mvn -q -DskipTests compile`:通过。
|
||||
- Stage-focused `EvidenceGuardTest,SemanticGuardTest,DiagnosisReleaseUseCaseTest`:19 tests,0 failure/error。
|
||||
- Harness/Tool/Agent regression selection:18 suites / 70 tests,0 failure/error/skipped。
|
||||
- `openspec validate single-react-evidence-semantic-guards --strict`:通过。
|
||||
- `openspec validate --specs --strict`:16 passed / 2 failed;失败是前序 `mysql-readonly-tool`、`rag-log-projections` scenario 标题格式,不阻塞本 change,计划阶段 7 统一修复。
|
||||
|
||||
## Browser or Manual Verification
|
||||
|
||||
- Not applicable。阶段 5 没有 UI 或公开入口变化。
|
||||
|
||||
## Not Verified
|
||||
|
||||
- 未运行真实 LLM、Redis、日志和 MySQL live E2E;按 ISS-014 串行门禁统一留到阶段 7。
|
||||
- Provider 是否立即响应 Java thread interrupt 取决于 SDK;Harness 已保证 Future cancel、迟到 Token 记账和迟到结果不释放,阶段 7 需用真实模型观察取消延迟。
|
||||
|
||||
## Remaining Work
|
||||
|
||||
- 阶段 6A:Chat Application Use Case、Intent Router、PreviousTurn 和 Run persistence。
|
||||
- 阶段 6B:公开 SSE 原子切换。
|
||||
- 阶段 7:旧链路清理、全局 spec 格式修复和最终 live E2E。
|
||||
|
||||
## Archive
|
||||
|
||||
- `.archive-ready`: created
|
||||
- OpenSpec archive: `openspec/changes/archive/2026-07-21-single-react-evidence-semantic-guards`
|
||||
- Main spec: `openspec/specs/single-react-evidence-semantic-guards/spec.md`
|
||||
@@ -1,32 +0,0 @@
|
||||
# Brief: single-react-evidence-semantic-guards
|
||||
|
||||
## Background
|
||||
|
||||
阶段 4 已能生成带框架 Tool Call ID 的 `DiagnosisDraft`,但草稿在发布前还缺少当前 Run 证据验真、独立语义审查和 fail-closed 释放边界。
|
||||
|
||||
## Goal
|
||||
|
||||
在不恢复业务 Graph、不切换公开入口的前提下,实现确定性 EvidenceGuard、一次语义不变的结构修复、无 Tool/无记忆的单轮 SemanticGuard,以及只发布原 Draft 或固定 SafeFallback 的内部 release use case。
|
||||
|
||||
## Scope
|
||||
|
||||
- Draft 结构、Analysis/报告引用和 canonical Tool invocation 验真。
|
||||
- RAG/log/MySQL verified evidence snapshot。
|
||||
- Evidence repair 单次调用与语义不变约束。
|
||||
- SemanticGuard 模型/Token/字节预算、超时、取消、技术重试和严格二元输出。
|
||||
- SUPPORTED/UNSUPPORTED/unavailable/evidence-failed release policy。
|
||||
- focused tests、Harness/Tool/Agent 回归和静态范围验证。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- 不切换 Chat/AiOps/SSE 公开协议。
|
||||
- 不实现 Intent Router、PreviousTurn、Run persistence 或最终报告渲染。
|
||||
- 不删除旧 Gatekeeper/Verifier/Composer/多 Agent 链路。
|
||||
- 不运行 live model/Redis/MySQL E2E;统一留到阶段 7。
|
||||
|
||||
## Metadata
|
||||
|
||||
- Scale: complex
|
||||
- Interface impact: L2 internal
|
||||
- OpenSpec: `single-react-evidence-semantic-guards`
|
||||
- Parent issue: `ISS-014`
|
||||
@@ -1,144 +0,0 @@
|
||||
# Decisions: single-react-evidence-semantic-guards
|
||||
|
||||
## Discover Status
|
||||
|
||||
- Checkpoint: Discover
|
||||
- Capability source: `sm-flow`,使用 `grill-with-docs` 做 evidence-driven 澄清;`codebase-retrieval`、LSP 和 GitNexus MCP 在当前会话不可用,降级为既有 GitNexus 研究结论、`rg` 调用点核对和逐文件源码阅读。
|
||||
- Scale: complex。变更跨 canonical store、三类 Tool projection、模型预算、超时/取消、结构修复、语义审查和释放边界,但不切换公开协议。
|
||||
- `devflow/index.md` 命中阶段 0-4 的设计冻结、RunContext、canonical store、Tool projection 和 Diagnosis Agent;没有与当前 OpenSpec 冲突的 ADR。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| # | 维度 | 问题 | 模式 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | 术语 | EvidenceGuard 是否判断证据足以推出结论? | evidence-driven | 已解决 |
|
||||
| Q2 | 边界 | verified snapshot 能读取哪些 canonical 字段,并向 SemanticGuard 暴露哪些内容? | evidence-driven | 已解决 |
|
||||
| Q3 | 边界 | `NO_EVIDENCE` 能支持哪类 Analysis? | evidence-driven | 已解决 |
|
||||
| Q4 | 修复 | 首次 EvidenceGuard 失败允许如何修复,是否可重跑 Agent 或 Tool? | evidence-driven | 已解决 |
|
||||
| Q5 | 语义 | SemanticGuard 是否拥有 Tool、记忆、ReAct loop 或报告写作能力? | evidence-driven | 已解决 |
|
||||
| Q6 | 重试 | 哪些 SemanticGuard 结果允许第二次 attempt? | evidence-driven | 已解决 |
|
||||
| Q7 | 超时 | 单轮模型超时和 Run 取消如何终止后台调用? | evidence-driven | 已解决 |
|
||||
| Q8 | 释放 | 三种 Fallback 能否包含 Draft、reason 或未验真来源? | evidence-driven | 已解决 |
|
||||
| Q9 | 接口 | 阶段 5 是否切换公开入口或修改 SSE/持久化协议? | evidence-driven | 已解决 |
|
||||
| Q10 | 验收 | 如何证明不存在隐式 Agent/repair/retry loop? | evidence-driven | 已解决 |
|
||||
|
||||
## Evidence-driven
|
||||
|
||||
| 结论 | 证据来源 | 是否已汇报用户 |
|
||||
|---|---|---|
|
||||
| EvidenceGuard 只验证结构、引用和 canonical invocation 真实性,不判断 Analysis/Conclusion 的语义充分性。 | ISS-014 4.3、阶段 5;glossary `EvidenceGuard` | 已汇报 |
|
||||
| Store 只能按 `ToolCallKeyFactory.create(runId, toolCallId)` 查找;可引用记录必须是当前 Run、`READY`、含 `agent_result` 且状态为 `EVIDENCE_FOUND|NO_EVIDENCE`。 | `CanonicalInvocationStore`、`CanonicalToolInvocation.isReferencableBy` | 已汇报 |
|
||||
| Snapshot 解析 `agent_result` 和必要的有界 request 字段,不读取 `raw_response`;输出按 `analysis_id` 分组且不包含 Tool Call ID。 | ISS-014 4.4、10.2、已冻结 Tool contracts | 已汇报 |
|
||||
| `NORMAL` 只绑定 `EVIDENCE_FOUND`;`NEGATIVE_OBSERVATION` 只绑定 `NO_EVIDENCE`,且零结果范围来自投影/请求。 | ISS-014 4.3、10.2;`EvidenceStatus` glossary | 已汇报 |
|
||||
| Evidence repair 只在首次物理验真失败后执行一次无 Tool单轮模型调用,不重跑 Diagnosis Agent 或 Tool loop。 | ISS-014 10.3、阶段 5、重试边界决策 | 已汇报 |
|
||||
| SemanticGuard 复用同一 `ChatModel`,使用全新 `Prompt` 单轮调用,无 Tool/记忆/ReAct;只返回二元 verdict 和审计 reason。 | ISS-014 4.4、阶段 5;Spring AI `ChatModel.call(Prompt)` | 已汇报 |
|
||||
| 仅超时、传输、解析或 Schema 技术失败可重试一次;`UNSUPPORTED` 是有效业务结果,不重试。 | `HarnessRetryPolicies.strict().semanticGuard()`、ISS-014 重试策略 | 已汇报 |
|
||||
| `ChatResponseMetadata.Usage` 可复用 Core 的 model/Token 预算;受控 `Future.get(timeout)` 可在超时或 Run 取消时取消任务。 | `HarnessModelInterceptor`、`DiagnosisHarnessCore`、`RunCancellation` | 已汇报 |
|
||||
| `EVIDENCE_VALIDATION_FAILED` 的来源必须为空;其余 Fallback 只能包含已验真来源,不包含 Draft 或 SemanticGuard reason。 | ISS-014 10.3、阶段 5;`SafeFallback`/`FallbackType` | 已汇报 |
|
||||
| 阶段 5 只新增内部用例,公开入口切换留到阶段 6B。 | ISS-014 阶段顺序和 6B 门禁 | 已汇报 |
|
||||
|
||||
## User-interview
|
||||
|
||||
- 本阶段没有新增 user-interview 问题。上述方向、范围、修复次数、模型复用、超时/重试、Fallback 和阶段串行规则均已在 ISS-014 评审及前序对话中由用户确认。
|
||||
|
||||
## Key Decisions
|
||||
|
||||
- Snapshot 使用 Tool-specific adapter 严格解析冻结 projection;未知 Tool、ID 不一致、projection 反序列化失败或 projection 的 EvidenceStatus 与 canonical record 不一致均 fail closed。
|
||||
- MySQL 的逻辑数据源和查询范围来自 canonical `request`,行/列和值来自 `agent_result`;RAG/log 以 `agent_result` 自带的稳定来源和范围为准。
|
||||
- SemanticGuard 使用直接 `ChatModel.call(Prompt)`,不创建第二个 `ReactAgent`;模型调用由受控 Executor 执行,超时/取消时调用 `Future.cancel(true)`。
|
||||
- Evidence repair 与 SemanticGuard 共用同一模型抽象,但各自拥有独立 prompt、严格输出类型和预算;repair 策略固定一次 attempt,不能嵌套 retry executor。
|
||||
- Release use case 只在 EvidenceGuard 成功后调用 SemanticGuard;SUPPORTED 返回原 Draft 对象,所有其他路径只返回固定 `SafeFallback`。
|
||||
- 不创建 ADR:这些是 ISS-014 已冻结架构的阶段实现,不产生新的难逆转跨项目决策。
|
||||
|
||||
## OpenSpec Backfill
|
||||
|
||||
- 需进入 proposal/design/spec/tasks:EvidenceGuard 规则、Tool-specific snapshot、无 raw/ID 泄漏、repair 单次边界、SemanticGuard 隔离/预算/超时/重试、原样发布与三类 Fallback、L2/公开隔离。
|
||||
- 不进入本阶段:公开 Chat/SSE 装配、Run 持久化、旧多 Agent 删除和 live E2E。
|
||||
|
||||
## Cross-artifact Alignment
|
||||
|
||||
| 上游 -> 下游 | 检查内容 | 状态 |
|
||||
|---|---|---|
|
||||
| ISS-014/brief -> proposal | 物理验真、结构修复、隔离语义审查、固定 Fallback、阶段边界 | 已对齐 |
|
||||
| proposal -> design | Store ownership、Tool-specific snapshot、timeout/cancel/retry、唯一报告作者和 L2 影响 | 已对齐 |
|
||||
| design -> specs/tasks | 每个关键决策均有可观察 requirement 和对应实现/测试切片 | 已对齐 |
|
||||
| specs -> tasks | 9 组 requirements 覆盖为 Evidence、model boundary、repair/release 和回归验证任务 | 已对齐 |
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
- 能力来源:`zoom-out`,使用 glossary 的 Diagnosis Harness、EvidenceGuard、SemanticGuard、RunContext、Invocation Status 和 Evidence Status 术语。
|
||||
- 链路为 `query + Draft + RunContext -> EvidenceGuard/store -> optional repair/shared model boundary -> SemanticGuard/shared model boundary -> original Draft or fixed Fallback`,没有外层 Graph 或第二个 Tool loop。
|
||||
- Store 拥有物理调用记录,EvidenceGuard 只读并生成 snapshot;Diagnosis Agent 拥有报告语义,repair 只修 ID,SemanticGuard 只审查,release 只做二选一,数据所有权没有重叠。
|
||||
- 最大运行风险是 provider 忽略 interrupt;design 要求 Future cancel、迟到 Token 记录和 `core.checkActive` 丢弃迟到结果,阶段 6A 再负责 Run 终态。
|
||||
- 架构审计未发现与阶段 0-4 或 ADR 冲突;所有风险缓解已回写 design/spec/tasks。
|
||||
|
||||
## Interface Impact
|
||||
|
||||
- 级别:L2 内部接口。
|
||||
- 变更对象:新增 guard/release records、interfaces、use cases、prompts 和 tests;现有方法签名不变。
|
||||
- 消费者:本阶段只有 focused tests,阶段 6A 才接入 production application use case。
|
||||
- 兼容性:公开 HTTP/SSE、Controller DTO、数据库、Redis key schema 和旧 Chat/AiOps 路径不变。
|
||||
|
||||
## Commit Gate Preflight
|
||||
|
||||
- proposal、design、specs、tasks 完整,`openspec status` 为 complete,`openspec validate single-react-evidence-semantic-guards --strict` 通过。
|
||||
- Question pool 全部为已汇报的 evidence-driven 结论;无未确认 user-interview、接口等级或风险接受问题。
|
||||
- Cross-artifact 四段对齐无 gap;架构审计的数据所有权、模型取消和唯一报告作者约束已进入 design/spec/tasks。
|
||||
- 接口影响为 L2,仅新增内部 Java API;公开 Controller/SSE/JPA/Redis schema/旧 ChatService 保持不变。
|
||||
- Apply、Archive 和阶段 Git commit 使用用户对 ISS-014 各阶段的持续授权;实现必须严格限制为 Committed OpenSpec。
|
||||
- `.committed` 已创建,Committed OpenSpec 可进入 Apply。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### Reference Implementations
|
||||
|
||||
- `harness/tool/store/CanonicalInvocationStore.java`、`CanonicalToolInvocation.java`、`ToolCallKeyFactory.java`:当前 Run 物理验真和 lifecycle 真理源。
|
||||
- `harness/tool/projection/RagResultProjector.java`、`QueryLogsResultProjector.java`、`harness/tool/mysql/MysqlResultProjector.java`:三类 `agent_result` 的唯一生产者和有界字段来源。
|
||||
- `harness/agent/HarnessModelInterceptor.java`:模型调用前预算、响应 Usage 记账和 late-result active check 模式。
|
||||
- `harness/retry/HarnessRetryExecutor.java`、`HarnessRetryPolicies.java`:SemanticGuard 两次技术 attempt 与 repair 一次 attempt 的装配边界。
|
||||
- `harness/core/RunCancellation.java`:取消 callback 注册和 first-cancel 语义。
|
||||
- `service/ExecutorGatekeeperService.java`:仅参考报告内部引用检查思想,不复用旧 Map/JPA/session DTO 或规则目录。
|
||||
|
||||
### Technology Stack
|
||||
|
||||
- Jackson strict `ObjectReader` 解析 frozen Draft/Tool projections;Tool-specific adapter 生成 typed snapshot,不透传 JsonNode/raw response。
|
||||
- Spring AI `ChatModel.call(Prompt)` 执行无 Tool 单轮 guard;`ChatResponseMetadata.Usage` 接入现有 Core Token 预算。
|
||||
- Java 17 `ExecutorService/Future.get(timeout)` 提供 per-attempt timeout,`Future.cancel(true)` 接入 Run cancellation;Semantic 总时限由 monotonic elapsed time 控制。
|
||||
- JUnit 5 scripted `ChatModel` 和 in-memory canonical store 作为外部边界 fake;测试只通过 EvidenceGuard/SemanticGuard/Release use case 公共接口断言行为。
|
||||
- 无 Controller、MQ、JPA、Flyway 或新 Maven dependency;不需要新共享基础设施。
|
||||
|
||||
## Apply Progress
|
||||
|
||||
- 首模块对齐:EvidenceGuard typed contracts、Draft/reference checks、current-Run canonical validation 和 RAG/log/MySQL snapshot adapters 已完成,tasks 1.1-1.4 完成。
|
||||
- 8 个 `EvidenceGuardTest` 行为测试通过;快照序列化不含 Tool Call ID 或 `raw_response`,`NO_EVIDENCE` 仅在 `NEGATIVE_OBSERVATION` 下进入带 scope/zero-match 的快照。
|
||||
- TODO:tasks 2.1-4.2,尚未实现模型边界、SemanticGuard、repair/release 和综合回归。
|
||||
- REVIEW 发现 corrupted Store key 下 record ID 可能与 Draft reference 不同;分类为代码偏离,已增加 exact canonical ID 校验和回归测试,无需改变规格方向。
|
||||
- REVIEW 发现 fallback `DiagnosisReleaseResult` 携带完整 snapshot 会通过 `analysis_text` 间接泄漏 Draft;分类为规格安全边界细化,已回写 design/spec,并让 fallback result 强制使用空 snapshot,安全来源只保留在 `SafeFallback.verified_sources`。
|
||||
|
||||
## Apply Result
|
||||
|
||||
- 新增确定性 EvidenceGuard:校验 typed Draft、唯一 Analysis ID、报告引用、exact current-Run Tool ID、READY lifecycle、agent result、Evidence Status 与 Analysis Kind,并严格展开 RAG/log/MySQL projection。
|
||||
- verified snapshot 按 Analysis ID 分组,只含稳定 source/scope/timestamp/excerpt/values;SemanticGuard 输入不含 Tool Call ID、Redis key 或 raw response。
|
||||
- 新增共享 `GuardModelCall`:复用系统 ChatModel,执行 Core model/Token/Run byte budget、per-attempt timeout、total timeout、Future cancellation 和 late-result active check。
|
||||
- 新增无 Tool/无记忆/无 ReAct 的单轮 SemanticGuard,严格解析 `SUPPORTED|UNSUPPORTED + reason`;仅技术失败使用既有两次 attempt,业务 UNSUPPORTED 不重试。
|
||||
- 新增一次 EvidenceRepair,只允许 ID/reference 修复;任何可见文本、kind、顺序、human-confirmation 或 limitations 变化都直接 Evidence fallback。
|
||||
- 新增 DiagnosisReleaseUseCase 和固定 SafeFallbackFactory:SUPPORTED 原样返回 Draft;evidence failed、semantic unsupported/unavailable 均不返回 Draft、完整 snapshot 或审计 reason。
|
||||
- 公开 Controller、ChatService、AiOpsService、SSE、JPA/Flyway 和旧多 Agent 链路无修改。
|
||||
|
||||
## Apply Verification
|
||||
|
||||
- 编译:`mvn -q -DskipTests compile` 通过。
|
||||
- 阶段 5 focused:`EvidenceGuardTest` 9、`SemanticGuardTest` 4、`DiagnosisReleaseUseCaseTest` 6,共 19 tests,0 failure/error。
|
||||
- 综合回归:阶段 5 + Harness Core/Retry/Tool boundary/store/projections/contracts + Diagnosis Agent,共 18 suites / 70 tests,0 failure/error/skipped。
|
||||
- OpenSpec:`openspec validate single-react-evidence-semantic-guards --strict` 通过。
|
||||
- 静态范围:公开 Controller/ChatService/AiOpsService diff 为空;SemanticGuard 无 Tool ID/raw response/ReactAgent/StateGraph/ThreadLocal/手写 while;新 guard/release 包无业务 Agent loop。
|
||||
- 仓库级 `openspec validate --specs --strict` 为 16 passed / 2 failed;失败仍是前序 `mysql-readonly-tool`、`rag-log-projections` 的 scenario 标题格式,按计划阶段 7 统一修复。
|
||||
- 未执行 live E2E:按 ISS-014 阶段门禁统一留到阶段 7。
|
||||
|
||||
## Archive Result
|
||||
|
||||
- 14/14 OpenSpec tasks 完成,`.archive-ready` 已创建。
|
||||
- 主规格已同步至 `openspec/specs/single-react-evidence-semantic-guards/spec.md`,新增 9 个 requirements。
|
||||
- Change 已归档至 `openspec/changes/archive/2026-07-21-single-react-evidence-semantic-guards`。
|
||||
- `devflow/index.md` 和 ISS-014 阶段表已更新为阶段 0-5 archived,下一阶段为 6A。
|
||||
- 未创建 ADR/compound knowledge:本阶段落实 ISS-014 已冻结边界,没有新的跨项目难逆转决策。
|
||||
@@ -1,29 +0,0 @@
|
||||
# Evidence: single-react-evidence-semantic-guards
|
||||
|
||||
## Code and Contract Evidence
|
||||
|
||||
- `CanonicalInvocationStore` 只提供 key lookup;`ToolCallKeyFactory` 冻结 `runId + toolCallId` 隔离,`CanonicalToolInvocation` 冻结 READY/agent_result/evidence status 可引用条件。
|
||||
- `RagToolResult`、`QueryLogsToolResult`、`MysqlToolResult` 是 Agent-facing 有界 projection,足以构造 snapshot;只有 MySQL 的逻辑数据源/SQL/params 需要从 canonical request 补足。
|
||||
- `AnalysisKind.accepts` 已冻结 `NORMAL -> EVIDENCE_FOUND`、`NEGATIVE_OBSERVATION -> NO_EVIDENCE`。
|
||||
- `HarnessRetryPolicies.strict()` 已冻结 SemanticGuard 两次技术 attempt 和 Evidence repair 一次 attempt。
|
||||
- `ChatModel.call(Prompt)`、`ChatResponseMetadata.Usage` 和 `RunCancellation.onCancel` 支持直接单轮模型调用、Token 记账与 Future cancellation,无需 ReactAgent。
|
||||
|
||||
## Confirmed Boundaries
|
||||
|
||||
- EvidenceGuard 不判断证据是否支持结论,只验证结构、引用和物理真实性。
|
||||
- SemanticGuard 只接收原始 Query、移除 Tool ID 的完整 Draft view 和 verified snapshot,不访问 Redis/raw response。
|
||||
- Evidence repair 只修改 ID/reference;用户可见语义发生任何变化即失败。
|
||||
- `UNSUPPORTED` 是有效业务结果,不重试;只有 timeout/transport/parse/schema 技术失败可进行第二次 attempt。
|
||||
- Fallback 不含 Draft、完整 snapshot 或 SemanticGuard reason;Evidence failure 的 verified sources 为空。
|
||||
|
||||
## Review Findings
|
||||
|
||||
- 增加 canonical record ID 与 Draft reference 的 exact match,防止 corrupted key 映射被误信任。
|
||||
- Fallback release result 强制使用空 snapshot,防止 `analysis_text` 通过误序列化泄漏 Draft;安全来源只保留在 `SafeFallback.verified_sources`。
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
- Stage-focused: 19 tests,覆盖 EvidenceGuard 9、SemanticGuard 4、DiagnosisReleaseUseCase 6。
|
||||
- Regression: 18 suites / 70 tests,0 failure/error/skipped。
|
||||
- Maven compile 和 change strict validation 通过。
|
||||
- 公开 Controller/ChatService/AiOpsService 零 diff;SemanticGuard 无 Tool ID/raw/ReactAgent/Graph/ThreadLocal/手写 loop。
|
||||
@@ -1,45 +0,0 @@
|
||||
# Acceptance: single-react-harness-run-context
|
||||
|
||||
## 实现结果
|
||||
|
||||
- 新增显式 `RunContext`、取消信号、deadline 检查、Run Lifecycle 和 first-terminal-wins。
|
||||
- 新增 caller-supplied limits、线程安全 Model/Tool/Token/Run bytes 预算和容量 CAS。
|
||||
- 新增 strict typed retry policies/executor,记录每个实际 attempt 并阻止取消/预算异常误重试。
|
||||
- 新增无 Redis 依赖的 ToolCallKeyFactory,精确保留框架 Tool Call ID。
|
||||
- Spring AI `spring.ai.retry.max-attempts` 设置为 1;未修改 provider/model routing。
|
||||
- 未接入旧 Chat/AIOps/Controller、ThreadLocal、JPA、Redis、Agent 或公开协议。
|
||||
|
||||
## 静态验证
|
||||
|
||||
- `openspec validate single-react-harness-run-context --strict`:通过。
|
||||
- 新 Harness 包 `rg`:无 ThreadLocal/current-holder/Redis 引用。
|
||||
- 旧 Chat/AIOps/Controller/JPA 调用链 diff:为空。
|
||||
- 受保护配置检查:仅新增 `spring.ai.retry.max-attempts: 1`,model routing/provider 保持不变。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
- `mvn -q -DskipTests compile`:通过。
|
||||
- Core focused suite:通过。
|
||||
- 综合回归 suite(阶段 0/1 契约 + 阶段 2 Core + ChatController):通过。
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
- 不适用。本阶段没有 UI、Controller、SSE 或公开协议变化。
|
||||
|
||||
## 未验证
|
||||
|
||||
- 未执行真实模型调用、Redis、CLS、MySQL 或客户端断开 live E2E;这些属于后续 Tool store/adapter/最终 E2E 门禁。
|
||||
- 未将 RunContext 接入旧 ChatService;这是本阶段明确非目标,阶段 6A 才接入。
|
||||
- `RunContext` 取消对已进入的同步第三方调用仍是协作式;实际 HTTP/JDBC future 取消留给后续 adapter。
|
||||
- Provider 侧凭据轮换状态不由仓库证明。
|
||||
|
||||
## 剩余风险与后续门禁
|
||||
|
||||
- 关闭 SDK 隐式 retry 会使旧路径瞬时错误不再自动重试,直到后续 Router/SemanticGuard 接入 Harness;该变化已记录并可通过恢复配置回滚。
|
||||
- 下一阶段 3A 必须在 ToolInterceptor 接收 RunContext 和框架 Tool Call ID,直接复用 Key/Capacity/Cancellation 门禁。
|
||||
|
||||
## 状态
|
||||
|
||||
- Stage acceptance: accepted
|
||||
- OpenSpec archive: archived at `openspec/changes/archive/2026-07-21-single-react-harness-run-context`
|
||||
- Main spec sync: `openspec/specs/diagnosis-harness-run-context/spec.md`(8 added requirements)
|
||||
@@ -1,32 +0,0 @@
|
||||
# Brief: single-react-harness-run-context
|
||||
|
||||
## 背景
|
||||
|
||||
旧 Chat/AIOps 通过多个 ThreadLocal 和业务方法内状态机传播 session/run/token/retry,无法成为后续 Tool、Agent、Guard 和新入口的稳定共同边界。Spring AI 默认 10 attempts 还会制造未被 Harness 记录的隐藏重试。
|
||||
|
||||
## 目标
|
||||
|
||||
- 建立显式、结构不可变、可异步传播的 RunContext。
|
||||
- 集中实现 deadline、协作式取消、线程安全预算和唯一 Run 终态。
|
||||
- 实现类型化、最多两次 attempt、逐 attempt 记录的 Harness retry。
|
||||
- 提供阶段 3A 可直接使用的 Tool Call Key Factory 和单 Run 容量计数器。
|
||||
- 将 Spring AI 底层 retry 压为一次。
|
||||
|
||||
## 范围
|
||||
|
||||
- 新增 Harness Core/Retry/Tool Store foundation 类型和 focused Fake tests。
|
||||
- 更新 `application.yml` 的 Spring AI retry 配置。
|
||||
- 更新 glossary 和 OpenSpec/devflow 档案。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不接入旧 ChatService/AiOpsService/Controller/SSE。
|
||||
- 不读写现有 ThreadLocal,不删除旧实现。
|
||||
- 不写 `diagnosis_run` 或 Redis,不实现 Tool projection。
|
||||
|
||||
## 元数据
|
||||
|
||||
- 分档:complex
|
||||
- 接口影响:L2;另有关闭旧 SDK 隐式 retry 的有意内部行为变化
|
||||
- 关联 Issue:ISS-014 阶段 2
|
||||
- 关联 OpenSpec:`openspec/changes/single-react-harness-run-context`
|
||||
@@ -1,110 +0,0 @@
|
||||
# Decisions: single-react-harness-run-context
|
||||
|
||||
## 规模与入口
|
||||
|
||||
- 分档:complex。
|
||||
- 入口:ISS-014 阶段 2;阶段 0/1 已分别由 Git commit `58c3910`、`4274f33` 固化并 Archive。
|
||||
- 目标:建立后续 Tool、Agent、Guard 和入口共同依赖的显式 Harness 运行边界,不接旧 ChatService。
|
||||
|
||||
## Context
|
||||
|
||||
- `devflow/index.md` 命中 design freeze、ACI contracts 和 session/run trace isolation。
|
||||
- 当前 `SessionContextHolder`、`VerifierContextHolder`、`TokenUsageHolder` 使用 ThreadLocal;新 Harness 禁止复用。
|
||||
- 当前 ChatService 自行生成 runId、写 `diagnosis_run`、执行两轮 retry loop 并在 finally 清理 ThreadLocal,职责与新 Harness 边界冲突。
|
||||
- `DiagnosisRun.status` 当前是字符串 `PENDING/RUNNING/SUCCESS/FAILED`;本阶段不修改实体或迁移,由后续应用用例映射。
|
||||
- Spring AI 1.1.7 `SpringAiRetryProperties` 的配置前缀是 `spring.ai.retry`,默认 `maxAttempts=10`。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| 维度 | 问题 | 模式 | 证据与结论 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| 术语 | “不可变 RunContext”是否意味着预算/取消也不能变化? | evidence-driven | ISS 要求上下文不可变同时要求计数/取消/终态;采用结构不可变 record + 线程安全单 Run 状态句柄。 | 已解决并汇报 |
|
||||
| 术语 | Run 与 DiagnosisRun 是否在阶段 2 直接持久化绑定? | evidence-driven | 阶段 2 只建 Core,阶段 6A 才接应用用例;本阶段生命周期为内存执行真理,不改 JPA。 | 已解决并汇报 |
|
||||
| 边界 | 是否迁移旧 ThreadLocal/ChatService 调用? | evidence-driven | ISS 1109-1111 明确禁止 ThreadLocal 和旧 ChatService 临时适配;只新增零消费者 Core。 | 已解决并汇报 |
|
||||
| 边界 | 取消是否承诺立即中断同步模型调用? | evidence-driven | 阶段 0 已确认分层取消;阻止后续边界并执行资源回调,不承诺不可证明的硬中断。 | 已解决并汇报 |
|
||||
| 验收 | 唯一终态如何证明? | evidence-driven | atomic first-terminal-wins lifecycle,并用取消/预算/异常/成功竞态测试证明后续终态不能覆盖。 | 已解决并汇报 |
|
||||
| 验收 | 异步传播如何证明不依赖 ThreadLocal? | evidence-driven | Fake Tool 在 `CompletableFuture` 线程只接收显式 RunContext,并验证相同 session/run/state handles。 | 已解决并汇报 |
|
||||
| 技术 | 隐藏重试如何关闭? | evidence-driven | 本地依赖 `SpringAiRetryProperties` 证实 `spring.ai.retry.max-attempts` 默认 10;配置改为 1 并加配置测试。 | 已解决并汇报 |
|
||||
| 技术 | 尚未校准的预算默认值如何处理? | evidence-driven | ISS 要求集中配置且不伪造数值;Core 接受显式 limits,不内置默认预算,后续 Spring wiring 决定配置值。 | 已解决并汇报 |
|
||||
| 技术 | Tool Call Key 是否生成 Tool ID? | evidence-driven | 阶段 0/1 冻结框架 ID;Factory 仅验证安全 segment 并拼接,不生成或改写。 | 已解决并汇报 |
|
||||
|
||||
## Grill 结论
|
||||
|
||||
- 术语、边界、验收和技术问题均可由已确认 ISS、现有代码和本地依赖 API 证明。
|
||||
- 没有新的产品偏好、公开协议或风险接受度问题需要 `user-interview`;短期关闭旧 SDK retry 的影响已在 proposal 明示。
|
||||
- `grill-with-docs` 的代码可证问题已先查证并向用户汇报;所有结论均已回写 proposal。
|
||||
|
||||
## 能力与工具限制
|
||||
|
||||
- Discover 能力来源:`sm-flow` + `grill-with-docs`。
|
||||
- 当前工具集没有 `codebase-retrieval` 和 LSP;使用 `rg`、源码阅读、本地依赖 `jar/javap`、编译和 focused tests 补足调用链与 API 核对。
|
||||
|
||||
## Cross-artifact 对齐
|
||||
|
||||
| 链路 | 状态 | 结论 |
|
||||
|---|---|---|
|
||||
| brief 目标/范围/非目标 -> proposal | 已对齐 | 显式 context、Core、预算/取消/终态、retry、key/capacity、隐藏 retry 和不接旧 runtime 全部覆盖。 |
|
||||
| proposal 范围/约束/承诺 -> design | 已对齐 | 类职责、并发语义、first-wins、配置变化、迁移和回滚均有明确设计。 |
|
||||
| design 决策/接口影响/风险 -> specs/tasks | 已对齐 | 每个状态边界都有 scenario,配置行为变化和 zero-consumer 边界有独立任务与验证。 |
|
||||
| specs 可观察行为 -> tasks | 已对齐 | 8 条 requirements 分解为 primitives、budget、Core、retry、key、配置和三层验证。 |
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
- 能力来源:`zoom-out`,使用 glossary 的 RunContext、Run Lifecycle、Run Budget、Harness Retry Policy 和 Diagnosis Run 术语。
|
||||
- 输入链路为未来 application use case 创建 RunContext,处理链路由 Core/Retry/Key/Capacity 通过显式参数消费,输出为唯一 RunTermination;当前 runtime 不接入。
|
||||
- RunContext 拥有单 Run 内存状态,应用用例拥有数据库映射,Tool store 拥有 Redis invocation;数据所有权没有重叠。
|
||||
- Core 不保存全局 Run map、不调用 Agent/数据库/Redis、不实现循环编排,因此不会演变为工作流引擎。
|
||||
- 最大风险是关闭 SDK retry 对旧路径的短期行为影响;已作为显式配置变更进入 proposal/spec/test 和回滚说明,无 ADR 冲突。
|
||||
|
||||
## Commit Gate Preflight
|
||||
|
||||
- proposal、design、specs、tasks 完整,OpenSpec status complete,strict validation 通过。
|
||||
- question pool 无未汇报 evidence-driven 结论、无未确认 user-interview 问题。
|
||||
- 接口影响 L2;`spring.ai.retry.max-attempts=1` 的有意内部行为变化已明确影响和回滚边界。
|
||||
- cross-artifact 四段对齐无 gap,架构审计约束已进入 design/spec/tasks。
|
||||
- Apply 持续授权已存在;执行范围严格限制为新 Harness foundation、配置 override 和 focused tests。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### 参考实现与反例
|
||||
|
||||
- `SessionContextHolder`:ThreadLocal session/run fallback,新 Harness 明确禁止复用。
|
||||
- `TokenUsageHolder` / `TokenTrackingChatModel`:当前只记录 total token 且依赖 ThreadLocal,后续 model boundary 应改为显式 RunBudget;本阶段不改旧类。
|
||||
- `ChatService.executeChatComplex`:当前业务方法内创建 Run、两轮 retry、写终态和清理 ThreadLocal,是后续替换对象,不是 Core 参考实现。
|
||||
- `DiagnosisRun`:现有持久化字段和字符串状态;本阶段只确认映射边界,不修改实体或 Repository。
|
||||
- Spring AI 1.1.7 `SpringAiRetryProperties`:`spring.ai.retry` 前缀、默认 `maxAttempts=10`,支持精确配置 override。
|
||||
|
||||
### 技术栈清单
|
||||
|
||||
- Java 17 record 表达结构不可变 context/limits/snapshot/policy/attempt。
|
||||
- `AtomicReference` 实现 first-reason/first-terminal-wins;`AtomicLong` 实现 capacity CAS;同步临界区维护复合预算一致性。
|
||||
- `Clock` 和 `Supplier<String>` 注入保证 deadline/ID 可测试,不引入 scheduler 或全局 registry。
|
||||
- SLF4J 只记录取消 callback 异常,不记录用户输入、Tool payload 或凭据。
|
||||
- SnakeYAML 直接解析 classpath `application.yml` 验证 retry override,不启动外部 MySQL/Redis/Milvus/模型。
|
||||
|
||||
### 新建基础设施
|
||||
|
||||
- `harness.core`:RunContext、Cancellation、Lifecycle、Budget、Capacity、Core 和类型化异常/状态。
|
||||
- `harness.retry`:RetryFailure/Policy/Policies/Attempt/Executor/Exception 与函数接口。
|
||||
- `harness.tool.store.ToolCallKeyFactory`:纯 Key 构造,不访问 Redis。
|
||||
- focused unit tests 与 Fake Model/Tool;无需新 Maven 依赖。
|
||||
|
||||
### 影响半径
|
||||
|
||||
- 新生产包在本阶段保持零消费者。
|
||||
- 唯一现有运行配置变化为 `spring.ai.retry.max-attempts=1`;Model 路由、provider、Controller、JPA 和 Redis 配置保持不变。
|
||||
|
||||
## Apply 结果
|
||||
|
||||
- 冲突分类:未发现 OpenSpec 遗漏、代码偏离或方向不确定项;一次自审发现 RetryExecutor 需要无条件拦截预算/取消异常,已回写代码并通过回归测试。
|
||||
- 新增 `RunContext`、Cancellation、Lifecycle、Budget、Capacity、DiagnosisHarnessCore、typed Retry 和 ToolCallKeyFactory;未接旧 Chat/AIOps/Controller/Redis/JPA。
|
||||
- Spring AI 全局 retry 已由默认 10 压为 1;Harness strict policies 只允许 Router/SemanticGuard 技术失败一次显式重试。
|
||||
- 首模块对齐:Run state/budget/Core/retry/key/config 与 design/tasks 全部完成;Tool interceptor/store/Agent/应用用例仍留给后续阶段。
|
||||
|
||||
## Apply 验证
|
||||
|
||||
- 编译:`mvn -q -DskipTests compile`:通过。
|
||||
- Core focused:`mvn -q '-Dtest=RunContextTest,RunBudgetTest,DiagnosisHarnessCoreTest,HarnessRetryExecutorTest,ToolCallKeyFactoryTest,SpringAiRetryConfigurationTest' test`:通过(加固后复跑通过)。
|
||||
- 综合回归:`mvn -q '-Dtest=HarnessContractTest,RagToolContractTest,QueryLogsToolContractTest,MysqlToolContractTest,RunContextTest,RunBudgetTest,DiagnosisHarnessCoreTest,HarnessRetryExecutorTest,ToolCallKeyFactoryTest,SpringAiRetryConfigurationTest,ChatControllerTest' test`:通过。
|
||||
- 静态 scope:新 Harness 包无 ThreadLocal/current-holder/Redis 引用;旧 Chat/AIOps/Controller/JPA 调用链 diff 为空;模型路由/provider 未改。
|
||||
- OpenSpec:`openspec validate single-react-harness-run-context --strict`:通过。
|
||||
@@ -1,25 +0,0 @@
|
||||
# Evidence: single-react-harness-run-context
|
||||
|
||||
## 文档与依赖证据
|
||||
|
||||
- ISS-014 4.2/阶段 2 要求显式 `RunContext`、deadline、取消、预算、retry、Key Factory 和 no-ThreadLocal 边界。
|
||||
- 阶段 0/1 OpenSpec 已冻结框架 `tool_call_id`、两套状态语义和后续阶段串行门禁。
|
||||
- 本地 Spring AI 1.1.7 `SpringAiRetryProperties` 的 `@ConfigurationProperties("spring.ai.retry")` 默认 `maxAttempts=10`;配置已覆盖为 1。
|
||||
|
||||
## 代码证据
|
||||
|
||||
- `SessionContextHolder`、`TokenUsageHolder`、`VerifierContextHolder` 当前是旧链路 ThreadLocal;新 `com.superbiz.agent.harness` 包无任何 holder/ThreadLocal/Redis 引用。
|
||||
- `ChatService.executeChatComplex` 当前自行创建 run、执行两轮 retry、写 `diagnosis_run` 和清理 ThreadLocal;新 Core 不接入该方法,后续应用用例负责迁移。
|
||||
- `DiagnosisRun` 仍保留现有字符串状态和 JPA Schema;阶段 2 未修改实体、Repository 或数据库。
|
||||
- `DiagnosisHarnessCore` 不保存全局 Run map;RunContext 结构不可变,Cancellation/Budget/Lifecycle 为同一 Run 的线程安全句柄。
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- first-reason-wins cancellation + first-terminal-wins lifecycle 可以用 AtomicReference 实现并跨异步边界共享。
|
||||
- 复合 Tool/Token 预算需要同步一致性;Run bytes 用 CAS 预留避免并发超限或部分增长。
|
||||
- SDK 隐藏 retry 压为一次后,Harness 才能记录 Router/SemanticGuard 的显式 attempt;Tool/Diagnosis/Evidence repair 固定一次。
|
||||
- Key Factory 可直接复用阶段 3A,但不生成或改写框架 Tool Call ID,也不访问 Redis。
|
||||
|
||||
## 工具限制
|
||||
|
||||
- `codebase-retrieval` 和 LSP 不在当前工具集中;使用 `rg`、源码阅读、`jar/javap`、Maven 编译、YAML 解析和 focused tests 补足核对。
|
||||
@@ -1,26 +0,0 @@
|
||||
# Acceptance: single-react-mysql-readonly-tool
|
||||
|
||||
## Commit preflight
|
||||
|
||||
- OpenSpec strict validation: passed.
|
||||
- Scope: fail-closed SQL validator, exact allowlist, JDBC read-only executor, bounded MySQL projection, ToolBoundary adapter and query-script safety cleanup.
|
||||
- Non-goals: public Agent/Chat cutover, metadata discovery, Agent persistence database access, dynamic/tenant authorization and live production datasource provisioning.
|
||||
- Security prerequisite: script write branch/default external connection values are explicitly included in this change.
|
||||
|
||||
## Apply acceptance
|
||||
|
||||
- Implemented and verified.
|
||||
- Static, Maven and script evidence is recorded in `evidence.md`.
|
||||
- No browser/manual verification applies; this stage adds no UI or public protocol change.
|
||||
- Residual risk is limited to later live datasource provisioning/driver behavior and stage 4 integration.
|
||||
|
||||
## Archive acceptance
|
||||
|
||||
- All OpenSpec tasks are complete.
|
||||
- `.archive-ready` marker is created after focused verification.
|
||||
- OpenSpec is ready to move to the dated archive directory.
|
||||
- Archive completed at `openspec/changes/archive/2026-07-21-single-react-mysql-readonly-tool`.
|
||||
|
||||
## Remaining work
|
||||
|
||||
- Stage 4 Diagnosis Agent integration and later live datasource/driver E2E remain outside this archive.
|
||||
@@ -1,26 +0,0 @@
|
||||
# Brief: single-react-mysql-readonly-tool
|
||||
|
||||
## Background
|
||||
|
||||
阶段 3A 提供了统一 ToolBoundary 和 canonical invocation store,阶段 3B 提供了 RAG/日志投影。3C 需要独立实现安全敏感的只读 MySQL Tool,避免 Agent 生成的 SQL 直接进入数据库。
|
||||
|
||||
## Goals
|
||||
|
||||
- 使用 JSqlParser 对保守 SELECT 子集进行 fail-closed AST 校验。
|
||||
- 使用逻辑数据源和 schema/table/column 精确 allowlist 授权。
|
||||
- 使用参数绑定、只读 JDBC、超时、取消和结果预算。
|
||||
- 通过阶段 3A boundary 投影为冻结的 `MysqlToolResult`。
|
||||
- 清理查询脚本的写入分支和默认连接风险。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- 不接入公开 Agent/Chat 入口。
|
||||
- 不提供元数据发现、动态授权、租户/行级权限或生产 datasource provisioning。
|
||||
- 不查询 Agent 自身持久化数据库。
|
||||
|
||||
## Classification
|
||||
|
||||
- Scale: complex
|
||||
- Interface impact: L2 internal Harness tool/adapter, plus build dependency and script safety behavior
|
||||
- Issue: ISS-014 stage 3C
|
||||
- Change slug: `single-react-mysql-readonly-tool`
|
||||
@@ -1,108 +0,0 @@
|
||||
# Decisions: single-react-mysql-readonly-tool
|
||||
|
||||
## Discover status
|
||||
|
||||
- Checkpoint: Discover
|
||||
- Capability source: `sm-flow` with local ISS-014, OpenSpec contracts, existing JDBC dependency/configuration and JSqlParser 4.6 already present in the local Maven cache.
|
||||
- Scale: complex, because this stage combines AST policy, authorization, JDBC resource limits, projection, and security cleanup.
|
||||
|
||||
## Evidence-driven findings
|
||||
|
||||
1. `MysqlToolRequest` and `MysqlToolResult` are already frozen under `harness.tool.contract`; no public DTO change is needed.
|
||||
2. The project already has MySQL JDBC/JPA dependencies, but no Agent-facing external read-only executor or SQL policy.
|
||||
3. JSqlParser 4.6 is available in the local Maven cache and exposes `CCJSqlParserUtil`, `Select`, `PlainSelect`, `Table`, `Column`, `Function`, `JdbcParameter` and visitor adapters compatible with Java 17.
|
||||
4. The current application datasource points to the Agent persistence database; the new Tool must use an independently configured logical datasource map and must not reuse that datasource implicitly.
|
||||
5. `scripts/query_mysql.py` currently defaults host/port/user values and contains a non-SELECT commit branch. This violates the ISS-014 security prerequisite and will be changed to read-only, environment-only behavior.
|
||||
|
||||
## Question pool
|
||||
|
||||
| Dimension | Question | Mode | Conclusion | Status |
|
||||
|---|---|---|---|---|
|
||||
| SQL language | Which SQL subset is executable? | evidence-driven | One SELECT, explicit columns, INNER/LEFT JOIN, predicates/group/order, parameter placeholders and allowlisted aggregates. | resolved |
|
||||
| Security | How is authorization decided? | evidence-driven | Independent exact schema/table/column allowlist; parser acceptance alone is insufficient. | resolved |
|
||||
| Data source | Can the Agent pass JDBC coordinates? | evidence-driven | No. Only logical data_source IDs are accepted; connection properties remain configuration/Secret data. | resolved |
|
||||
| Execution | Which JDBC controls are mandatory? | evidence-driven | PreparedStatement, readOnly connection, setMaxRows, query timeout and Run cancellation. | resolved |
|
||||
| Metadata | Can the Tool discover tables/columns? | evidence-driven | No. SHOW/DESCRIBE/information_schema are rejected. | resolved |
|
||||
| Compatibility | Does this cut over public runtime now? | evidence-driven | No. Add internal adapter/executor; Diagnosis Agent integration is stage 4. | resolved |
|
||||
|
||||
## User-confirmed direction
|
||||
|
||||
- Use the frozen `MysqlToolRequest`/`MysqlToolResult` contract.
|
||||
- Reuse the existing ToolBoundary and canonical invocation store.
|
||||
- Keep stage boundaries serial: archive and commit 3C before stage 4.
|
||||
- Do not pause for routine apply/archive/commit confirmation.
|
||||
|
||||
## Pre-apply research
|
||||
|
||||
### Existing implementations and dependencies
|
||||
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/contract/MysqlToolRequest.java`
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/contract/MysqlToolResult.java`
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/boundary/ToolBoundary.java`
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/adapter/QueryLogsToolAdapter.java`
|
||||
- `src/main/resources/application.yml`
|
||||
- `pom.xml` (`mysql-connector-j` already present; add JSqlParser 4.6)
|
||||
- `scripts/query_mysql.py`
|
||||
|
||||
### New classes
|
||||
|
||||
- `MysqlToolLimits`
|
||||
- `MysqlDataSourceDefinition` / allowlist value objects
|
||||
- `MysqlQueryPlan`
|
||||
- `MysqlSqlValidator`
|
||||
- `MysqlReadOnlyExecutor` and JDBC implementation
|
||||
- `MysqlResultProjector`
|
||||
- `MysqlToolAdapter`
|
||||
|
||||
### Risk controls
|
||||
|
||||
- Do not create a generic plugin/DSL layer.
|
||||
- Do not use regex or `startsWith` as SQL authorization.
|
||||
- Fail closed on parser/visitor uncertainty.
|
||||
- Keep raw result canonical-only and expose only bounded projection.
|
||||
|
||||
## Commit checkpoint preparation
|
||||
|
||||
- Proposal scope, design choices, frozen SQL subset, security script cleanup and acceptance scenarios are ready for Commit artifact generation.
|
||||
|
||||
## Commit audit
|
||||
|
||||
- Capability source: `sm-flow` and local OpenSpec CLI.
|
||||
- OpenSpec strict validation: passed for `single-react-mysql-readonly-tool`.
|
||||
- Cross-artifact alignment:
|
||||
- brief goals/non-goals -> proposal scope: aligned.
|
||||
- proposal SQL/security boundaries -> design architecture: aligned.
|
||||
- design validator/executor/projector decisions -> spec requirements: aligned.
|
||||
- spec scenarios -> tasks for dependency, policy, JDBC, projection, adapter and verification: aligned.
|
||||
- Interface impact: L2 internal Harness tool/adapter plus JSqlParser dependency and query-script behavior; no public protocol changes.
|
||||
- Preflight risk accepted: parser ambiguity, datasource isolation, driver cancellation behavior and sensitive result values all fail closed or remain Harness-only.
|
||||
|
||||
## Commit gate
|
||||
|
||||
- [x] proposal, design, specs and tasks exist.
|
||||
- [x] strict OpenSpec validation passes.
|
||||
- [x] all evidence-driven questions are resolved.
|
||||
- [x] no unresolved interface decision remains.
|
||||
- [x] `.committed` marker created for Apply.
|
||||
|
||||
## Apply result
|
||||
|
||||
- Added JSqlParser 4.6 and fail-closed `MysqlSqlValidator`.
|
||||
- Added immutable logical datasource/allowlist/limit/query-plan/raw-result models and independent `MysqlToolProperties` binding.
|
||||
- Added `JdbcMysqlReadOnlyExecutor` with read-only connection, PreparedStatement binding, query timeout, max rows, cell/result limits and Run cancellation callback.
|
||||
- Added `MysqlResultProjector` with sensitive-column redaction, row/cell/total UTF-8 bounds and `NO_EVIDENCE`.
|
||||
- Added `MysqlToolAdapter` through the existing ToolBoundary; invalid SQL is rejected before database execution.
|
||||
- Replaced `scripts/query_mysql.py` with environment-only, read-only transaction behavior and pre-connect write/metadata rejection.
|
||||
|
||||
## Apply conflicts and corrections
|
||||
|
||||
- `COUNT(*)` is represented by JSqlParser as an `AllColumns` parameter in this version; the visitor was corrected to permit only the explicit `COUNT(*)` exception.
|
||||
- JDBC metadata access cannot be used as a checked-exception stream method reference; the implementation uses an explicit column loop.
|
||||
- No OpenSpec/design conflict was found; both corrections were implementation details.
|
||||
|
||||
## Archive result
|
||||
|
||||
- Apply tasks complete and `.archive-ready` created.
|
||||
- OpenSpec archived at `openspec/changes/archive/2026-07-21-single-react-mysql-readonly-tool`.
|
||||
- Main capability specification added at `openspec/specs/mysql-readonly-tool/spec.md`.
|
||||
- Stage 4 may consume the internal adapter only after this stage is committed.
|
||||
@@ -1,29 +0,0 @@
|
||||
# Evidence: single-react-mysql-readonly-tool
|
||||
|
||||
## Static verification
|
||||
|
||||
- `git diff --check`: passed before archive.
|
||||
- Security scan confirms the query helper has no default external host/port/root user and no `commit()` write path.
|
||||
- New MySQL Harness code receives only injected logical DataSources and does not reference `spring.datasource` or the application persistence datasource.
|
||||
- OpenSpec strict validation passed for `single-react-mysql-readonly-tool`.
|
||||
|
||||
## Script/build verification
|
||||
|
||||
- `mvn -q -DskipTests compile`: passed.
|
||||
- Focused suite passed: `MysqlSqlValidatorTest`, `MysqlResultProjectorTest`, `JdbcMysqlReadOnlyExecutorTest`, `MysqlToolAdapterTest`, `MysqlToolContractTest`, `ToolBoundaryTest`, `CanonicalInvocationStoreTest`.
|
||||
- Python syntax compilation passed for `scripts/query_mysql.py`.
|
||||
- Missing connection environment variables exit before connection with code 2.
|
||||
- A write SQL invocation is rejected before connection with code 3.
|
||||
|
||||
## Security coverage
|
||||
|
||||
- Allowed: explicit allowlisted SELECT, parameter placeholders, qualified INNER JOIN and `COUNT(*)`.
|
||||
- Rejected: write, WITH, subquery, UNION, wildcard projection, unknown table/column, ambiguous column, dangerous function, inline literal, CASE, FOR UPDATE, multi-statement and placeholder mismatch.
|
||||
- JDBC controls verified: `setReadOnly(true)`, `PreparedStatement`, `setQueryTimeout`, `setMaxRows`, ordered parameter binding and cancellation-before-execution.
|
||||
- Projection controls verified: max rows, max cell chars, total UTF-8 bytes, sensitive-column redaction, valid bounded JSON and `NO_EVIDENCE`.
|
||||
|
||||
## Not verified in this stage
|
||||
|
||||
- No live production business datasource was provisioned or queried; ISS-014 explicitly assigns live E2E to a later issue/stage.
|
||||
- No public Diagnosis Agent/Chat integration was performed; stage 4 will consume the adapter internally.
|
||||
- JDBC driver timeout/cancel behavior against a real remote MySQL server remains an operational integration risk.
|
||||
@@ -1,25 +0,0 @@
|
||||
# Acceptance: single-react-rag-log-projections
|
||||
|
||||
## Commit preflight
|
||||
|
||||
- OpenSpec strict validation: passed.
|
||||
- Scope: RAG and Mock query-log projectors/adapters through the existing ToolBoundary.
|
||||
- Explicit non-goals: real CLS/MCP, MySQL, Diagnosis Agent cutover, public Chat/AIOps/SSE changes, legacy recorder cleanup.
|
||||
- Main residual risk: legacy log payloads contain sensitive values; projector tests must prove redaction before Agent serialization.
|
||||
|
||||
## Apply acceptance
|
||||
|
||||
- Implemented and verified.
|
||||
- Static verification and focused/regression Maven tests are recorded in `evidence.md`.
|
||||
- No browser/manual verification applies; this stage adds no UI or public protocol change.
|
||||
- Residual risks: live Redis/CLS integration and Agent cutover remain later stages.
|
||||
|
||||
## Archive acceptance
|
||||
|
||||
- `.archive-ready` marker is created after all tasks and checks pass.
|
||||
- OpenSpec is ready to move to the dated archive directory.
|
||||
- Archive completed at `openspec/changes/archive/2026-07-21-single-react-rag-log-projections`.
|
||||
|
||||
## Remaining work
|
||||
|
||||
- Real Redis/CLS integration, MySQL projection, Diagnosis Agent cutover and final E2E remain later stages.
|
||||
@@ -1,24 +0,0 @@
|
||||
# Brief: single-react-rag-log-projections
|
||||
|
||||
## Background
|
||||
|
||||
阶段 3A 已经统一 ToolBoundary 和 canonical invocation store。下一阶段需要把现有 RAG 与 Mock 日志工具接入该边界,并把旧工具输出投影为冻结的 Agent-facing ACI 结果。
|
||||
|
||||
## Goal
|
||||
|
||||
- 提供 bounded RAG evidence projection。
|
||||
- 提供带完整 logical scope 和 Mock provenance 的 query-log projection。
|
||||
- 复用阶段 3A 生命周期、Run ownership、tool_call_id、预算、错误和 canonical record。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- 不接入真实 CLS/MCP。
|
||||
- 不实现 MySQL projection。
|
||||
- 不切换 Diagnosis Agent、Chat/AIOps、SSE 或旧 recorder。
|
||||
|
||||
## Classification
|
||||
|
||||
- Scale: complex
|
||||
- Interface impact: L2 internal Harness adapter/projector
|
||||
- Issue: ISS-014 stage 3B
|
||||
- Change slug: `single-react-rag-log-projections`
|
||||
@@ -1,72 +0,0 @@
|
||||
# Decisions: single-react-rag-log-projections
|
||||
|
||||
## Discover status
|
||||
|
||||
- Checkpoint: Discover
|
||||
- Capability source: `sm-flow` with `grill-with-docs` codebase evidence; no external service integration required.
|
||||
- Scale: complex, because two tool adapters share a lifecycle boundary and define bounded Agent-facing output semantics.
|
||||
|
||||
## Evidence-driven findings
|
||||
|
||||
1. `ToolBoundary` currently accepts `project(String rawResponse)` and already owns Run/ID/authorization/read-only/JSON/budget/lifecycle enforcement.
|
||||
2. `LookupKnowledgeTool` emits `evidenceBlocks`, `contextPack`, `retrievalTrace`, `rerankTrace`, session domains, and message; these are internal retrieval/audit fields and must not be projected.
|
||||
3. `QueryLogsTools` emits region, physical log topic, result limit, instance and metrics; the frozen contract requires logical topic/query/lookback scope and `source_kind=MOCK` instead.
|
||||
4. Existing ACI records already define the required snake_case fields and immutable collections.
|
||||
5. The request scope must be passed to the log projector through a typed adapter method rather than inferred from raw output.
|
||||
|
||||
## User-confirmed direction
|
||||
|
||||
- Use the framework-provided `tool_call_id` only.
|
||||
- Keep lifecycle status and evidence status separate.
|
||||
- Implement the stage in phases and complete sm-flow archive plus Git commit before the next stage.
|
||||
- Adopt the request-aware projector adapter for log scope preservation.
|
||||
|
||||
## Question pool
|
||||
|
||||
| Dimension | Question | Mode | Conclusion | Status |
|
||||
|---|---|---|---|---|
|
||||
| Terminology | Are RAG traces and context packs Agent evidence? | evidence-driven | No. They are internal retrieval/audit details and are excluded from projection. | resolved |
|
||||
| Boundary | How is log scope preserved when the generic projector has no request? | evidence-driven | Typed adapter carries `QueryLogsRequest` into a request-aware projector method. | resolved |
|
||||
| Provenance | Which log source is implemented now? | evidence-driven | Existing Mock source only; result always records `source_kind=MOCK`. | resolved |
|
||||
| Negative result | What does an empty query mean? | evidence-driven | `NO_EVIDENCE` for the recorded scope, with no health/problem inference. | resolved |
|
||||
| Compatibility | Should legacy tools and public paths be changed now? | evidence-driven | No. Add adapters/projectors only; cutover is later. | resolved |
|
||||
|
||||
## Risks
|
||||
|
||||
- Existing mock messages contain hostnames, pod IDs, SQL literals, and stack-like text; sanitization must happen before projection.
|
||||
- Collection limits and excerpt limits can make the Agent result incomplete; `truncated` must be explicit.
|
||||
- The generic boundary API should remain reusable for stage 3C, so request-aware behavior belongs in an adapter or specialized projector interface.
|
||||
|
||||
## Discover checkpoint
|
||||
|
||||
- Proposal created: `openspec/changes/single-react-rag-log-projections/proposal.md`
|
||||
- Context and issue evidence recorded.
|
||||
- No unresolved user-interview question remains for this bounded stage; implementation direction was explicitly accepted in the conversation.
|
||||
|
||||
## Commit audit
|
||||
|
||||
- Capability source: `sm-flow` and local OpenSpec CLI.
|
||||
- OpenSpec strict validation: passed for `single-react-rag-log-projections`.
|
||||
- Cross-artifact alignment:
|
||||
- brief goals/non-goals -> proposal scope: aligned.
|
||||
- proposal boundaries and request-aware projector decision -> design: aligned.
|
||||
- design projection bounds, redaction, scope and adapter ownership -> spec requirements: aligned.
|
||||
- spec scenarios -> tasks for limits, RAG, logs, boundary integration and verification: aligned.
|
||||
- Interface impact: L2 internal Harness adapter/projector only; no public protocol or legacy runtime cutover.
|
||||
- Preflight risks accepted: legacy payload drift fails closed; sensitive log fields are redacted; total projection budget is explicit.
|
||||
|
||||
## Commit gate
|
||||
|
||||
- [x] proposal, design, specs and tasks exist.
|
||||
- [x] strict OpenSpec validation passes.
|
||||
- [x] all evidence-driven questions are resolved.
|
||||
- [x] no unresolved interface decision remains.
|
||||
- [x] `.committed` marker created for Apply.
|
||||
|
||||
## Archive result
|
||||
|
||||
- Apply tasks complete.
|
||||
- `.archive-ready` marker created.
|
||||
- OpenSpec archived at `openspec/changes/archive/2026-07-21-single-react-rag-log-projections`.
|
||||
- Main capability specification added at `openspec/specs/rag-log-projections/spec.md`.
|
||||
- Next stage remains 3C MySQL projection; no Agent cutover is implied by this archive.
|
||||
@@ -1,25 +0,0 @@
|
||||
# Evidence: single-react-rag-log-projections
|
||||
|
||||
## Static verification
|
||||
|
||||
- `git diff --check`: passed.
|
||||
- Existing legacy files were checked and have no diff: `LookupKnowledgeTool`, `QueryLogsTools`, `ChatService`, `AiOpsService`, and `ToolInvocationRecorder`.
|
||||
- OpenSpec strict validation: passed for `single-react-rag-log-projections`.
|
||||
|
||||
## Script/build verification
|
||||
|
||||
- `mvn -q -DskipTests compile`: passed.
|
||||
- Focused projection tests: passed (`RagResultProjectorTest`, `QueryLogsResultProjectorTest`).
|
||||
- Adapter tests: passed (`ToolAdapterTest`).
|
||||
- Stage regression suite: passed (`CanonicalInvocationStoreTest`, `ToolBoundaryTest`, ACI/Core/retry/key/config/ChatController tests plus the new projection tests).
|
||||
|
||||
## Coverage
|
||||
|
||||
- RAG: bounded exact excerpts, duplicate document IDs, internal field exclusion, `NO_EVIDENCE`, truncation and framework ID.
|
||||
- Logs: logical scope, Mock provenance, pattern aggregation, timeline sampling, sensitive value redaction, empty result and bounded output.
|
||||
- Boundary: adapters use the existing canonical lifecycle and do not return raw payloads.
|
||||
|
||||
## Not verified in this stage
|
||||
|
||||
- Real Redis connectivity and live CLS/MCP integration.
|
||||
- Diagnosis Agent/application cutover and end-to-end Maven runtime flow.
|
||||
@@ -1,43 +0,0 @@
|
||||
# Acceptance: single-react-tool-invocation-store
|
||||
|
||||
## 实现结果
|
||||
|
||||
- 新增 canonical record/limits/exceptions/store interface/Redis JSON adapter。
|
||||
- 新增 ToolBoundary envelope/result、executor/projector interfaces 和稳定错误码。
|
||||
- 实现 preflight、Run/Tool budget、Run capacity、PROJECTING、READY/ERROR、evidence semantics、TTL 和 UTF-8 limits。
|
||||
- 旧 ToolInvocationRecorder、JPA、Chat/AIOps、Controller、Repository 和公开协议未修改。
|
||||
|
||||
## 静态验证
|
||||
|
||||
- `openspec validate single-react-tool-invocation-store --strict`:通过。
|
||||
- 新 Harness 包 Redis 引用仅为 `RedisCanonicalInvocationStore`。
|
||||
- legacy recorder/JPA/Chat/AIOps/Controller/repository/resources diff:为空。
|
||||
- staged diff check 与 Secret scan:提交前执行并通过。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
- `mvn -q -DskipTests compile`:通过。
|
||||
- `mvn -q '-Dtest=CanonicalInvocationStoreTest,ToolBoundaryTest' test`:通过。
|
||||
- 综合阶段 0/1/2/3A suite(含 Harness/ACI/Core/retry/key/config/ChatController):通过。
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
- 不适用。本阶段没有 UI、Controller、SSE 或公开协议变化。
|
||||
|
||||
## 未验证
|
||||
|
||||
- 未连接真实 Redis,未做 ACL/network/TTL live 验证;最终 E2E 阶段执行。
|
||||
- 未接入 Alibaba ToolInterceptor,真实框架 ID 传播留给后续 Agent/application stage。
|
||||
- 未实现 RAG/log/MySQL projector,留给 3B/3C。
|
||||
- canonical update 的 read-TTL-write 并发窗口已记录为风险,尚未 Lua/CAS 化。
|
||||
|
||||
## 剩余风险与后续门禁
|
||||
|
||||
- 新旧 JPA audit 与 canonical store 短期并存,后续 projector 必须只以新 boundary 的 READY record 作为引用来源。
|
||||
- 下一阶段 3B/3C 必须复用本 ToolBoundary,不复制 Redis 状态机。
|
||||
|
||||
## 状态
|
||||
|
||||
- Stage acceptance: accepted
|
||||
- OpenSpec archive: archived at `openspec/changes/archive/2026-07-21-single-react-tool-invocation-store`
|
||||
- Main spec sync: `openspec/specs/canonical-tool-invocation-store/spec.md`(7 added requirements)
|
||||
@@ -1,29 +0,0 @@
|
||||
# Brief: single-react-tool-invocation-store
|
||||
|
||||
## 背景
|
||||
|
||||
旧 `ToolInvocationRecorder` 依赖 ThreadLocal 和 JPA preview,不能证明完整 Tool 结果、生命周期和当前 Run 所有权。阶段 2 已提供 RunContext/Key/Capacity,需要统一 canonical ToolBoundary 和 Redis store 供后续 projector 复用。
|
||||
|
||||
## 目标
|
||||
|
||||
- 统一 Pre-Tool 门禁、PROJECTING/READY/ERROR 状态和 evidence semantics。
|
||||
- 在同一 Redis record 保存 request/raw_response/agent_result、框架 ID、Run、时间和错误。
|
||||
- 固定 TTL 不续期、容量/结果大小 fail-closed、raw 不静默截断。
|
||||
- 用 Fake Tool/Projector/Store 覆盖 duplicate、cross-run、no-evidence、error、TTL 和 oversize。
|
||||
|
||||
## 范围
|
||||
|
||||
- Canonical invocation model/store、Redis JSON adapter、ToolBoundary 和 focused tests。
|
||||
- 复用阶段 2 Core、budget、capacity、ToolCallKeyFactory。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不实现 RAG/log/MySQL projector。
|
||||
- 不修改旧 recorder/JPA、Chat/AIOps、Controller/SSE 或公开协议。
|
||||
|
||||
## 元数据
|
||||
|
||||
- 分档:complex
|
||||
- 接口影响:L2 内部 Harness boundary/store
|
||||
- 关联 Issue:ISS-014 阶段 3A
|
||||
- 关联 OpenSpec:`openspec/changes/single-react-tool-invocation-store`
|
||||
@@ -1,106 +0,0 @@
|
||||
# Decisions: single-react-tool-invocation-store
|
||||
|
||||
## 规模与入口
|
||||
|
||||
- 分档:complex。
|
||||
- 入口:ISS-014 阶段 3A;阶段 0/1/2 已 Archive 并由 `58c3910`、`4274f33`、`6b74990` 提交。
|
||||
- 目标:统一 ToolBoundary 和 Redis canonical invocation store,不实现 Tool-specific projection。
|
||||
|
||||
## Context
|
||||
|
||||
- 阶段 1 主规格已冻结 RAG/log/MySQL Agent-facing Request/Result 和 `EvidenceStatus`。
|
||||
- 阶段 2 主规格已冻结 `RunContext`、预算、取消、Key Factory 和 strict retry。
|
||||
- 旧 `ToolInvocationRecorder` 依赖 `SessionContextHolder`、JPA `ToolInvocation` 和 500 字符 preview,属于 durable audit 兼容路径,不是 canonical store。
|
||||
- 既有 `SessionConfiguration` 提供 `RedisTemplate<String,Object>` + JSON serializer;新 store 复用 bean,不新增连接配置。
|
||||
|
||||
## Question Pool
|
||||
|
||||
| 维度 | 问题 | 模式 | 证据与结论 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| 术语 | canonical invocation 与旧 JPA ToolInvocation 是否同一记录? | evidence-driven | ISS-014 数据分层明确 Redis canonical 保存完整 request/raw/agent,JPA 只做 durable audit;两者分离。 | 已解决并汇报 |
|
||||
| 术语 | `PROJECTING/READY/ERROR` 与 evidence status 如何组合? | evidence-driven | 阶段 0/1 规格:只有 READY 可为 FOUND/NO_EVIDENCE,ERROR 不可引用;PROJECTING 是内部暂态。 | 已解决并汇报 |
|
||||
| 边界 | 阶段 3A 是否实现 RAG/log projector? | evidence-driven | ISS-014 3A 明确不实现 Tool-specific projection,3B/3C 单独接入。 | 已解决并汇报 |
|
||||
| 边界 | Redis 读取是否刷新 TTL? | evidence-driven | ISS-014 固定“创建设置、读取/更新不续期”;更新采用当前剩余 TTL,不恢复初始 TTL。 | 已解决并汇报 |
|
||||
| 验收 | raw 超限是否静默截断? | evidence-driven | ISS-014 明确 `RESULT_TOO_LARGE` ERROR,raw 不静默截断;agent projection 才可按 projector 预算截断并标记。 | 已解决并汇报 |
|
||||
| 验收 | 缺失/重复/cross-run ID 如何处理? | evidence-driven | 阶段 3A 任务明确覆盖;Key Factory 保留框架 ID,ToolBoundary 在 store 创建前校验 Run/ID 和 duplicate。 | 已解决并汇报 |
|
||||
| 技术 | Redis 如何避免 update 重置 TTL? | evidence-driven | 既有 RedisTemplate;begin 使用 setIfAbsent + TTL,update 先读取剩余 TTL 再写回相同/更短 TTL,get 不调用 expire。 | 已解决并汇报 |
|
||||
| 技术 | 是否修改旧 recorder 以复用新 store? | evidence-driven | 旧链路大量测试依赖 JPA preview/evidence_refs;本阶段零消费者,保持旧 recorder 不变,避免行为回归。 | 已解决并汇报 |
|
||||
|
||||
## Grill 结论
|
||||
|
||||
- 所有术语、边界、验收和技术问题均由 ISS、阶段规格、旧代码和 Redis 配置事实证明。
|
||||
- 没有新增产品偏好或兼容性取舍需要 user-interview;并发更新窗口作为已接受风险记录。
|
||||
- `grill-with-docs` 的代码可证结论已回写 proposal;没有未确认问题。
|
||||
|
||||
## 能力与工具限制
|
||||
|
||||
- Discover 能力来源:`sm-flow` + `grill-with-docs`。
|
||||
- 当前无 `codebase-retrieval`/LSP;使用 `rg`、源码、既有测试、本地 Redis 配置和 focused fake tests 进行等价核对。
|
||||
|
||||
## Cross-artifact 对齐
|
||||
|
||||
| 链路 | 状态 | 结论 |
|
||||
|---|---|---|
|
||||
| brief 目标/范围/非目标 -> proposal | 已对齐 | Boundary、canonical record、TTL/size、Fake tests 和 legacy isolation 全部覆盖。 |
|
||||
| proposal 范围/约束/承诺 -> design | 已对齐 | Redis value、状态机、preflight 顺序、raw/projection 和失败处理均已设计。 |
|
||||
| design 决策/接口影响/风险 -> specs/tasks | 已对齐 | L2 boundary、TTL 更新窗口、oversize/error、ID/Run 所有权有对应要求和任务。 |
|
||||
| specs 可观察行为 -> tasks | 已对齐 | 7 条 requirements 分解为 store、boundary、limits/failure 和隔离验证纵向切片。 |
|
||||
|
||||
## Architecture Audit
|
||||
|
||||
- 能力来源:`zoom-out`,按 RunContext、Invocation Status、Evidence Status、canonical invocation 和 durable audit 术语审计。
|
||||
- ToolBoundary 只编排一次调用;CanonicalInvocationStore 独占 Redis 状态转换;DiagnosisHarnessCore 独占 Run budget/cancellation;旧 recorder 只写 JPA audit。
|
||||
- request/raw/agent result 归同一 canonical record,Agent 只获得 ToolBoundaryResult,不存在 raw 旁路。
|
||||
- Redis adapter 是唯一 Redis 访问点,接口/Fake 不依赖 Redis;后续 3B/3C 可直接复用而不复制状态机。
|
||||
- 风险集中在 read-TTL-write 并发窗口和 canonical raw 敏感性,已进入 design/spec/limits,无架构或 ADR 冲突。
|
||||
|
||||
## Commit Gate Preflight
|
||||
|
||||
- proposal、design、specs、tasks 完整,OpenSpec status complete,strict validation 通过。
|
||||
- question pool 无未汇报 evidence-driven 或未确认 user-interview 项。
|
||||
- L2 内部接口影响已记录;旧 JPA/Chat/Controller/协议不改。
|
||||
- cross-artifact 无 gap,所有错误、TTL、size、ID/Run 所有权和隔离要求可由 Fake tests 验证。
|
||||
- Apply 已获持续授权,范围只包括新 store/boundary 与 focused tests。
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
### 参考实现与复用
|
||||
|
||||
- 复用 `DiagnosisHarnessCore` 的 active/deadline/Tool budget/Run bytes 门禁。
|
||||
- 复用 `ToolCallKeyFactory` 精确保留框架 Tool Call ID 并隔离 Run key。
|
||||
- 复用阶段 0 `InvocationStatus` / `EvidenceStatus`,不创建字符串状态副本。
|
||||
- 复用 `SessionConfiguration` 提供的 `RedisTemplate<String,Object>` 和 Spring Boot ObjectMapper。
|
||||
- 旧 `ToolInvocationRecorder`/JPA preview 仅作为 durable audit 反例,本阶段不修改或调用。
|
||||
|
||||
### 技术栈清单
|
||||
|
||||
- canonical record:Java 17 record + Jackson JSON String,所有状态组合在 record transition 方法中校验。
|
||||
- Redis create:`ValueOperations.setIfAbsent` + TTL;update:读取当前 remaining TTL 后写回;get 不调用 expire。
|
||||
- 大小:UTF-8 bytes;record/agent result/store limits 与 RunContext 累计 capacity 双重门禁。
|
||||
- 测试:Mockito RedisTemplate/ValueOperations 验证 TTL API;In-memory fake store + Fake Tool/Projector 验证 boundary,不连接外部 Redis。
|
||||
|
||||
### 新建类型
|
||||
|
||||
- canonical model/limits/store/exceptions/Redis adapter。
|
||||
- ToolCallRequestEnvelope、ToolBoundaryResult、ProjectedToolResult、ToolExecutor、ToolResultProjector、ToolBoundary 和稳定 error codes。
|
||||
- Redis adapter tests 与 boundary fake tests。
|
||||
|
||||
### 影响半径
|
||||
|
||||
- 新 package 在阶段 3A 保持零现有消费者。
|
||||
- Redis 访问只允许出现在 `RedisCanonicalInvocationStore`;旧 Chat/AIOps/Controller/JPA/Recorder 不修改。
|
||||
|
||||
## Apply 结果
|
||||
|
||||
- 冲突分类:一次 focused test 断言错误(duplicate 场景应调用 `setIfAbsent` 两次)已修正并复跑通过;无规格偏离。
|
||||
- 新增 canonical record/limits/store exceptions、Redis JSON adapter、ToolBoundary envelope/result/interfaces 和 stable error codes。
|
||||
- ToolBoundary 已实现 preflight、Core budget/capacity、PROJECTING、raw/projection size、READY/ERROR 和安全返回边界;未接具体 projector。
|
||||
- 首模块对齐:store/boundary/limits/failure 与 design/tasks 全部完成;RAG/log/MySQL adapters 仍留给后续阶段。
|
||||
|
||||
## Apply 验证
|
||||
|
||||
- 编译:`mvn -q -DskipTests compile`:通过。
|
||||
- Store/Boundary focused:`mvn -q '-Dtest=CanonicalInvocationStoreTest,ToolBoundaryTest' test`:通过。
|
||||
- 综合回归:`mvn -q '-Dtest=CanonicalInvocationStoreTest,ToolBoundaryTest,HarnessContractTest,RagToolContractTest,QueryLogsToolContractTest,MysqlToolContractTest,RunContextTest,RunBudgetTest,DiagnosisHarnessCoreTest,HarnessRetryExecutorTest,ToolCallKeyFactoryTest,SpringAiRetryConfigurationTest,ChatControllerTest' test`:通过。
|
||||
- 静态隔离:新 Harness 包仅 `RedisCanonicalInvocationStore` 引用 Redis;legacy recorder/JPA/Chat/AIOps/Controller/repository/resources diff 为空。
|
||||
- OpenSpec:`openspec validate single-react-tool-invocation-store --strict`:通过。
|
||||
@@ -1,20 +0,0 @@
|
||||
# Evidence: single-react-tool-invocation-store
|
||||
|
||||
## 文档与代码证据
|
||||
|
||||
- ISS-014 阶段 3A 明确要求统一 ToolBoundary、canonical invocation、PROJECTING/READY/ERROR、TTL/容量、ID/Run 所有权,且不实现 3B/3C projector。
|
||||
- 阶段 2 已提供 `RunContext`、Run bytes capacity 和 `ToolCallKeyFactory`,本阶段直接复用。
|
||||
- 旧 `ToolInvocationRecorder` 使用 JPA preview 和 ThreadLocal fallback;新 canonical record 独立保存完整 request/raw/agent,不修改旧 recorder/JPA。
|
||||
- 既有 `SessionConfiguration` 提供 `RedisTemplate<String,Object>` JSON bean;`RedisCanonicalInvocationStore` 是新 Harness 包唯一 Redis 引用。
|
||||
|
||||
## Evidence-driven 结论
|
||||
|
||||
- `setIfAbsent` 确保同一 `runId+toolCallId` 不覆盖;读取不调用 expire;更新使用剩余 TTL。
|
||||
- canonical record transition 只允许 PROJECTING -> READY/ERROR;READY 只接受 FOUND/NO_EVIDENCE,ERROR 不可引用。
|
||||
- ToolBoundary 在执行前校验 Run、ID、JSON、授权、只读和预算;raw 只在可信 store 保存,不返回 Agent。
|
||||
- UTF-8 record/Agent limits 与 Run capacity 双门禁;raw oversize 跳过 projector,Agent oversize 不返回,均产生 RESULT_TOO_LARGE。
|
||||
- Fake store/Redis mock tests 已覆盖 duplicate、cross-run、unauthorized、writable、execution/projection error、NO_EVIDENCE、TTL、raw/agent oversize。
|
||||
|
||||
## 工具限制
|
||||
|
||||
- 当前无 `codebase-retrieval`/LSP;使用 `rg`、源码、Maven 编译、Mockito Redis API 和 in-memory fake 完成等价验证。
|
||||
@@ -31,7 +31,7 @@
|
||||
**配置信息**(已完成):
|
||||
- **MySQL**: 119.29.78.52:33306/superbiz_agent
|
||||
- 用户: root
|
||||
- 密码: 已从仓库移除,使用环境变量注入
|
||||
- 密码: !Fucker123..
|
||||
- driver: com.mysql.cj.jdbc.Driver
|
||||
- URL参数: useUnicode=true&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
||||
- **Redis**: 119.29.78.52:6379
|
||||
@@ -165,7 +165,7 @@ openspec/changes/phase-1-infrastructure/
|
||||
|
||||
## 敏感信息(已编辑)
|
||||
|
||||
- MySQL 密码:已从仓库移除,使用环境变量注入
|
||||
- MySQL 密码:已配置在 application.yml(`!Fucker123..`)
|
||||
- Redis:无密码
|
||||
|
||||
---
|
||||
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Spring AI Alibaba Graph:诊断编排改造</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
|
||||
<style>
|
||||
:root { --bg:#f4f7fb; --card:rgba(255,255,255,.86); --text:#172033; --muted:#5c6880; --blue:#2563eb; --line:#dbe3f0; }
|
||||
* { box-sizing:border-box; }
|
||||
body { margin:0; font-family:Inter,"PingFang SC","Microsoft YaHei",sans-serif; background:linear-gradient(135deg,#eef4ff,#f8fafc); color:var(--text); line-height:1.75; }
|
||||
.wrap { max-width:1000px; margin:0 auto; padding:42px 24px 110px; }
|
||||
header,.card { background:var(--card); border:1px solid rgba(255,255,255,.9); box-shadow:0 12px 35px rgba(35,55,90,.09); backdrop-filter:blur(14px); border-radius:20px; padding:28px; margin-bottom:22px; }
|
||||
h1 { margin:0 0 8px; font-size:34px; }
|
||||
h2 { margin-top:0; color:#173c85; }
|
||||
h3 { color:#244c92; }
|
||||
code,pre { font-family:"Cascadia Code",Consolas,monospace; }
|
||||
pre { background:#101827; color:#e5edf9; padding:18px; border-radius:14px; overflow:auto; }
|
||||
.tag { display:inline-block; padding:4px 10px; margin-right:6px; border-radius:999px; background:#e4edff; color:#2453a6; font-size:13px; }
|
||||
.mnemonic-card { background:#fff8cf; border:2px dashed #e6b800; padding:16px; border-radius:14px; }
|
||||
.fission-section { background:#fff1f2; border-left:5px solid #e11d48; padding:18px; border-radius:12px; }
|
||||
.truth { border-left:4px solid #2563eb; background:#eff6ff; padding:14px; border-radius:10px; }
|
||||
details { background:#f8fafc; border:1px solid var(--line); border-radius:12px; padding:12px 15px; margin:9px 0; }
|
||||
summary { cursor:pointer; font-weight:700; }
|
||||
.search { position:fixed; bottom:22px; left:50%; transform:translateX(-50%); width:min(720px,calc(100% - 36px)); background:rgba(15,23,42,.93); padding:12px; border-radius:16px; box-shadow:0 15px 40px rgba(0,0,0,.25); z-index:5; }
|
||||
.search input { width:100%; border:0; outline:0; border-radius:10px; padding:12px 14px; font-size:15px; }
|
||||
.hidden { display:none !important; }
|
||||
ul,ol { padding-left:24px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap" id="content-area">
|
||||
<header>
|
||||
<h1>Spring AI Alibaba Graph:诊断编排改造</h1>
|
||||
<p>作者:叫我小杨同学的小码酱</p>
|
||||
<span class="tag">StateGraph</span><span class="tag">Agent 编排</span><span class="tag">条件边</span><span class="tag">故障诊断</span>
|
||||
</header>
|
||||
|
||||
<section class="card">
|
||||
<h2>0. 核心摘要</h2>
|
||||
<p><strong>让 ReactAgent 继续负责做事,让 StateGraph 负责下一步去哪里。</strong></p>
|
||||
<p>生活类比:Planner、Executor、Verifier 是医院科室,Graph 是分诊和转诊制度。</p>
|
||||
<p class="truth">官方核心模型是 State、Nodes、Edges。本地依赖 1.1.2.0 已确认支持 StateGraph、条件边、编译配置、中断和 threadId。</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>1. 概念破冰</h2>
|
||||
<div class="mnemonic-card">状态记事实,节点做任务,边管下一步,检查点管恢复。</div>
|
||||
<p>当前 ChatService 已经是半个状态机:SequentialAgent 运行 Planner、Executor、Verifier,外层 Java 再根据 PASS、LOW_CONFID、REJECT 决定 Composer 或重试。Graph 改造的价值,是把分散的控制权显式化。</p>
|
||||
<pre>当前:SequentialAgent + 外层 if/else
|
||||
目标:StateGraph 条件边 + ReactAgent 语义节点</pre>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>2. 深度解析</h2>
|
||||
<p>Supervisor 适合动态选择专科 Agent;Gatekeeper、Verifier 等强制门禁应由代码边控制。普通工具失败也不需要 interrupt,只有等待人工输入或审批时才暂停。</p>
|
||||
<div class="mermaid">
|
||||
flowchart TD
|
||||
S["START"] --> P["Planner"]
|
||||
P --> E["Executor"]
|
||||
E -- "结构有效" --> G["Gatekeeper"]
|
||||
E -- "阻断或非法" --> F["Fallback"]
|
||||
G -- "允许" --> V["Verifier"]
|
||||
G -- "拒绝" --> F
|
||||
V -- "通过或拒绝" --> C["Composer"]
|
||||
V -- "低置信且有预算" --> R["Retry Guard"]
|
||||
R -- "补证据" --> P
|
||||
R -- "停止" --> C
|
||||
C --> X["END"]
|
||||
F --> X
|
||||
</div>
|
||||
|
||||
<h3>状态设计</h3>
|
||||
<p>保存统一诊断上下文、计划、Executor 结构化输出、Gatekeeper 结果、Verifier verdict、重试轮次和最终结果。不要在 State 里复制所有原始日志或完整思考过程。</p>
|
||||
|
||||
<h3>核心伪代码</h3>
|
||||
<pre>StateGraph graph = new StateGraph("diagnosis_workflow", strategies)
|
||||
.addNode("planner", plannerNode)
|
||||
.addNode("executor", executorNode)
|
||||
.addNode("gatekeeper", gatekeeperNode)
|
||||
.addNode("verifier", verifierNode)
|
||||
.addNode("retry_guard", retryGuardNode)
|
||||
.addNode("composer", composerNode)
|
||||
.addNode("fallback", fallbackNode)
|
||||
.addEdge(START, "planner")
|
||||
.addEdge("planner", "executor")
|
||||
.addConditionalEdges("executor", routeAfterExecutor,
|
||||
Map.of("gatekeeper","gatekeeper",
|
||||
"retry_guard","retry_guard",
|
||||
"fallback","fallback"))
|
||||
.addConditionalEdges("gatekeeper", routeAfterGatekeeper,
|
||||
Map.of("verifier","verifier","fallback","fallback"))
|
||||
.addConditionalEdges("verifier", routeAfterVerifier,
|
||||
Map.of("retry_guard","retry_guard",
|
||||
"composer","composer",
|
||||
"fallback","fallback"))
|
||||
.addConditionalEdges("retry_guard", routeAfterRetry,
|
||||
Map.of("planner","planner","composer","composer"))
|
||||
.addEdge("composer", END)
|
||||
.addEdge("fallback", END);</pre>
|
||||
|
||||
<h3>运行边界</h3>
|
||||
<pre>RunnableConfig config = RunnableConfig.builder()
|
||||
.threadId(runId)
|
||||
.addMetadata("sessionId", sessionId)
|
||||
.addMetadata("runId", runId)
|
||||
.build();</pre>
|
||||
<p>一个 diagnosis_run 使用一个 Graph thread,避免同一 session 下多个 run 共享检查点。MemorySaver 不是跨重启持久化。</p>
|
||||
|
||||
<h3>ReactAgent 的接入</h3>
|
||||
<p>本地 ReactAgent 提供 asNode(boolean, boolean)。当前项目第一阶段更适合用适配节点调用已有 Agent,显式控制输入、outputKey 和解析;状态契约稳定后再评估直接 asNode。</p>
|
||||
</section>
|
||||
|
||||
<section class="card fission-section">
|
||||
<h2>3. 深度裂变</h2>
|
||||
<h3>🔍 搜索内化:改造的是控制权,不是 Agent</h3>
|
||||
<p>Graph 的节点可以是 LLM,也可以是普通 Java 代码;ReactAgent 本身已经是子图。所谓“Multi-Agent 改 Graph”,实际上是把跨 Agent 状态转换交给父 Graph。</p>
|
||||
<p>官方页面示例有 OverAllStaste 拼写错误,实际类型是 OverAllState。网站主分支可能领先于本地依赖,最终必须以项目 JAR 和编译测试为准。</p>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>4. 实战指南</h2>
|
||||
<ol>
|
||||
<li>先定义节点结果状态,不改 Prompt。</li>
|
||||
<li>把现有 Planner、Executor、Verifier 包装为 Node。</li>
|
||||
<li>Gatekeeper 和固定降级做成 Java Node。</li>
|
||||
<li>迁移现有两轮 LOW_CONFID 控制。</li>
|
||||
<li>加入 Executor 阻断、非法结构和 Gatekeeper REJECT 条件边。</li>
|
||||
<li>保留旧 Sequential 链路作为短期回退。</li>
|
||||
<li>最后再增加 HITL、并行和专科 SubAgent。</li>
|
||||
</ol>
|
||||
<h3>避坑</h3>
|
||||
<ul>
|
||||
<li>不要让 Supervisor 决定是否跳过安全门禁。</li>
|
||||
<li>不要把 no_evidence 当成 Executor 失败。</li>
|
||||
<li>不要让多个 run 共用 sessionId 作为 Graph threadId。</li>
|
||||
<li>不要把 MemorySaver 当成生产持久化。</li>
|
||||
<li>不要未验证 messages 传播就直接大量使用 asNode(true, true)。</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="card">
|
||||
<h2>5. 温故知新</h2>
|
||||
<h3>FAQ</h3>
|
||||
<details><summary>1. Graph 会替代 ReactAgent 吗?</summary><p>不会,ReactAgent 可以作为子图节点继续使用。</p></details>
|
||||
<details><summary>2. 为什么不用 Supervisor 控制失败?</summary><p>失败跳转是确定性规则,不需要增加一次模型决策。</p></details>
|
||||
<details><summary>3. no_evidence 是否直接 fallback?</summary><p>不一定,合法 no-evidence 引用仍要经过 Gatekeeper 和 Verifier。</p></details>
|
||||
<details><summary>4. Composer 必须是 Agent 吗?</summary><p>正常表达可以使用轻量 Agent,系统失败要保留固定模板。</p></details>
|
||||
<details><summary>5. threadId 用什么?</summary><p>当前数据模型下优先使用 runId,sessionId 作为元数据。</p></details>
|
||||
<details><summary>6. 何时需要 Checkpointer?</summary><p>需要暂停、恢复和检查 Graph 历史状态时。</p></details>
|
||||
<details><summary>7. 能直接使用 agent.asNode 吗?</summary><p>可以,但要验证 outputKey、messages 和父子检查点。</p></details>
|
||||
<details><summary>8. AIOps 要单独 Graph 吗?</summary><p>入口和输出策略独立,诊断核心可以共用。</p></details>
|
||||
|
||||
<h3>自测题</h3>
|
||||
<ol>
|
||||
<li>为什么 Executor 工具阻断不应由 Verifier 决定重试?</li>
|
||||
<li>ReplaceStrategy 和 AppendStrategy 各适合什么状态?</li>
|
||||
<li>为什么合法 no_evidence 仍然需要 Gatekeeper?</li>
|
||||
<li>Supervisor 与条件边的决策权有什么不同?</li>
|
||||
<li>为什么 Graph threadId 更适合使用 runId?</li>
|
||||
<li>什么情况下才应该配置 interruptBefore?</li>
|
||||
</ol>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="search"><input id="search-input" placeholder="搜索本文内容……"></div>
|
||||
<script>
|
||||
mermaid.initialize({ startOnLoad: true, theme: 'neutral' });
|
||||
window.onload = function() {
|
||||
const input = document.getElementById('search-input');
|
||||
if(!input) return;
|
||||
input.addEventListener('input', (e) => {
|
||||
const term = e.target.value.toLowerCase().trim();
|
||||
const contentArea = document.getElementById('content-area');
|
||||
const blocks = contentArea.querySelectorAll('p, li, blockquote, .fission-section, .mnemonic-card, details, .mermaid');
|
||||
if(term.length === 0) {
|
||||
blocks.forEach(el => el.classList.remove('hidden'));
|
||||
document.querySelectorAll('h1, h2, h3').forEach(el => el.classList.remove('hidden'));
|
||||
return;
|
||||
}
|
||||
blocks.forEach(el => el.classList.add('hidden'));
|
||||
document.querySelectorAll('h1, h2, h3').forEach(el => el.classList.add('hidden'));
|
||||
blocks.forEach(el => {
|
||||
if(el.innerText.toLowerCase().includes(term)) {
|
||||
el.classList.remove('hidden');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+383
@@ -0,0 +1,383 @@
|
||||
# Spring AI Alibaba Graph:诊断编排改造
|
||||
|
||||
作者:叫我小杨同学的小码酱
|
||||
标签:Spring AI Alibaba、StateGraph、Agent 编排、条件边、故障诊断
|
||||
|
||||
## 0. 核心摘要
|
||||
|
||||
一句话:让 ReactAgent 继续负责“做事”,让 StateGraph 负责“下一步去哪里”。
|
||||
|
||||
生活类比:Planner、Executor、Verifier 是医院里的不同科室,Graph 是分诊和转诊制度;不能让某个科室自己决定跳过检验和会诊。
|
||||
|
||||
真理锚点:官方文档将 Graph 概括为 State、Nodes、Edges,核心关系是“节点完成工作,边决定下一步做什么”。当前项目依赖的 `spring-ai-alibaba-graph-core:1.1.2.0` 本地 JAR 已确认提供 `StateGraph.addConditionalEdges(...)`、`CompileConfig.interruptBefore/After(...)` 和 `RunnableConfig.threadId(...)`。
|
||||
|
||||
## 1. 概念破冰
|
||||
|
||||
> 巧记:状态记事实,节点做任务,边管下一步,检查点管恢复。
|
||||
|
||||
当前 `ChatService` 已经像一个半成品状态机:`SequentialAgent` 固定执行 Planner、Executor、Verifier,外层 Java 循环再判断 PASS、LOW_CONFID、REJECT,并决定 Composer 或下一轮。问题不是 Agent 不够多,而是状态转换分散在 `SequentialAgent`、Hook 和外层 `if/else` 中。
|
||||
|
||||
```text
|
||||
当前
|
||||
SequentialAgent: Planner -> Executor -> Verifier
|
||||
|
|
||||
ChatService 外层: PASS / LOW_CONFID / REJECT -> Composer / retry
|
||||
|
||||
目标
|
||||
StateGraph 显式表示所有阶段和条件边
|
||||
ReactAgent 作为图中的语义节点继续复用
|
||||
```
|
||||
|
||||
## 2. 深度解析
|
||||
|
||||
### 2.1 为什么不是直接换成 SupervisorAgent
|
||||
|
||||
SupervisorAgent 适合在多个专科 Agent 之间动态选择,例如 Database、Redis、JVM。当前诊断链路中的 Gatekeeper、Verifier 是不能随意跳过的质量门禁。如果让 LLM Supervisor 决定下一步,关键流程会从代码控制变成模型决策。
|
||||
|
||||
当前真正需要的是确定性路由:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S["START"] --> P["Planner"]
|
||||
P --> E["Executor"]
|
||||
E -- "证据结构有效" --> G["Gatekeeper"]
|
||||
E -- "执行阻断或非法输出" --> F["Fallback"]
|
||||
G -- "PASS 或 LOW_CONFID" --> V["Verifier"]
|
||||
G -- "REJECT" --> F
|
||||
V -- "PASS" --> C["Composer"]
|
||||
V -- "LOW_CONFID 且有预算" --> R["Retry Guard"]
|
||||
V -- "REJECT 或无预算" --> C
|
||||
R -- "允许补证据" --> P
|
||||
R -- "停止" --> C
|
||||
C --> X["END"]
|
||||
F --> X
|
||||
```
|
||||
|
||||
### 2.2 State 应保存什么
|
||||
|
||||
状态应该保存跨节点需要共享的原始事实和结构化结果,不保存拼好的 Prompt,也不保存无边界增长的模型思考过程。
|
||||
|
||||
建议的语义状态:
|
||||
|
||||
- `diagnosis_context`:入口适配后的统一诊断上下文。
|
||||
- `planner_plan`:Planner 的结构化计划。
|
||||
- `executor_output`:`executor_evidence_v2`。
|
||||
- `executor_status`:成功、阻断、非法输出或失败。
|
||||
- `gatekeeper_result`:代码验真结果。
|
||||
- `verifier_output`、`verdict`:可推导性结果。
|
||||
- `retry_context`、`round`:有限补证据状态。
|
||||
- `final_answer`:最终表达。
|
||||
- `failure_reason`:确定性的失败原因。
|
||||
|
||||
现有 Trace 已由 `agent_step` 和 `tool_invocation` 持久化,Graph State 不需要复制所有原始日志。
|
||||
|
||||
### 2.3 KeyStrategy 如何选择
|
||||
|
||||
诊断状态大多使用 `ReplaceStrategy`,因为每个阶段产生当前轮的最新结果。只有确实需要累计的轻量事件列表才使用 `AppendStrategy`。
|
||||
|
||||
```java
|
||||
KeyStrategyFactory diagnosisStateStrategies() {
|
||||
return () -> {
|
||||
Map<String, KeyStrategy> strategies = new HashMap<>();
|
||||
strategies.put("diagnosis_context", new ReplaceStrategy());
|
||||
strategies.put("planner_plan", new ReplaceStrategy());
|
||||
strategies.put("executor_output", new ReplaceStrategy());
|
||||
strategies.put("executor_status", new ReplaceStrategy());
|
||||
strategies.put("gatekeeper_result", new ReplaceStrategy());
|
||||
strategies.put("verifier_output", new ReplaceStrategy());
|
||||
strategies.put("verdict", new ReplaceStrategy());
|
||||
strategies.put("retry_context", new ReplaceStrategy());
|
||||
strategies.put("round", new ReplaceStrategy());
|
||||
strategies.put("final_answer", new ReplaceStrategy());
|
||||
strategies.put("failure_reason", new ReplaceStrategy());
|
||||
return strategies;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 ReactAgent 怎样放进 Graph
|
||||
|
||||
本地 `1.1.2.0` 的 `ReactAgent` 提供 `asNode(boolean includeContents, boolean returnReasoningContents)`,可以直接作为子图节点。但当前项目 Planner、Executor、Verifier 的输入组织和输出解析已经有较多定制,第一阶段更推荐使用适配节点显式调用现有 Agent:
|
||||
|
||||
```java
|
||||
var plannerNode = node_async((state, config) -> {
|
||||
DiagnosisContext context = requireContext(state);
|
||||
String prompt = plannerInput(context, state.value("retry_context").orElse(null));
|
||||
|
||||
AssistantMessage response = plannerAgent.call(prompt, childConfig(config, "planner"));
|
||||
PlannerPlan plan = plannerParser.parse(extractText(response));
|
||||
|
||||
return Map.of(
|
||||
"planner_plan", plan,
|
||||
"failure_reason", ""
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
适配节点的好处是不会意外把父图全部 `messages` 注入所有 Agent,也能继续复用当前解析器、Hook、Prompt 和 ToolCallback。
|
||||
|
||||
等统一状态契约稳定后,可以评估:
|
||||
|
||||
```java
|
||||
graph.addNode("planner", plannerAgent.asNode(false, false));
|
||||
```
|
||||
|
||||
但需要先验证父子图的 `messages`、outputKey 和 Checkpointer 是否符合预期。
|
||||
|
||||
### 2.5 Executor 节点只报告状态,不决定路由
|
||||
|
||||
```java
|
||||
var executorNode = node_async((state, config) -> {
|
||||
try {
|
||||
PlannerPlan plan = requirePlan(state);
|
||||
DiagnosisContext context = requireContext(state);
|
||||
|
||||
AssistantMessage response = executorAgent.call(
|
||||
executorInput(context, plan),
|
||||
childConfig(config, "executor")
|
||||
);
|
||||
|
||||
ExecutorEvidence output = executorParser.parse(extractText(response));
|
||||
|
||||
if (!output.isStructurallyValid()) {
|
||||
return Map.of(
|
||||
"executor_status", "INVALID_OUTPUT",
|
||||
"failure_reason", "executor_evidence_v2 解析失败"
|
||||
);
|
||||
}
|
||||
|
||||
// no_evidence 仍然是合法结构,需要交给 Gatekeeper 验证真实引用。
|
||||
return Map.of(
|
||||
"executor_status", "COMPLETED",
|
||||
"executor_output", output
|
||||
);
|
||||
}
|
||||
catch (ToolCapabilityBlockedException e) {
|
||||
return Map.of(
|
||||
"executor_status", "TOOL_BLOCKED",
|
||||
"failure_reason", e.getMessage()
|
||||
);
|
||||
}
|
||||
catch (Exception e) {
|
||||
return Map.of(
|
||||
"executor_status", "FAILED",
|
||||
"failure_reason", safeMessage(e)
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
注意:`no_evidence` 不是 Executor 失败。当前项目已经用 `$.no_evidence` 表达“查询成功但无匹配证据”,它仍应进入 Gatekeeper 和 Verifier,防止被过度表达为“问题不存在”。
|
||||
|
||||
### 2.6 Gatekeeper 节点保持纯代码
|
||||
|
||||
```java
|
||||
var gatekeeperNode = node_async((state, config) -> {
|
||||
ExecutorEvidence output = requireExecutorOutput(state);
|
||||
String runId = metadata(config, "runId");
|
||||
|
||||
GatekeeperResult result = executorGatekeeperService.validate(runId, output);
|
||||
|
||||
return Map.of(
|
||||
"gatekeeper_result", result,
|
||||
"gatekeeper_status", result.severity()
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
Gatekeeper 不需要改造成 Agent。它负责确定性引用验真,是 Graph 中的普通 Java Node。
|
||||
|
||||
### 2.7 条件边是改造核心
|
||||
|
||||
```java
|
||||
StateGraph graph = new StateGraph("diagnosis_workflow", diagnosisStateStrategies())
|
||||
.addNode("planner", plannerNode)
|
||||
.addNode("executor", executorNode)
|
||||
.addNode("gatekeeper", gatekeeperNode)
|
||||
.addNode("verifier", verifierNode)
|
||||
.addNode("retry_guard", retryGuardNode)
|
||||
.addNode("composer", composerNode)
|
||||
.addNode("fallback", fallbackNode)
|
||||
|
||||
.addEdge(START, "planner")
|
||||
.addEdge("planner", "executor")
|
||||
|
||||
.addConditionalEdges(
|
||||
"executor",
|
||||
edge_async(state -> switch (stringValue(state, "executor_status")) {
|
||||
case "COMPLETED" -> "gatekeeper";
|
||||
case "INVALID_OUTPUT" -> retryAvailable(state) ? "retry_guard" : "fallback";
|
||||
case "TOOL_BLOCKED", "FAILED" -> "fallback";
|
||||
default -> "fallback";
|
||||
}),
|
||||
Map.of(
|
||||
"gatekeeper", "gatekeeper",
|
||||
"retry_guard", "retry_guard",
|
||||
"fallback", "fallback"
|
||||
)
|
||||
)
|
||||
|
||||
.addConditionalEdges(
|
||||
"gatekeeper",
|
||||
edge_async(state -> switch (stringValue(state, "gatekeeper_status")) {
|
||||
case "REJECT" -> "fallback";
|
||||
default -> "verifier";
|
||||
}),
|
||||
Map.of("verifier", "verifier", "fallback", "fallback")
|
||||
)
|
||||
|
||||
.addConditionalEdges(
|
||||
"verifier",
|
||||
edge_async(state -> switch (stringValue(state, "verdict")) {
|
||||
case "LOW_CONFID" -> retryAvailable(state) ? "retry_guard" : "composer";
|
||||
case "PASS", "REJECT" -> "composer";
|
||||
default -> "fallback";
|
||||
}),
|
||||
Map.of(
|
||||
"retry_guard", "retry_guard",
|
||||
"composer", "composer",
|
||||
"fallback", "fallback"
|
||||
)
|
||||
)
|
||||
|
||||
.addConditionalEdges(
|
||||
"retry_guard",
|
||||
edge_async(state -> shouldRetry(state) ? "planner" : "composer"),
|
||||
Map.of("planner", "planner", "composer", "composer")
|
||||
)
|
||||
|
||||
.addEdge("composer", END)
|
||||
.addEdge("fallback", END);
|
||||
```
|
||||
|
||||
### 2.8 编译和执行
|
||||
|
||||
```java
|
||||
SaverConfig saverConfig = SaverConfig.builder()
|
||||
.register(new MemorySaver())
|
||||
.build();
|
||||
|
||||
CompileConfig compileConfig = CompileConfig.builder()
|
||||
.recursionLimit(20)
|
||||
.saverConfig(saverConfig)
|
||||
.build();
|
||||
|
||||
CompiledGraph compiledGraph = graph.compile(compileConfig);
|
||||
|
||||
RunnableConfig runConfig = RunnableConfig.builder()
|
||||
// 一个 diagnosis_run 对应一个 Graph thread,避免同一 session 下多个 run 混状态。
|
||||
.threadId(runId)
|
||||
.addMetadata("sessionId", sessionId)
|
||||
.addMetadata("runId", runId)
|
||||
.build();
|
||||
|
||||
Map<String, Object> initialState = Map.of(
|
||||
"diagnosis_context", diagnosisContext,
|
||||
"round", 1
|
||||
);
|
||||
|
||||
Optional<OverAllState> finalState = compiledGraph.invoke(initialState, runConfig);
|
||||
```
|
||||
|
||||
`MemorySaver` 只适合进程内检查点,不等价于重启后可恢复的持久化。当前项目已有数据库 Trace,可以先把 Graph 用于流程控制;只有真正需要跨进程暂停恢复时,再引入持久 Checkpointer 或显式恢复模型。
|
||||
|
||||
### 2.9 Chat 与 AIOps 怎样共用
|
||||
|
||||
入口适配不同,公共 Graph 接收统一 `DiagnosisContext`:
|
||||
|
||||
```java
|
||||
DiagnosisContext chatContext = chatAdapter.from(question, history);
|
||||
DiagnosisContext aiOpsContext = aiOpsAdapter.from(alertPayload);
|
||||
|
||||
DiagnosisResult chatResult = diagnosisGraph.execute(chatContext, sessionId, runId);
|
||||
DiagnosisResult aiOpsResult = diagnosisGraph.execute(aiOpsContext, sessionId, runId);
|
||||
|
||||
return chatOutputAdapter.render(chatResult);
|
||||
return aiOpsOutputAdapter.render(aiOpsResult);
|
||||
```
|
||||
|
||||
Chat 的普通问答仍走轻量链路;复杂诊断才进入公共 Graph。AIOps 在入口阶段固定主告警范围,Graph 内部继续复用证据收集和验证。
|
||||
|
||||
### 2.10 人工中断怎么放
|
||||
|
||||
普通工具失败不需要 interrupt,条件边即可。只有确实需要等待人工输入或审批时才增加节点:
|
||||
|
||||
```java
|
||||
CompileConfig compileConfig = CompileConfig.builder()
|
||||
.saverConfig(saverConfig)
|
||||
.interruptBefore("human_review")
|
||||
.build();
|
||||
```
|
||||
|
||||
恢复时使用相同 `threadId` 和 checkpoint 信息,并通过 `RunnableConfig.builder(oldConfig).resume()` 或状态更新接口继续。具体恢复协议需要结合当前版本做集成测试,不能只凭文档假设。
|
||||
|
||||
## 3. 深度裂变
|
||||
|
||||
<div class="fission-section">
|
||||
|
||||
### 🔍 搜索内化:真正的改造对象不是 Agent,而是控制权
|
||||
|
||||
官方文档和本地 `1.1.2.0` JAR 均证明 Graph 节点既可以是 LLM,也可以是普通 Java 代码,条件边由状态决定目标节点。`ReactAgent` 本身已经是一个子图,并提供 `asNode(...)` 适配能力。
|
||||
|
||||
因此“从 Multi-Agent 改成 Graph”并不准确。更准确的是:把跨 Agent 的状态转换从高层 Flow 抽出来,交给父 Graph;ReactAgent 继续作为子图存在。
|
||||
|
||||
文档页面示例存在 `OverAllStaste` 拼写错误,实际类名是 `OverAllState`。网站主分支可能领先于本地依赖,因此最终应以项目锁定版本的 JAR 签名和编译测试为准。
|
||||
|
||||
</div>
|
||||
|
||||
## 4. 实战指南
|
||||
|
||||
### 4.1 最小迁移顺序
|
||||
|
||||
1. 定义统一的节点结果状态,不先改 Prompt。
|
||||
2. 把现有 Planner、Executor、Verifier 调用包装为 Graph Node。
|
||||
3. 将 Gatekeeper 和固定降级模板做成普通 Java Node。
|
||||
4. 先迁移当前两轮 LOW_CONFID 循环。
|
||||
5. 为 Executor 阻断、非法结构、Gatekeeper REJECT 增加条件边。
|
||||
6. 保留原 Sequential 链路作为回退,完成行为对比后再删除。
|
||||
7. 最后再考虑 HITL、并行和专科 SubAgent。
|
||||
|
||||
### 4.2 常见反模式
|
||||
|
||||
- 把每个异常都交给 LLM Supervisor 决策。
|
||||
- Graph State 存放所有原始日志和完整思考过程。
|
||||
- 把 `no_evidence` 当作 Executor 执行失败。
|
||||
- 同一 session 的多个 run 共用一个 Graph `threadId`。
|
||||
- 一开始就设计几十个节点和完整 Incident 状态机。
|
||||
- 未验证父子图消息传播就直接大量使用 `ReactAgent.asNode(true, true)`。
|
||||
- 把 `MemorySaver` 当成生产级持久化。
|
||||
|
||||
### 4.3 ROI
|
||||
|
||||
收益:条件分支可见、失败可测试、门禁不可跳过、Trace 更容易与节点对齐。
|
||||
代价:需要维护状态契约、条件边和父子图上下文,并增加 Graph 级测试。
|
||||
判断标准:如果当前只有固定顺序且失败直接结束,SequentialAgent 更简单;当局部重试、降级、HITL 和多入口策略已经出现时,StateGraph 的控制收益开始超过复杂度。
|
||||
|
||||
## 5. 温故知新
|
||||
|
||||
### FAQ
|
||||
|
||||
1. **Graph 会替代 ReactAgent 吗?** 不会,ReactAgent 可以作为 Graph 节点或由适配节点调用。
|
||||
2. **为什么不用 Supervisor 控制失败?** 失败跳转是确定性规则,不应增加一次 LLM 决策。
|
||||
3. **no_evidence 是否直接走 fallback?** 不一定。合法的 no-evidence 引用仍要经过 Gatekeeper 和 Verifier。
|
||||
4. **Composer 是否必须是 Agent?** 正常表达可以是轻量 Agent,系统失败场景应保留固定模板。
|
||||
5. **threadId 用 sessionId 还是 runId?** 当前模型下优先用 runId,避免同一会话多次运行状态串扰。
|
||||
6. **什么时候需要 Checkpointer?** 需要暂停、恢复、查看历史 Graph 状态时;普通 Trace 持久化不自动等于 Graph Checkpoint。
|
||||
7. **能否直接使用 agent.asNode?** 可以,但需要验证输入、outputKey、messages 和父子 Checkpointer 行为。
|
||||
8. **AIOps 是否要单独一张 Graph?** 可以先共用诊断核心,入口范围策略和输出报告保持独立。
|
||||
|
||||
### 自测题
|
||||
|
||||
1. 为什么 Executor 工具阻断不应该由 Verifier 判断是否重试?
|
||||
2. `ReplaceStrategy` 和 `AppendStrategy` 在诊断状态中分别适合什么数据?
|
||||
3. 为什么合法 `no_evidence` 仍然需要 Gatekeeper?
|
||||
4. SupervisorAgent 和 StateGraph 条件边的决策权有什么区别?
|
||||
5. 为什么当前 Graph `threadId` 更适合使用 runId?
|
||||
6. 什么情况下才应该增加 `interruptBefore`?
|
||||
|
||||
### 参考资源
|
||||
|
||||
- https://java2ai.com/docs/frameworks/graph-core/core/core-library
|
||||
- https://java2ai.com/docs/frameworks/graph-core/quick-start
|
||||
- Spring AI Alibaba 本地依赖:`spring-ai-alibaba-graph-core:1.1.2.0`
|
||||
- 当前项目:`ChatService`、`AiOpsService`、`ExecutorGatekeeperService`、`VerifierInputHook`
|
||||
+5
-3
@@ -1,6 +1,6 @@
|
||||
# SuperBizAgent MVP 文档
|
||||
|
||||
**更新日期**:2026-07-10
|
||||
**更新日期**:2026-07-20
|
||||
|
||||
本目录保存 MVP 阶段的架构、问题、演示、评测和数据表说明。当前材料按“当前入口”和“历史归档”拆开,避免把早期设计稿当成当前实现。
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|---|---|
|
||||
| [architecture/README.md](architecture/README.md) | 当前 MVP 架构入口 |
|
||||
| [architecture/current-mvp-architecture.md](architecture/current-mvp-architecture.md) | 当前可运行系统架构 |
|
||||
| [architecture/stategraph-runtime-architecture.md](architecture/stategraph-runtime-architecture.md) | 复杂 Chat StateGraph 运行时架构 |
|
||||
| [architecture/interview-one-pager.md](architecture/interview-one-pager.md) | 面试一页式架构讲解 |
|
||||
| [architecture/agent-orchestration.md](architecture/agent-orchestration.md) | Agent 编排架构 |
|
||||
| [architecture/executor-evidence-pipeline-refactor.md](architecture/executor-evidence-pipeline-refactor.md) | Executor 证据链路改造记录 |
|
||||
@@ -39,6 +40,7 @@ mvp/
|
||||
architecture/
|
||||
README.md
|
||||
current-mvp-architecture.md
|
||||
stategraph-runtime-architecture.md
|
||||
interview-one-pager.md
|
||||
agent-orchestration.md
|
||||
executor-evidence-pipeline-refactor.md
|
||||
@@ -55,7 +57,6 @@ mvp/
|
||||
README.md
|
||||
active/
|
||||
archived/
|
||||
design-notes/
|
||||
rag/
|
||||
tables/
|
||||
README.md
|
||||
@@ -118,9 +119,10 @@ RAG
|
||||
|
||||
## 归档说明
|
||||
|
||||
历史材料分两类:
|
||||
历史材料分三类:
|
||||
|
||||
- 旧架构文档:[architecture/archive/2026-07-05-legacy/](architecture/archive/2026-07-05-legacy/)
|
||||
- 本次文档清理归档:[archive/2026-07-09-doc-cleanup/](archive/2026-07-09-doc-cleanup/)
|
||||
- Run-only v2 和 StateGraph 收口后的旧材料:[archive/2026-07-20-doc-cleanup/](archive/2026-07-20-doc-cleanup/)
|
||||
|
||||
归档文档只用于追溯设计历史。当前实现和后续规划以 `architecture/`、`issues/README.md`、`tables/README.md` 和 OpenSpec/devflow 的最新记录为准。
|
||||
|
||||
+18
-16
@@ -1,6 +1,6 @@
|
||||
# MVP 架构文档
|
||||
|
||||
**更新日期**:2026-07-10
|
||||
**更新日期**:2026-07-20
|
||||
|
||||
这里是 MVP 当前架构的唯一入口。旧版设计、早期拆解和已经被新实现替代的方案已归档到:
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
| 文档 | 用途 |
|
||||
|---|---|
|
||||
| [current-mvp-architecture.md](current-mvp-architecture.md) | 当前可运行 MVP 的总体架构、链路、持久化和质量门禁 |
|
||||
| [stategraph-runtime-architecture.md](stategraph-runtime-architecture.md) | 最新复杂 Chat StateGraph 运行时权威快照,覆盖 Node 路由、状态边界、Run/Trace 持久化和验收层次 |
|
||||
| [interview-one-pager.md](interview-one-pager.md) | 面试一页式架构讲解,包含总图、亮点、取舍和追问回答 |
|
||||
| [agent-orchestration.md](agent-orchestration.md) | Agent 编排细节,覆盖 Chat SequentialAgent、AIOps SupervisorAgent、工具边界 |
|
||||
| [agent-orchestration.md](agent-orchestration.md) | Agent 编排细节,覆盖 Chat bounded StateGraph、AIOps SupervisorAgent、工具边界 |
|
||||
| [executor-evidence-pipeline-refactor.md](executor-evidence-pipeline-refactor.md) | Chat 证据链路当前数据契约,覆盖 Executor V2、Gatekeeper、Verifier、Composer、`evidence_refs` |
|
||||
| [harness-quality-gates.md](harness-quality-gates.md) | Prompt、Hook、Trace、Gatekeeper、Verifier、Composer、评测基线组成的质量门禁 |
|
||||
| [harness-quality-gates.md](harness-quality-gates.md) | Prompt、StateGraph、Trace、Gatekeeper、Verifier、Composer、评测基线组成的质量门禁 |
|
||||
| [rag-architecture.md](rag-architecture.md) | RAG/知识检索新架构,覆盖 L0 hint、VectorStore 主路径、SDK fallback、证据追踪 |
|
||||
| [modular-rag-pipeline.md](modular-rag-pipeline.md) | `lookup_knowledge` 模块化 RAG 落地架构,覆盖 pipeline、fallback、evidence-first contract、trace |
|
||||
| [rag-eval-closure.md](rag-eval-closure.md) | RAG 评测闭环,覆盖 offline baseline、baseline diff、diagnosis eval 和 live acceptance |
|
||||
@@ -29,20 +30,21 @@
|
||||
|
||||
## 当前架构一句话
|
||||
|
||||
SuperBizAgent MVP 是一个面向故障诊断的可追踪 Agent 系统:Chat 和 AIOps 入口统一进入 Agent 编排,Executor 通过显式工具收集日志、指标和知识库证据,Chat 链路由 Gatekeeper 做引用真实性校验、Verifier 做可推导性判断、Composer 生成最终表达;多轮会话元数据落到 `chat_session`,每次诊断运行落到 `diagnosis_run`,步骤和工具明细通过 `agent_step.run_id`、`tool_invocation.run_id` 关联,最终通过 Trace API 和评测脚本证明诊断链路可解释、可回放、可对比。
|
||||
SuperBizAgent MVP 是一个面向故障诊断的可追踪 Agent 系统:复杂 Chat 由有界 StateGraph 显式编排 Planner、Executor、Gatekeeper、Verified Input、Verifier、Composer 与安全 Fallback,Executor 通过工具收集日志、指标和知识库证据;多轮会话元数据落到 `chat_session`,每次诊断运行落到 `diagnosis_run`,步骤和工具明细通过 `run_id` 关联,Graph 路由摘要独立保存为 `orchestration_trace`,最终通过精确 Run Trace API 和评测脚本证明诊断链路可解释、可回放、可对比。
|
||||
|
||||
## 阅读顺序
|
||||
|
||||
1. 先读 [current-mvp-architecture.md](current-mvp-architecture.md),理解系统边界和主链路。
|
||||
2. 面试前读 [interview-one-pager.md](interview-one-pager.md),准备 2-5 分钟讲解。
|
||||
3. 再读 [agent-orchestration.md](agent-orchestration.md),理解当前 Agent 如何协作。
|
||||
4. 接着读 [executor-evidence-pipeline-refactor.md](executor-evidence-pipeline-refactor.md),理解 Chat 证据链路的数据结构和验真边界。
|
||||
5. 然后读 [harness-quality-gates.md](harness-quality-gates.md),理解为什么系统可追踪、可验证。
|
||||
6. 再读 [rag-architecture.md](rag-architecture.md),理解当前 RAG 为什么保留显式 `lookup_knowledge`,以及 Spring AI VectorStore 如何接入。
|
||||
7. 继续读 [modular-rag-pipeline.md](modular-rag-pipeline.md),看 `lookup_knowledge` 的模块化落地和 evidence-first contract。
|
||||
8. 再读 [rag-eval-closure.md](rag-eval-closure.md),看 RAG baseline 如何形成质量闭环。
|
||||
9. 然后读 [retrieval-observability.md](retrieval-observability.md),看检索细节和质量回归方式。
|
||||
10. 再读 [feedback-architecture.md](feedback-architecture.md),理解 self_evaluation、用户反馈和案例沉淀。
|
||||
11. 按需读 [session-trace-lifecycle.md](session-trace-lifecycle.md)、[knowledge-base-authoring.md](knowledge-base-authoring.md)、[data-model.md](data-model.md),补齐运行生命周期、知识库维护和数据关系。
|
||||
12. 最后读 [evolution-roadmap.md](evolution-roadmap.md),区分后续演进和当前实现。
|
||||
13. 需要追溯旧方案时,再进入 `archive/2026-07-05-legacy/`。
|
||||
2. 再读 [stategraph-runtime-architecture.md](stategraph-runtime-architecture.md),理解复杂 Chat 的真实运行时和路由边界。
|
||||
3. 面试前读 [interview-one-pager.md](interview-one-pager.md),准备 2-5 分钟讲解。
|
||||
4. 再读 [agent-orchestration.md](agent-orchestration.md),理解当前 Agent 如何协作。
|
||||
5. 接着读 [executor-evidence-pipeline-refactor.md](executor-evidence-pipeline-refactor.md),理解 Chat 证据链路的数据结构和验真边界。
|
||||
6. 然后读 [harness-quality-gates.md](harness-quality-gates.md),理解为什么系统可追踪、可验证。
|
||||
7. 再读 [rag-architecture.md](rag-architecture.md),理解当前 RAG 为什么保留显式 `lookup_knowledge`,以及 Spring AI VectorStore 如何接入。
|
||||
8. 继续读 [modular-rag-pipeline.md](modular-rag-pipeline.md),看 `lookup_knowledge` 的模块化落地和 evidence-first contract。
|
||||
9. 再读 [rag-eval-closure.md](rag-eval-closure.md),看 RAG baseline 如何形成质量闭环。
|
||||
10. 然后读 [retrieval-observability.md](retrieval-observability.md),看检索细节和质量回归方式。
|
||||
11. 再读 [feedback-architecture.md](feedback-architecture.md),理解 self_evaluation、用户反馈和案例沉淀。
|
||||
12. 按需读 [session-trace-lifecycle.md](session-trace-lifecycle.md)、[knowledge-base-authoring.md](knowledge-base-authoring.md)、[data-model.md](data-model.md),补齐运行生命周期、知识库维护和数据关系。
|
||||
13. 最后读 [evolution-roadmap.md](evolution-roadmap.md),区分后续演进和当前实现。
|
||||
14. 需要追溯旧方案时,再进入 `archive/2026-07-05-legacy/`。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Agent 编排架构
|
||||
|
||||
**更新日期**:2026-07-08
|
||||
**更新日期**:2026-07-20
|
||||
**状态**:当前可运行架构
|
||||
**参考历史文档**:`archive/2026-07-05-legacy/agent-architecture.md`
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
旧版 Agent 架构把系统描述为 Supervisor、Planner、SubAgent、Verifier 的团队协作。当前 MVP 保留这个核心思想,但实现更收敛:
|
||||
|
||||
- Chat 链路使用固定顺序工作流:`Planner -> Executor -> Gatekeeper -> Verifier -> Composer`。
|
||||
- Chat 复杂诊断使用有递归上限的显式 StateGraph;正常路径是 `Planner -> Executor -> Gatekeeper -> Verified Input -> Verifier -> Composer`,条件边负责有限技术重试、一次补证据和安全 Fallback。
|
||||
- AIOps 链路使用 `SupervisorAgent` 调度 `Planner + Executor`,最终由规则评估器做轻量验证。
|
||||
- 当前没有拆分 ExternalApiSubAgent、InternalErrorSubAgent、DatabaseSubAgent;这些作为后续演进方向保留。
|
||||
- 证据工具不直接散落在各个 Agent 里,而是通过 Spring AI ToolCallback / `@Tool` 统一暴露。
|
||||
@@ -19,15 +19,19 @@
|
||||
flowchart TB
|
||||
subgraph Chat["Chat diagnosis"]
|
||||
ChatIn["POST /api/chat"] --> ChatService["ChatService"]
|
||||
ChatService --> ChatPlanner["chat_planner"]
|
||||
ChatService --> ChatGraph["ChatDiagnosisGraphRuntime / StateGraph"]
|
||||
ChatGraph --> ChatPlanner["Planner Node"]
|
||||
ChatPlanner --> ChatExecutor["chat_executor"]
|
||||
ChatExecutor --> ChatTools["evidence tools"]
|
||||
ChatTools --> ChatExecutor
|
||||
ChatExecutor --> ChatGatekeeper["ExecutorGatekeeperService"]
|
||||
ChatGatekeeper --> ChatVerifier["chat_verifier"]
|
||||
ChatExecutor --> ChatGatekeeper["Gatekeeper Node"]
|
||||
ChatGatekeeper --> VerifiedInput["Verified Input Node"]
|
||||
VerifiedInput --> ChatVerifier["Verifier Node"]
|
||||
ChatVerifier --> ChatDecision{"PASS / LOW_CONFID / REJECT"}
|
||||
ChatDecision --> ChatComposer["chat_composer"]
|
||||
ChatDecision --> ChatComposer["Composer Node"]
|
||||
ChatDecision --> ChatFallback["Fallback Node"]
|
||||
ChatComposer --> ChatAnswer["final answer"]
|
||||
ChatFallback --> ChatAnswer
|
||||
end
|
||||
|
||||
subgraph AiOps["AIOps diagnosis"]
|
||||
@@ -54,6 +58,7 @@ flowchart TB
|
||||
ChatPlanner --> Step
|
||||
ChatExecutor --> Step
|
||||
ChatGatekeeper --> SelfEval
|
||||
ChatGraph --> Run
|
||||
ChatVerifier --> Step
|
||||
ChatTools --> Invocation
|
||||
ChatDecision --> SelfEval
|
||||
@@ -69,19 +74,13 @@ flowchart TB
|
||||
|
||||
## 3. Chat 编排
|
||||
|
||||
Chat 复杂诊断采用 `SequentialAgent`,顺序固定:
|
||||
Chat 复杂诊断采用 `ChatDiagnosisGraphRuntime` 执行、`DiagnosisGraphFactory` 编译的 bounded StateGraph。它有一条正常路径和显式条件边,不再依赖固定顺序 Agent 或隐式前置校验:
|
||||
|
||||
```text
|
||||
chat_planner
|
||||
-> chat_executor
|
||||
-> lookup_knowledge / query_logs / query_metrics / date_time
|
||||
-> outputs executor_evidence_v2
|
||||
-> VerifierInputHook / ExecutorGatekeeperService
|
||||
-> validates source_invocation_id / raw_path / evidence_excerpt
|
||||
-> chat_verifier
|
||||
-> judges whether verified evidence can derive claims
|
||||
-> chat_composer
|
||||
-> writes final user-facing answer
|
||||
START -> PLANNER -> EXECUTOR -> GATEKEEPER -> VERIFIED_INPUT -> VERIFIER -> COMPOSER -> END
|
||||
| | | | |
|
||||
+ retry + fallback + fallback + retry + retry/fallback
|
||||
+ EVIDENCE_RETRY -> PLANNER (最多一次)
|
||||
```
|
||||
|
||||
关键行为:
|
||||
@@ -90,16 +89,18 @@ chat_planner
|
||||
|---|---|---|
|
||||
| `chat_planner` | 拆解问题,注入知识域地图和对话历史,给出排查方向 | `planner_plan` |
|
||||
| `chat_executor` | 按计划调用证据工具,抽取带 `source_invocation_id + raw_path + evidence_excerpt` 的微观事实 | `executor_evidence_v2` |
|
||||
| `ExecutorGatekeeperService` | 在 Verifier 前做代码级引用验真,拒绝伪造 ID、错配 raw_path、错配 excerpt | `gatekeeper_result` |
|
||||
| `chat_verifier` | 只判断已验真 evidence excerpt 是否能推出 claim,不做新检索 | `verifier_output` |
|
||||
| `GatekeeperNode` / `ExecutorGatekeeperService` | 按当前 `runId` 做代码级引用验真,拒绝伪造 ID、错配 raw_path、错配 excerpt | `gatekeeper_result` |
|
||||
| `VerifiedInputNode` | 只投影 Gatekeeper 通过的 claims 与 matched evidence,隔离完整工具 Trace | `verified_executor_output`、`verified_evidence` |
|
||||
| `chat_verifier` | 只判断已验真的 evidence excerpt 是否能推出 claim,不做新检索、不读取完整工具 Trace | `verifier_output` |
|
||||
| `chat_composer` | 只表达 Verifier 允许输出的 claims、缺口和建议,生成最终用户答复 | `composer_output` |
|
||||
| `FallbackNode` | 在不可恢复失败或路由上限触发时生成非空安全答复 | `final_answer`、degraded trace |
|
||||
|
||||
Chat 链路最多支持两轮验证:
|
||||
Chat Graph 支持有限技术重试,并只允许一次 evidence retry;所有分支最终进入 Composer 或 Fallback:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
participant C as ChatService
|
||||
participant C as ChatService / StateGraph
|
||||
participant P as chat_planner
|
||||
participant E as chat_executor
|
||||
participant T as tools
|
||||
@@ -114,18 +115,22 @@ sequenceDiagram
|
||||
E->>T: 调用证据工具
|
||||
T-->>E: 证据结果
|
||||
E-->>C: executor_evidence_v2
|
||||
C->>G: executor_structured_output + tool_invocation.evidence_refs
|
||||
C->>G: executor_output + run-owned tool_invocation.evidence_refs
|
||||
G-->>C: gatekeeper_result
|
||||
C->>V: executor_structured_output + gatekeeper_result + tool_trace_summary
|
||||
C->>C: VerifiedInputNode projects passed claims/evidence
|
||||
C->>V: verified_executor_output + verified_evidence + gatekeeper_audit
|
||||
V-->>C: PASS / LOW_CONFID / REJECT
|
||||
C->>R: 写入 verifier_evaluation
|
||||
alt LOW_CONFID 且允许补证据
|
||||
alt LOW_CONFID 且允许一次补证据
|
||||
C->>P: retry_context: 仅补缺失证据
|
||||
else PASS 或 REJECT
|
||||
else PASS / LOW_CONFID 可输出
|
||||
C->>M: allowed_claims + missing_info + recommended_actions
|
||||
M-->>C: composer_output
|
||||
C->>R: 保存 Composer 最终 answer
|
||||
else 不可恢复失败
|
||||
C->>R: Fallback 安全答复
|
||||
end
|
||||
C->>R: 保存 orchestration_trace(version/transitions/final_node/termination_reason/degraded/evidence_retry_count)
|
||||
```
|
||||
|
||||
决策语义:
|
||||
@@ -134,7 +139,17 @@ sequenceDiagram
|
||||
|---|---|
|
||||
| `PASS` | 把 Verifier 允许表达的 claims 交给 Composer 输出 |
|
||||
| `LOW_CONFID` | 如果分数低于阈值且仍有轮次,构造 `retry_context` 补证据;否则输出低置信提示 |
|
||||
| `REJECT` | 输出降级答复,只保留已确认信息和下一步建议 |
|
||||
| `REJECT` | Verifier 完成后仍进入 Composer,但 Composer 只能表达允许材料和诊断限制;Gatekeeper REJECT 才直接进入 Fallback |
|
||||
|
||||
### 3.1 运行时边界
|
||||
|
||||
- 外层 Graph 使用 `runId` 作为 `RunnableConfig.threadId`,metadata 只承载 `sessionId/runId` 等业务身份。
|
||||
- `ReactAgentDiagnosisInvoker` 为 nested Agent 创建独立 config,不传播外层 human-feedback、state-update、checkpoint/resume 控制 metadata。
|
||||
- Graph State 默认 replace,只有 `orchestration_events` append;事件使用 portable Map,避免 DevTools classloader 的 record identity 问题。
|
||||
- Planner、Verifier、Composer 各最多一次技术重试;evidence retry 独立计数且最多一次;Graph recursion limit 为 32。
|
||||
- `DiagnosisGraphResultMapper` 负责质量评估,`DiagnosisOrchestrationTraceBuilder` 负责路由摘要,两者分别写入 `self_evaluation` 和 `orchestration_trace`。
|
||||
|
||||
完整运行时拓扑、路由表和失败语义见 [stategraph-runtime-architecture.md](stategraph-runtime-architecture.md)。
|
||||
|
||||
## 4. AIOps 编排
|
||||
|
||||
@@ -207,7 +222,7 @@ flowchart LR
|
||||
| Planner | 只看 skill name / description,并输出 `selected_skill` | 不暴露 `read_skill` |
|
||||
| Executor | 读取 Planner 选中的 skill 正文 | 暴露官方 `read_skill` 和证据工具 |
|
||||
| Gatekeeper | 不看 skill catalog,也不读 skill 正文 | 只读取 Executor 输出和 `tool_invocation.retrieval_details.evidence_refs` |
|
||||
| Verifier | 不看 skill catalog,也不读 skill 正文 | 只读取 Gatekeeper 结果、结构化 claims 和 trace summary |
|
||||
| Verifier | 不看 skill catalog,也不读 skill 正文 | 只读取 Verified Input 投影和 Gatekeeper audit |
|
||||
| Composer | 不看 skill catalog,也不读 skill 正文 | 只读取 Verifier 允许表达的内容 |
|
||||
|
||||
## 7. 与旧版设计的差异
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 当前 MVP 架构
|
||||
|
||||
**更新日期**:2026-07-08
|
||||
**更新日期**:2026-07-20
|
||||
**状态**:当前可运行架构
|
||||
**适用范围**:Demo、面试讲解、后续迭代规划
|
||||
|
||||
@@ -36,11 +36,14 @@ flowchart TB
|
||||
|
||||
subgraph Agent["Agent Orchestration"]
|
||||
Supervisor["Supervisor"]
|
||||
StateGraph["Chat Diagnosis StateGraph"]
|
||||
Planner["Planner"]
|
||||
Executor["Executor"]
|
||||
Gatekeeper["Gatekeeper"]
|
||||
VerifiedInput["Verified Input"]
|
||||
Verifier["Verifier"]
|
||||
Composer["Composer"]
|
||||
Fallback["Fallback"]
|
||||
end
|
||||
|
||||
subgraph Tools["Evidence Tools"]
|
||||
@@ -74,7 +77,14 @@ flowchart TB
|
||||
end
|
||||
|
||||
API --> App
|
||||
ChatService --> Agent
|
||||
ChatService --> StateGraph
|
||||
StateGraph --> Planner
|
||||
StateGraph --> Executor
|
||||
StateGraph --> Gatekeeper
|
||||
StateGraph --> VerifiedInput
|
||||
StateGraph --> Verifier
|
||||
StateGraph --> Composer
|
||||
StateGraph --> Fallback
|
||||
AiOpsService --> Agent
|
||||
SkillRegistry --> PlannerSkillHook
|
||||
PlannerSkillHook --> Planner
|
||||
@@ -86,8 +96,8 @@ flowchart TB
|
||||
RAG --> Store
|
||||
Tools --> Invocation
|
||||
Agent --> Step
|
||||
App --> Session
|
||||
TraceService --> Session
|
||||
App --> ChatSession
|
||||
TraceService --> ChatSession
|
||||
TraceService --> Step
|
||||
TraceService --> Invocation
|
||||
```
|
||||
@@ -157,7 +167,8 @@ sequenceDiagram
|
||||
participant Planner as Planner Agent
|
||||
participant Executor as Executor Agent
|
||||
participant Tool as Evidence Tools
|
||||
participant Gatekeeper as Gatekeeper Hook
|
||||
participant Gatekeeper as Gatekeeper Node
|
||||
participant Projection as Verified Input Node
|
||||
participant Verifier as Verifier Agent
|
||||
participant Composer as Composer Agent
|
||||
participant DB as Trace Tables
|
||||
@@ -174,11 +185,12 @@ sequenceDiagram
|
||||
Tool-->>Executor: 返回证据
|
||||
Executor->>Gatekeeper: 输出 executor_evidence_v2
|
||||
Gatekeeper->>DB: 读取 tool_invocation.evidence_refs 并校验引用
|
||||
Gatekeeper->>Verifier: 传入已验真的 claims / excerpts
|
||||
Gatekeeper->>Projection: 输出通过验真的 bindings
|
||||
Projection->>Verifier: 只传入 verified claims / evidence
|
||||
Verifier->>DB: 合并 diagnosis_run.self_evaluation.verifier_evaluation
|
||||
Verifier->>Composer: 传入 allowed_claims / missing_info / actions
|
||||
Composer->>Chat: 生成最终用户答复
|
||||
Chat->>DB: 保存 diagnosis_run.answer
|
||||
Chat->>DB: 保存 answer / self_evaluation / orchestration_trace
|
||||
User->>Trace: GET /api/diagnosis/{sessionId}/trace?runId=...
|
||||
Trace->>DB: 聚合 run / step / tool
|
||||
Trace-->>User: 返回可回放诊断链路
|
||||
@@ -194,19 +206,21 @@ POST /api/chat
|
||||
-> lookup_knowledge
|
||||
-> query_logs
|
||||
-> query_metrics
|
||||
-> Gatekeeper 校验 Executor 证据引用真实性
|
||||
-> Verifier 判断 claim 是否能由已核验证据推出
|
||||
-> Gatekeeper Node 校验 Executor 证据引用真实性
|
||||
-> Verified Input Node 只投影通过验真的 claims/evidence
|
||||
-> Verifier 判断 claim 是否能由已验真证据推出
|
||||
-> Composer 生成最终用户答复
|
||||
-> 保存 chat_session metadata
|
||||
-> 保存 diagnosis_run
|
||||
-> 保存 agent_step.run_id
|
||||
-> 保存 tool_invocation.run_id
|
||||
-> 合并 diagnosis_run.self_evaluation.verifier_evaluation
|
||||
-> 保存 diagnosis_run.orchestration_trace
|
||||
```
|
||||
|
||||
Chat 链路的质量门禁由三段组成:Gatekeeper 先做代码级引用验真,Verifier 再做 LLM 可推导性判断,Composer 最后控制对用户的表达边界。Gatekeeper、Verifier、Composer 的输出合并到当前 `diagnosis_run.self_evaluation.verifier_evaluation`,Trace API 会展示该验证结果。
|
||||
Chat 链路的质量门禁由四段组成:Gatekeeper 先做代码级引用验真,Verified Input 再隔离未通过的 binding,Verifier 做 LLM 可推导性判断,Composer 最后控制对用户的表达边界。结构化质量结果合并到 `diagnosis_run.self_evaluation.verifier_evaluation`;Node 路由、重试和降级摘要独立写入 `diagnosis_run.orchestration_trace`。
|
||||
|
||||
Agent 编排细节见 [agent-orchestration.md](agent-orchestration.md)。
|
||||
最新运行时、路由和状态边界见 [stategraph-runtime-architecture.md](stategraph-runtime-architecture.md),Agent 职责见 [agent-orchestration.md](agent-orchestration.md)。
|
||||
|
||||
关键代码:
|
||||
|
||||
@@ -333,6 +347,7 @@ diagnosis_run
|
||||
-> run_id / session_id
|
||||
-> query / status / agent_flow / answer
|
||||
-> self_evaluation
|
||||
-> orchestration_trace
|
||||
-> step_count / tool_call_count / duration
|
||||
|
||||
agent_step
|
||||
@@ -355,7 +370,7 @@ tool_invocation
|
||||
说明:
|
||||
|
||||
- 旧的 `diagnosis_record` 已不是当前主模型。
|
||||
- `diagnosis_session` 已降级为历史兼容和回滚表,新执行写入 `chat_session + diagnosis_run`。
|
||||
- 当前运行时只使用 `chat_session + diagnosis_run`,不再映射、读取或写入 `diagnosis_session`。
|
||||
- `api_document` 仍用于文档元数据管理。
|
||||
- 文档向量内容存放在 Milvus/Zilliz collection 中。
|
||||
|
||||
@@ -374,11 +389,12 @@ Trace API 聚合:
|
||||
- Agent step 序列。
|
||||
- 工具调用和检索细节。
|
||||
- Chat Gatekeeper / Verifier / Composer 结果。
|
||||
- Chat `run.orchestrationTrace` 路由摘要,解析自 `diagnosis_run.orchestration_trace`,独立于 self-evaluation 和步骤/工具明细。
|
||||
- AIOps rule evaluation 结果。
|
||||
|
||||
Trace 是本项目区别于普通问答系统的关键:答案不是孤立文本,而是可以追溯到 Agent 决策、工具调用和证据来源。
|
||||
|
||||
Prompt、Hook、Gatekeeper、Verifier、Composer 和评测门禁的完整说明见 [harness-quality-gates.md](harness-quality-gates.md),用户反馈与 `self_evaluation` 闭环见 [feedback-architecture.md](feedback-architecture.md)。
|
||||
Prompt、StateGraph、Gatekeeper、Verifier、Composer 和评测门禁的完整说明见 [harness-quality-gates.md](harness-quality-gates.md),用户反馈与 `self_evaluation` 闭环见 [feedback-architecture.md](feedback-architecture.md)。
|
||||
|
||||
## 8. 质量门禁
|
||||
|
||||
@@ -386,9 +402,11 @@ Prompt、Hook、Gatekeeper、Verifier、Composer 和评测门禁的完整说明
|
||||
|
||||
| 门禁 | 位置 | 作用 |
|
||||
|---|---|---|
|
||||
| Executor Gatekeeper | `VerifierInputHook` / `ExecutorGatekeeperService` | 校验 Executor 引用的 invocation、`raw_path`、`evidence_excerpt` 是否真实 |
|
||||
| Chat Verifier | `ChatService` | 判断已验真证据是否能推出 Executor claims |
|
||||
| Chat Composer | `ChatService` | 只表达 Verifier 允许输出的内容,避免把 no-evidence 说成已排除 |
|
||||
| Executor Gatekeeper | `GatekeeperNode` / `ExecutorGatekeeperService` | 校验当前 Run 的 invocation、`raw_path`、`evidence_excerpt` 是否真实 |
|
||||
| Verified Input | `VerifiedInputNode` | 仅投影 Gatekeeper 通过的 claims/evidence,阻断完整工具 Trace 进入 Verifier |
|
||||
| Chat Verifier | `VerifierNodeAdapter` | 判断已验真证据是否能推出 Executor claims |
|
||||
| Chat Composer / Fallback | `ComposerNodeAdapter` / `FallbackNode` | 输出受控答复;异常分支也必须安全终止 |
|
||||
| Graph routing | `DiagnosisGraphWorkflowTest` / `run.orchestrationTrace` | 验证条件边、有限重试、最终节点和终止原因 |
|
||||
| AIOps Rule Evaluation | `AiOpsRuleEvaluationService` | 校验告警诊断是否聚焦 payload 并使用证据 |
|
||||
| Diagnosis Eval Baseline | `mvp/eval/` | 固化诊断 trace 和报告行为 |
|
||||
| RAG Retrieval Baseline | `eval/rag-retrieval/` | 固化检索召回行为,避免 RAG 重构回退 |
|
||||
@@ -399,6 +417,7 @@ Prompt、Hook、Gatekeeper、Verifier、Composer 和评测门禁的完整说明
|
||||
已经完成:
|
||||
|
||||
- Chat 和 AIOps 两条入口链路。
|
||||
- Chat 复杂诊断已单轨切换到 bounded StateGraph,并持久化 Run-owned `orchestration_trace`;Graph event 使用 portable Map,nested ReactAgent config 与外层 checkpoint/resume 控制信息隔离。
|
||||
- 显式 `lookup_knowledge` Agent Tool。
|
||||
- L0 从最终决策降级为 domain/entity hint。
|
||||
- `VectorSearchService` 作为稳定检索门面。
|
||||
@@ -423,13 +442,16 @@ Prompt、Hook、Gatekeeper、Verifier、Composer 和评测门禁的完整说明
|
||||
- VectorStore 写入路径全面迁移。
|
||||
- 完整 LLM-based AIOps verifier。
|
||||
|
||||
后续 Agent 拆分、Skill/Playbook、MCP 工具协议化和进程隔离等方向见 [evolution-roadmap.md](evolution-roadmap.md)。
|
||||
后续 Agent 拆分、Playbook 版本化增强、MCP 工具协议化和进程隔离等方向见 [evolution-roadmap.md](evolution-roadmap.md)。
|
||||
|
||||
## 10. 关键代码索引
|
||||
|
||||
| 能力 | 代码 |
|
||||
|---|---|
|
||||
| Chat 入口与编排 | `ChatController`, `ChatService` |
|
||||
| Chat StateGraph runtime | `ChatDiagnosisGraphRuntime`, `DiagnosisGraphFactory`, `DiagnosisGraphRouter`, `DiagnosisGraphState` |
|
||||
| Chat Node assembly/config isolation | `DiagnosisRealGraphActionsFactory`, `ReactAgentDiagnosisInvoker` |
|
||||
| Graph result/audit mapping | `DiagnosisGraphResultMapper`, `DiagnosisOrchestrationTraceBuilder` |
|
||||
| AIOps 入口与编排 | `ChatController.aiOps`, `AiOpsService` |
|
||||
| AIOps 规则验证 | `AiOpsRuleEvaluationService` |
|
||||
| 知识库工具 | `LookupKnowledgeTool` |
|
||||
@@ -440,5 +462,5 @@ Prompt、Hook、Gatekeeper、Verifier、Composer 和评测门禁的完整说明
|
||||
| Spring AI VectorStore 配置辅助 | `SpringAiVectorStoreSidecarService` |
|
||||
| Trace 聚合 | `DiagnosisTraceService` |
|
||||
| 工具调用记录 | `ToolInvocationRecorder` |
|
||||
| Executor 引用验真 | `ExecutorGatekeeperService`, `VerifierInputHook` |
|
||||
| Executor 引用验真与投影 | `GatekeeperNode`, `ExecutorGatekeeperService`, `VerifiedInputNode` |
|
||||
| self_evaluation 合并 | `SelfEvaluationMergeService` |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 数据模型总览
|
||||
|
||||
**更新日期**:2026-07-10
|
||||
**更新日期**:2026-07-20
|
||||
**状态**:当前可运行架构
|
||||
|
||||
## 1. 定位
|
||||
@@ -13,7 +13,7 @@
|
||||
- 知识库:`api_document`、`knowledge_domain`、Milvus/Zilliz metadata
|
||||
- 反馈沉淀:`case_library`
|
||||
|
||||
`diagnosis_session` 仍保留为历史兼容和回滚表,不再是新执行写入的主模型。
|
||||
当前运行时只使用 `chat_session + diagnosis_run`;旧 `diagnosis_session` 表不属于当前版本契约。
|
||||
|
||||
## 2. 总体关系
|
||||
|
||||
@@ -44,6 +44,7 @@ erDiagram
|
||||
varchar agent_flow
|
||||
longtext answer
|
||||
json self_evaluation
|
||||
json orchestration_trace
|
||||
varchar feedback
|
||||
}
|
||||
|
||||
@@ -111,6 +112,7 @@ erDiagram
|
||||
| `agent_flow` | `CHAT` / `AI_OPS` |
|
||||
| `answer` | 本次运行最终答复或告警报告 |
|
||||
| `self_evaluation` | 本次运行的 rule/verifier/aiops 自评估容器 |
|
||||
| `orchestration_trace` | nullable JSON;复杂 Chat 的 StateGraph 路由摘要,非 StateGraph Run 可为空 |
|
||||
| `feedback` | 本次运行的用户反馈 |
|
||||
|
||||
同一个 `sessionId` 可以有多个 `runId`。Trace、反馈、评测和案例沉淀都应优先使用 `runId`,避免多轮同 session 下的数据混合。
|
||||
@@ -139,7 +141,19 @@ erDiagram
|
||||
|
||||
`$.no_evidence` 只表示“本次工具查询未检索到匹配证据”,不能被解释为“问题不存在”或“根因已排除”。
|
||||
|
||||
## 5. 反馈沉淀模型
|
||||
## 5. Run 级审计分层
|
||||
|
||||
一次 Run 的可审计信息分为三层,不能互相替代:
|
||||
|
||||
| 层次 | 存储 | 语义 |
|
||||
|---|---|---|
|
||||
| 执行明细 | `agent_step`、`tool_invocation` | 模型步骤、工具输入输出、检索细节和证据事实 |
|
||||
| 质量评估 | `diagnosis_run.self_evaluation` | rule/verifier/aiops 判断、Gatekeeper 审计、Prompt 版本和允许输出材料 |
|
||||
| 编排摘要 | `diagnosis_run.orchestration_trace` | StateGraph transitions、final node、termination reason、degraded、evidence retry count |
|
||||
|
||||
`orchestration_trace` 只通过 exact Run 的 `run.orchestrationTrace` 暴露,Trace 响应不再包含兼容 `session` 投影。Run 状态仍只表达执行生命周期:安全 Fallback 是 `SUCCESS + degraded=true`,只有无法生成安全响应或未处理失败才是 `FAILED`。
|
||||
|
||||
## 6. 反馈沉淀模型
|
||||
|
||||
`useful` 反馈会触发 `CaseLibraryService.createFromRun`。
|
||||
|
||||
@@ -148,7 +162,7 @@ erDiagram
|
||||
| 字段 | 来源 |
|
||||
|---|---|
|
||||
| `case_id` | UUID |
|
||||
| `diagnosis_id` | 新数据为 `diagnosis_run.run_id`;历史数据可能为 `diagnosis_session.session_id` |
|
||||
| `diagnosis_id` | `diagnosis_run.run_id` |
|
||||
| `source_type` | `AUTO` |
|
||||
| `fault_category` | 当前默认 `GENERAL` |
|
||||
| `title` | run query 前 100 字符 |
|
||||
@@ -156,7 +170,7 @@ erDiagram
|
||||
| `solution` | run answer |
|
||||
| `created_by` | `system` |
|
||||
|
||||
## 6. self_evaluation 结构
|
||||
## 7. self_evaluation 结构
|
||||
|
||||
`diagnosis_run.self_evaluation` 是运行级 JSON 容器:
|
||||
|
||||
@@ -170,16 +184,19 @@ erDiagram
|
||||
|
||||
Chat 通常写入 `rule_evaluation` 和 `verifier_evaluation`;AIOps 写入 `aiops_rule_evaluation`。
|
||||
|
||||
## 7. 当前边界和后续
|
||||
`orchestration_trace` 不放入该 JSON,避免把答案质量和 Graph 路由混成同一审计维度。
|
||||
|
||||
## 8. 当前边界和后续
|
||||
|
||||
当前边界:
|
||||
|
||||
- `chat_session` 只存会话元数据,不存完整正文历史。
|
||||
- `diagnosis_run` 存一次运行的长期审计状态。
|
||||
- `agent_step.run_id` 和 `tool_invocation.run_id` 是 Trace、Verifier、Eval 的运行边界。
|
||||
- `diagnosis_run.orchestration_trace` 是 nullable Run-owned Graph 摘要;非 StateGraph Run 可以为空。
|
||||
- 当前实现主要使用逻辑关联,不依赖数据库外键。
|
||||
- `case_library.diagnosis_id` 是过渡字段,新值按 `run_id` 解释,旧值可能按 `session_id` 解释。
|
||||
- `diagnosis_session` 只作为历史兼容和回滚表保留。
|
||||
- 当前 Java 运行时不存在 `diagnosis_session` entity/repository 或 fallback。
|
||||
|
||||
后续可增强:
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# Agent 架构演进路线
|
||||
|
||||
**更新日期**:2026-07-05
|
||||
**更新日期**:2026-07-20
|
||||
**状态**:后续演进设计,不代表当前已实现
|
||||
**参考历史文档**:`archive/2026-07-05-legacy/agent-architecture.md`
|
||||
|
||||
## 1. 为什么需要演进路线
|
||||
|
||||
旧版 `agent-architecture.md` 包含很多生产级设想:专科 SubAgent、Skill 体系、进程隔离、回退路由、MCP 工具协议化、进化引擎。它们不应作为当前 MVP 事实写入主架构,但可以作为后续扩展路线。
|
||||
旧版 `agent-architecture.md` 包含很多生产级设想:专科 SubAgent、完整 Skill 治理、进程隔离、跨 Agent 回退、MCP 工具协议化、进化引擎。当前已经落地 bounded StateGraph、安全 Fallback 和基础 Skill/Playbook 接入;本文件只描述它们之上的后续增强。
|
||||
|
||||
当前原则:
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
MVP["Current MVP: Planner + Executor + Verifier"] --> Split{"Executor 是否过载?"}
|
||||
MVP["Current MVP: bounded StateGraph + evidence gates"] --> Split{"Executor 是否过载?"}
|
||||
Split -->|是| SubAgents["专科 SubAgent"]
|
||||
Split -->|否| Keep["继续强化通用 Executor"]
|
||||
|
||||
SubAgents --> Skills["Skill / Playbook 体系"]
|
||||
Skills --> Fallback["回退路由"]
|
||||
SubAgents --> Skills["Skill / Playbook 版本化治理"]
|
||||
Skills --> Fallback["跨 SubAgent 回退路由"]
|
||||
Fallback --> Isolation["进程或 Pod 隔离"]
|
||||
|
||||
MVP --> ToolGrowth{"工具数量和来源是否增长?"}
|
||||
@@ -59,9 +59,9 @@ flowchart TD
|
||||
- 过早拆分会增加 Prompt、评测和 trace 分析成本。
|
||||
- 没有足够分类评测前,拆分可能只是移动复杂度。
|
||||
|
||||
## 4. Skill / Playbook 体系
|
||||
## 4. Skill / Playbook 版本化治理
|
||||
|
||||
旧版设计中的 Skill 可以在当前项目中演进为可版本化的诊断 Playbook。
|
||||
当前已经通过 Planner metadata selection + Executor `read_skill` 接入诊断 Playbook。下一阶段不是重新建设 Skill 入口,而是增加版本、评测、回退和审计治理。
|
||||
|
||||
```text
|
||||
fault_category
|
||||
@@ -73,14 +73,14 @@ fault_category
|
||||
-> evaluation checks
|
||||
```
|
||||
|
||||
优先落地方向:
|
||||
当前已覆盖的方向:
|
||||
|
||||
- AIOps 告警处理 Playbook。
|
||||
- 支付超时 Playbook。
|
||||
- MySQL 连接池风险 Playbook。
|
||||
- Redis timeout Playbook。
|
||||
|
||||
落地前提:
|
||||
后续增强前提:
|
||||
|
||||
- 每个 Playbook 至少有 3-5 个 eval case。
|
||||
- Playbook 失败时可以回退到通用 Executor。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Chat Evidence Pipeline Contracts
|
||||
|
||||
**状态**:当前实现
|
||||
**更新日期**:2026-07-08
|
||||
**更新日期**:2026-07-17
|
||||
**范围**:Chat 复杂诊断链路中的 Planner、Executor、Gatekeeper、Verifier、Composer 数据契约
|
||||
|
||||
当前 Chat 复杂诊断链路是:
|
||||
@@ -9,7 +9,8 @@
|
||||
```text
|
||||
chat_planner
|
||||
-> chat_executor
|
||||
-> VerifierInputHook / ExecutorGatekeeperService
|
||||
-> GatekeeperNode / ExecutorGatekeeperService
|
||||
-> VerifiedInputNode
|
||||
-> chat_verifier
|
||||
-> chat_composer
|
||||
-> final answer
|
||||
@@ -219,13 +220,13 @@ Executor 必须遵守:
|
||||
|
||||
## 4. Gatekeeper
|
||||
|
||||
Gatekeeper 位于 Verifier 前,由 `VerifierInputHook` 触发,负责代码级引用真实性校验。
|
||||
Gatekeeper 是 StateGraph 中的显式 Node,调用 `ExecutorGatekeeperService` 对当前 Run 的证据引用做代码级真实性校验。
|
||||
|
||||
### 4.1 输入
|
||||
|
||||
- `sessionId`
|
||||
- `sessionId + runId`(来自 `RunnableConfig`,工具查询以 `runId` 为边界)
|
||||
- `executor_structured_output`
|
||||
- 当前 session 的 `tool_invocation`
|
||||
- 当前 run 的 `tool_invocation`
|
||||
|
||||
### 4.2 输出
|
||||
|
||||
@@ -304,22 +305,20 @@ Gatekeeper 位于 Verifier 前,由 `VerifierInputHook` 触发,负责代码
|
||||
|
||||
## 5. Verifier
|
||||
|
||||
Verifier 输入由 `VerifierInputHook` 构造:
|
||||
`VerifiedInputNode` 只保留 Gatekeeper 检查通过的 claim/binding,并为 Verifier 构造最小输入:
|
||||
|
||||
```json
|
||||
{
|
||||
"original_query": "用户原始问题",
|
||||
"executor_final_answer": "{...executor raw text for debug/fallback only...}",
|
||||
"executor_structured_output": {
|
||||
"diagnosis_context": {
|
||||
"query": "用户原始问题"
|
||||
},
|
||||
"verified_executor_output": {
|
||||
"answer_version": "executor_evidence_v2",
|
||||
"claims": []
|
||||
},
|
||||
"executor_output_parse_status": {
|
||||
"status": "valid",
|
||||
"detail": "parsed executor evidence contract"
|
||||
},
|
||||
"tool_trace_summary": [],
|
||||
"gatekeeper_result": {},
|
||||
"verified_evidence": [],
|
||||
"gatekeeper_audit": {},
|
||||
"verdict_ceiling": "PASS",
|
||||
"retry_context": null
|
||||
}
|
||||
```
|
||||
@@ -330,7 +329,7 @@ Verifier 职责:
|
||||
- 不读 skill。
|
||||
- 不逐字核验 excerpt 真伪;这由 Gatekeeper 完成。
|
||||
- 只判断 `claim_text` 是否能由已核验的 `evidence_excerpt` 推出。
|
||||
- 结构化输出有效时,不得从 `executor_final_answer` 抽取额外确认事实。
|
||||
- 不读取 Executor 原始答复或完整工具 Trace,只读取 verified projection。
|
||||
- 对 `gatekeeper_result.severity=reject` 不得输出 `PASS`。
|
||||
- 对 `gatekeeper_result.severity=low_confid` 不得输出 `PASS`。
|
||||
|
||||
@@ -410,7 +409,7 @@ Composer 位于 Verifier 之后,输入是 ChatService 过滤后的允许表达
|
||||
"rule_set_version": "gatekeeper-rules-v1"
|
||||
},
|
||||
"composer_output": {},
|
||||
"tool_trace_summary": []
|
||||
"verified_evidence": []
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -422,6 +421,9 @@ Trace API 可用于回放:
|
||||
- Gatekeeper 是否通过、是否自动回填。
|
||||
- Verifier 如何判断可推导性。
|
||||
- Composer 最终如何表达给用户。
|
||||
- `run.orchestrationTrace` 如何经过条件边、有限重试并终止。
|
||||
|
||||
当前版本不生成、读取或展示 `verifier_evaluation.tool_trace_summary`;Verifier 只消费 verified projection。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 反馈与自评估架构
|
||||
|
||||
**更新日期**:2026-07-10
|
||||
**更新日期**:2026-07-17
|
||||
**状态**:当前可运行架构
|
||||
**参考历史文档**:`archive/2026-07-05-legacy/confidence-feedback.md`
|
||||
|
||||
@@ -27,9 +27,8 @@ flowchart TD
|
||||
Invocation["tool_invocation"] --> RuleEval["EvaluationService: rule_evaluation"]
|
||||
Invocation --> EvidenceRefs["evidence_refs"]
|
||||
EvidenceRefs --> Gatekeeper["ExecutorGatekeeperService"]
|
||||
Invocation --> TraceSummary["ToolTraceSummaryService"]
|
||||
Gatekeeper --> Verifier["chat_verifier"]
|
||||
TraceSummary --> Verifier
|
||||
Gatekeeper --> Projection["VerifiedInputNode"]
|
||||
Projection --> Verifier["chat_verifier"]
|
||||
Verifier --> VerifierEval["verifier_evaluation"]
|
||||
Verifier --> Composer["chat_composer"]
|
||||
Composer --> VerifierEval
|
||||
@@ -57,7 +56,7 @@ flowchart TD
|
||||
|
||||
## 3. self_evaluation JSON
|
||||
|
||||
`SelfEvaluationMergeService` 统一维护当前运行的 `diagnosis_run.self_evaluation`。历史兼容数据可能仍存在于 `diagnosis_session.self_evaluation`,但新 Chat/AIOps 执行不再写旧表。
|
||||
`SelfEvaluationMergeService` 只维护当前运行的 `diagnosis_run.self_evaluation`,不再解析或写入旧 `diagnosis_session` 数据。
|
||||
|
||||
当前结构:
|
||||
|
||||
@@ -81,7 +80,7 @@ flowchart TD
|
||||
"executor_structured_output": {},
|
||||
"gatekeeper_result": {},
|
||||
"composer_output": {},
|
||||
"tool_trace_summary": []
|
||||
"verified_evidence": []
|
||||
},
|
||||
"aiops_rule_evaluation": {
|
||||
"verdict": "...",
|
||||
@@ -90,10 +89,7 @@ flowchart TD
|
||||
}
|
||||
```
|
||||
|
||||
兼容逻辑:
|
||||
|
||||
- 如果旧 JSON 根节点包含 `evidence_score`,会被包进 `rule_evaluation`。
|
||||
- 如果旧 JSON 根节点包含 `verdict` / `groundedness_score`,会被包进 `verifier_evaluation`。
|
||||
输入必须使用当前分层 JSON:`rule_evaluation`、`verifier_evaluation`、`aiops_rule_evaluation`。旧扁平 JSON 不再自动包装。
|
||||
|
||||
## 4. 规则评分
|
||||
|
||||
@@ -136,14 +132,13 @@ Chat 自评估分三步:
|
||||
```mermaid
|
||||
flowchart LR
|
||||
ExecutorOutput["executor_evidence_v2"] --> Gatekeeper["ExecutorGatekeeperService"]
|
||||
Invocation["tool_invocation"] --> Summary["ToolTraceSummaryService"]
|
||||
Invocation --> EvidenceRefs["retrieval_details.evidence_refs"]
|
||||
Invocation["tool_invocation"] --> EvidenceRefs["retrieval_details.evidence_refs"]
|
||||
EvidenceRefs --> Gatekeeper
|
||||
Gatekeeper --> GateResult["gatekeeper_result"]
|
||||
Summary --> Evidence["tool_trace_summary"]
|
||||
GateResult --> Verifier["chat_verifier"]
|
||||
ExecutorOutput --> Verifier
|
||||
Evidence --> Verifier
|
||||
GateResult --> Projection["VerifiedInputNode"]
|
||||
ExecutorOutput --> Projection
|
||||
Projection --> VerifiedOutput["verified_executor_output + verified_evidence"]
|
||||
VerifiedOutput --> Verifier["chat_verifier"]
|
||||
Verifier --> Output["verifier_output JSON"]
|
||||
Output --> Composer["chat_composer"]
|
||||
Composer --> ComposerOutput["composer_output"]
|
||||
@@ -163,9 +158,9 @@ Verifier 输出:
|
||||
| `facts_checked` | 逐条事实校验 |
|
||||
| `rationale` | 判定原因 |
|
||||
| `executor_structured_output` | Executor 输出的结构化 claims 与证据绑定 |
|
||||
| `verified_evidence` | Gatekeeper 通过并投影给 Verifier 的最小 matched evidence |
|
||||
| `gatekeeper_result` | 引用真实性校验结果 |
|
||||
| `composer_output` | 最终表达的解析状态和摘要 |
|
||||
| `tool_trace_summary` | 本次校验使用的工具调用导航索引 |
|
||||
|
||||
ChatService 根据 verdict 决定:
|
||||
|
||||
@@ -177,6 +172,7 @@ ChatService 根据 verdict 决定:
|
||||
|
||||
- `executor_final_answer` 只作为 debug/fallback 上下文;结构化输出有效时,Verifier 不得从中抽取额外确认事实。
|
||||
- `$.no_evidence` 只能表达“当前查询未检索到匹配证据”,不能表达“已排除/确认没有”。
|
||||
- `run.orchestrationTrace` 是独立的 StateGraph 路由摘要,不属于 `self_evaluation`;当前版本不生成或读取 `tool_trace_summary`。
|
||||
|
||||
## 6. AIOps 规则自评估
|
||||
|
||||
@@ -211,7 +207,6 @@ Content-Type: application/json
|
||||
"success": true,
|
||||
"message": "反馈已记录",
|
||||
"runId": "run-xxx",
|
||||
"fallbackToLatestRun": false,
|
||||
"caseId": "uuid 或 null"
|
||||
}
|
||||
```
|
||||
@@ -224,11 +219,7 @@ Content-Type: application/json
|
||||
| `not_useful` | 写入 `DiagnosisRun.feedback`,不改变 run status |
|
||||
| 其他值 | 返回 HTTP 400 |
|
||||
|
||||
兼容行为:
|
||||
|
||||
- 请求带 `runId` 时,后端验证 `runId` 属于 `sessionId`。
|
||||
- 请求缺少 `runId` 且存在 run-backed 数据时,后端绑定 latest run,并返回 `fallbackToLatestRun=true` 和实际 `runId`。
|
||||
- 仅当没有 `diagnosis_run` 但存在历史 `diagnosis_session` 时,才使用历史 fallback;该路径不声明 latest-run fallback。
|
||||
新版本要求请求必须携带 `sessionId + runId`。后端验证 `runId` 属于 `sessionId`;缺少 `runId`、Run 不存在或归属错误时直接拒绝,不绑定 latest run,也不回退历史表。
|
||||
|
||||
## 8. 案例沉淀
|
||||
|
||||
@@ -239,7 +230,7 @@ Content-Type: application/json
|
||||
| CaseLibrary 字段 | 来源 |
|
||||
|---|---|
|
||||
| `caseId` | UUID |
|
||||
| `diagnosisId` | 新数据为 `DiagnosisRun.runId`;历史数据可能为 `DiagnosisSession.sessionId` |
|
||||
| `diagnosisId` | `DiagnosisRun.runId` |
|
||||
| `sourceType` | `AUTO` |
|
||||
| `faultCategory` | 当前固定为 `GENERAL` |
|
||||
| `title` | `query` 前 100 字符 |
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Harness 与质量门禁架构
|
||||
|
||||
**更新日期**:2026-07-08
|
||||
**更新日期**:2026-07-17
|
||||
**状态**:当前可运行架构 + 后续门禁规划
|
||||
**参考历史文档**:`archive/2026-07-05-legacy/agent-architecture.md`
|
||||
|
||||
@@ -20,6 +20,7 @@ Agent 系统的核心风险不是“没有答案”,而是:
|
||||
Prompt contract
|
||||
+ Tool boundary
|
||||
+ Agent hooks
|
||||
+ StateGraph routing contract
|
||||
+ Trace persistence
|
||||
+ Gatekeeper deterministic validation
|
||||
+ Verifier / rule evaluation
|
||||
@@ -31,7 +32,7 @@ Prompt contract
|
||||
```mermaid
|
||||
flowchart TB
|
||||
Input["User / AIOps input"] --> Prompt["Prompt contract"]
|
||||
Prompt --> Agent["Planner / Executor / Verifier / Composer"]
|
||||
Prompt --> Agent["Diagnosis StateGraph Nodes"]
|
||||
Agent --> Tools["Evidence tools"]
|
||||
Tools --> Invocation["tool_invocation"]
|
||||
Agent --> StepHook["AgentLoggingHook"]
|
||||
@@ -41,15 +42,16 @@ flowchart TB
|
||||
Invocation --> EvidenceRefs["retrieval_details.evidence_refs"]
|
||||
EvidenceRefs --> Gatekeeper["ExecutorGatekeeperService"]
|
||||
Agent --> Gatekeeper
|
||||
Invocation --> TraceSummary["ToolTraceSummaryService"]
|
||||
Gatekeeper --> Verifier["chat_verifier"]
|
||||
TraceSummary --> Verifier
|
||||
Gatekeeper --> Projection["VerifiedInputNode"]
|
||||
Projection --> Verifier["chat_verifier"]
|
||||
Verifier --> SelfEval["self_evaluation.verifier_evaluation"]
|
||||
|
||||
Invocation --> AiOpsRule["AiOpsRuleEvaluationService"]
|
||||
AiOpsRule --> AiOpsEval["self_evaluation.aiops_rule_evaluation"]
|
||||
|
||||
Run --> TraceAPI["DiagnosisTraceService"]
|
||||
Agent --> Routing["diagnosis_run.orchestration_trace"]
|
||||
Routing --> TraceAPI
|
||||
Step --> TraceAPI
|
||||
Invocation --> TraceAPI
|
||||
SelfEval --> TraceAPI
|
||||
@@ -126,7 +128,7 @@ sequenceDiagram
|
||||
- token count。
|
||||
- Verifier 的 JSON 输出摘要。
|
||||
|
||||
新写入必须带 `run_id`;`session_id` 仍保留用于粗粒度排查和历史兼容。
|
||||
新写入必须带 `run_id`;`session_id` 只用于会话归属和粗粒度排查,不能替代 Run 边界。
|
||||
|
||||
## 5. Tool Invocation 门禁
|
||||
|
||||
@@ -161,7 +163,7 @@ error_message
|
||||
|
||||
## 6. Gatekeeper 与 Verifier 门禁
|
||||
|
||||
Chat Verifier 前置一层 Gatekeeper。Gatekeeper 不调用 LLM,只用代码检查 Executor 输出的证据引用是否真实存在。
|
||||
Chat StateGraph 在 Verifier 前显式执行 Gatekeeper 和 Verified Input。Gatekeeper 不调用 LLM,只用代码检查 Executor 输出的证据引用是否真实存在;Verified Input 只投影通过的 binding。
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@@ -169,11 +171,12 @@ flowchart LR
|
||||
ExecutorOutput["executor_evidence_v2"] --> Gatekeeper["ExecutorGatekeeperService"]
|
||||
EvidenceRefs --> Gatekeeper
|
||||
Gatekeeper --> GateResult["gatekeeper_result"]
|
||||
Invocation --> Summary["ToolTraceSummaryService"]
|
||||
Summary --> EvidenceIndex["tool_trace_summary"]
|
||||
GateResult --> Projection["VerifiedInputNode"]
|
||||
Projection --> VerifiedClaims["verified_executor_output"]
|
||||
Projection --> VerifiedEvidence["verified_evidence"]
|
||||
GateResult --> Verifier["chat_verifier"]
|
||||
ExecutorOutput --> Verifier
|
||||
EvidenceIndex --> Verifier
|
||||
VerifiedClaims --> Verifier
|
||||
VerifiedEvidence --> Verifier
|
||||
Verifier --> Verdict{"verdict"}
|
||||
Verdict -->|PASS| Composer["chat_composer"]
|
||||
Composer --> Pass["输出最终答复"]
|
||||
@@ -215,7 +218,7 @@ Verifier 不再逐字核验 excerpt 真伪;这由 Gatekeeper 完成。Verifier
|
||||
diagnosis_run.self_evaluation.verifier_evaluation
|
||||
```
|
||||
|
||||
其中同时持久化 `executor_structured_output`、`gatekeeper_result`、`tool_trace_summary`、`prompt_audit` 和 `composer_output`,用于 Trace 回放。
|
||||
其中持久化 verified `executor_structured_output`、`verified_evidence`、`gatekeeper_result`、`prompt_audit` 和 `composer_output`,用于 Trace 回放。Graph 路由另存 `diagnosis_run.orchestration_trace`;当前版本不生成或读取 `tool_trace_summary`。
|
||||
|
||||
## 7. AIOps 规则门禁
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
# 面试一页式架构讲解
|
||||
|
||||
**更新日期**:2026-07-20
|
||||
**用途**:面试现场 2-5 分钟讲清项目
|
||||
**适合场景**:开场介绍、架构追问、Demo 前铺垫
|
||||
|
||||
## 1. 一句话
|
||||
|
||||
SuperBizAgent 是一个面向企业故障诊断的可追踪 Agent 系统:它把用户问题或 AIOps 告警转换成 Planner、Executor、Gatekeeper、Verifier、Composer 的诊断链路,`sessionId` 保留多轮上下文,`runId` 精确绑定一次诊断运行;所有工具证据、模型步骤、最终答案、自评估和用户反馈都能按 `sessionId + runId` 回放。
|
||||
SuperBizAgent 是一个面向企业故障诊断的可追踪 Agent 系统:复杂 Chat 通过 bounded StateGraph 编排 Planner、Executor、Gatekeeper、Verified Input、Verifier、Composer 和安全 Fallback,`sessionId` 保留多轮上下文,`runId` 精确绑定一次诊断运行;工具证据、模型步骤、Graph 路由、自评估、最终答案和用户反馈都能按 `sessionId + runId` 回放。
|
||||
|
||||
## 2. 一张图
|
||||
|
||||
@@ -16,7 +17,7 @@ flowchart TB
|
||||
API --> Chat["ChatService"]
|
||||
API --> AiOps["AiOpsService"]
|
||||
|
||||
Chat --> ChatFlow["Chat: Planner -> Executor -> Gatekeeper -> Verifier -> Composer"]
|
||||
Chat --> ChatFlow["Chat StateGraph: Planner -> Executor -> Gatekeeper -> Verified Input -> Verifier -> Composer/Fallback"]
|
||||
AiOps --> AiOpsFlow["AIOps: Supervisor -> Planner / Executor"]
|
||||
|
||||
ChatFlow --> Tools["Evidence Tools"]
|
||||
@@ -39,10 +40,14 @@ flowchart TB
|
||||
Trace --> Step["agent_step"]
|
||||
Trace --> Invocation["tool_invocation"]
|
||||
|
||||
Invocation --> Verifier["Verifier / Rule Evaluation"]
|
||||
Invocation --> Gate["Gatekeeper / Rule Evaluation"]
|
||||
Gate --> Projection["Verified Input"]
|
||||
Projection --> Verifier["Verifier"]
|
||||
Verifier --> SelfEval["self_evaluation"]
|
||||
|
||||
Run --> RouteTrace["orchestration_trace"]
|
||||
Run --> TraceAPI["GET /api/diagnosis/{sessionId}/trace?runId=..."]
|
||||
RouteTrace --> TraceAPI
|
||||
Step --> TraceAPI
|
||||
Invocation --> TraceAPI
|
||||
SelfEval --> TraceAPI
|
||||
@@ -56,21 +61,21 @@ flowchart TB
|
||||
```text
|
||||
这个项目不是把问题直接丢给大模型,而是把诊断拆成可审计的执行链路。
|
||||
|
||||
Chat 复杂问题走 Planner -> Executor -> Gatekeeper -> Verifier -> Composer:
|
||||
Planner 负责拆解,Executor 只负责调用知识库、日志和指标工具并提炼带证据引用的微观事实;Gatekeeper 用代码核对 invocation、raw_path 和 excerpt 是否真实;Verifier 判断这些事实能否由已验真的证据推出;Composer 只把允许表达的结论写成最终答案。
|
||||
Chat 复杂问题走 bounded StateGraph:
|
||||
Planner 负责拆解,Executor 调用知识库、日志和指标工具并提炼带证据引用的微观事实;Gatekeeper 用代码核对 invocation、raw_path 和 excerpt 是否真实;Verified Input 只投影通过的 binding;Verifier 判断这些事实能否由已验真的证据推出;Composer 只把允许表达的结论写成最终答案,不可恢复分支由 Fallback 生成安全答复。
|
||||
|
||||
AIOps 告警入口走 Supervisor 调度 Planner/Executor:
|
||||
如果请求里有 alert payload,系统会进入 PAYLOAD_TARGETED 模式,报告必须聚焦这个告警,而不是被当前环境中的其他活跃告警带偏。
|
||||
|
||||
会话元数据会落到 chat_session,每次诊断运行会落到 diagnosis_run,步骤和工具明细通过 run_id 关联。
|
||||
所以我可以用 sessionId + runId 精确回放:模型怎么规划、调了哪些工具、工具返回什么、Gatekeeper 怎么验真、Verifier 怎么判定、Composer 最后怎么表达、用户最后是否反馈有用。
|
||||
会话元数据会落到 chat_session,每次诊断运行会落到 diagnosis_run,步骤和工具明细通过 run_id 关联;证据质量写入 self_evaluation,Graph 路由独立写入 orchestration_trace。
|
||||
所以我可以用 sessionId + runId 精确回放:模型怎么规划、调了哪些工具、Gatekeeper 怎么验真、Graph 为什么重试或降级、Verifier 怎么判定、Composer/Fallback 如何结束、用户最后是否反馈有用。
|
||||
```
|
||||
|
||||
## 4. 五个亮点
|
||||
|
||||
| 亮点 | 怎么讲 |
|
||||
|---|---|
|
||||
| 可追踪 Agent | 每次诊断都有 `runId`,Trace API 可以回放 run、step、tool;同一 `sessionId` 可有多次独立 run |
|
||||
| 可追踪 StateGraph | 每次诊断都有 `runId`,Trace API 可以回放 run、step、tool 和 `run.orchestrationTrace`;同一 `sessionId` 可有多次独立 run |
|
||||
| 显式工具证据链 | `lookup_knowledge`、日志、指标都记录到 `tool_invocation` |
|
||||
| RAG 工程化 | L0 降级为 hint,Spring AI VectorStore 做主检索,SDK fallback 保底 |
|
||||
| 质量门禁 | Chat Gatekeeper 验引用、Verifier 判可推导、Composer 控表达,AIOps rule evaluation 控制告警聚焦 |
|
||||
|
||||
@@ -142,7 +142,7 @@ post-retrieval 层再把检索候选归一为:
|
||||
- 给 Agent 输出 completeness hint。
|
||||
- 写入 `tool_invocation.relevance_level`。
|
||||
- 给 Gatekeeper 提供 `evidence_refs` 引用验真源。
|
||||
- 给 Verifier 构造 `tool_trace_summary` 审计导航。
|
||||
- 由 Gatekeeper 核验后,经 `VerifiedInputNode` 给 Verifier 构造最小 `verified_evidence` 投影。
|
||||
- 供 EvaluationService 计算 evidence score。
|
||||
|
||||
## 6. 文档切片和 metadata
|
||||
@@ -180,11 +180,13 @@ flowchart LR
|
||||
Recorder --> Invocation["tool_invocation"]
|
||||
Invocation --> Trace["DiagnosisTraceService"]
|
||||
Invocation --> Gatekeeper["ExecutorGatekeeperService"]
|
||||
Invocation --> Summary["ToolTraceSummaryService"]
|
||||
Summary --> Verifier["chat_verifier"]
|
||||
Gatekeeper --> Projection["VerifiedInputNode"]
|
||||
Projection --> Verifier["chat_verifier"]
|
||||
Invocation --> Eval["EvaluationService / RAG eval"]
|
||||
```
|
||||
|
||||
当前 StateGraph 不生成或读取 `tool_trace_summary`,也不会把完整工具调用摘要输入 Verifier。
|
||||
|
||||
`tool_invocation` 中与检索相关的字段:
|
||||
|
||||
```text
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 会话与 Trace 生命周期
|
||||
|
||||
**更新日期**:2026-07-10
|
||||
**更新日期**:2026-07-17
|
||||
**状态**:当前可运行架构
|
||||
**参考历史文档**:`archive/2026-07-05-legacy/session-management.md`
|
||||
|
||||
@@ -18,7 +18,7 @@ chat_session(sessionId)
|
||||
- `sessionId` 表示多轮会话目录和 Redis 上下文。
|
||||
- `runId` 表示一次可回放诊断执行。
|
||||
- `DiagnosisTraceService` 聚合一个 run 的主记录、步骤和工具调用,形成可回放 Trace。
|
||||
- `diagnosis_session` 只保留为历史兼容和回滚表。
|
||||
- 运行时不再映射、读取或写入 `diagnosis_session`;数据库中的旧表不属于当前版本契约。
|
||||
|
||||
## 2. 生命周期总图
|
||||
|
||||
@@ -29,7 +29,7 @@ flowchart TD
|
||||
Session --> Run["create diagnosis_run(runId)"]
|
||||
Run --> Running["run.status = RUNNING"]
|
||||
|
||||
Running --> Agent["Agent workflow"]
|
||||
Running --> Agent["Chat StateGraph / AIOps workflow"]
|
||||
Agent --> Context["execution context(sessionId, runId)"]
|
||||
Context --> StepHook["AgentLoggingHook"]
|
||||
StepHook --> Step["agent_step(session_id, run_id)"]
|
||||
@@ -37,7 +37,8 @@ flowchart TD
|
||||
Tool --> Invocation["tool_invocation(session_id, run_id)"]
|
||||
Invocation --> Gatekeeper["Gatekeeper evidence validation"]
|
||||
|
||||
Agent --> Final{"workflow result"}
|
||||
Agent --> GraphTrace["Chat: save orchestration_trace"]
|
||||
GraphTrace --> Final{"workflow result"}
|
||||
Final -->|success| Success["run.status = SUCCESS, answer saved"]
|
||||
Final -->|failed| Failed["run.status = FAILED"]
|
||||
|
||||
@@ -59,8 +60,7 @@ flowchart TD
|
||||
|
||||
- 同一个 `sessionId` 可以贯穿多轮 Chat。
|
||||
- 每次有效 Chat/AIOps 执行都会创建新的 `runId`。
|
||||
- Trace 和 Feedback 新客户端应传 `runId`;只传 `sessionId` 时兼容解析 latest run。
|
||||
- latest run 排序使用 `diagnosis_run.created_at DESC, id DESC`,不使用 `updated_at`。
|
||||
- Trace 和 Feedback 必须同时传 `sessionId + runId`;后端不解析 latest run,也不回退旧表。
|
||||
|
||||
## 4. 运行状态流转
|
||||
|
||||
@@ -81,6 +81,7 @@ stateDiagram-v2
|
||||
| `status` | `diagnosis_run` | 单次运行执行状态 |
|
||||
| `answer` | `diagnosis_run` | 本次运行最终报告或答复 |
|
||||
| `self_evaluation` | `diagnosis_run` | 本次运行系统自评估 JSON |
|
||||
| `orchestration_trace` | `diagnosis_run` | Chat StateGraph 路由摘要;包含 version、transitions、final node、termination reason、degraded 和 evidence retry count |
|
||||
| `feedback` | `diagnosis_run` | 本次运行用户反馈 |
|
||||
|
||||
`feedback` 不修改 `status`。一个执行成功但用户标记 `not_useful` 的 run,仍然应该是 `SUCCESS + feedback=not_useful`。
|
||||
@@ -115,7 +116,7 @@ ToolInvocationRecorder
|
||||
-> retrieval_details / evidence_refs
|
||||
```
|
||||
|
||||
Verifier、Gatekeeper 和 EvaluationService 应按 `run_id` 读取工具调用,避免同一 session 的其他 run 参与评分或证据校验。
|
||||
Gatekeeper 和 EvaluationService 按 `run_id` 读取工具调用,避免同一 session 的其他 run 参与评分或证据校验。Verifier 只读取 `VerifiedInputNode` 生成的 verified projection,不直接读取完整工具调用列表。
|
||||
|
||||
## 7. Trace API 聚合
|
||||
|
||||
@@ -128,24 +129,29 @@ GET /api/diagnosis/{sessionId}/trace?runId=run-...
|
||||
|
||||
```text
|
||||
diagnosis_run by sessionId + runId
|
||||
+ run.orchestrationTrace parsed from diagnosis_run.orchestration_trace
|
||||
+ chat_session metadata when available
|
||||
+ agent_step where run_id = runId, ordered by the Trace API
|
||||
+ tool_invocation where run_id = runId order by id
|
||||
-> DiagnosisTraceResponse
|
||||
```
|
||||
|
||||
当 `runId` 缺失时,Trace API 为兼容旧客户端解析最新 run,并在响应中返回 resolved `runId`。当 `runId` 属于其他 `sessionId` 时,API 必须拒绝,不能泄漏其他会话的 Trace。
|
||||
当 `runId` 缺失时,Trace API 直接拒绝请求。当 `runId` 属于其他 `sessionId` 时,API 同样拒绝,不能泄漏其他会话的 Trace。
|
||||
|
||||
`run.orchestrationTrace` 只属于精确 Run 投影,响应不再提供兼容 `session` 对象。它解释 Graph 路由;`selfEvaluation` 解释证据/答案质量;`steps` 和 `toolInvocations` 保存详细执行证据,三者职责互不替代。非 StateGraph Run 的该字段可以为空。
|
||||
|
||||
## 8. Chat 与 AIOps 差异
|
||||
|
||||
| 维度 | Chat | AIOps |
|
||||
|---|---|---|
|
||||
| `agent_flow` | `CHAT` | `AI_OPS` |
|
||||
| 编排方式 | `SequentialAgent`: Planner -> Executor -> Gatekeeper -> Verifier -> Composer | `SupervisorAgent`: Planner + Executor |
|
||||
| 编排方式 | bounded `StateGraph`: Planner / Executor / Gatekeeper / Verified Input / Verifier / Composer / Fallback | `SupervisorAgent`: Planner + Executor |
|
||||
| 自评估 | `rule_evaluation` + `verifier_evaluation` | `aiops_rule_evaluation` |
|
||||
| 答案字段 | Chat 最终答复 | 告警分析报告 |
|
||||
| runId 暴露 | `/api/chat` JSON response | `/api/ai_ops` SSE metadata message |
|
||||
|
||||
Chat StateGraph 的权威自动化验收分三层:`DiagnosisGraphWorkflowTest` 验证路由,`DiagnosisGraphNodeContractTest` 验证真实 Node 输入输出,`ChatServiceGraphIntegrationTest` 验证 Run 生命周期、Trace 持久化和对外集成。
|
||||
|
||||
## 9. 清理与边界
|
||||
|
||||
- Redis 会话历史用于多轮上下文,不是长期审计记录。
|
||||
@@ -157,4 +163,4 @@ diagnosis_run by sessionId + runId
|
||||
|
||||
1. Trace API 增加更结构化的 `self_evaluation` 展示。
|
||||
2. `agent_step` 与 `tool_invocation.step_id` 建立更严格关联。
|
||||
3. 旧 `diagnosis_session` 只读观察期结束后,再评估数据库层面的约束收紧或归档策略。
|
||||
3. 数据库中的旧 `diagnosis_session` 表按独立数据治理任务决定是否物理删除;当前应用不再依赖它。
|
||||
|
||||
@@ -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`
|
||||
@@ -0,0 +1,19 @@
|
||||
# 2026-07-20 MVP 文档清理归档
|
||||
|
||||
本目录保存已被当前 StateGraph、Executor Evidence Pipeline 和 Run-only v2 架构替代的历史材料。归档文件仅用于追溯,不代表当前运行时、接口或数据模型契约。
|
||||
|
||||
## 归档清单
|
||||
|
||||
| 原路径 | 归档文件 | 归档原因 | 当前依据 |
|
||||
|---|---|---|---|
|
||||
| `mvp/.backup/database-design-backup-20240622.md` | [database-design-backup-20240622.md](database/database-design-backup-20240622.md) | 早期数据库设计备份,模型和表关系已过时 | [data-model.md](../../architecture/data-model.md) |
|
||||
| `mvp/issues/design-notes/executor-self-evidence-loop-design-note.md` | [executor-self-evidence-loop-design-note.md](issues/design-notes/executor-self-evidence-loop-design-note.md) | 早期问题分析已被可执行证据链契约吸收 | [executor-evidence-pipeline-refactor.md](../../architecture/executor-evidence-pipeline-refactor.md) |
|
||||
| `mvp/issues/design-notes/executor-structured-output-v2.md` | [executor-structured-output-v2.md](issues/design-notes/executor-structured-output-v2.md) | 分阶段实施说明已完成并由当前契约和 OpenSpec 接管 | [executor-evidence-pipeline-refactor.md](../../architecture/executor-evidence-pipeline-refactor.md)、[OpenSpec 主规格](../../../openspec/specs/) |
|
||||
| `mvp/tables/诊断会话表-diagnosis_session.md` | [诊断会话表-diagnosis_session.md](tables/诊断会话表-diagnosis_session.md) | 运行时已不再映射、读取或写入旧会话级诊断表 | [session-trace-lifecycle.md](../../architecture/session-trace-lifecycle.md)、[诊断运行表-diagnosis_run.md](../../tables/诊断运行表-diagnosis_run.md) |
|
||||
|
||||
## 使用约束
|
||||
|
||||
- 当前架构从 `mvp/architecture/README.md` 进入。
|
||||
- 当前问题状态从 `mvp/issues/README.md` 进入。
|
||||
- 当前表模型从 `mvp/tables/README.md` 进入。
|
||||
- 归档中的兼容、回退和阶段状态描述均为历史快照,不得用于推导当前行为。
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
# 数据库设计文档
|
||||
|
||||
> 归档说明:这是 2024 年数据库设计备份,已被当前 `chat_session + diagnosis_run + run-scoped trace detail` 模型替代,仅用于历史追溯。
|
||||
|
||||
## 一、设计原则
|
||||
|
||||
### 1.1 核心原则
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
# Executor 自证循环与证据摘要链路设计记录
|
||||
|
||||
> 归档说明:本文是实施前的问题分析。当前实现以 `mvp/architecture/executor-evidence-pipeline-refactor.md` 和 OpenSpec 主规格为准。
|
||||
|
||||
**状态**:已形成方向,待创建 OpenSpec change
|
||||
**严重程度**:高
|
||||
**记录时间**:2026-07-07
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
# Executor Structured Output V2 可执行设计与实施 Issue
|
||||
|
||||
> 归档说明:本文记录旧的分阶段实施方案,其中的兼容期和待启动状态不再适用。当前实现以 `mvp/architecture/executor-evidence-pipeline-refactor.md` 和 OpenSpec 主规格为准。
|
||||
|
||||
**状态**:阶段四待启动,前三阶段已归档并提交
|
||||
**严重程度**:高
|
||||
**创建日期**:2026-07-07
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
# 诊断会话表:diagnosis_session
|
||||
|
||||
**状态**:历史兼容和回滚表
|
||||
**来源**:`V005__create_session_storage.sql`、`V008__add_answer_to_diagnosis_session.sql`、`DiagnosisSession`
|
||||
> 归档说明:本文记录 Run-only v2 之前的旧表语义。当前 Java 运行时不再映射、读取或写入 `diagnosis_session`;数据库中物理表是否保留由独立数据治理任务决定。
|
||||
|
||||
**状态**:历史快照,不属于当前版本契约
|
||||
**历史来源**:`V005__create_session_storage.sql`、`V008__add_answer_to_diagnosis_session.sql`
|
||||
|
||||
## 定位
|
||||
|
||||
+9
-2
@@ -8,7 +8,7 @@
|
||||
- `interview-walkthrough.md`:面试讲解话术。
|
||||
- `evidence-pipeline-scenarios.md`:PASS / LOW_CONFID / REJECT / no-evidence 场景矩阵。
|
||||
- `trace-inspection-checklist.md`:Trace 字段检查清单。
|
||||
- `scripts/run-interview-demo-check.ps1`:面试预检脚本,包含服务可达性、Chat、Trace、反馈和 summary 输出。
|
||||
- `scripts/run-interview-demo-check.ps1`:面试预检脚本,绑定 exact runId,强制校验 Run orchestration trace,并输出 Chat、Trace、反馈和 summary。
|
||||
- `scripts/run-payment-timeout-demo.ps1`:本地可执行 Demo 脚本。
|
||||
- `interview-q-and-a.md`:面试追问回答,覆盖 Agent 工程取舍、审计和评测。
|
||||
- `requests/payment-timeout-chat.json`:固定 Chat 请求 payload。
|
||||
@@ -51,6 +51,8 @@ mvp/demo/output/feedback-response.json
|
||||
mvp/demo/output/interview-demo-summary.json
|
||||
```
|
||||
|
||||
自动化验收应传入唯一 `-SessionId`,并用 `-OutputDir target/...` 避免覆盖仓库样例。脚本从 Chat 响应取得 exact `runId`,缺少 `data.run.orchestrationTrace` 或 version/final node/termination reason/transitions/degraded/evidence retry count 时会立即失败。summary 额外包含 `orchestrationVersion`、`finalNode`、`terminationReason`、`degraded`、`transitionCount` 和 `evidenceRetryCount`。
|
||||
|
||||
手动请求:
|
||||
|
||||
```powershell
|
||||
@@ -100,6 +102,10 @@ Invoke-RestMethod `
|
||||
- `data.runId` 等于 `$runId`
|
||||
- `data.session.sessionId` 等于 Chat session id
|
||||
- `data.run.runId` 等于 `$runId`
|
||||
- `data.run.orchestrationTrace.version` 非空
|
||||
- `data.run.orchestrationTrace.final_node` 和 `termination_reason` 非空
|
||||
- `data.run.orchestrationTrace.transitions` 是本次 Graph 的条件边记录
|
||||
- `data.run.orchestrationTrace.degraded` 和 `evidence_retry_count` 记录安全降级与补证据次数
|
||||
- `data.steps` 包含 planner / executor / verifier 等步骤
|
||||
- `data.toolInvocations` 包含 `lookup_knowledge`、`query_logs`、`query_metrics` 等证据工具
|
||||
- `data.session.selfEvaluation` 包含 verifier 或 rule evaluation
|
||||
@@ -174,9 +180,10 @@ Chat 主线:
|
||||
```text
|
||||
一个 session id + 一个 run id
|
||||
-> 用户问题
|
||||
-> 多 Agent 执行
|
||||
-> bounded StateGraph(Planner / Executor / Gatekeeper / Verified Input / Verifier / Composer / Fallback)
|
||||
-> 证据工具
|
||||
-> Verifier / self_evaluation
|
||||
-> run.orchestrationTrace 路由摘要
|
||||
-> 最终答案
|
||||
-> 用户反馈
|
||||
-> Trace API 回放
|
||||
|
||||
@@ -79,6 +79,15 @@ $chatPath = Join-Path $OutputDir "chat-response.json"
|
||||
$chat | ConvertTo-Json -Depth 30 | Set-Content -Encoding UTF8 -Path $chatPath
|
||||
|
||||
$runId = $chat.data.runId
|
||||
if ($chat.data.success -ne $true) {
|
||||
throw "Chat response was not successful."
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace([string]$chat.data.answer)) {
|
||||
throw "Chat response did not include a non-empty answer."
|
||||
}
|
||||
if ($chat.data.sessionId -ne $SessionId) {
|
||||
throw "Chat response sessionId '$($chat.data.sessionId)' did not match requested sessionId '$SessionId'."
|
||||
}
|
||||
if (-not $runId) {
|
||||
throw "Chat response did not include runId; exact trace verification cannot continue."
|
||||
}
|
||||
@@ -92,6 +101,51 @@ $trace = Invoke-RestMethod @traceRequest
|
||||
$tracePath = Join-Path $OutputDir "trace-response.json"
|
||||
$trace | ConvertTo-Json -Depth 80 | Set-Content -Encoding UTF8 -Path $tracePath
|
||||
|
||||
$traceData = Get-TraceData -TraceResponse $trace
|
||||
if ($null -eq $traceData -or $null -eq $traceData.run) {
|
||||
throw "Exact Trace response did not include data.run."
|
||||
}
|
||||
if ($traceData.runId -ne $runId -or $traceData.run.runId -ne $runId) {
|
||||
throw "Exact Trace runId did not match Chat runId '$runId'."
|
||||
}
|
||||
if ($traceData.run.sessionId -ne $SessionId) {
|
||||
throw "Exact Trace run did not belong to requested sessionId '$SessionId'."
|
||||
}
|
||||
|
||||
$orchestrationTrace = $traceData.run.orchestrationTrace
|
||||
if ($null -eq $orchestrationTrace) {
|
||||
throw "Exact Trace data.run.orchestrationTrace is missing."
|
||||
}
|
||||
foreach ($field in @("version", "final_node", "termination_reason")) {
|
||||
if (-not ($orchestrationTrace.PSObject.Properties.Name -contains $field) -or
|
||||
[string]::IsNullOrWhiteSpace([string]$orchestrationTrace.$field)) {
|
||||
throw "Exact Trace data.run.orchestrationTrace.$field is missing."
|
||||
}
|
||||
}
|
||||
foreach ($field in @("transitions", "degraded", "evidence_retry_count")) {
|
||||
if (-not ($orchestrationTrace.PSObject.Properties.Name -contains $field)) {
|
||||
throw "Exact Trace data.run.orchestrationTrace.$field is missing."
|
||||
}
|
||||
}
|
||||
if ($null -eq $orchestrationTrace.transitions) {
|
||||
throw "Exact Trace data.run.orchestrationTrace.transitions must be an array."
|
||||
}
|
||||
if ([int]$orchestrationTrace.evidence_retry_count -lt 0) {
|
||||
throw "Exact Trace data.run.orchestrationTrace.evidence_retry_count must not be negative."
|
||||
}
|
||||
if ($traceData.run.status -ne "SUCCESS" -or $traceData.run.agentFlow -ne "CHAT") {
|
||||
throw "Exact Trace run must be CHAT/SUCCESS."
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace([string]$traceData.run.answer)) {
|
||||
throw "Exact Trace run did not include a non-empty answer."
|
||||
}
|
||||
if (@($traceData.steps).Count -eq 0 -or @($traceData.toolInvocations).Count -eq 0) {
|
||||
throw "Exact Trace did not include both Agent steps and tool invocation evidence."
|
||||
}
|
||||
if ($null -eq $traceData.run.selfEvaluation) {
|
||||
throw "Exact Trace run did not include selfEvaluation."
|
||||
}
|
||||
|
||||
$feedbackBody = @{
|
||||
sessionId = $SessionId
|
||||
runId = $runId
|
||||
@@ -105,11 +159,13 @@ $feedbackRequest = @{
|
||||
Body = $feedbackBody
|
||||
}
|
||||
$feedback = Invoke-RestMethod @feedbackRequest
|
||||
if ($feedback.success -ne $true) {
|
||||
throw "Feedback request was not successful for runId '$runId'."
|
||||
}
|
||||
|
||||
$feedbackPath = Join-Path $OutputDir "feedback-response.json"
|
||||
$feedback | ConvertTo-Json -Depth 30 | Set-Content -Encoding UTF8 -Path $feedbackPath
|
||||
|
||||
$traceData = Get-TraceData -TraceResponse $trace
|
||||
$selfEvaluation = Get-SelfEvaluation -TraceData $traceData
|
||||
$verifierEvaluation = $null
|
||||
if ($null -ne $selfEvaluation) {
|
||||
@@ -138,6 +194,7 @@ if ($null -ne $promptAudit) {
|
||||
$promptAuditVersion = $promptAudit.version
|
||||
}
|
||||
$toolNames = Get-ToolNames -TraceData $traceData
|
||||
$transitionCount = @($orchestrationTrace.transitions).Count
|
||||
$summaryPath = Join-Path $OutputDir "interview-demo-summary.json"
|
||||
|
||||
$summary = [ordered]@{
|
||||
@@ -149,6 +206,12 @@ $summary = [ordered]@{
|
||||
gatekeeperStatus = $gatekeeperStatus
|
||||
gatekeeperRuleSetVersion = $gatekeeperRuleSetVersion
|
||||
promptAuditVersion = $promptAuditVersion
|
||||
orchestrationVersion = $orchestrationTrace.version
|
||||
finalNode = $orchestrationTrace.final_node
|
||||
terminationReason = $orchestrationTrace.termination_reason
|
||||
degraded = [bool]$orchestrationTrace.degraded
|
||||
transitionCount = $transitionCount
|
||||
evidenceRetryCount = [int]$orchestrationTrace.evidence_retry_count
|
||||
toolNames = $toolNames
|
||||
paths = [ordered]@{
|
||||
chat = $chatPath
|
||||
@@ -165,4 +228,6 @@ Write-Host "Interview demo preflight completed."
|
||||
Write-Host "Verdict: $($summary.verdict)"
|
||||
Write-Host "Gatekeeper rules: $($summary.gatekeeperRuleSetVersion)"
|
||||
Write-Host "Prompt audit: $($summary.promptAuditVersion)"
|
||||
Write-Host "Graph final node: $($summary.finalNode)"
|
||||
Write-Host "Graph termination: $($summary.terminationReason)"
|
||||
Write-Host "Summary: $summaryPath"
|
||||
|
||||
@@ -7,16 +7,30 @@
|
||||
| JSON path | 检查点 | 面试讲点 |
|
||||
|---|---|---|
|
||||
| `data.runId` / `data.run.runId` | 是否等于 demo 响应中的 `runId` | `runId` 精确绑定这一次诊断运行 |
|
||||
| `data.session.sessionId` | 是否等于 `mvp-demo-payment-timeout-001` | `sessionId` 保留多轮上下文,Trace 精确回放依赖 `runId` |
|
||||
| `data.session.query` | 是否包含支付超时问题 | Trace 记录了原始用户意图 |
|
||||
| `data.session.answer` | 是否包含最终诊断答案 | 最终答案没有脱离 Trace |
|
||||
| `data.session.selfEvaluation` | 是否包含 verifier 或 rule evaluation | 答案经过质量门,不只是模型原始输出 |
|
||||
| `data.session.selfEvaluation.verifier_evaluation.gatekeeper_result.rule_set_version` | 如果是 Chat V2 链路,是否记录 Gatekeeper 规则版本 | 安全规则可审计、可回归 |
|
||||
| `data.session.selfEvaluation.verifier_evaluation.prompt_audit.version` | 如果是 Chat V2 链路,是否记录 Prompt 审计版本 | Prompt 变更可解释、可回归 |
|
||||
| `data.session.selfEvaluation.verifier_evaluation.prompt_audit.prompts[*].version` | 是否记录 planner / executor / verifier / composer 版本 | 便于定位 Prompt 变更影响 |
|
||||
| `data.session.feedback` | 提交反馈后是否变为 `useful` | 用户反馈挂在当前 diagnosis run 上 |
|
||||
| `data.run.sessionId` | 是否等于本次 Chat 请求的唯一 sessionId | `sessionId` 保留多轮上下文,Trace 精确回放依赖 `runId` |
|
||||
| `data.run.query` | 是否包含支付超时问题 | Trace 记录了原始用户意图 |
|
||||
| `data.run.answer` | 是否包含最终诊断答案 | 最终答案没有脱离 Trace |
|
||||
| `data.run.selfEvaluation` | 是否包含 verifier 或 rule evaluation | 答案经过质量门,不只是模型原始输出 |
|
||||
| `data.run.selfEvaluation.verifier_evaluation.gatekeeper_result.rule_set_version` | 是否记录 Gatekeeper 规则版本 | 安全规则可审计、可回归 |
|
||||
| `data.run.selfEvaluation.verifier_evaluation.prompt_audit.version` | 是否记录 Prompt 审计版本 | Prompt 变更可解释、可回归 |
|
||||
| `data.run.selfEvaluation.verifier_evaluation.prompt_audit.prompts[*].version` | 是否记录 planner / executor / verifier / composer 版本 | 便于定位 Prompt 变更影响 |
|
||||
| `data.run.feedback` | 提交反馈后是否变为 `useful` | 用户反馈挂在当前 diagnosis run 上 |
|
||||
|
||||
## 2. Agent 步骤
|
||||
## 2. StateGraph 路由
|
||||
|
||||
| JSON path | 检查点 | 面试讲点 |
|
||||
|---|---|---|
|
||||
| `data.run.orchestrationTrace.version` | 是否存在当前 trace contract 版本 | 路由摘要可演进、可兼容 |
|
||||
| `data.run.orchestrationTrace.transitions[*]` | 是否记录实际经过的 Node 和 route | Graph 条件边不是从日志推断 |
|
||||
| `data.run.orchestrationTrace.final_node` | 最终是 Composer 还是 Fallback | 正常输出与安全降级明确区分 |
|
||||
| `data.run.orchestrationTrace.termination_reason` | 是否给出终止原因 | 每次 Run 都有可解释终点 |
|
||||
| `data.run.orchestrationTrace.degraded` | 是否发生安全降级 | fallback 是可审计行为 |
|
||||
| `data.run.orchestrationTrace.evidence_retry_count` | 是否为 0 或 1 | 补证据循环有硬上限 |
|
||||
| `interview-demo-summary.json.finalNode` 等摘要字段 | 是否与 exact Trace 一致 | summary 只消费 Run 路由真理源 |
|
||||
|
||||
`orchestrationTrace` 负责路由;`selfEvaluation` 负责证据和答案质量;AgentStep/ToolInvocation 负责详细执行与工具证据。三者不能互相替代。
|
||||
|
||||
## 3. Agent 步骤
|
||||
|
||||
| JSON path | 检查点 | 面试讲点 |
|
||||
|---|---|---|
|
||||
@@ -25,7 +39,7 @@
|
||||
| `data.steps[*].durationMs` | 是否有步骤耗时 | Trace 可用于耗时分析 |
|
||||
| `data.steps[*].tokenCount` | 如可用,是否记录 token | Trace 可用于模型成本分析 |
|
||||
|
||||
## 3. 工具证据
|
||||
## 4. 工具证据
|
||||
|
||||
| JSON path | 检查点 | 面试讲点 |
|
||||
|---|---|---|
|
||||
@@ -37,7 +51,7 @@
|
||||
| `data.toolInvocations[*].retrievalDetails.evidence_refs` | 是否包含 `raw_path + text` | Gatekeeper 可以用代码核对 Executor 引用 |
|
||||
| `data.toolInvocations[*].relevanceLevel` | 是否有相关性等级 | 可解释检索结果强弱 |
|
||||
|
||||
## 4. Summary
|
||||
## 5. Summary
|
||||
|
||||
| JSON path | 检查点 | 面试讲点 |
|
||||
|---|---|---|
|
||||
@@ -46,7 +60,7 @@
|
||||
| `data.summary.hasVerifierEvaluation` | 是否存在 Verifier 结果 | 最终答案经过质量门 |
|
||||
| `data.summary.hasFeedback` | 提交反馈后是否为 true | 人类反馈闭环完成 |
|
||||
|
||||
## 5. 好的结果长什么样
|
||||
## 6. 好的结果长什么样
|
||||
|
||||
```text
|
||||
同一个 session id + run id
|
||||
@@ -54,5 +68,6 @@
|
||||
-> 持久化 agent steps
|
||||
-> 持久化 evidence tool calls
|
||||
-> verifier / self-evaluation
|
||||
-> run.orchestrationTrace routing summary
|
||||
-> feedback attached to the same run
|
||||
```
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
结合你在前几轮对话中梳理出的“过度设计”痛点,既然你已经决定回归单 Agent(ReAct)+ 强 Harness 架构,接下来你需要做一次彻底的“架构物理重构”。
|
||||
以下是为你量身定制的5步落地行动指南,按优先级从高到低执行:
|
||||
第一步:链路合并,砍掉“伪 Graph”节点
|
||||
目标:把被拆散的推理逻辑还给单一的 ReAct 循环。
|
||||
|
||||
删除节点:直接在 Graph/状态机中抹掉 Planner、Executor、Composer 以及串联它们的边。
|
||||
合并为单一 Agent:创建一个 DiagnosisAgent。在它的 System Prompt 中明确:“你需要自行规划排查路径,调用工具获取证据,并在证据充分后输出最终的结构化诊断报告。”
|
||||
保留机制:该 Agent 内部运行一个带最大步数限制的 While 循环(如 max_iterations=10),防止死循环。
|
||||
|
||||
第二步:实施“上下文卸载”与“工具清洗”(解决7次调用膨胀问题)
|
||||
目标:确保单 Agent 在多轮工具调用后,上下文依然干净,从源头切断幻觉。
|
||||
|
||||
工具输出清洗(RTK 机制):改造你的所有工具(如 queryLogs, queryDB)。在工具的 Callback 层加代码,将原始的大段返回结果(如 1000 行日志)强制过滤、聚合,只把最核心的 5-10 行 ERROR 或统计指标返回给 Agent。
|
||||
上下文卸载:如果某些原始数据必须保留,在工具返回时,将全量数据写入本地文件(如 refs/log_001.md),上下文里只注入一行:[发现5个504错误,详见 refs/log_001.md]。
|
||||
|
||||
第三步:下沉确定性逻辑,用代码替代 LLM 节点
|
||||
目标:将你之前用 Gatekeeper 和 VerifiedInput 做的事,降级为零 LLM 调用的代码拦截器。
|
||||
|
||||
前置拦截(Pre-Tool Hook):Agent 发起工具调用时,Harness 代码用 JSON Schema 校验参数格式。不合法直接报错打回,不执行工具。
|
||||
后置断言(Post-Tool Hook):Agent 输出最终诊断报告时,代码层强制校验报告中引用的 evidence_id 和 raw_path 是否真实存在于历史记录或文件系统中。不合法直接拒绝输出,发回重试。
|
||||
|
||||
第四步:锁死输出契约
|
||||
目标:防止 Executor 过度输出和发散。
|
||||
|
||||
在 System Prompt 中强制规定 Agent 的中间思考步和最终输出步必须符合严格的 JSON 结构。
|
||||
例如,中间步必须是 {"thought": "<不超过50字>", "action": "queryLogs", "parameters": {...}}。Harness 代码检查字数,超长直接打回。
|
||||
|
||||
第五步:剥离异步验证(保留你最初的“防幻觉”初衷)
|
||||
目标:在不增加主链路复杂度的前提下,保留交叉验证能力。
|
||||
|
||||
主 ReAct Agent 输出报告后,不要在主 Graph 里串行接一个 Verifier 节点。
|
||||
改为异步触发一个轻量级 LLM(或小模型),只传入“压缩后的证据摘要 + 草稿结论”。让它判断时间线与逻辑是否一致。如果不一致,在最终输出上加“低置信度警告”;如果一致,直接放行。
|
||||
|
||||
总结:你的重构后架构全景图
|
||||
重构后,你的代码结构应该极其清爽,大致如下:
|
||||
[用户输入]
|
||||
│
|
||||
▼
|
||||
[Diagnosis ReAct Agent] (唯一的 LLM 推理节点,自带规划、执行、总结)
|
||||
│
|
||||
├── Tool: queryLogs
|
||||
│ └── [Harness 代码]: 过滤 INFO,提取 ERROR,写入 refs,返回摘要
|
||||
├── Tool: queryMetrics
|
||||
│ └── [Harness 代码]: 聚合统计值,返回 3 行核心指标
|
||||
│
|
||||
▼ (Agent 输出最终 JSON 报告)
|
||||
[Output Schema Linter] (纯代码层,0 LLM)
|
||||
│
|
||||
├─ 校验失败 ──> 返回错误给 [Agent] 重新生成
|
||||
│
|
||||
▼ (校验通过)
|
||||
[Async Verifier] (异步轻量 LLM,只做时间线/逻辑一致性校验)
|
||||
│
|
||||
▼
|
||||
[最终输出 / 带警告输出]
|
||||
现在你应该做的第一件事:打开你的代码,把主链路上除 Diagnosis Agent 以外的所有 LLM 编排节点全部注释掉,然后按照上面的结构,给工具加上 Pre-Tool 和 Post-Tool 的代码拦截器。把精力从“画 Graph”转移到“写工具清洗代码”上。
|
||||
+7
-5
@@ -4,13 +4,15 @@ This folder contains the fixed offline regression set for the MVP diagnosis Agen
|
||||
|
||||
## Background
|
||||
|
||||
The current diagnosis chain is:
|
||||
The current complex Chat diagnosis chain is a bounded StateGraph:
|
||||
|
||||
```text
|
||||
Planner -> Executor -> Gatekeeper -> Verifier -> Composer -> final answer
|
||||
Planner -> Executor -> Gatekeeper -> Verified Input -> Verifier -> Composer -> final answer
|
||||
| |
|
||||
+ bounded evidence retry + safe Fallback
|
||||
```
|
||||
|
||||
Stages 1-4 introduced Executor V2 structured output, deterministic Gatekeeper audit, Verifier `claim_checks`, and Composer final-answer rendering. Stage 5 makes those audit fields part of the offline regression harness so future prompt, tool, or chain changes can be checked without relying on a one-off demo.
|
||||
Executor V2 structured output, deterministic Gatekeeper audit, verified-only Verifier input, `claim_checks`, Composer rendering, and StateGraph routing are covered by deterministic tests so future prompt, tool, or graph changes can be checked without relying on a one-off demo.
|
||||
|
||||
## Scope
|
||||
|
||||
@@ -55,10 +57,10 @@ Run the focused evaluator test:
|
||||
mvn -q "-Dtest=DiagnosisTraceEvaluatorTest" test
|
||||
```
|
||||
|
||||
Run the broader phase-5 regression set:
|
||||
Run the authoritative Graph layers plus the fixed evaluator checks:
|
||||
|
||||
```powershell
|
||||
mvn "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test
|
||||
mvn -q "-Dtest=DiagnosisGraphWorkflowTest,DiagnosisGraphNodeContractTest,ChatServiceGraphIntegrationTest,DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ExecutorGatekeeperServiceTest" test
|
||||
```
|
||||
|
||||
When fixtures or evaluator rules change, regenerate both baseline reports from the same case file and fixture directory, then update JSON and Markdown together.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-audit-metadata-low-confid",
|
||||
"query": "订单超时是否可以确认由数据库主库故障导致,并检查审计元数据是否完整?",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-composer-fallback-no-raw-json",
|
||||
"query": "库存服务慢响应是否可以直接输出 Executor JSON?",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-gatekeeper-fabricated-invocation",
|
||||
"query": "支付失败是否能确认由日志中的连接池耗尽导致?",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-hikari-no-evidence-negative-observation",
|
||||
"query": "确认 inventory-service 当前是否有 HikariCP 连接池耗尽日志。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-jvm-memory-risk",
|
||||
"query": "订单服务内存使用率过高,请判断是否存在 OOM 风险。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-mysql-pool",
|
||||
"query": "订单服务大量请求超时,请判断是否和 MySQL 连接池有关。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-narrow-highcpu-observation",
|
||||
"query": "确认 payment-service 当前是否存在 HighCPUUsage 告警。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-payment-timeout",
|
||||
"query": "支付接口最近出现超时,请结合知识库、日志和指标判断可能原因,并给出修复建议。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-prompt-gatekeeper-audit-closure",
|
||||
"query": "确认 payment-service 当前是否存在 HighCPUUsage 告警,并检查审计元数据是否完整。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-redis-timeout",
|
||||
"query": "支付服务出现 Redis 连接超时,请定位可能原因。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"session": {
|
||||
"run": {
|
||||
"sessionId": "eval-slow-response",
|
||||
"query": "用户服务 P99 响应时间升高,请结合指标和日志分析。",
|
||||
"status": "SUCCESS",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user