120 lines
6.2 KiB
Markdown
120 lines
6.2 KiB
Markdown
# ISS-012 Executor Token 预算与上下文膨胀
|
||
|
||
**状态**:待规划
|
||
**严重程度**:高
|
||
**发现时间**:2026-07-20
|
||
**关联**:ISS-002、ISS-004、ISS-011
|
||
|
||
---
|
||
|
||
## 背景
|
||
|
||
ISS-011 完成 StateGraph 切换后,复杂 Chat 链路已经具备显式 Node、Gatekeeper、Verifier、Composer 和 Run 级 Trace。但最终 live E2E 暴露出 Executor 的 Token 成本和上下文增长问题:一次只返回安全 Fallback 的请求消耗了超过 11 万 Token。
|
||
|
||
## 现象
|
||
|
||
最终验收 Run:
|
||
|
||
- `runId`:`run-808ac38f-3ad0-4462-a6d0-ed50d8686473`
|
||
- 总耗时:`75964ms`
|
||
- 最终答案:109 字符,Run 为 `CHAT/SUCCESS`,`degraded=true`
|
||
- AgentStep:8 条,其中 Planner 1 次、Executor 7 次
|
||
- ToolInvocation:12 次
|
||
- Run `total_token_count`:`111802`
|
||
|
||
Executor 每次模型调用的 Token 逐步上升:
|
||
|
||
```text
|
||
6396 -> 11265 -> 12786 -> 16774 -> 17965 -> 19340 -> 24236
|
||
```
|
||
|
||
工具调用包括 4 次 `lookup_knowledge`、6 次 `query_logs`、1 次 `query_metrics` 和 1 次 `get_available_log_topics`。最终因模型输出缺少 `source_invocation_id`,Gatekeeper 将结果降为 `LOW_CONFID` 并进入安全 Fallback。
|
||
|
||
## 已确认事实
|
||
|
||
1. 数据库中 8 条 `agent_step` 均为不同记录,不存在重复插入;`111802` 等于各步骤 `token_count` 的求和。
|
||
2. `TokenTrackingChatModel` 当前只保存供应商返回的 `usage.totalTokens`,没有拆分输入、输出、缓存和推理 Token。
|
||
3. `ChatService.backfillRunMetrics` 直接累加每条 AgentStep 的 `token_count`。
|
||
4. `AgentLoggingHook` 只把模型输入截断为 500 字符写入审计表,无法从当前 Trace 还原模型实际发送的完整 Prompt。
|
||
5. Executor 当前没有独立的模型调用次数、工具调用次数或 Token 预算;Graph recursion limit 不能限制 ReactAgent 内部工具循环。
|
||
|
||
## 初步根因假设
|
||
|
||
- 每次 Executor 模型调用都会重新携带 Planner 结果、历史消息和之前的工具返回,导致输入上下文随工具循环增长。
|
||
- 工具返回内容包含较多日志、知识库结果和检索明细,完整结果被反复带入后续模型请求。
|
||
- 工具结果没有稳定返回 `source_invocation_id`,模型无法可靠生成精确证据引用,导致高成本检索后仍然进入 Fallback。
|
||
- 当前只能看到 `totalTokens`,尚未确认供应商 usage 中 input/output/cached/reasoning 的精确占比。
|
||
|
||
## 影响
|
||
|
||
- 单次诊断成本和延迟不可控,复杂问题可能继续超过模型上下文窗口。
|
||
- Token 消耗与最终答案质量不匹配,出现“高成本检索 + 安全降级”的低收益路径。
|
||
- 缺少 Token 分项指标,无法建立成本预算、P95 延迟和 degraded rate 门禁。
|
||
- Executor 可能重复查询相同或相近的知识域、日志主题和指标。
|
||
|
||
## 目标
|
||
|
||
1. 建立按 Run/AgentStep 的 input、output、cached、reasoning Token 可观测性。
|
||
2. 为 Executor 增加硬性模型轮数、工具调用和 Token 预算。
|
||
3. 将完整工具结果留在 Run Trace/数据库中,模型上下文只接收有界证据投影。
|
||
4. 让工具结果直接携带可引用的 `source_invocation_id` 和紧凑 `evidence_refs`。
|
||
5. 在预算耗尽时安全结束并明确记录原因,不绕过 Gatekeeper、Verifier 或 Run Trace。
|
||
|
||
## 建议方案
|
||
|
||
### 1. Token 统计拆分
|
||
|
||
- 从 ChatModel usage 中记录 `input_tokens`、`output_tokens`、`cached_tokens`、`reasoning_tokens`(供应商提供时)。
|
||
- 保留 `total_token_count` 作为汇总字段,但明确其计算口径。
|
||
- 在 `orchestration_trace` 中记录每个 Agent 的累计 Token 和预算命中情况。
|
||
|
||
### 2. Executor 硬预算
|
||
|
||
初版建议从以下上限开始,并通过固定 E2E 调整:
|
||
|
||
- Executor 模型调用最多 4 次。
|
||
- 工具调用最多 8 次。
|
||
- `lookup_knowledge` 最多 2 次。
|
||
- `query_logs` 默认最多返回 5 条日志,并限制单次输出长度。
|
||
- 达到预算后停止扩展检索,基于已验真证据输出,或进入带原因的安全 Fallback。
|
||
|
||
### 3. 有界证据上下文
|
||
|
||
- 工具完整原始结果继续写入 `tool_invocation`,不直接作为下一轮完整上下文。
|
||
- 返回模型的工具视图只保留 invocation ID、工具名、查询条件、有限 evidence refs、excerpt 和 no-evidence 状态。
|
||
- 同一工具数组项禁止重复绑定;相同知识域和日志主题不重复查询。
|
||
|
||
### 4. 证据引用闭环
|
||
|
||
- 每次 evidence tool 返回结果时直接包含 `source_invocation_id`。
|
||
- Executor 输出必须引用该 ID;Gatekeeper 不再依赖事后猜测或唯一候选补全。
|
||
- 由于引用失败进入 Fallback 时,Trace 必须记录具体缺失字段和预算消耗。
|
||
|
||
## 验收标准
|
||
|
||
- [ ] 每个 AgentStep 可查看 input/output/total Token,供应商支持时可查看 cached/reasoning Token。
|
||
- [ ] 固定 `payment-timeout` E2E 的 Token 上限、工具调用上限和最大延迟已定义并通过回归。
|
||
- [ ] 连续至少 10 次相同 fixture 运行,Token 和延迟 P95 不超过定义的预算。
|
||
- [ ] Executor 预算耗尽时只走安全 Fallback,不绕过 Gatekeeper、Verifier 或 Trace 持久化。
|
||
- [ ] 工具返回包含真实 `source_invocation_id`;正常证据链不再因缺少该字段而无谓降级。
|
||
- [ ] 12 个 diagnosis eval fixture、Graph workflow/node contract、Trace ownership 回归全部通过。
|
||
- [ ] E2E 日志和数据库能按 exact `sessionId + runId` 对齐 Token、工具调用、Fallback 原因和最终状态。
|
||
|
||
## 非目标
|
||
|
||
- 不删除 Gatekeeper、Verified Input 或 Verifier。
|
||
- 不以降低模型 `maxTokens` 代替上下文治理。
|
||
- 不恢复 Sequential/StateGraph 双轨或旧兼容协议。
|
||
- 不在本 Issue 中物理删除数据库中的历史 `diagnosis_session` 表。
|
||
|
||
## 相关文件
|
||
|
||
- `src/main/java/com/superbiz/agent/hook/TokenTrackingChatModel.java`
|
||
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`
|
||
- `src/main/java/com/superbiz/agent/service/ChatService.java`
|
||
- `src/main/java/com/superbiz/agent/graph/diagnosis/ReactAgentDiagnosisInvoker.java`
|
||
- `src/main/java/com/superbiz/agent/service/ToolInvocationRecorder.java`
|
||
- `src/main/resources/prompts/chat-executor-prompt.md`
|
||
- `mvp/architecture/stategraph-runtime-architecture.md`
|
||
- `devflow/projects/2026-07-17-chat-diagnosis-stategraph-cleanup-docs/evidence.md`
|