# ISS-014 单体 ReAct Agent、Harness 与 ACI 工具瘦身 **状态**:实施中(阶段 0-3C 已归档,下一阶段 4) **严重程度**:高 **发现时间**: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` | Pending | | 5 | `single-react-evidence-semantic-guards` | Pending | | 6A | `single-react-chat-application-usecase` | Pending | | 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`