这次抓包里,Kimi 在第一次模型响应中发起两个 Bash 调用。CLI 执行命令后,又向模型发送了第二个请求。第二个请求包含原系统消息、环境、任务、模型给出的工具调用以及两条工具结果。

这条轨迹让我看到一个容易被最终回答掩盖的问题:Agent 每多运行一轮,上下文就会继续增长。

先区分四个经常混用的量

上下文窗口是单次模型调用能够处理的 Token 上限;Token 是模型处理文本时使用的离散单元,并不等于字符。输入 Token是某次调用实际送入模型的数量,累计输入量则是一次任务中所有模型调用的输入之和。

若固定规则和工具定义占 S + T,第 i 轮新增消息占 M_i,完整历史模式下,第 n 轮输入近似为:

input_n = S + T + M_1 + M_2 + ... + M_n

累计输入不是最后一轮的长度。早期内容会在后续请求中再次出现,所以长会话的累计量增长得更快。

本次抓包能确认什么

Codex 的成功轨迹记录了以下用量:

指标Token
输入33,348
其中缓存输入16,128
输出156
其中推理输出36

缓存输入约占本次输入的 48.4%。这个比例只表示服务端把多少输入计入缓存命中,不能直接解释成费用下降 48.4%,因为缓存 Token 的价格由服务端和具体模型决定。

Kimi 的两次 HTTP 请求正文分别约为 94 KB 和 96 KB。字节数可以证明第二次请求更大,却不能换算成 Token:JSON 转义、中文编码、字段名和分词方式都会改变换算关系。因此这里保留字节级观察,不把它包装成 Token 统计。

Claude Code 返回 403,Grok 返回 402。两者都没有进入第二轮,无法从本次数据判断其成功会话怎样增长。

四种控制方法解决的是不同问题

方法保留什么主要收益主要风险
前缀缓存不变的请求前缀减少重复计算前部动态字段会破坏命中
历史裁剪最近且仍相关的消息直接减少输入可能删掉约束或失败原因
会话摘要目标、事实、未完成项用较短文本代替历史摘要可能写错或遗漏
状态引用服务端保存的前序响应客户端少传历史调试依赖服务端状态

Prompt 缓存是对相同前缀的复用。它不会扩大上下文窗口,也不会阻止历史继续变长。摘要和裁剪会改变模型能看到的内容,属于信息管理;缓存不改变语义,属于计算复用。

Anthropic 的缓存文档把请求前缀按 toolssystemmessages 的顺序处理。稳定内容放在前面、每轮变化的工具结果放在后面,较容易保留相同前缀。Claude Prompt Caching

动态字段放在哪里很重要

日期、随机标识、工作目录和实时状态如果出现在请求开头,缓存会在较早位置分叉。后面的长系统规则即使没有变化,也可能无法沿用同一前缀。

我会把上下文按变化频率排列:

顺序内容更新频率
1平台规则、工具定义客户端升级时
2项目规则、技能说明切换项目时
3会话摘要、历史消息多轮对话中
4最新工具结果、当前输入每一轮

这不是指令优先级表。优先级描述冲突时听谁的,排列顺序描述怎样形成稳定前缀,两者要分别维护。

摘要至少要保留哪些事实

摘要如果只写“用户正在分析项目”,恢复后会缺少继续执行所需的目标、约束和进度。一个可用的会话摘要至少要包含:

  • 当前目标与明确禁止事项。
  • 已读取或修改的资源。
  • 已完成步骤及其证据。
  • 工具失败、错误类型与重试次数。
  • 尚未完成的步骤。
  • 需要用户确认的操作。

还要保存摘要基于哪一段历史生成。否则出现错误时,无法回到摘要前定位被遗漏的信息。

我会怎样验证缓存设计

同一任务连续执行五轮,每轮只改变末尾的一小段用户输入。日志同时记录输入 Token、缓存 Token、首 Token 延迟和总延迟。随后把当前时间移到系统块最前部,再运行同一组任务。

如果第二组的缓存命中位置提前失效,就能证明问题来自上下文排列,而不是模型回答内容。最终答案相同,并不代表运行成本相同。

版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。

(采用 CC BY-NC-SA 4.0 许可协议进行授权)

本文标题:02. Prompt 长度、上下文增长与缓存成本

本文链接:https://www.sshipanoo.com/blog/ai/agent-runtime-lab/02-上下文增长与缓存成本/