Files
SuperBizAgent-java/mvp/issues/active/ISS-014-single-react-agent-harness-aci-ptk-refactor.md
T

1409 lines
72 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ISS-014 单体 ReAct Agent、Harness 与 ACI 工具瘦身
**状态**:实施中(阶段 0-6B 已归档,下一阶段 7)
**严重程度**:高
**发现时间**:2026-07-20
**目标分支**:`refactor/chat-single-react-harness`
**基线分支**:`refactor/mvp1.0`
**关联**:ISS-003、ISS-012、ISS-013、executor-evidence-attribution-hallucination
---
## 1. 摘要
当前 Chat 诊断链路将一次完整 ReAct 生命周期拆成 Planner、Executor、Verifier、Composer 等多个 LLM 角色,再通过服务方法、Hook、ThreadLocal、结构化协议和多轮重试串联。该设计把 Agent 本身已经具备的“思考、行动、观察、继续行动、最终回答”重复提升为外层编排,造成职责分散、上下文重复、失败语义不一致和 Token 成本失控。
本 Issue 将后续实现收敛为:
```text
一个负责实际工作的 Diagnosis ReAct Agent
+ 一个负责确定性控制的 Harness
+ 一个上下文隔离的 SemanticGuard Agent
```
Diagnosis ReAct Agent 和 SemanticGuard Agent 都通过同一个 Harness 执行边界运行;不为 SemanticGuard 再复制一套 Harness,也不引入新的 Graph 或编排器。
同时重构 Agent 可见 Tool Contract,使 RAG、日志和新增 MySQL Tool 遵守 ACI 原则,并通过工具结果清洗与投影层控制上下文体积、敏感数据和证据引用。
本 Issue 是后续实现的总设计来源。ISS-012 继续保留 Token/预算问题背景,ISS-013 继续保留入口/SSE 问题背景;实现范围和阶段顺序以本 Issue 最终确认版本为准。
## 2. 根因判断
### 2.1 ReAct 被重复实现
原有角色实际对应一个完整 ReAct 生命周期:
```text
Planner -> 内部规划与推理
Executor -> 工具调用与观察循环
Verifier -> 证据充分性自检
Composer -> 最终用户回答
```
将这些职责拆成多个 Agent 后,需要额外维护:
- 多套 Prompt 和输出 Schema;
- Agent 间 JSON 转换;
- 多套重试状态;
- 证据和上下文在不同角色之间重复搬运;
- 失败、低置信度和 Fallback 的分支组合;
- 主链路与审计链路之间的隐式 ThreadLocal 状态。
### 2.2 工具返回面向开发者而不是面向 Agent
当前 Tool 结果混合了:
- Agent 真正需要的证据;
- 检索/查询内部实现细节;
- 调试 Trace 和 Rerank 数据;
- 重复正文和 ContextPack;
- 原始大结果;
- Session 隐式记忆;
- 无结果、错误和去重等含义不一致的状态。
这违反 ACI 的清晰、稳定、有界、可恢复和可继续操作原则,也是 Agent 上下文膨胀的重要来源。
### 2.3 安全约束与业务编排耦合
证据真实性校验属于确定性执行约束,不需要成为独立 LLM 节点或业务编排角色。语义推导校验确实需要独立上下文,但它不应拥有工具、记忆、ReAct 循环或回调主 Agent 的能力。
## 3. 目标架构
```text
POST /api/chat (SSE)
-> Chat Application Use Case
-> Intent Router(一次轻量 Chat)
-> SYSTEM_CHAT
-> KNOWLEDGE_QUERY
-> DIAGNOSIS
SYSTEM_CHAT
-> 无 Tool 普通 Chat
KNOWLEDGE_QUERY
-> 单次 lookup_knowledge
-> 普通 Chat 基于 RAG Evidence 回答
-> Harness 校验证据引用
DIAGNOSIS
-> Harness 启动 Diagnosis ReAct Agent
-> Agent 接收当前原始 Query 和可选 previous_turn
-> Agent 内部规划
-> Agent 自主调用受控 Tool
-> Harness 在 Tool 边界校验、记录、清洗和投影
-> Agent 内部检查证据是否足够
-> Agent 输出结构化诊断草稿、Analysis Items、Conclusion 和 Tool Call Refs
-> Harness EvidenceGuard(0 LLM)
-> Schema 校验
-> 当前 Run 证据所有权校验
-> tool_call_id 当前 Run 归属和调用结果校验
-> SemanticGuard Agent(独立隔离上下文)
-> 接收原始 Query、完整 Draft 和已物理验真的精确证据
-> 判断整份用户报告是否语义成立且没有超出证据范围
-> Harness Release Policy
-> SUPPORTED:释放完整答案
-> UNSUPPORTED:安全降级
-> TIMEOUT/ERROR:不释放未验证草稿
```
业务层不使用 StateGraph。底层 ReactAgent 框架内部是否使用 Graph 属于框架实现细节,不构成项目业务编排。
## 4. 已确认设计决策
### 4.1 单体 Diagnosis ReAct Agent
主 Agent 负责:
1. 接收当前原始 Query 和 Harness 组装的可选极简 previous_turn;
2. 理解诊断目标;
3. 在内部形成排查方向;
4. 选择并调用只读证据 Tool;
5. 观察 Tool 结果并决定是否继续;
6. 检查证据是否足以支持准备输出的结论;
7. 形成结论先行的结构化诊断草稿、Analysis Items 和 Tool Call Refs;
8. 证据不足时明确输出无法确认,不补造事实。
主 Agent 不负责:
- 意图路由;
- Session/Run 生命周期;
- Token、工具、超时和取消预算;
- 数据库存储和 Trace;
- HTTP/SSE 协议;
- 证据物理真实性校验;
- 调用其他 Agent;
- 外层重试状态机。
不要求 Agent 输出 Thought 或 Chain of Thought。内部规划不形成对外协议,也不持久化为业务事实。
### 4.2 Harness
Harness 负责确定性执行控制,而不是业务推理:
#### Run 控制
- 创建和传播 `sessionId + runId`;
- 建立请求 Deadline 和取消信号;
- 限制模型调用、工具调用、Token 和总耗时;
- 客户端断开时取消后续执行;
- 保证 Run 进入明确终态。
#### Model 边界
- 包装 ChatModel;
- 记录 input/output/total Token;
- 应用调用次数和上下文预算;
- 不修改 Agent 的业务判断。
#### Tool 边界
- Pre-Tool 参数 Schema、权限、只读和预算校验;
- 执行真实 Tool;
- 接收框架在 Tool 执行请求中提供的 `tool_call_id`,并在执行前完成校验;
- Tool 返回后将请求、原始响应、状态和时间写入 Redis;当前版本暂不做持久化脱敏;
- 调用对应 `ToolResultProjector` 生成规范化、聚合、截断后的 `agent_result`,并写回同一 Redis 调用记录;
- 只把有界 `agent_result` 返回 Agent,禁止透传 `raw_response`;
- 清洗失败时返回 Tool ERROR,禁止透传未清洗原始结果。
Redis 中的完整调用记录至少包含:`tool_call_id`、`run_id`、`tool_name`、`request`、`raw_response`、`agent_result`、调用状态和起止时间。`tool_call_id` 使用框架提供的 Tool Call 协议 ID,是一次 Tool 调用在当前 Run 内的唯一引用;Harness 不另造第二套调用 ID,并可按 `runId + toolCallId` 取得完整记录。
Redis 是 Harness 内部基础设施,只允许 Harness 访问。任何 Agent 都不能获得 Redis Client、Redis Tool、key、连接信息或完整调用记录。本 Issue 不提供历史来源召回 Tool;Redis 只用于 Harness 的证据验真、短期调用追踪和最终引用生成,不作为 Agent 记忆。当前诊断若需要新的日志或数据库事实,由 Diagnosis Agent 通过当前受控 Tool 重新查询。
Redis 存储契约固定为:
```text
key = superbiz:harness:tool-call:{runId}:{toolCallId}
status = PROJECTING | READY | ERROR
evidence_status = EVIDENCE_FOUND | NO_EVIDENCE | ERROR
```
- 一次 Tool Call 对应一个 Key,不建立额外 Evidence Index;Key 不包含 Query、Session 内容或 Tool 参数;
- `status` 表示调用/投影生命周期:Tool 原始响应写入后为 `PROJECTING`,`ToolResultProjector` 成功并写入 `agent_result` 后为 `READY`,执行或清洗失败为 `ERROR`;
- `evidence_status` 表示结果语义,只有 `status=READY` 时才允许为 `EVIDENCE_FOUND` 或 `NO_EVIDENCE`;失败记录为 `ERROR`;
- EvidenceGuard 只接受当前 Run 下 `status=READY` 且存在 `agent_result` 的记录;`evidence_status=ERROR` 不可引用,`NO_EVIDENCE` 只能用于负向观察;
- TTL 默认 2 小时并可配置,必须大于最大 Run 耗时、SemanticGuard 总耗时和安全缓冲;
- TTL 在创建时设置,后续读取或更新不得续期;取消和失败记录保留到 TTL,首版不永久归档;
- 首版默认 `max-record-bytes=1MB`、`max-agent-result-bytes=64KB`、`max-run-bytes=5MB`,均由 Harness 配置并根据运行数据校准;
- `raw_response` 超过单记录上限时不静默截断,调用进入 `ERROR/RESULT_TOO_LARGE`;`agent_result` 可按投影预算截断并标记 `truncated=true`;
- 使用 UTF-8 JSON,首版不压缩、不分片、不使用 Java 原生序列化或对象存储;
- Redis 使用独立 Key 前缀和 ACL,应用日志不得输出 `request/raw_response`。
数据分层术语固定为:
- **Redis canonical invocation**:短期保存 `request/raw_response/agent_result` 的完整调用记录;当前版本允许未脱敏,但受 Harness-only ACL、TTL 和容量上限保护;
- **Agent projection**:`ToolResultProjector` 生成的有界 `agent_result`,经过 Tool-specific 聚合、截断和必要敏感字段清洗,只向 Diagnosis Agent、EvidenceGuard 和 SemanticGuard 的隔离快照开放;
- **Durable audit**:应用日志或业务审计表中的长期记录,只保存调用元数据、脱敏参数、耗时、状态和有界结果摘要,不保存 Redis `raw_response`。
```yaml
harness:
evidence:
key-prefix: "superbiz:harness:tool-call"
ttl: 2h
max-record-bytes: 1MB
max-agent-result-bytes: 64KB
max-run-bytes: 5MB
```
#### Output 边界
- 校验主 Agent 输出 Schema;
- 校验 Analysis Items 与 Tool Call IDs 的绑定;
- 执行 EvidenceGuard;
- 组装 SemanticGuard 的隔离输入;
- 根据验证结果决定最终释放或降级。
#### SSE 与审计
- 按最小 SSE 契约发送 metadata、脱敏 status/tool progress、最终 content 或 failure,以及 done;
- 记录模型调用、工具调用、验证结果、预算消耗和降级原因;
- 不输出内部 Prompt、Thought、原始 Tool 载荷和内部堆栈。
#### 预算配置
所有暂时无法准确估算的预算先集中提取为 Harness 配置,不在本 Issue 中伪造固定数值:
- 主 Agent 最大模型调用次数、总 Tool 次数、单 Tool 次数、上下文/Token 和总耗时;
- SemanticGuard 单次超时、总耗时和输入大小;
- RAG 最大证据数、单条摘录和总字符数;
- 日志最大 Pattern/Event 数、消息长度、lookback 和总字符数;
- MySQL 最大行数、单元格长度、总字节数和查询超时;
- Redis Tool 调用记录的 TTL、单记录/Agent 投影/单 Run 大小上限。
首版使用静态应用配置和可调默认值,不建设配置中心、热更新、按租户覆盖或按模型路由配置。Harness 必须校验配置合法性、记录实际消耗和触发的预算原因;后续根据 Trace、Token、延迟和截断数据校准默认值。已经确认的“最多重试一次”属于失败语义,不允许通过配置放大为隐式重试循环。
#### 重试策略装配
重试策略从业务流程中提取为小型类型化配置,由 Harness 统一装配,不分散在 Agent、Tool、Controller 或 SDK 中:
```text
RetryPolicy
-> max_attempts
-> retryable_failures
HarnessRetryPolicies
-> intent_router: max_attempts=2
-> diagnosis_agent: max_attempts=1
-> tool_call: max_attempts=1
-> semantic_guard: max_attempts=2
-> evidence_repair: max_attempts=1
```
- `HarnessRetryExecutor` 只承载“同一操作再次执行”的技术重试,首版用于 Intent Router 和 SemanticGuard;
- Intent Router 只在超时、传输失败或非法枚举输出时重试一次;第二次失败返回安全入口错误,不默认路由到 Diagnosis;
- Diagnosis Agent 整体和其单次模型调用不自动重试,ReAct 的正常模型/Tool 轮次不算重试;
- Tool 调用不自动重试;Tool `ERROR` 作为 Observation 返回,Agent 再次调用属于新的 Tool Action,必须由框架生成新的 `tool_call_id` 并计入预算;
- EvidenceGuard 的一次无 Tool 结构修复不是同操作重试,由 Harness 按显式流程执行;
- SemanticGuard 只在超时、传输失败、解析失败或 Schema 无效时使用同一输入重试一次;`UNSUPPORTED` 是有效业务结果,不重试;
- `NO_EVIDENCE`、取消、预算耗尽和业务拒绝均不可重试;
- 关闭或限制 SDK、HTTP Client 和数据库驱动的隐藏重试,所有实际 attempt 必须由 Harness 记录;
- 首版不引入 Retry DSL、插件注册中心、动态策略脚本或多级退避状态机。
Harness 不应包含:
- StateGraph;
- Planner/Executor/Composer 节点;
- Agent 间消息路由;
- 通用工作流 DSL;
- HarnessPlugin 注册中心;
- 多级业务重试状态机;
- 自行实现的 ReAct While 循环。
### 4.3 EvidenceGuard
原 Gatekeeper 不再作为独立编排组件存在。其能力进入 Diagnosis ReAct Agent 的 Harness:
```text
Post-Tool
-> 按 tool_call_id 保存完整调用记录和 agent_result
Pre-Release
-> 校验 Draft Schema
-> 校验 analysis_id 唯一
-> 校验每条 Analysis 至少引用一个 tool_call_id
-> 校验 Conclusion/Action Plan/Recommendation 引用的 analysis_id 均存在
-> 校验 tool_call_id 是否存在且属于当前 Run
-> 校验 Tool 调用返回可引用证据状态
-> 校验 agent_result 存在
-> 生成带真实性保证的 verified evidence snapshot
```
EvidenceGuard 使用确定性代码,不调用 LLM,不决定语义推导是否成立。它是原 Gatekeeper 的 Harness 内能力,而不是独立 Agent 或编排节点。具体规则包括:
- `analysis_id` 在当前 Draft 内唯一;
- 每条 Analysis 的 `tool_call_ids` 非空,且每个 ID 对应当前 Run 中 `status=READY`、存在 `agent_result`、`evidence_status` 可引用的 Tool Call;
- `kind=NORMAL` 的 Analysis 只能引用 `EVIDENCE_FOUND`;`kind=NEGATIVE_OBSERVATION` 可以引用 `NO_EVIDENCE`,其 `agent_result` 必须保留原始查询条件、时间/数据范围和零匹配信息;
- `NO_EVIDENCE` 只证明当前查询范围内无匹配结果,不能被 EvidenceGuard 当作问题不存在、根因排除或系统健康的正向证据;`evidence_status=ERROR` 一律不可引用;
- 非空 Conclusion 的 `based_on_analysis_ids` 非空且全部指向已有 Analysis;
- 每条 Action Plan 和 Recommendation 的 `based_on_analysis_ids` 非空且全部指向已有 Analysis;
- `conclusion=null` 时允许保留有真实证据支撑、但尚不能形成结论的 Analysis;不要求每条 Analysis 都必须被 Conclusion 引用;
- 最终引用清单只能从 Draft 实际引用且通过上述校验的 Tool Calls 确定性展开。
通过后,所引用 Tool 调用的 Run 归属、执行状态和 `agent_result` 被视为可信;`ToolResultProjector` 的投影正确性由代码和单元测试保证。EvidenceGuard 不判断 Analysis 是否正确解释证据,也不判断 Analysis 是否足以推出 Conclusion,这些属于 SemanticGuard。SemanticGuard 不再重复访问 Redis 或重新验证真实性。
### 4.4 SemanticGuard Agent
SemanticGuard 是独立审查 Agent,不加入主 ReAct Agent 上下文。
SemanticGuard 复用系统当前唯一配置的 ChatModel,不引入模型路由。它由 Harness 使用受限执行参数启动,Harness 负责隔离上下文、输入预算、调用超时、取消、最多一次重试、结构化输出校验、审计和最终释放策略。
必须满足:
- 使用全新的隔离上下文;
- 没有工具;
- 没有隐式记忆;
- 没有 ReAct 循环;
- 不读取主 Agent Thought、完整历史或 System Prompt;
- 不读取未通过 EvidenceGuard 的数据;
- 不访问 Redis,不重新校验 tool_call_id 或 agent_result 真实性;
- 不重新规划、查询、总结、润色、改写或补充用户答案;
- 不回调主 Agent 形成循环;
- 每次尝试只执行单轮语义和时间线审查,不允许 Agent 自身循环;仅 Harness 可在超时、调用失败或结构化输出无效时重试一次。
输入只包含:
- 原始 Query;
- 主 Agent Draft 的完整用户可见语义内容:Conclusion、Analysis、Action Plan、Recommendations 和 Limitations,但不包含内部 `tool_call_id`;
- 经过 EvidenceGuard 验真的 Evidence snapshot,包括精确 excerpt/value 和必要的可读来源信息:RAG 的 document_id/title/breadcrumb,或日志/MySQL 的 source、timestamp、scope。
`tool_call_id` 只在主 Agent 与 Harness、EvidenceGuard 之间使用,不注入 SemanticGuard 或其他 Agent。Harness 在组装 snapshot 时取出所引用调用的完整有界 `agent_result`,不读取或注入 `raw_response`,并将其中的来源信息、精确摘录和结构化值按 `analysis_id` 分组。该转换使用确定性代码,不调用 LLM 重新摘要;Harness 在模型调用之外保留 Tool 调用映射。
```json
{
"analysis_id": "a1",
"analysis_text": "连接池活跃连接达到 50/50",
"verified_evidence": [
{
"source_type": "LOG",
"source": "APPLICATION",
"scope": "order-service,最近 30 分钟",
"timestamp": "2026-07-21T10:30:00+08:00",
"excerpt": "HikariPool active=50, max=50, pending=23"
}
]
}
```
RAG 使用稳定 `document_id/title/breadcrumb/excerpt`,日志使用 `source/scope/timestamp/pattern/event`,MySQL 使用逻辑数据源、查询范围、列名和有界行/值。SemanticGuard 依靠 `analysis_id -> verified_evidence` 关系校验每条 Analysis,不需要理解 Tool ID,也不能访问完整工具正文。
不向 SemanticGuard 传递 Diagnosis Plan、Tool 调用过程或其他审计数据。SemanticGuard 对最终将展示给用户的完整 Draft 做报告级校验:
- Evidence 是否支持 Analysis;
- Analysis 是否能够推出 Conclusion;
- Action Plan 是否与已支持的分析/结论相关,危险行动是否标记人工确认;
- Recommendations 是否与诊断结果及 RAG/分析依据一致;
- Limitations 是否准确覆盖实际查询范围和缺失信息;
- 所有内容是否超出证据的服务、时间和数据范围。
SemanticGuard 只是审稿人,不是报告作者:它不能输出 corrected report、new conclusion、new action、new recommendation 或 user answer。真实性并不自动代表相关性、充分性或推导成立。
输出使用报告级二元状态,不使用未校准数字作为在线释放门禁,也不返回逐条 Analysis 状态:
```json
{
"verdict": "SUPPORTED",
"reason": "已验证证据能够支持诊断草稿中的分析并推出结论"
}
```
`verdict` 只允许 `SUPPORTED` 或 `UNSUPPORTED`。Diagnosis Agent 是唯一报告作者;SemanticGuard 不生成、改写或裁剪用户报告;Harness 不总结报告,只发布原 Draft 或固定 Fallback。`reason` 只进入审计,不直接作为用户答案。
第一次超时、调用失败、解析失败或 Schema 校验失败时,Harness 使用相同的已验真证据快照重试一次,不重新运行主 Agent 或 Tool。第二次仍失败则按未通过处理:不释放未验证草稿,只返回安全降级报告并正常结束 SSE。单次与总超时由 Harness 配置提供,初期不冻结具体数值。
### 4.5 意图识别
使用一次轻量 Chat 对当前 Query 做三分类:
```text
SYSTEM_CHAT
KNOWLEDGE_QUERY
DIAGNOSIS
```
约束:
- 输入只包含当前原始 `query`、可选 `last_intent` 和可选 `last_user_query`;
- 当前 Query 明确表达新主题时以当前 Query 为准;只有“继续”“那另一个服务呢”等追问才参考前一意图和问题;
- 不改写 Query;
- 不传完整历史、来源文档、evidence refs、Tool 结果或已发布答案;
- 不配置 Tool、Skill、记忆和 ReAct 循环;
- 输出只允许三个固定路由值;
- 原关键词 `QuestionComplexity` 不再作为主路由。
```json
{
"query": "那退款服务呢?",
"last_intent": "DIAGNOSIS",
"last_user_query": "订单 order-123 支付超时,帮我排查"
}
```
三个意图使用以下固定执行器:
#### SYSTEM_CHAT
- 用于系统定位、能力说明、使用方式、简单问候和非业务闲聊;
- 使用无 Tool 的普通 ChatModel;
- 系统能力来自简短、受控的能力说明,不依赖模型隐式知识;
- 不进入 ReAct、EvidenceGuard 或 SemanticGuard;
- 输出普通用户答案。
#### KNOWLEDGE_QUERY
- 用于内部文档、流程、API、错误码、配置规范和排障手册;
- 原始 Query 只执行一次有界 `lookup_knowledge`;
- 使用普通 Chat 基于 RAG Evidence 生成答案;
- Harness 校验证据引用;
- 不开放 query_logs、query_metrics 或 query_mysql;
- 不进入完整 Diagnosis ReAct 循环;
- 输出 `answer + references + limitations`。
#### DIAGNOSIS
- 用于故障排查、根因定位、实时状态分析和多证据组合;
- 进入完整 Diagnosis ReAct Agent;
- 可使用 RAG、日志和 MySQL 等受控证据 Tool;本 Issue 不提供 `query_metrics`;
- 经过 Harness EvidenceGuard 和独立 SemanticGuard;
- 输出完整诊断报告。
三个执行路径都接收同一个原始 Query,不做 Query 改写,不相互调用。原 `DATABASE_QUERY` 路由删除;MySQL Tool 只作为 DIAGNOSIS 的证据工具,不对应独立意图。
### 4.6 Diagnosis Agent 极简上下文
Diagnosis Agent 不接收完整 Session 历史,只接收当前 Query 和可选的上一个已完成回合:
```json
{
"query": "那退款服务呢?",
"previous_turn": {
"user_query": "订单 order-123 支付超时,帮我排查",
"published_conclusion": "支付超时与连接池耗尽有关",
"scope": "order-service,最近 30 分钟",
"limitations": ["尚未取得长事务数据"],
"source_documents": [
{
"document_id": "payment-timeout-guide",
"title": "支付超时排查手册"
}
]
}
}
```
- `previous_turn` 只取同一 Session 上一个已完成回合;无上一回合或上一回合未安全发布时为 `null`;
- 只读取已安全发布的结构化 Conclusion、Scope、Limitations 和 RAG 来源文档元数据;
- `source_documents` 只包含稳定 document ID 和 title,不包含正文、Tool Call ID、Tool 结果或内部引用;
- 不复用历史日志或 MySQL 数据,需要当前运行事实时重新调用受控 Tool;
- Harness 从上一回合结构化最终结果确定性组装,不调用 LLM 生成摘要;
- 字段长度和来源文档数量使用集中配置,超限时按字段边界截断或删除末尾来源;
- 当前 Query 始终优先,`previous_turn` 只辅助理解追问,不作为当前事实证据。
`previous_turn` 的持久化真理源固定为 `diagnosis_run`。Run 记录保存 `intent`、`release_outcome` 和 `published_result`;`published_result` 只包含 `user_query/published_conclusion/scope/limitations/source_documents`,不包含 Tool Call ID、原始证据、完整 Draft 或 SemanticGuard 审计原因。只允许读取同一 Session 最近一个 `intent=DIAGNOSIS`、`release_outcome=SUCCESS` 且 `published_result` 非空的 Run;`FALLBACK/FAILED/CANCELLED` 只用于审计,不进入下一轮上下文。Redis SessionContext 只作为短期会话缓存,不是该契约的真理源。
### 4.7 SSE 用户交互
SSE 采用“过程事件实时发送、最终报告安全释放”的口径:
- SSE 连接在整个诊断期间保持打开;
- 计划、Tool 进度、清洗、EvidenceGuard 和 SemanticGuard 状态实时发送;
- SemanticGuard 完成前不发送最终结论;
- 校验通过后以一个 `content` 事件释放结构化最终报告;
- 不将已生成的完整答案切片伪装成 Token 流;
- SemanticGuard 超时/失败时发送安全降级内容并结束;
- 不引入 WebSocket、轮询或验证后的第二个 Composer Agent。
首版只定义五种业务事件,固定顺序为:
```text
metadata -> status* -> content|failure -> done
```
- `metadata`:固定第一个且只发送一次,包含 `session_id` 和 `run_id`;
- `status`:可发送零到多次,只包含固定阶段码和安全的用户可见说明;
- `content`:最多一次,承载正常答案或固定安全 Fallback,不做 Token 切片;
- `failure`:最多一次,只用于 Router/Harness 等无法生成任何安全响应的技术失败,不能与 `content` 同时发送;
- `done`:固定最后一个且只发送一次,`outcome` 只允许 `SUCCESS/FALLBACK/FAILED`。
最小事件结构:
```text
event: metadata
data: {"session_id":"...","run_id":"..."}
event: status
data: {"code":"SEMANTIC_VALIDATING","message":"正在进行安全校验"}
event: content
data: {"content_type":"DIAGNOSIS_REPORT","payload":{...}}
event: failure
data: {"code":"ROUTING_UNAVAILABLE","message":"当前暂时无法处理该请求,请稍后重试"}
event: done
data: {"outcome":"SUCCESS"}
```
EvidenceGuard 或 SemanticGuard 降级使用 `content + done(FALLBACK)`;Router 重试后仍失败等无法形成安全内容的技术错误使用 `failure + done(FAILED)`。客户端主动断开后不再尝试发送终态事件,Harness 必须取消当前模型和 Tool 调用,并只在内部将 Run 记录为 `CANCELLED`。首版不实现断线续传、事件重放、事件序号恢复、轮询或 WebSocket。
禁止输出:
- Chain of Thought 和内部规划;
- System Prompt、模型 Prompt 和完整上下文;
- 未脱敏 Tool 参数;
- 原始日志、完整数据库行和完整检索 Trace;
- 内部异常、供应商错误和 Java 堆栈;
- 尚未通过释放门禁的强结论;
- Planner plan、Verifier verdict、Graph retry 等内部实现状态。
只保留一个 `POST /api/chat` SSE 接口,不保留同步 Chat 或 `/api/chat_stream` 兼容路径。
## 5. ACI Tool Contract
### 5.1 原则
Agent-facing Tool 必须满足:
1. 名称说明 Agent 能做什么,不暴露内部实现;
2. 描述说明什么时候调用、输入什么、不能用于什么;
3. 参数数量最小、含义明确、具备 Schema;
4. Agent 不控制连接、凭据、region、topK、limit 等基础设施参数,除非业务确有必要;
5. 输出稳定、结构化、有界;
6. 明确区分成功有证据、成功无证据和工具失败;
7. 输出包含可继续使用的稳定 Tool Call Reference;
8. 错误信息安全、可恢复,不泄露内部细节;
9. 相同输入不因隐藏 Session 记忆产生不可解释的语义变化;
10. Agent 只看到执行结果,不看到审计/调试实现。
### 5.2 通用状态语义
Agent-facing evidence Tool 统一使用 `evidence_status`:
```text
evidence_status = EVIDENCE_FOUND 查询成功且返回可使用证据
evidence_status = NO_EVIDENCE 查询成功但范围内没有证据
evidence_status = ERROR Tool 执行、参数、权限或清洗失败
```
`EVIDENCE_FOUND` 只表达 Tool 找到了证据,不声明证据支持任何分析或结论。`NO_EVIDENCE` 不是异常,只能支持明确标记为负向观察的 Analysis,不能推出问题不存在、问题已排除或系统健康。`ERROR` 不能伪装成无结果。`SUPPORTED/UNSUPPORTED` 只保留给 SemanticGuard。
### 5.3 通用 Tool Call Reference
每次可引用 Tool 调用只需要框架提供的一个稳定 ID:
```text
tool_call_id
```
`tool_call_id` 由框架随 Tool Call 请求提供,Harness 不替换或重新生成该 ID,只负责在 Tool 执行前校验并贯穿 Agent response、Redis 调用记录、EvidenceGuard 和最终 Trace。该 ID 必须非空、满足长度/字符集约束,并在同一 Run 内唯一;重复、非法或缺失 ID 不得覆盖既有记录,直接进入 Tool ERROR。Redis Key 使用 `runId + toolCallId` 隔离不同 Run。SemanticGuard 不接收该 ID,只接收 Harness 从对应调用的 `agent_result` 组装的 verified evidence snapshot。
## 6. 工具结果清洗与投影层
本 Issue 使用中文“工具结果清洗与投影层”作为架构名称,不再使用 PTK/RTK 缩写。代码统一使用 `ToolResultProjector`,首版只有三个 Tool-specific 实现:`RagResultProjector`、`QueryLogsResultProjector` 和 `MysqlResultProjector`。不再拆分 Cleaner、Sanitizer、ContextBuilder 或通用转换 Pipeline。
统一处理顺序:
```text
Agent Tool Request
-> Pre-Tool Guard
-> Mock Tool / MCP / DataSource
-> Raw Invocation Persistence
-> Tool-specific ToolResultProjector
-> Agent Result Persistence
-> Bounded Agent-facing Result
```
原则:
- 完整结果只在可信边界内保存;
- 当前版本不在 canonical evidence 持久化阶段做脱敏;Agent 仍只能接收有界的 Tool-specific 投影,原始 Redis 结果只能由 Harness 读取;
- Agent 只接收有界投影;
- Agent 看到的证据必须可回到 canonical result;
- `ToolResultProjector` 使用确定性代码,不调用 LLM 做二次摘要;
- 不建立万能清洗算法;统一 Envelope,下沉 Tool-specific projection;
- 不把完整结果写入进程本地 `refs/*.md` 作为主存储;
- 清洗失败不能绕过 Harness。
## 7. RAG Tool 设计
### 7.1 ACI 描述
Tool 只说明:
```text
查询内部知识库中的文档、接口说明、错误码和排障手册。
适用于稳定背景知识,不用于查询实时日志、指标或数据库状态。
输入 query:需要查询的问题或关键词。
```
不向 Agent 解释 L0/L1、category filter、fallback attempt、rerank 和 VectorStore/Milvus 实现。
### 7.2 Agent-facing 输出
```json
{
"evidence_status": "EVIDENCE_FOUND",
"tool_call_id": "tool-123",
"query": "支付超时处理方式",
"evidence": [
{
"document_id": "payment-timeout-guide",
"source": "payment-timeout.md",
"title": "支付超时排查",
"breadcrumb": "支付系统 > 故障排查",
"excerpt": "当支付请求出现 ERR_TIMEOUT 时,应先检查……"
}
],
"returned_count": 1,
"truncated": false
}
```
### 7.3 Agent 不可见内容
- ContextPack;
- RetrievalTrace;
- RerankTrace;
- L0 hints;
- 原始候选列表;
- 向量原始分数;
- hit reasons;
- fallback attempts;
- Session 级 retrieved domains;
- 完整 Metadata;
- 完整文档正文。
这些内容按审计需要保存或删除,但不进入 Agent 上下文。
### 7.4 RAG 结果投影
- 删除 EvidenceBlock 与 ContextPack 的重复正文;
- 返回精确文档摘录,不使用 LLM 摘要;
- 相同文档/段落去重;
- 限制 evidence 数量、单条 excerpt 和整体字符数;
- 文档内容作为不可信证据数据,不执行其中的指令;
- 明确 `NO_EVIDENCE` 和 `ERROR`;
- 删除 Session 隐式去重或改为显式 Run 内重复查询控制。
## 8. query_logs Tool 设计
### 8.1 ACI 输入
删除 Agent 可见的 `getAvailableLogTopics`。固定/动态 Topic 目录由 Harness 或 Tool Adapter 管理。
当前环境没有真实日志数据,本 Issue 首版继续使用现有 Mock 日志实现;不新增 MCP 或 Java CLS 适配器。Mock 只作为数据源实现,仍必须经过相同的 ACI、Harness、canonical evidence 和 Agent projection 链路。后续真实适配器若接入,必须复用本节 Contract,不在本 Issue 提前设计适配平台。
```json
{
"topic": "APPLICATION",
"query": "order-service HikariCP connection timeout",
"lookback_minutes": 30
}
```
约束:
- topic 使用稳定逻辑枚举;
- query 表达日志检索目标;
- lookback 有默认值和最大值;
- region、TopicId、limit 由系统控制;
- Agent 不需要先调用发现工具;
- 当前仅验证本地 Mock 返回 Agent-facing Contract;真实 CLS/MCP 的兼容性留待后续接入时验证。
### 8.2 Agent-facing 输出
```json
{
"evidence_status": "EVIDENCE_FOUND",
"tool_call_id": "tool-456",
"source_kind": "MOCK",
"scope": {
"topic": "APPLICATION",
"query": "order-service HikariCP connection timeout",
"start_time": "...",
"end_time": "..."
},
"match_count": 126,
"returned_count": 1,
"patterns": [
{
"count": 84,
"first_seen": "...",
"last_seen": "...",
"level": "ERROR",
"service": "order-service",
"example": "HikariPool connection is not available"
}
],
"events": [
{
"timestamp": "...",
"level": "ERROR",
"service": "order-service",
"message": "HikariPool connection is not available"
}
],
"truncated": true
}
```
### 8.3 日志结果投影
- 按稳定日志模板聚合重复事件;
- Pattern 保存 count、first_seen、last_seen 和代表样本;
- 额外保留少量按时间排序的事件,防止丢失时间线;
- 不固定删除 INFO,只根据 Query 和有界投影选择证据;
- 脱敏 Token、密码、Authorization Header 等敏感数据;
- 限制单条消息、Pattern 数、Event 数和整体字符数;
- 返回完整查询范围,防止将局部结果扩大为全局结论;
- `match_count` 表示查询范围内的原始匹配事件总数,`returned_count` 表示 `events` 中实际返回的有界时间线事件数量;Pattern 数量直接由 `patterns` 数组长度表示;
- Redis `raw_response` 不进入 Agent 上下文;持久化审计只保存脱敏参数、聚合元数据和有界结果摘要。
- `source_kind=MOCK` 必须保留在 `agent_result` 和诊断范围中;Harness 不得把 Mock 数据表述为生产实时事实。
## 9. 新增 MySQL Tool 设计
### 9.1 定位
新增一个只读、受限、可审计的外部 MySQL 查询 Tool。该 Tool 查询独立配置的业务/诊断数据源,不连接 Agent 自身的持久化数据库。
连接和安全策略由后续新增的独立配置文件提供。配置只暴露逻辑数据源 ID,不把真实连接信息交给 Agent:
- 数据源 URL、账号和密码不写入 Prompt、Skill 或 RAG 文档;
- 密码等敏感值使用环境变量或受控 Secret 注入,不在配置文件中硬编码;
- 配置定义允许的 schema/table/column、超时、最大行数和最大结果大小;
- Tool 通过逻辑数据源 ID 选择连接,不接受 Agent 传入 URL、账号、密码或任意 JDBC 参数;
- 不复用现有 Python 查询脚本的连接和执行方式;现有脚本中的硬编码凭据和可写执行分支必须清理。
表名、字段名、关联关系和业务语义后续从 Skill 或 RAG 召回的数据字典/查询知识中获得,MySQL Tool 本身不负责发现表结构。Skill 或 RAG 文档可以帮助 Agent 生成 SQL,但它们只是候选查询知识,不是授权来源。Harness 必须将 SQL AST 中实际使用的 schema/table/column 与独立配置的 allowlist 做最终校验;文档中出现但配置未授权的对象一律拒绝。
首版只提供静态“库、表、字段”三层白名单,不在本 Issue 设计租户或行级权限:
```yaml
harness:
mysql-tools:
data-sources:
order_readonly:
jdbc-url: ${ORDER_MYSQL_JDBC_URL}
username: ${ORDER_MYSQL_USERNAME}
password: ${ORDER_MYSQL_PASSWORD}
default-schema: order_db
allowed-schemas:
order_db:
tables:
biz_order:
columns:
- order_id
- user_id
- payment_status
- created_at
- updated_at
payment_record:
columns:
- payment_id
- order_id
- channel
- status
- created_at
- updated_at
```
配置语义:
- `data-sources` Key 是 Agent 可传入的逻辑数据源 ID,不是真实连接名;
- `allowed-schemas` 下每个 Key 是允许访问的 MySQL 库/schema;未配置的库一律拒绝;
- 每个库只允许 `tables` 中显式列出的表;每张表只允许 `columns` 中显式列出的字段;
- 首版不支持 `*`、正则、前缀匹配、继承或动态白名单;库、表、字段均为精确匹配;
- SQL 未显式写库名时只能使用该数据源的 `default-schema`,且 default schema 必须同时存在于 `allowed-schemas`;
- JOIN 中每个表及每个投影、过滤、关联、分组、排序字段都必须通过对应库/表/字段校验;
- 未限定字段通过 JSqlParser 的表别名和作用域解析到唯一表;无法唯一解析时拒绝;
- 函数白名单、超时、行数和字节预算继续使用 Harness 的独立配置,不混入库表字段结构;
- 凭据只引用环境变量/Secret,不允许在配置文件中写明文。
固定调用链:
```text
Skill/RAG 召回候选数据字典
-> Agent 使用明确表名和列名生成参数化 SQL
-> Harness 解析 SQL AST 并用独立配置做授权裁决
-> MySQL Tool 使用配置映射的只读数据源执行
-> Harness 清洗、持久化 canonical evidence 并投影给 Agent
```
MySQL Tool 不向 Agent 开放 `SHOW TABLES`、`SHOW COLUMNS`、`DESCRIBE` 或直接查询 `information_schema` 的元数据发现能力,避免绕过 Skill/RAG 知识边界和配置授权。
### 9.2 ACI 输入
初步推荐采用参数绑定的受限 SQL:
```json
{
"data_source": "order_readonly",
"sql": "SELECT order_id, payment_status, updated_at FROM biz_order WHERE order_id = ?",
"params": ["order-123"]
}
```
只允许:
- 单条 `SELECT`;
- 显式列名;
- `INNER JOIN` 和 `LEFT JOIN`;
- `WHERE`、`GROUP BY`、`HAVING`、`ORDER BY` 和受控 `LIMIT`;
- allowlist 中的聚合/标量函数,首版至少覆盖 `COUNT`、`SUM`、`AVG`、`MIN` 和 `MAX`;
- 参数绑定;
- 独立配置中存在的逻辑数据源 ID;
- 上述静态 allowlist 内的 schema/table/column 精确匹配;
- Harness 注入或限制的行数、超时和字节预算。
必须阻止:
- INSERT/UPDATE/DELETE/REPLACE;
- CREATE/ALTER/DROP/TRUNCATE;
- 投影通配符 `SELECT *` 和 `table.*`,包括子查询中的通配符;
- `WITH`、子查询、`UNION` 和窗口函数;
- `CROSS JOIN`、未在 allowlist 中的函数和无法识别的 AST 节点;
- `SHOW TABLES`、`SHOW COLUMNS`、`DESCRIBE` 和 `information_schema` 元数据查询;
- CALL;
- 多语句;
- SELECT INTO OUTFILE/DUMPFILE;
- FOR UPDATE;
- SLEEP/BENCHMARK/LOAD_FILE 等危险函数;
- 任意事务控制和写入路径。
`COUNT(*)` 作为聚合函数例外允许,因为它不返回全部字段;禁止的是字段投影通配符。若后续需要完全禁止星号,可将查询知识统一改为 `COUNT(1)`,不影响整体校验结构。
### 9.3 JSqlParser 校验
首版引入 JSqlParser 将 Agent 生成的 SQL 解析为 AST。JSqlParser 只负责理解 SQL 结构,不连接或执行数据库;Harness 使用 AST visitor 执行 fail-closed 白名单校验:
```text
解析且确认只有一个 Statement
-> 确认根节点是允许的 SELECT
-> 遍历所有 table/column/join/function/子表达式
-> 校验逻辑数据源和 schema/table/column/function allowlist
-> 校验占位符数量与 params 一致
-> 注入或压低 LIMIT
-> 通过 PreparedStatement 执行
```
解析失败、遍历到未知节点或无法证明符合允许子集时直接拒绝,不回退到正则、`startsWith` 或容错执行。具体依赖版本在实施阶段选择兼容 Java 17 的稳定版本,并通过固定安全用例验证后锁定。
安全边界必须同时包含:
- MySQL 专用只读账号;
- JSqlParser AST 校验,而不是 startsWith/正则;
- 独立配置提供的 schema/table/column allowlist;
- JDBC/数据库侧 read-only;
- JDBC `PreparedStatement` 和 `setMaxRows`;
- 查询超时;
- 最大行数、单元格长度和总字节数;
- 客户端断开时取消查询;
- 独立连接池或明确资源隔离。
### 9.4 Agent-facing 输出
```json
{
"evidence_status": "EVIDENCE_FOUND",
"tool_call_id": "tool-789",
"columns": ["order_id", "payment_status", "updated_at"],
"rows": [
{
"order_id": "order-123",
"payment_status": "FAILED",
"updated_at": "2026-07-20 10:30:00"
}
],
"returned_count": 1,
"truncated": false
}
```
### 9.5 MySQL 结果投影
- 限制返回行数;
- 限制单元格、整行和整体结果大小;
- Blob、长文本和长 JSON 截断并标记;
- 按字段策略脱敏密码、Token、个人敏感信息;
- 每行保留结构化字段,整次调用通过 `tool_call_id` 引用;
- SQL 模板、脱敏参数、耗时、状态和有界结果摘要进入持久化审计;完整 `raw_response` 只按 Redis canonical invocation 契约短期保存;
- 连接字符串、账号、密码和内部堆栈不得进入 Agent 或审计明文。
## 10. 主 Agent 输出契约与低置信度处理
### 10.1 两类 Plan 必须分离
- **Diagnosis Plan**:主 Agent 开始排查时产生的 3–5 个高层步骤,通过 SSE status 提前输出;只描述准备查什么,不输出 Thought、完整 SQL、敏感参数或内部推理。
- **Action Plan**:诊断完成后给用户的下一步操作;与 Diagnosis Plan 不是同一个字段。
Diagnosis Plan 不参与 EvidenceGuard 或 SemanticGuard,因为它不是事实结论。执行中需要补充查询时只发送脱敏状态事件,不建立复杂 Plan 版本状态机。
### 10.2 已确认的 Agent Draft Schema
Diagnosis Agent 是诊断报告唯一的语义作者,负责生成结论、分析支撑、行动计划、长期建议、诊断范围与限制,并通过 Tool Call ID 选择各项分析所引用的证据。Harness 不生成、补充、删改或覆盖这些语义字段。
主 Agent 不输出不可安全裁剪的自由文本 answer,而是输出以下结构:
```json
{
"conclusion": {
"text": "支付超时的主要原因是数据库连接池耗尽",
"based_on_analysis_ids": ["a1"]
},
"analysis": [
{
"analysis_id": "a1",
"kind": "NORMAL",
"text": "连接池活跃连接达到 50/50,并存在等待线程",
"tool_call_ids": ["tool-456"]
}
],
"action_plan": [
{
"action": "查询连接泄漏和长事务",
"based_on_analysis_ids": ["a1"],
"requires_human_confirmation": false
},
{
"action": "临时扩大连接池容量",
"based_on_analysis_ids": ["a1"],
"requires_human_confirmation": true
}
],
"recommendations": [
{
"text": "增加连接池等待线程和获取耗时告警",
"based_on_analysis_ids": ["a1"]
}
],
"limitations": {
"scope": "order-service,最近 30 分钟",
"missing_info": ["尚未取得慢 SQL 和长事务数据"]
}
}
```
字段语义:
- `conclusion`:结论先行;引用支撑它的 analysis IDs,不重复绑定 Evidence;证据不足时允许为 `null`。
- `analysis`:可独立验证的分析支撑。每一项必须有唯一 analysis ID、固定 `kind=NORMAL|NEGATIVE_OBSERVATION` 和至少一个 `tool_call_id`,拒绝无来源分析。负向观察只能绑定 `NO_EVIDENCE`,并严格限定为对应 Tool 的实际查询范围。
- `action_plan`:立即执行的下一步,必须通过 `based_on_analysis_ids` 绑定分析。危险或有副作用的操作必须标记 `requires_human_confirmation=true`,Harness/HITL 策略拥有最终决定权。
- `recommendations`:长期治理建议,必须通过 `based_on_analysis_ids` 绑定分析;来自知识库或外部规范时,支撑该分析的 Tool Call 应来自 RAG。
- `limitations.scope`:由 Diagnosis Agent 根据本次实际查询范围生成;Harness 不改写或覆盖,SemanticGuard 负责校验它是否超出 verified evidence 中的真实 Tool scope。
- `limitations.missing_info`:尚未取得、导致结论受限的关键材料。
主 Agent 只向 Harness 输出 Tool Call IDs,不输出可自行编造的完整 Reference 内容。Harness 在调用 SemanticGuard 前使用这些 IDs 读取对应的 `agent_result`,仅传递已解析的来源文档/来源工具和证据内容。Harness 只把 Agent 已选择的 Tool Call ID 确定性展开为最终引用清单,展示来源、scope/timestamp 和精确 evidence excerpt/value;它不能选择额外来源、生成引用摘要或改变报告语义。
最终用户报告顺序固定为:
```text
1. 结论
2. 分析支撑
3. 行动计划
4. 长期建议
5. 诊断范围与限制
6. 引用
```
### 10.3 释放语义
不使用主 Agent 自报的 0–1 数值置信度作为释放依据。
```text
EvidenceGuard 失败
-> 不进入 SemanticGuard
-> 首次失败执行一次无 Tool 的结构化输出修复
-> 修复后重新执行 EvidenceGuard
-> 第二次仍失败则安全 Fallback
SemanticGuard SUPPORTED
-> Harness 原样释放主 Agent 的语义报告,并附加由其 Tool Call IDs 确定性展开的引用清单
SemanticGuard UNSUPPORTED/TIMEOUT/ERROR
-> 不释放主 Agent 草稿、分析、结论、行动或建议
-> Harness 返回固定安全 Fallback,只包含已验证来源、证据不足说明和诊断限制
```
固定安全 Fallback 由 Harness 通过确定性模板生成,不调用 LLM 或 Composer:
```json
{
"type": "SEMANTIC_UNSUPPORTED",
"conclusion": null,
"message": "当前证据不足,无法确认根因",
"verified_sources": [
{
"source_type": "LOG",
"source": "APPLICATION (MOCK)",
"scope": "order-service,最近 30 分钟"
}
],
"limitations": ["语义校验未通过或暂不可用"],
"next_steps": ["补充当前缺失的数据后重新发起诊断"]
}
```
- `type` 是稳定的用户可见降级分类,只允许 `EVIDENCE_VALIDATION_FAILED`、`SEMANTIC_UNSUPPORTED` 和 `SEMANTIC_UNAVAILABLE`;
- `EVIDENCE_VALIDATION_FAILED` 表示 EvidenceGuard 修复后仍未通过,此时 `verified_sources` 必须为空;
- `SEMANTIC_UNSUPPORTED` 表示证据已通过 EvidenceGuard,但不支持 Agent 报告;`SEMANTIC_UNAVAILABLE` 表示 SemanticGuard 第二次超时、调用失败或输出无效;这两类可以返回本次已通过 EvidenceGuard 的来源;
- `verified_sources` 只列出 EvidenceGuard 已通过的来源名称和查询范围,不包含主 Agent 的 Analysis、Conclusion 或推导文本;
- `limitations` 使用稳定的用户可见原因分类,不直接展示 SemanticGuard `reason`、供应商错误或内部异常;
- `next_steps` 只列出补充数据、缩小范围或稍后重试等安全动作,不包含主 Agent 未校验的 Action Plan/Recommendations;
- 三种降级使用同一 Fallback Schema;内部可使用比 `type` 更细的 `fallback_reason` 审计码,但不得将供应商错误或异常细节暴露给用户;
- Fallback 通过最终 `content` 事件发送并正常 `done`,不作为 HTTP/SSE 系统错误。
## 11. 行为与协议变化
这是有意的不兼容重构:
- 删除同步 `/api/chat` 响应模式;
- 删除 `/api/chat_stream`;
- `POST /api/chat` 改为唯一 SSE Chat 协议;
- 删除 `QuestionComplexity` 主路由;
- Planner/Executor/Verifier/Composer 不再作为主链路多 Agent 角色;
- 不引入业务 StateGraph;
- Tool 参数和返回协议发生不兼容变化;
- RAG Session 隐式检索记忆删除或改为显式 Run 控制;
- `getAvailableLogTopics` 不再对 Agent 暴露;
- 新增只读 MySQL Tool;
- 原 Gatekeeper 编排身份消失,能力进入 Harness EvidenceGuard;
- SemanticGuard 使用隔离上下文且不能形成 Agent 回路。
受影响的消费者包括前端 Chat、Controller tests、ChatService/Agent tests、Prompt contracts、Tool contract tests、Trace/Eval fixtures 和任何直接调用旧 Tool 方法的代码。
## 12. 分阶段实施计划
ISS-014 是总设计 Issue,不创建跨阶段共享的 OpenSpec change。以下 11 个实施切片各自执行一个完整、串行的 sm-flow:
| 阶段 | OpenSpec change | 状态 |
|---|---|---|
| 0 | `single-react-design-freeze` | Completed;已归档,Git commit 见阶段历史 |
| 1 | `single-react-aci-tool-contracts` | Completed;已归档 |
| 2 | `single-react-harness-run-context` | Completed;已归档 |
| 3A | `single-react-tool-invocation-store` | Completed;已归档 |
| 3B | `single-react-rag-log-projections` | Completed;已归档 |
| 3C | `single-react-mysql-readonly-tool` | Completed;已归档 |
| 4 | `single-react-diagnosis-agent` | Completed;已归档 |
| 5 | `single-react-evidence-semantic-guards` | Completed;已归档 |
| 6A | `single-react-chat-application-usecase` | Completed;已归档 |
| 6B | `single-react-chat-sse-cutover` | Pending |
| 7 | `single-react-cleanup-e2e` | Pending |
每个 change 独立完成 Discover、Commit、Apply、阶段验收、Archive 和 Git commit;前一阶段 Archive 且提交后才允许启动下一阶段,不并行实施相邻阶段。
### 阶段 0:设计冻结与安全前置
目标:冻结本 Issue 的未决契约,不修改业务执行链。
任务:
- 将已确认的主 Agent Draft/Analysis/Conclusion Schema 固化为契约测试;
- 将 EvidenceGuard 一次无 Tool 输出修复和二次失败 Fallback 固化为契约测试;
- 冻结 SemanticGuard 报告级 `SUPPORTED/UNSUPPORTED` 二元契约和固定安全 Fallback;
- 将过程事件实时 SSE、最终报告门禁后释放的口径固化为协议;
- 将已确认的 SYSTEM_CHAT/KNOWLEDGE_QUERY/DIAGNOSIS 执行器映射固化为契约测试;
- 冻结 Harness 预算配置项、合法性校验和预算耗尽语义,不要求在本阶段冻结准确默认数值;
- 冻结 `RetryPolicy/HarnessRetryPolicies/HarnessRetryExecutor`、固定重试矩阵和隐藏重试禁用规则;
- 冻结工具结果清洗与投影层及 `ToolResultProjector` 代码命名;
- 确认 Redis 调用记录保存 `request + raw_response + agent_result`,冻结单 Key、状态、默认 TTL/容量、非续期和 Harness-only ACL;当前版本明确暂不做持久化脱敏,并记录为后续安全增强项;
- 确认 JSqlParser、首版 SQL 允许子集、MySQL allowlist 和只读账号方案;
- 移除并轮换现有脚本中的硬编码数据库凭据;
- 建立改造前 focused baseline。
验收:
- 所有阻塞性问题有明确决策;
- 无业务 Java 行为变化时可跳过单元测试,并记录理由;
- Security prerequisite 完成后才能进入 MySQL Tool 实现。
### 阶段 1:ACI Tool Contract 冻结
目标:先定义 Agent 能看到的工具界面,不实现 Agent 架构切换。
任务:
- 冻结 RAG、query_logs、query_mysql Request/Response Schema;
- 冻结调用生命周期 `status=PROJECTING/READY/ERROR` 与结果语义 `evidence_status=EVIDENCE_FOUND/NO_EVIDENCE/ERROR`,禁止混用;
- 冻结 `tool_call_id` 调用引用契约;
- 缩短 Tool descriptions,移除内部实现泄漏;
- 为三类 Tool 添加独立契约测试;
- 确认现有 Mock Tool 的 Agent-facing Contract 和后续适配边界;本阶段不实现真实 MCP/CLS 适配器。
验收:
- Schema 和错误语义契约测试通过;
- Agent-facing 与 audit-facing 字段清单无交叉歧义;
- 不新增通用插件框架或工作流 DSL。
### 阶段 2:Harness Core 与 RunContext
目标:先建立后续 Tool、Agent、Guard 和入口共同依赖的显式运行上下文,不提前切换 HTTP/SSE 协议。
任务:
- 定义不可变 `RunContext`,显式携带 `sessionId/runId/deadline/cancellation/budget/retryPolicies`;
- 定义 Run 创建、预算计数、取消传播和终态管理的 Harness Core;
- 装配 `HarnessRetryPolicies/HarnessRetryExecutor`,关闭或纳管底层隐藏重试;
- 定义 Redis Tool Call Key Factory 和单 Run 容量计数器,但不实现具体 Tool 投影;
- 所有后续边界通过参数或受控上下文对象显式接收 `RunContext`,禁止 ThreadLocal;
- 使用 Fake Model/Tool 验证 deadline、取消、预算、重试记录和 Run 终态;
- 不修改 Controller 协议,不接入旧 ChatService 的临时适配层。
验收:
- RunContext 无隐式线程状态,可在同步/异步边界显式传播;
- 预算耗尽、取消和异常均产生唯一 Run 终态;
- 阶段 3A 可直接依赖 Harness Core,不需要临时耦合旧 ChatService;
- focused Harness Core tests 通过。
### 阶段 3A:Harness Tool Boundary 与 Canonical Invocation Store
目标:实现所有 Tool 共用的 Pre/Post 边界、canonical invocation store 和统一状态机,不在本阶段实现 Tool-specific 投影。
任务:
- 接收、校验并传播框架提供的 `tool_call_id`,覆盖缺失、非法、重复和跨 Run 引用测试;
- 实现 Pre-Tool Schema/权限/只读/预算校验;
- 将 `request + raw_response + agent_result` 写入同一 Redis Tool 调用记录;禁止仅依赖截断 preview 做验真;
- 实现 `PROJECTING/READY/ERROR` 生命周期和独立 `evidence_status`,以及 TTL 不续期、单记录/单 Run 容量门禁和 `RESULT_TOO_LARGE`;
- 清洗失败显式 ERROR;
- 使用 Fake Tool/Projector 增加 invocation store、状态、TTL、容量、no-evidence 和 error tests。
验收:
- 未清洗原始结果不会进入 Agent;
- 每条返回证据可以回到当前 Run 的 canonical result;
- 只有当前 Run 的 `READY` 记录可进入引用校验;`EVIDENCE_FOUND`、`NO_EVIDENCE` 和 `ERROR` 的引用边界有契约测试,读取不会刷新 TTL,超限原始响应不会被静默截断;
- 阶段 3B/3C 可复用同一 Tool boundary 和 invocation store,不复制状态机或 Redis 访问逻辑。
### 阶段 3B:RAG 与 query_logs 结果投影
目标:在阶段 3A 的统一边界上迁移两个现有证据 Tool,并完成 Agent-facing 有界投影。
任务:
- RAG:审计分离、去重复正文、精确摘录和上下文预算;
- query_logs:在现有 Mock 上实现统一 Contract、模板聚合、时间线抽样和脱敏;不实现真实 MCP/CLS 适配器;
- 两个 Tool 统一接入阶段 3A 的 canonical invocation store、`evidence_status` 和 Tool Call ID 契约;
- 增加 Tool contract、truncation、no-evidence、负向观察和 error tests。
验收:
- RAG/日志原始结果不会未经投影进入 Agent;
- RAG/日志的长度、数量、查询范围和脱敏预算有 focused tests;
- `NO_EVIDENCE` 保留查询范围并且不会被表述为问题不存在;
- 不实现真实 MCP/CLS 适配器。
### 阶段 3C:只读 MySQL Tool
目标:独立实现安全敏感的只读 MySQL Tool,避免与现有 Tool 迁移共享归档边界。
任务:
- 引入 JSqlParser,完成保守 SELECT 子集的 fail-closed AST 校验;
- 实现逻辑数据源、schema/table/column allowlist、参数绑定、只读执行、超时、取消和结果投影;
- 接入阶段 3A 的 canonical invocation store、预算、`evidence_status` 和 Tool Call ID 契约;
- 使用隔离测试数据源完成 security、truncation、no-evidence 和 error tests。
验收:
- MySQL 的行数、单元格、总字节和查询超时预算有测试;
- MySQL write、WITH、子查询、UNION、投影通配符、未知 AST、allowlist bypass、timeout 和其他 security cases 被拒绝;合法显式列 SELECT 和 `COUNT(*)` 通过。
### 阶段 4:单体 Diagnosis ReAct Agent
目标:将 Planner、Executor、内部 Verifier、自身 Composer 职责合并为一个完整 ReAct Agent;本阶段只通过内部应用用例和测试入口验证,不接管公开 Chat 入口。
任务:
- 创建单一 Diagnosis Agent Prompt;
- Agent 接收当前原始 Query 和可选的固定 Schema `previous_turn`;
- 使用框架已有 ReAct/tool loop,不手写 While;
- 接入 Harness 包装后的 Tool;
- 输出结构化 Draft/Analysis/Conclusion/Tool Call IDs;
- 证据不足时明确停止;
- 新 Agent 通过独立内部应用用例接入 Harness,公开 `/api/chat` 暂不切换;
- 旧多 Agent 主链路在阶段 5/6A/6B 完成释放门禁和切换前继续保留,禁止阶段 4 直接删除导致公开入口失效;
- 保留 Run/AgentStep/ToolInvocation 基础审计。
验收:
- 新诊断链路只有一个拥有工具循环的 Agent,且只在内部测试入口运行;
- Diagnosis Agent 整体、单次模型调用和 Tool 调用均无 Harness 自动重试;
- 无 Planner/Executor/Composer Agent 间 JSON 搬运;
- 无外层 Graph;
- focused Agent/tool-loop/output tests 通过;
- 工具、模型和上下文预算均有可配置且被 Harness 强制执行的确定性上限。
### 阶段 5:EvidenceGuard、SemanticGuard 与释放策略
目标:在不恢复 Graph 的前提下完成物理验真和独立语义审查。
任务:
- EvidenceGuard 校验 Draft Schema、Analysis ID 唯一性、Analysis `kind`、报告内部引用完整性,以及当前 Run、Tool Call ID、调用生命周期、`evidence_status` 和 `agent_result`;
- 格式/物理验真首次失败只执行一次无 Tool 输出修复,禁止重新运行诊断或 Tool 循环;
- 修复后再次执行 EvidenceGuard,仍失败则直接安全 Fallback;
- 构造 SemanticGuard 最小隔离输入;
- 复用系统当前唯一 ChatModel,实现由同一 Harness 受限控制的无工具、无记忆、单轮 SemanticGuard Agent;
- Harness 控制 SemanticGuard 输入预算、超时、取消、一次重试、结构校验、审计和降级释放,禁止 Agent 自身重试或形成回路;
- 实现 SUPPORTED/UNSUPPORTED/TIMEOUT/ERROR release policy;
- 确保 SemanticGuard 不回调主 Agent;
- 增加 duplicate/missing Analysis ID、empty evidence reference、fabricated Tool ID、cross-run、failed call、missing agent_result、`NO_EVIDENCE` 负向观察、无证据过度推断、unsupported report、timeout、Fallback type 和 `verified_sources` 规则测试。
验收:
- 重复/缺失 Analysis ID、空引用、伪造/跨 Run/失败调用或缺失 `agent_result` 不会进入 SemanticGuard;
- SemanticGuard 只看到 verified evidence;
- SemanticGuard 与主 Agent 复用同一模型配置,但不共享上下文、工具或记忆;
- EvidenceGuard 修复最多一次,且修复调用没有 Tool;
- 第二次物理验真失败直接 Fallback;
- 超时和失败不释放草稿;
- UNSUPPORTED 不会释放或局部裁剪主 Agent 草稿;
- Fallback 不包含主 Agent 草稿或 SemanticGuard 内部 reason,并以 `content + done` 正常结束;
- 无隐式 retry loop。
### 阶段 6A:Chat Application Use Case、意图路由与 previous turn
目标:在不切换公开协议的前提下完成 Chat 应用用例、三类意图路由和上一安全回合组装。
任务:
- 会话、历史和执行生命周期下沉应用用例,由应用用例创建并传播阶段 2 定义的 `RunContext`;
- 引入三分类轻量 Intent Router;
- Intent Router 技术失败或非法枚举只由 Harness 重试一次,第二次失败不默认进入 Diagnosis;
- 由应用用例确定性组装 Diagnosis Agent 的上一个已安全发布回合,不调用上下文摘要模型;
- 原始 Query 原样进入选定执行路径;
- 新应用用例只通过内部测试入口验证,公开 `/api/chat` 和 `/api/chat_stream` 暂不切换;
验收:
- SYSTEM_CHAT、KNOWLEDGE_QUERY 和 DIAGNOSIS 路由映射及失败语义通过 focused tests;
- previous turn 只来自同一 Session 上一个符合安全发布条件的结构化结果;
- 应用用例显式传播同一个 sessionId/runId,不依赖 Controller 提供模型和工具;
- 阶段 6B 可直接完成协议切换,不需要重写应用用例。
### 阶段 6B:唯一 `/api/chat` SSE 切换
目标:将公开 Chat 原子切换到阶段 6A 的应用用例,并完成破坏性 SSE 协议迁移。
任务:
- Controller 只负责请求校验、HTTP/SSE 协议和连接生命周期;
- 仅在阶段 5 的 EvidenceGuard、SemanticGuard 和 Release Policy 全部通过后,原子切换 `/api/chat` 到新链路;
- 切换前后均不得出现未经过释放门禁的公开 Draft;
- 只保留 `POST /api/chat`;
- 删除 `/api/chat_stream` 和同步兼容路径;
- 同步迁移前端 Chat 消费者到固定 SSE 事件契约;
- 按固定顺序输出 `metadata -> status* -> content|failure -> done`,终态只允许 `SUCCESS/FALLBACK/FAILED`;
- 处理断开、取消、超时和 Run 终态;
- 不创建 Controller 自有无界线程池。
验收:
- Controller 不依赖 ChatModel/ToolCallbackProvider;
- 同一请求 sessionId/runId 在 SSE、日志和数据库一致;
- 禁止输出 Thought、Prompt、raw Tool data 和内部错误;
- SSE 事件 Schema、顺序、互斥、唯一终态、客户端取消和错误单元/集成测试通过。
### 阶段 7:物理清理、文档与最终验收
目标:删除旧架构和完成一次最终端到端验收。
任务:
- 物理删除被替代的旧 Agent、Hook、ThreadLocal、路由和死代码;
- 删除旧 Tool compatibility contract 和过时测试;
- 不保留注释旧代码或双轨开关;
- 更新 MVP 架构、接口、Tool、Trace 和安全文档;
- 审查 ISS-012/ISS-013 是否可归档或被本 Issue 吸收;
- 运行最终 Maven 启动 E2E;
- 核对 `logs/`;
- 使用安全的数据库查询方式核对 exact sessionId/runId;
- 验证 Token、工具次数、SSE、EvidenceGuard、SemanticGuard 和 Fallback。
- query_logs 和外部 MySQL Tool 使用现有 Mock/测试数据完成契约、安全与编排验收;本阶段不声称完成真实 CLS 或生产业务 MySQL 数据源的 live E2E。
验收:
- 旧多 Agent/Graph/伪流式入口不存在;
- 全部 focused tests 通过;
- 最终 E2E、日志和数据库证据归档;
- 无硬编码凭据、临时 refs 文件、未解释兼容层和死代码;
- 工作区改动范围与本 Issue 一致。
## 13. 阶段门禁
实施时每阶段必须满足:
1. 当前阶段范围和行为变化已确认;
2. 需要的单元/契约测试已补充并通过;无必要时记录跳过理由;
3. 当前独立 OpenSpec change 已完成 Apply 和阶段验收,证据已归档;
4. 当前 change 已 Archive,OpenSpec 索引/规格同步完成;
5. `git diff` 精确审查完成,当前阶段已独立 Git commit;
6. 前一阶段 Archive 和 Git commit 完成后才进入下一阶段,不并行实施相邻阶段;
7. 阶段 0–6B 不运行完整 live E2E;阶段 7 全部完成后统一执行 Maven E2E、日志和数据库核验。
8. 阶段 4 和 6A 不得接管公开入口;公开入口切换只能发生在阶段 6B,且必须依赖阶段 5 的释放门禁。
## 14. 总体验收标准
- [ ] 复杂诊断只存在一个拥有工具循环的 Diagnosis ReAct Agent。
- [ ] 不存在业务 StateGraph 或 Planner/Executor/Composer 多 Agent 主链路。
- [ ] Harness 不承担业务推理,不演变为工作流引擎。
- [ ] EvidenceGuard 是 Harness 内的确定性能力,不是独立编排节点。
- [ ] SemanticGuard 使用完全隔离上下文,无工具、无记忆、无回调循环。
- [ ] SemanticGuard 不使用未校准数值置信度控制在线释放。
- [ ] 所有 Agent-facing evidence Tool 符合 ACI 状态和 Tool Call ID 契约。
- [ ] RAG 不再向 Agent 返回 ContextPack/Trace/Rerank 等审计数据。
- [ ] query_logs 不要求 Agent 先调用 Topic discovery,且返回聚合、抽样、脱敏结果。
- [ ] MySQL Tool 只读、安全解析、参数绑定、allowlist、超时和结果上限全部生效。
- [ ] Tool 原始结果不会未经有界投影进入 Agent 上下文;Redis canonical evidence 当前可暂不脱敏,但不得被 Agent 直接读取。
- [ ] Redis 每次 Tool Call 单 Key 保存,状态、TTL、容量、ACL 和日志禁泄漏规则均有测试。
- [ ] 每个 Tool Call ID 可以按 exact runId 和调用记录状态验真,并取得对应 `agent_result`。
- [ ] 只保留一个 `/api/chat` SSE 接口。
- [ ] SSE 不输出 Thought、Prompt、原始 Tool 载荷和未验证结论。
- [ ] 客户端断开、模型/Tool/SemanticGuard 超时均有明确取消和 Run 终态。
- [ ] 所有重试由 Harness 按类型化策略装配和记录,无 SDK/HTTP/数据库隐藏重试或整个 Diagnosis Agent 重跑。
- [ ] 最终 E2E 能按 sessionId/runId 对齐 SSE、日志、AgentStep、ToolInvocation 和最终答案。
- [ ] Token、工具调用、Tool 投影、Redis TTL 和总延迟预算均来自集中配置,并有可验证的强制上限和耗尽原因。
- [ ] 11 个 OpenSpec changes 均已独立 Archive,并分别对应一个范围清晰的 Git commit。
- [ ] 不保留旧兼容分支、注释代码、本地 refs 卸载和硬编码凭据。
## 15. 非目标
- 不构建多 Agent 协作平台;
- 不引入业务 StateGraph;
- 不实现 Harness 插件市场、通用 Pipeline DSL 或策略语言;
- 不保留旧同步 Chat、`/chat_stream` 或旧 Tool Contract;
- 不输出或持久化 Chain of Thought;
- 不使用本地 `refs/*.md` 作为 Tool 原始结果主存储;
- 不向 Agent 暴露 Redis Client、Redis Tool、key、连接信息或完整调用记录;
- 不提供历史来源召回 Tool、通用 Memory Tool 或完整上下文恢复能力;
- 不让 `ToolResultProjector` 调用 LLM 生成证据摘要;
- 不允许 MySQL 写操作;
- 不允许 MySQL Tool 查询 Agent 自身的持久化数据库;
- 不允许 Skill/RAG 文档绕过独立配置授予数据库访问权限;
- 本 Issue 不实现 MySQL 租户、行级权限或动态数据授权;首版只落实库/表/字段白名单;
- 不提供 `query_metrics` Tool;指标查询和其 ACI/结果投影设计另立后续 Issue;
- 不用调低模型 maxTokens 代替上下文治理;
- 不因 SemanticGuard 超时而释放未验证草稿;
- 不以追加“人工复核”警告替代删除不受支持的强结论。
## 16. 设计 Review:已确认决策
以下决策已经完成讨论,作为阶段 0 契约冻结的输入:
### 已确认项
1. **Canonical Evidence 存储**:已确认 Redis 每个 Tool Call 使用单 Key `superbiz:harness:tool-call:{runId}:{toolCallId}`,保存 `request/raw_response/agent_result/status/evidence_status/timestamps`。`status=PROJECTING/READY/ERROR` 表示调用生命周期,`evidence_status=EVIDENCE_FOUND/NO_EVIDENCE/ERROR` 表示结果语义;`NO_EVIDENCE` 只能支持限定查询范围的负向观察。默认 TTL 2 小时且不续期,默认单记录 1MB、Agent Result 64KB、单 Run 5MB;Harness-only ACL,原始超限进入 `RESULT_TOO_LARGE`,不静默截断。当前版本暂不做持久化脱敏,默认值后续按运行数据校准。
2. **SemanticGuard 模型与超时**:已确认复用当前唯一 ChatModel,由同一 Harness 控制;首次超时/失败/结构无效时使用相同证据快照重试一次,仍失败则安全降级。单次和总超时提取为集中配置,初期不冻结具体数值。
3. **SemanticGuard 完整报告审查**:已确认接收原始 Query、Diagnosis Agent 完整 Draft 和 EvidenceGuard 生成的 verified evidence snapshot;校验结论、分析、行动计划、建议、限制和范围是否语义成立。它不访问 Redis、不重复验真、不接收 Diagnosis Plan/Tool 过程,也不生成、总结、改写或补充用户报告。Diagnosis Agent 是唯一报告作者,Harness 只发布原 Draft 或固定 Fallback。
4. **预算数值**:已确认主 Agent、Tool、SemanticGuard 和 Redis 的预算全部集中配置,首版使用可调默认值,不在设计阶段冻结未经数据验证的数值;Harness 负责强制执行和记录耗尽原因。
5. **RAG 投影预算**:最大 Evidence 数、单条 excerpt 和总字符预算提取为同一配置;默认值根据后续 Trace 和截断数据校准。
6. **日志投影预算**:最大 Pattern/Event 数、消息长度、lookback 和总字符预算提取为同一配置;聚合指纹规则仍属于 Tool 行为契约,不作为数值配置问题处理。
7. **真实日志适配**:已确认本 Issue 首版只沿用现有 Mock;真实 MCP/Java CLS 适配器和生产接入另立后续 Issue,当前只保留可复用的 Agent-facing Contract。
8. **MySQL SQL Parser**:已确认使用 JSqlParser。首版只允许显式列的单条 SELECT、INNER/LEFT JOIN、常用筛选/分组/排序和函数 allowlist;允许 `COUNT(*)`,禁止 WITH、子查询、UNION、窗口函数、投影通配符和未知 AST;Harness 注入或压低 LIMIT,并以 PreparedStatement、只读账号、超时和 `setMaxRows` 兜底。
9. **MySQL allowlist 配置**:已冻结为逻辑数据源下的静态 `allowed-schemas -> tables -> columns` 三层精确白名单,并配置 `default-schema`。不支持通配符、正则或动态授权;凭据通过环境变量/Secret 注入。本 Issue 暂不展开租户和行级权限。
10. **对话历史**:已确认只使用显式极简上下文,不提供完整历史或 Redis 历史召回。Intent Router 接收当前 `query + last_intent + last_user_query`。`diagnosis_run` 持久化 `intent/release_outcome/published_result`,只有同 Session 最近一个 `DIAGNOSIS + SUCCESS` 的安全结构化结果可进入 `previous_turn`;Fallback、失败和取消均排除。Diagnosis Agent 接收当前 Query 和固定字段 `user_query/published_conclusion/scope/limitations/source_documents`,由 Harness 确定性组装并按配置截断,不调用 LLM 摘要,不复用旧日志/MySQL 结果。SemanticGuard 只接收当前诊断的 Query、完整 Draft 和 verified evidence snapshot。
11. **重试边界**:已确认由 Harness 装配类型化重试策略。Router 与 SemanticGuard 的技术失败最多重试一次;Diagnosis Agent、主模型调用和 Tool 调用不自动重试;EvidenceGuard 只执行一次显式无 Tool 结构修复;禁止隐藏和嵌套重试。
12. **阶段依赖顺序**:已调整为阶段 0 设计冻结、1 ACI Contract、2 Harness Core/RunContext、3A invocation store、3B RAG/日志投影、3C MySQL Tool、4 Diagnosis Agent、5 Guards、6A Chat 应用用例、6B SSE 切换、7 清理/E2E。阶段 3A 起只依赖显式 RunContext,不临时耦合旧 ChatService。
13. **OpenSpec/sm-flow 映射**:已确认 ISS-014 作为总 Issue,11 个实施切片各自使用独立 OpenSpec change 和完整串行 sm-flow;每阶段 Archive 并 Git commit 后才能进入下一阶段,最终 E2E 只在阶段 7 执行。
14. **EvidenceGuard 与报告作者边界**:Diagnosis Agent 是唯一语义作者;EvidenceGuard 作为 Harness 内的确定性能力校验 Draft Schema、Analysis 引用完整性和当前 Run Tool Call 真实性,不判断语义推导。Harness 只确定性展开 Agent 已选择的引用,不改写报告。
15. **SemanticGuard evidence snapshot**:Harness 将已验证 Tool Calls 的有界 `agent_result` 按 `analysis_id` 分组,不注入 `tool_call_id`、Redis 或 `raw_response`,SemanticGuard 据此校验 Analysis、Conclusion、Action Plan、Recommendations、Scope 和 Limitations。
16. **Fallback 与 SSE**:Fallback 使用统一 Schema 和三种稳定 `type`;EvidenceGuard 失败时 `verified_sources=[]`。SSE 首版固定为 `metadata -> status* -> content|failure -> done`,不实现断线续传、事件重放、轮询或 WebSocket。
### Review 结论
当前架构和关键契约已经足够进入阶段 0,不再继续增加设计组件。阶段 0 负责把上述决策固化为 OpenSpec、Schema、契约测试和安全基线;完成 Archive 与 Git commit 前不得进入阶段 1。
剩余风险属于实施期验证项,而不是继续扩展架构的理由:
- SemanticGuard 是否能稳定执行报告级二元语义校验;
- canonical evidence 是否按 Redis TTL 和访问边界承载完整调用结果;
- Harness 是否能严格执行集中预算,并为耗尽和截断提供可观察原因;
- MySQL Tool 的 AST 白名单、只读、超时和容量边界能否通过 Mock/隔离测试数据源的安全用例;真实生产数据源接入另立后续 Issue 验证。
实现中不得为这些风险创建 HarnessPlugin、Graph、通用 Tool DSL 或大量预留接口;按各阶段最小范围实现并通过门禁验证。
## 17. 相关文件
- `mvp/issues/active/ISS-012-executor-token-budget-and-context-growth.md`
- `mvp/issues/active/ISS-013-chat-entry-decoupling-and-sse.md`
- `mvp/disscus/plan.md`
- `src/main/java/com/superbiz/agent/controller/ChatController.java`
- `src/main/java/com/superbiz/agent/service/ChatService.java`
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`
- `src/main/java/com/superbiz/agent/hook/TokenTrackingChatModel.java`
- `src/main/java/com/superbiz/agent/hook/VerifierInputHook.java`
- `src/main/java/com/superbiz/agent/service/ExecutorGatekeeperService.java`
- `src/main/java/com/superbiz/agent/service/ToolInvocationRecorder.java`
- `src/main/java/com/superbiz/agent/tool/LookupKnowledgeTool.java`
- `src/main/java/com/superbiz/agent/agent/tool/QueryLogsTools.java`
- `src/main/resources/prompts/chat-planner-prompt.md`
- `src/main/resources/prompts/chat-executor-prompt.md`
- `src/main/resources/prompts/chat-verifier-prompt.md`
- `src/main/resources/prompts/chat-composer-prompt.md`
- `scripts/query_mysql.py`
- `mvp/architecture/current-mvp-architecture.md`