1. 为什么需要压缩上下文

bash-agent 是一个可以长时间自主工作的 AI 智能体。每完成一轮对话,它都会把用户的消息、模型的回复、工具调用的结果等全部记录下来,形成对话历史

问题在于,历史会越来越长,带来两个麻烦:

  • 上下文窗口有限:每个大模型都有能处理的“上下文上限”,历史太长就会超出限制。
  • 成本持续增长:每次调用模型都要把整个历史重新提交一次,即使内容重复,API 也会按全价计费。

为此,bash-agent 需要定期对历史进行 压缩——把冗长的对话提炼成一段精炼的摘要,让后续对话只携带摘要,而不必携带完整的旧消息。

2. 传统摘要方式的代价

一种直接的方法是:当历史快满时,单独向模型发起一个“请把上面的对话总结一下”的请求。但这个专门的摘要请求本身也要花钱,因为我们必须把需要压缩的历史消息重新发送一遍。

如果这个请求的结构和之前的正常对话不一样,那么这些历史消息就无法命中 API 的提示缓存,全部都要按全价计费。

一笔简单的账: 假设要压缩 45,000 token 的历史,在 Claude 上单独发送一次摘要请求大约需要 $0.143。这好比“为了省电去买了个节能灯泡,但灯泡本身的价格比省下来的电费还贵”。

3. 关键武器:LLM 的提示缓存

许多大模型 API(如 Anthropic Claude、OpenAI)都支持提示缓存(Prompt Caching)。原理很简单:

sequenceDiagram
    participant Client as bash-agent
    participant API as LLM API 服务端

    Note over Client,API: 正常对话轮次 1
    Client->>API: 请求 A:系统提示词 + 工具定义 + 消息 1
    API->>API: 检查前缀,全新内容,按全价计算
    API-->>Client: 回复 A

    Note over Client,API: 正常对话轮次 2
    Client->>API: 请求 B:系统提示词 + 工具定义 + 消息 1 + 消息 2
    API->>API: 前缀“系统提示词+工具定义”与请求 A 完全相同<br/>这部分仅按缓存价计费(约全价的10%)
    API-->>Client: 回复 B

在 bash-agent 里,所有正常的对话请求都以相同的系统提示词和工具定义开头,所以这个公共前缀在连续调用中会稳定命中缓存,成本极低。

4. 缓存对齐摘要的核心原理

缓存对齐摘要的设计思路很自然:让摘要请求尽量“长得像”正常对话请求,从而蹭上已经存在的缓存。

具体做法只有一条:不改变请求结构,只是在正常对话的末尾追加一句简短的“请总结”指令。

这样一来,一次摘要请求的 token 分布如下:

pie title 摘要请求的 token 计费分布
    "命中缓存(系统提示词 + 工具定义 + 旧摘要)" : 5000
    "命中缓存(需要被压缩的历史消息)" : 39500
    "新增指令(按全价计费)" : 500
  • 前两部分都是之前正常对话中已经发送过的内容,API 端有缓存,按极低价格(通常为全价的 10%)计费。
  • 只有末尾追加的摘要指令是全新的,需要按正常输入价格计费,但它的体积通常只有几百 token。

整个过程中,系统提示词本身没有做任何改动。如果改变系统提示词,公共前缀就会断裂,缓存命中就会从第一个 token 起失效,省钱效果也就没有了。

5. 成本对比

仍然以压缩 45,000 token 为例:

flowchart LR
    subgraph A["传统压缩(无对齐)"]
        direction LR
        A1["45,000 token 全部按全价计费"] --> A2["单次成本 ≈ $0.143"]
    end
    subgraph B["缓存对齐压缩"]
        direction LR
        B1["44,500 token 命中缓存<br/>按缓存价计费"] --> B2["单次成本 ≈ $0.015"]
        B3["500 token 新增指令<br/>按全价计费"] --> B2
    end

缓存对齐让单次压缩的成本降低了大约 90%。这使得 bash-agent 可以在几乎不增加额外开销的情况下,频繁、及时地进行压缩,始终保持一个健康可控的上下文窗口。

6. 摘要的保存与复用

压缩完成后,模型输出的文本摘要会被保存下来,并在后续每一轮对话的开头注入。这样,模型在阅读新对话之前会先看到“之前发生了什么”,而冗长的完整历史则被截断或丢弃。

flowchart LR
    A["对话历史太长<br/>需要压缩"] --> B["发起缓存对齐摘要请求"]
    B --> C["生成摘要文本"]
    C --> D["保存为 summary.txt"]
    D --> E["后续对话开头注入摘要"]
    E --> F["上下文窗口保持健康"]

这个摘要内容本身又成为了后续请求公共前缀的一部分,同样可以稳定命中缓存,不会带来新的缓存断裂成本。

7. 小结

缓存对齐摘要是 bash-agent 用来经济高效地压缩对话上下文的核心策略。它巧妙地利用了 LLM API 已有的提示缓存机制:

  • 不改变请求结构:摘要请求与正常对话共用完全相同的前缀。
  • 只在末尾附加指令:需要额外支付全价的只有那一句简短的“请总结”。
  • 成本剧降约 90%:压缩操作从“奢侈”变成“平价”,可以放心高频执行。
  • 系统提示词保持稳定:保证缓存链条不断,最大化长期收益。

通过这一设计,bash-agent 在长时间、多轮次的自主任务中,既能维持可控的上下文规模,又不会让压缩本身吃掉原本节省下来的费用。


更多信息请见:bash-agent 项目主页README 中的相关说明

标签: none

添加新评论