KV Cache 压缩
🎯 学习目标
- 解释 KV Cache 命中条件与前缀稳定的关系
- 了解 Prompt Cache 对 API 计费的影响
- 选择摘要、滑动窗口、可恢复压缩等策略
- 在成本、延迟、质量之间做显式 trade-off
引言
长 Agent 会话贵且慢,不全是因为「字多」,还因为自回归推理要反复处理前缀。理解 KV Cache 与 Prompt Cache,才能设计既省钱又不太笨的压缩策略。
章节正文
第 1 步:KV Cache 是什么
自回归生成时,模型对已算过的 Token 会缓存 Key/Value,下一步不必重算整段前缀。
命中条件:新请求的前缀与上次逐 Token 一致。System、工具定义若每轮微调一个字,cache 可能整段失效。
设计原则:
- 固定 system 放最前
- 可变 RAG/历史放后面
- 工具列表大改动时用 Deferred Loading(3.6)
第 2 步:Prompt Cache(API 层)
Anthropic/OpenAI 等对重复长前缀提供折扣或 latency 优化(政策随厂商变)。
实践:
- 标记 cache breakpoint(按厂商 API)
- 监控 cache hit rate
- 多租户时 system 前缀尽量一致,个性化放后缀
别把「能 cache」当作唯一目标——正确性优先于 cache 命中。
第 3 步:上下文压缩策略
| 策略 | 做法 | 风险 |
|---|---|---|
| 滑动窗口 | 只保留最近 K 轮 | 丢早期约束 |
| 摘要回填 | 旧对话压成 summary | Collapse |
| 可恢复压缩 | 摘要 + ref id,需要时再拉 | 实现复杂 |
| 结构化 facts | 只保留 key-value 事实 | 丢叙事 |
Agent 会话推荐:摘要 + structured facts 双轨,关键数字不进散文摘要。
第 4 步:压缩触发点
function maybeCompress(state: AgentState) {
if (estimateTokens(state.messages) > TOKEN_SOFT_LIMIT) {
const { summary, facts } = compress(state.messages.slice(0, -4))
state.messages = [
state.messages[0], // system
{ role: 'system', content: `Earlier summary: ${summary}\nFacts: ${JSON.stringify(facts)}` },
...state.messages.slice(-4),
]
}
}在 soft limit 压缩,留 hard limit 给 Planner 收尾。
第 5 步:三角权衡与监控
建 dashboard:
- 平均 input tokens / session
- cache hit rate(若可观测)
- 压缩后 task success rate 变化
若压缩后 success 降 5%,可能不如换小模型或减工具噪音。
动手练习
- 画一次多轮 Agent 的消息顺序,标哪些部分应稳定以利 KV Cache。
- 写 compress 函数接口(输入 messages,输出 summary + facts)。
- 设定 TOKEN_SOFT_LIMIT/HARD_LIMIT 数值并解释依据(假设 128K 窗口)。
- 查所用 API 文档,记录 Prompt Cache 规则与 breakpoint 用法。
- 设计实验:全历史 vs 摘要,同一 golden task 比较成功率与 cost。
常见问题
Q:工具结果很大,要全部进 history 吗?
不必。Observer 阶段 shrink + 只保留最近相关结果;完整 raw 存 object storage,需要时用 ref 展开。
Q:KV Cache 和 RAG 检索冲突吗?
不冲突。RAG 变后缀导致前缀 stable 部分仍可 cache;只是 RAG 段本身每次是新 Token。
Q:压缩由小模型还是规则做?
关键 facts 用规则/JSON 提取更稳;叙事摘要可用小 LLM。避免用大模型压缩省大模型费用——算 ROI。
本节小结
KV/Prompt Cache 奖励稳定前缀;压缩对抗窗口与成本。用 soft/hard limit、summary+facts 双轨,并监控 success rate,避免省钱的压缩毁掉任务质量。