Forge 如何组织请求,实现提示缓存(Prompt Cache)复用

HN AI Best Practices 2026-10-01T00:14:47.192655

引言

过去几个月,我们一直在做一个开源项目:Forge,一款以终端为中心的 AI IDE,面向 Vim 和终端的重度用户,让他们不必切换上下文就能用上 AI 辅助编程。Forge 的目标是让软件从想法一路走到上线,全程不离开终端工作区。你可以把它理解成 Vim + Claude Code + 终端 + Git 的结合体,全都跑在你的终端里。

Forge 的核心之一,是它的 AI 编程辅助模块(harness)。它接收用户的自然语言提示,负责调研、设计并构建软件。在第一版里,即便小心翼翼地挑选模型,OpenCode Go 订阅的每周额度也撑不过一天。对一个自筹资金的项目来说,这给预算带来不小的压力,也影响到产品的持续使用。

OpenCode Go 按美元金额计费,而缓存后的输入比未缓存的输入便宜,通常能差一个数量级。于是提示缓存(prompt caching)成了一条很有希望的路子,可以把可用额度撑得更久。

本文会深入讲 Forge 里是怎么实现并测试提示缓存的,最终做到了 99% 以上的缓存命中率。

为什么要用提示缓存

编程类请求往往反复带上之前请求里的指令和上下文。这些共享上下文每次都要重新处理,白白花掉成本和时间。

模型推理时,会先处理输入、生成中间态的键值(KV)状态,然后一个 token 一个 token 地输出。有了提示缓存,服务商就能把提示前缀对应的合格 KV 状态保留下来;之后如果新请求的开头前缀相同,就可以直接复用。

能不能被缓存、能不能被复用,取决于服务商的缓存策略。对编程辅助工具来说,把请求内容排一排顺序——稳定的指令和上下文放前面,请求之间会变的内容放后面——就能提高复用的概率。

时序图:LLM 服务商为后续请求的匹配前缀复用已缓存的键值状态

只要后续请求的开头前缀相同且符合条件,服务商就能复用已缓存的键值状态。

2026 年,顶级的编程工具缓存命中率平均在 90% 左右。Forge 内部给自己定的目标是 95%。

Forge 如何构造请求

为了保持前缀稳定,Forge 把静态内容放在请求开头,动态内容放在末尾。

Forge 的请求路径分两层。

Forge 请求流程:从系统提示词、日志历史、新一轮对话和工具 schema,经过准备阶段生成与提供商无关的 ModelRequest,再交给各提供商专属的序列化器

Forge 先构造一条规范请求,再由提供商适配器做序列化,并加上各自的缓存标记或路由提示。

构造规范消息时,Forge 的步骤如下:

规范消息就绪后,Forge 会把它转换成提供商专属的网络请求。

Forge 如何保持前缀稳定

为了保持前缀稳定,Forge 做了这几件事:

我们如何统计缓存命中

每次模型返回后,Forge 会读取服务商上报的缓存输入 token 数并做归一化处理。

Forge 把各次模型调用中的已缓存和未缓存输入 token 相加。由于 Anthropic 单独上报未缓存输入,而 OpenAI 会把已缓存 token 计入总量,因此需要对各服务商的总 prompt token 做归一化。

我们如何评估 Prompt Caching

我们测试了 Forge 的缓存感知请求流程,使用 DeepSeek V4.1 Flash、OpenCode Go 订阅。评估基于工具调用、代码仓库内容和系统指令的快照。我们用了三个不同的用例,覆盖不同场景。

  1. 对话持续增长:起始系统消息相同。之后每个请求都会新增相同的用户消息、助手回复和工具返回结果。以此衡量对话变长时缓存复用的表现。

  2. 仅结尾变化:每个请求的开头部分保持一致,只改动最后的用户消息或工具返回结果。以此衡量近期上下文变化时,Forge 能否复用前面的内容。

  3. 早期指令变化:改动工作区指令中的一行,然后发送相同的后续对话和工具结果。以此衡量当提示词靠前部分发生变化时,复用会在哪里中断。之后重复发送改动后的请求,衡量新前缀的复用情况。

每个用例我们各运行了 10 次评估。

结果与发现

均值、最小值、最大值和标准差均基于每个用例的 10 次缓存感知运行计算得出。按 token 加权的比率等于缓存读取 token 总数除以输入 token 总数。

各用例的 token 总数为 10 次运行的合计。未缓存输入是从总输入中减去缓存读取和缓存写入后的剩余部分。

查看原文