5.8 KiB
Context
当前 ToolInvocationRecorder 将 JPA ToolInvocation 作为旧链路的 durable audit,保存 output_preview(500 字符)和 retrieval details,并通过 SessionContextHolder 补 session/run。它不能作为 EvidenceGuard 的 canonical source:raw response 已被截断、生命周期没有 PROJECTING/READY/ERROR、没有框架 Tool Call ID,也没有单 Run 容量/TTL 门禁。
阶段 2 已提供 RunContext、budget、capacity 和 ToolCallKeyFactory。本阶段需把所有 Tool 共用的执行边界与 canonical invocation store 建起来,供阶段 3B/3C 的 projector 直接复用。
Goals / Non-Goals
Goals:
- 在 Tool 调用前统一校验 Run 所有权、框架 ID、JSON object、授权、只读和 Tool/Run budget。
- 保存同一 canonical record 的完整 request/raw_response/agent_result 及状态、证据语义、时间和错误。
- 集中执行 PROJECTING -> READY/ERROR,防止未经投影的 raw 进入 Agent。
- 固定 TTL 不续期、单记录/Agent result/Run bytes 上限和 RESULT_TOO_LARGE 语义。
- 提供 Redis 实现和 store-independent Fake boundary tests。
Non-Goals:
- 不实现 RAG/log/MySQL specific projector 或 adapter。
- 不修改旧 ToolInvocationRecorder/JPA/数据库、Chat/AIOps、Controller/SSE。
- 不让 Agent 访问 Redis/client/key/raw record。
- 不实现并发 Lua/CAS 更新、永久 audit、脱敏或跨 Run 查询。
Decisions
1. Internal ToolBoundary envelope and result
ToolCallRequestEnvelope 是 Harness 内部输入,包含 runId、框架 toolCallId、toolName、JSON request、authorized 和 readOnly。Agent-facing DTO 不暴露这些门禁字段;后续 Alibaba ToolInterceptor 负责组装 envelope。
ToolBoundaryResult 只返回 invocation status、evidence status、原始框架 ID、bounded agentResult 或安全 errorCode;raw 只进入 store,不返回 Agent。
2. Canonical record and lifecycle
CanonicalToolInvocation 是 JSON serializable record,字段包含 toolCallId、runId、toolName、request、rawResponse、agentResult、InvocationStatus、EvidenceStatus、errorCode、startedAt、completedAt。begin 只接受 PROJECTING;markReady 只接受 PROJECTING + 非空 bounded projection + FOUND/NO_EVIDENCE;markError 将 evidence status 固定为 ERROR。
状态转换和 duplicate 检查在 CanonicalInvocationStore 内集中执行。ToolBoundary 不直接写 Redis。
3. Redis value and TTL
Redis 实现复用现有 RedisTemplate<String,Object>,将 record 序列化为 JSON String。创建使用 setIfAbsent(key,json,ttl),保证同一 runId+toolCallId 不覆盖;读取不调用 expire。更新先读取剩余毫秒 TTL,再用不大于该值的 TTL 写回,避免恢复初始 TTL。过期/缺失读取返回 empty。
替代方案是 Redis Hash;单 JSON value 能保证 request/raw/agent 原子同记录,并让 Fake/序列化 schema 与 canonical record 一致,故采用。并发 projector 更新窗口是已接受风险,后续需要时再升级 Lua/CAS。
4. Size and status rules
CanonicalInvocationLimits 由 caller 提供 TTL、maxRecordBytes 和 maxAgentResultBytes。request/raw/agent 使用 UTF-8 bytes 计数;raw 超过 record 或 agent projection 超过独立上限,均不截断,记录 ERROR/RESULT_TOO_LARGE。Run bytes 通过阶段 2 Core 再做单 Run 累计门禁。
PROJECTING 时 evidence status 仅作为内部未知/ERROR 占位;READY 只接受 EVIDENCE_FOUND 或 NO_EVIDENCE;ERROR 永远不可引用。NO_EVIDENCE 不触发重试或成功解释。
5. Preflight and projector boundary
ToolBoundary 顺序固定:
RunContext active/deadline
-> runId + toolCallId + authorization + read-only + JSON object
-> Core.beforeToolCall + request/run capacity
-> store.begin(PROJECTING)
-> ToolExecutor(raw)
-> raw size/capacity
-> ToolResultProjector(agentResult,evidenceStatus)
-> agent size/capacity
-> store.markReady or markError
-> bounded ToolBoundaryResult
执行或投影异常都会写 ERROR;raw 已在可信边界且未超限时保留在 canonical record,但不返回 Agent。preflight/duplicate/cross-run 错误在 begin 前返回安全 ERROR。
6. Old audit separation
旧 recorder/JPA 继续接收旧 Tool 调用,阶段 3A 不改其字段和 ThreadLocal fallback。新 canonical store 没有旧消费者;阶段 3B/3C 接入时必须明确写新 boundary,并在需要 durable audit 时另行脱敏摘要。
Module Flow
Alibaba ToolInterceptor (future)
-> ToolCallRequestEnvelope
-> ToolBoundary
-> DiagnosisHarnessCore + ToolCallKeyFactory
-> CanonicalInvocationStore (Redis JSON / Fake)
-> ToolExecutor
-> ToolResultProjector (future RAG/log/MySQL)
-> bounded ToolBoundaryResult
Risks / Trade-offs
- [Redis update read-TTL-write 存在并发窗口] -> 当前每个 invocation 只允许 boundary 顺序更新;后续并发需求升级 Lua/CAS。
- [canonical raw 可能敏感] -> 仅 Harness store 访问,TTL/ACL/容量受限;脱敏在 projector/durable audit 阶段处理。
- [旧 recorder 与新 store 短期并存] -> 包和接口隔离,spec 明确旧 preview 不能作为 canonical evidence。
- [preflight 失败可能没有 canonical record] -> 返回安全 ERROR 且不执行 Tool;阶段 3A 的可引用记录只针对已通过 begin 的调用。
Migration Plan
- 本阶段新增 boundary/store/Redis adapter 和 fake tests,旧运行链路不变。
- 阶段 3B/3C 将各 Tool adapter/projector 包装到本 boundary。
- 阶段 4 Diagnosis Agent 只接收 boundary 的 bounded result。
- 阶段 6A/7 再决定 durable audit 如何从 canonical 摘要回填,并清理旧 recorder/ThreadLocal。
Open Questions
无。真实 Redis 的 ACL、网络和 TTL 由最终运行/E2E 阶段验证;并发更新 Lua 化留作后续需求。