6.1 KiB
Context
当前 LookupKnowledgeTool 返回 LookupResult,包含 ContextPack、RetrievalTrace、RerankTrace 等内部检索信息;QueryLogsTools 暴露 region、TopicId、limit、Topic discovery 和旧 success/total/logs 结构。MySQL evidence Tool 尚不存在。阶段 0 已创建共享 InvocationStatus 与 EvidenceStatus,但尚无三类 Agent-facing DTO 或稳定 Tool 描述。
本地依赖验证显示,Spring AI 1.1.7 的 AssistantMessage.ToolCall 持有 id,Spring AI Alibaba 1.1.2.0 的 ToolCallRequest 将其暴露为 getToolCallId() 并允许通过 ToolInterceptor 包装调用;普通 Spring AI ToolContext 只包含调用方传入的 context 和 history,不自动提供当前 Tool Call ID。因此后续 Harness 必须以 Alibaba interceptor request 为 ID 接入边界。
Goals / Non-Goals
Goals:
- 用 Java 类型冻结 RAG、日志和 MySQL 的最小 Agent Request/Result JSON Schema。
- 复用统一证据状态,并保持 invocation lifecycle 与 evidence result 两套语义正交。
- 保证所有可引用结果只携带框架 Tool Call ID,不生成替代 ID。
- 冻结简短、面向行动的 Tool 名称和描述,禁止基础设施/审计实现泄漏。
- 通过三个独立契约测试锁定字段、集合不可变性、描述边界和 Mock 来源标识。
Non-Goals:
- 不修改旧
@Tool方法、当前 Chat/AIOps 工具注册或返回行为。 - 不实现
ToolInterceptor、Pre/Post Tool、Redis invocation store 或 ToolResultProjector。 - 不实现真实 CLS/MCP、MySQL 连接、JSqlParser 校验、allowlist 或脱敏。
- 不删除旧 DTO、Topic discovery 或审计服务;这些在后续切片接入和清理。
Decisions
1. 契约放在独立 Harness Tool 包
新增类型放在 com.superbiz.agent.harness.tool.contract,共享状态继续引用 com.superbiz.agent.harness.contract。这使新 Harness 边界与旧 dto、旧工具内部模型明确隔离。
替代方案是在旧工具类内新增嵌套 DTO;这会继续把运行实现与 Agent Contract 绑定,并妨碍三个 projector 复用,故不采用。
2. Tool Call ID 是结果字段,不是 Agent 输入字段
三类 Request 均不包含 tool_call_id。后续 Harness 从 ToolCallRequest.getToolCallId() 取得 ID,在投影 Result 时写入;模型不能选择或覆盖该值。EVIDENCE_FOUND 和 NO_EVIDENCE 结果必须具备合法 ID;如果 Pre-Tool 失败原因就是 ID 缺失/非法,ERROR 可以没有可引用 ID。
替代方案是让模型把 ID 作为参数回传,或由 Harness 生成 UUID;两者都会形成不可信输入或第二套标识,违反阶段 0 决策。
3. Result 直接携带 evidence status,不携带 invocation status
RagToolResult、QueryLogsToolResult 和 MysqlToolResult 只包含 EvidenceStatus。InvocationStatus 继续描述 Redis canonical invocation 的 PROJECTING/READY/ERROR 生命周期,由阶段 3A 的存储模型承载。契约测试分别锁定两个枚举,防止把 READY 当成“找到证据”或把 NO_EVIDENCE 当成生命周期状态。
4. 使用 record 和 defensive copy
Request/Result 使用 Java 17 record,并用 Jackson @JsonProperty 固定 snake_case。所有 list 和 row map 在构造时 defensive copy,避免后续投影、存储或测试在对象创建后改变 Agent-visible 结果。
替代方案是沿用 Lombok mutable bean;它更贴近旧代码,但无法天然表达冻结后的值对象边界。
5. 三类最小 Schema
- RAG Request 只有
query;Result 只有查询回显、有界 evidence、计数和截断标记。 - Logs Request 只有逻辑
topic、query和可选lookback_minutes;Result 保留source_kind、完整 scope、聚合 patterns、少量 timeline events、计数和截断标记。 - MySQL Request 只有逻辑
data_source、参数化sql和params;Result 保留 columns、结构化 rows、计数和截断标记。
日志逻辑 Topic 首版冻结为 APPLICATION、DATABASE_SLOW_QUERY、SYSTEM_EVENTS。旧 system-metrics 不纳入日志 Contract;指标 Tool 不属于本 Issue。SourceKind 首版只有 MOCK,真实适配器以后在保持字段语义的前提下扩展。
6. Tool 描述作为常量契约
使用单一 AgentToolContracts 定义三个 snake_case Tool 名称和 ACI 描述。测试禁止描述中出现 Milvus、L0/L1、rerank、CLS region/TopicId、连接、凭据、topK、limit、Redis、Trace 等实现词。旧 @Tool 注解暂不引用这些常量,以免本阶段提前改变模型可观察行为。
Module Flow
ReactAgent tool call
-> [later] Alibaba ToolInterceptor obtains framework tool_call_id
-> typed Request contract
-> [later] data adapter + canonical persistence + ToolResultProjector
-> typed bounded Result contract
-> Agent observation
阶段 1 只实现图中的 typed contracts 和描述常量。旧 ChatService/AiOpsService -> LookupKnowledgeTool/QueryLogsTools 调用链保持不变。
Risks / Trade-offs
- [新旧 Contract 短期并存,容易误判迁移已完成] -> 契约放独立包,proposal/spec/tasks 明确禁止本阶段改旧工具,并用
rg验证旧注册路径未切换。 - [DTO 不能自行保证 ID 来自框架] -> spec 明确 provenance,阶段 2/3 在
ToolInterceptor测试真实ToolCallRequest.getToolCallId()传播。 - [record 只做结构冻结,不做业务校验] -> 参数范围、SQL allowlist、ID 格式和状态组合由后续 Pre-Tool/Projector validator 实现;本阶段不在构造器复制安全策略。
- [逻辑 Topic 与旧 TopicId 需要映射] -> mapping 属于日志 adapter/projector 阶段,Agent Contract 不接受 region 或物理 TopicId。
Migration Plan
- 本阶段新增契约和测试,不切换消费者;回滚只需删除新增类型。
- 阶段 2/3A 从 Alibaba
ToolInterceptor接入框架 ID 和 invocation lifecycle。 - 阶段 3B/3C 分别让 RAG/日志/MySQL adapter 输出本契约。
- 阶段 6B 原子切换公开 Chat;旧 Contract 最终由阶段 7 清理。
Open Questions
无。真实日志 adapter 的 SourceKind 扩展和值映射在后续接入 change 决策,不阻塞本阶段。