6.2 KiB
6.2 KiB
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 逐步上升:
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。
已确认事实
- 数据库中 8 条
agent_step均为不同记录,不存在重复插入;111802等于各步骤token_count的求和。 TokenTrackingChatModel当前只保存供应商返回的usage.totalTokens,没有拆分输入、输出、缓存和推理 Token。ChatService.backfillRunMetrics直接累加每条 AgentStep 的token_count。AgentLoggingHook只把模型输入截断为 500 字符写入审计表,无法从当前 Trace 还原模型实际发送的完整 Prompt。- Executor 当前没有独立的模型调用次数、工具调用次数或 Token 预算;Graph recursion limit 不能限制 ReactAgent 内部工具循环。
初步根因假设
- 每次 Executor 模型调用都会重新携带 Planner 结果、历史消息和之前的工具返回,导致输入上下文随工具循环增长。
- 工具返回内容包含较多日志、知识库结果和检索明细,完整结果被反复带入后续模型请求。
- 工具结果没有稳定返回
source_invocation_id,模型无法可靠生成精确证据引用,导致高成本检索后仍然进入 Fallback。 - 当前只能看到
totalTokens,尚未确认供应商 usage 中 input/output/cached/reasoning 的精确占比。
影响
- 单次诊断成本和延迟不可控,复杂问题可能继续超过模型上下文窗口。
- Token 消耗与最终答案质量不匹配,出现“高成本检索 + 安全降级”的低收益路径。
- 缺少 Token 分项指标,无法建立成本预算、P95 延迟和 degraded rate 门禁。
- Executor 可能重复查询相同或相近的知识域、日志主题和指标。
目标
- 建立按 Run/AgentStep 的 input、output、cached、reasoning Token 可观测性。
- 为 Executor 增加硬性模型轮数、工具调用和 Token 预算。
- 将完整工具结果留在 Run Trace/数据库中,模型上下文只接收有界证据投影。
- 让工具结果直接携带可引用的
source_invocation_id和紧凑evidence_refs。 - 在预算耗尽时安全结束并明确记录原因,不绕过 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-timeoutE2E 的 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.javasrc/main/java/com/superbiz/agent/hook/AgentLoggingHook.javasrc/main/java/com/superbiz/agent/service/ChatService.javasrc/main/java/com/superbiz/agent/graph/diagnosis/ReactAgentDiagnosisInvoker.javasrc/main/java/com/superbiz/agent/service/ToolInvocationRecorder.javasrc/main/resources/prompts/chat-executor-prompt.mdmvp/architecture/stategraph-runtime-architecture.mddevflow/projects/2026-07-17-chat-diagnosis-stategraph-cleanup-docs/evidence.md