CodexQA

Industry & PracticeTools & Frameworks

Inspect 缓存:相同输入不再重复请求模型

CodexQA 团队6 min read

Inspect 把已经跑过的模型调用存进缓存。模型版本变了不会误用旧结果。也可以改成按样本或按任务共享,并单独看提供方自己的缓存读写。

In this piece

缓存(把已经跑过的模型调用结果存起来,相同输入不再重复请求)

概述

缓存可以把模型输出存下来,从而减少 API 调用次数,既省时间,也省费用。缓存在开发阶段往往也很有用——例如你在反复调整评分器时,可能希望模型输出直接从缓存提供,这样既能省时间,也能提高确定性。

可用的缓存有两种:Inspect 本地缓存,以及提供方层面的缓存。下面先说明本地缓存(对所有模型都有效),再介绍提供方缓存(目前只适用于 Anthropic 模型)。

缓存基础

使用 GenerateConfig 的 cache 选项即可启用缓存。缓存键(决定一次请求能否由缓存满足)如下:

  • 模型名称与基础 URL(例如 openai/gpt-6-luna)
  • 模型提示(即消息历史)
  • 轮次编号(用于保证每一轮的生成彼此不同)
  • 生成配置(例如 temperature、top_p 等)
  • 当前启用的 tools 与 tool_choice

若上述输入全部相同,模型响应就从缓存提供。默认情况下,模型响应会缓存 1 周(如何自定义见下文「缓存策略」)。

下面是在命令行中使用 --cache 的几个例子:

inspect eval arc.py --cache     # 7 day cache (default)
inspect eval arc.py --cache 1D  # 1 day cache
inspect eval arc.py --cache 4W  # 4 week cache

也可以在 Python 里调用 eval() 时使用:

eval("arc.py", cache=True)

也可以在更底层的 generate() 调用中使用缓存(例如通过 get_model() 取得的模型实例)。例如:

model = get_model("anthropic/claude-sonnet-4-20250514")
output = model.generate(
  input, config=GenerateConfig(cache = True)
)

模型版本

模型名称(例如 openai/gpt-5.5)会作为缓存键的一部分。不过要注意,许多模型名称只是某个具体版本的别名。例如,随着更新发布,gpt-5.5 可能会在不同时间解析到不同版本。

若希望在模型版本更新后让旧缓存失效,最好使用带明确版本号的模型名称。例如:

$ inspect eval ctf.py --model openai/gpt-5.5-2026-04-23

这样做之后,一旦部署了 gpt-5.5 的新版本,就会真正向模型发起调用,而不是从缓存中取结果。

缓存策略

默认情况下,若指定 cache = True,缓存会在 1 周后过期。可以把布尔值换成 CachePolicy 来自定义。例如:

cache = CachePolicy(expiry="3h")
cache = CachePolicy(expiry="4D")
cache = CachePolicy(expiry="2W")
cache = CachePolicy(expiry="3M")

过期时间可以使用 s、m、h、D、W、M 和 Y 作为缩写(依次为秒、分钟、小时、日、周、月、年)。

若希望缓存永不过期,请指定 None。例如:

cache = CachePolicy(expiry = None)

还可以为缓存过期定义作用域(例如针对特定任务或使用方式分别缓存)。使用 scopes 参数把具名作用域加入缓存键:

cache = CachePolicy(
    expiry="1M",
    scopes={"role": "attacker", "team": "red"})
)

如上所述,缓存默认按轮次进行(即每一轮有自己的缓存作用域)。将 per_epoch 设为 False 即可关闭这一默认行为。例如:

cache = CachePolicy(per_epoch=False)

管理

使用 inspect cache 命令可以查看缓存的当前内容、清理过期条目,或彻底清空条目。例如:

# list the current contents of the cache
$ inspect cache list

# clear the cache (globally or by model)
$ inspect cache clear
$ inspect cache clear --model openai/gpt-5.5-2026-04-23

# prune expired entries from the cache
$ inspect cache list --pruneable
$ inspect cache prune
$ inspect cache prune --model openai/gpt-5.5-2026-04-23

管理命令的更多细节见 inspect cache --help。

缓存目录

默认情况下,模型生成缓存存放在系统为用户缓存文件准备的默认位置(例如 Linux 上的 XDG_CACHE_HOME)。可以使用环境变量 INSPECT_CACHE_DIR 覆盖该位置,为缓存文件指定其他目录。例如:

$ export INSPECT_CACHE_DIR=/tmp/inspect-cache

提供方缓存

模型提供方也可能提供提示缓存功能,以便优化多轮对话的成本与性能。目前唯一允许关闭提示缓存的提供方是 Anthropic,可以通过生成配置选项 cache-prompt 来关闭。例如:

inspect eval ctf.py --cache-prompt=false # force caching off

也可以使用 eval() 函数:

eval("ctf.py", cache_prompt=False)

缓存作用域

提供方通常会提供多种方式来自定义缓存的使用范围。Inspect 的 cache-prompt 选项默认会尽量充分利用提供方缓存(在 Anthropic 的实现中,系统消息、工具定义,以及直到最后一条用户消息为止的全部消息,都会纳入缓存)。

Anthropic 的实现会在系统提示末尾、最后一个工具定义上、倒数第二个消息块上,以及(自动地)在提示末尾放置缓存断点。自动断点会对最后一个块做缓存写入;若这个块每次调用都变、且从不被读回,这次写入就是浪费(例如评分标准固定、但题目每次不同的 LLM 评判器)。

ContentText(text=..., cache_breakpoint=True) 则把显式断点放在某个特定块上。只要有任意块带上了这种标记——无论是消息块还是系统提示块——Inspect 就不再添加自动的消息断点(没有回看标记,也没有提示末尾标记);系统提示断点与工具定义断点只有在额度允许时,才会与你的标记一并保留。Anthropic 每次请求最多允许 4 个断点,因此你自己最多可以标记 4 个块;若你的标记加上自动的系统提示与工具断点会超过 4 个,Inspect 会先丢掉自动断点来腾出位置。你自己标记超过 4 个块会抛出 ValueError,错误信息里写明数量与上限,而不会静默退回常规的自动缓存——重新启用自动缓存,会恰好把这些标记本想避免的「变化的尾部写入」再带回来。

from inspect_ai.model import ChatMessageUser, ContentText

judge_prompt = ChatMessageUser(
    content=[
        ContentText(text=rubric, cache_breakpoint=True),
        ContentText(text=item),
    ]
)

显式标记可以加在开头的系统消息上,以及普通的用户消息块与助手消息块上。工具结果上的标记,或对话中途系统消息上的标记,则不受支持——Anthropic 无法在这两者内部标记边界,除非挪动或扩大该边界,因此这些位置会保守地回退,而不会被照做。只要有任一标记落在不支持的位置,Inspect 就会静默丢弃全部标记,并对整次请求退回常规的自动缓存行为,而不是挪动、扩大,或只部分遵从你所标记的布局。提供超过 4 个标记则不同:Inspect 不会回退,而是抛出 ValueError,因为静默恢复自动缓存会把标记存在就是为了阻止的「变化的尾部写入」重新引入。

OpenAI 的 gpt-5.6 及更新模型,在用户消息以及系统消息、开发者消息的文本块上,支持同样的 ContentText(cache_breakpoint=True) 标记。未加标记的请求仍像以往一样使用 OpenAI 的自动(隐式)缓存;给某个块加上标记后,该次调用会切换到显式模式,因此只有被标记的边界才是缓存点。OpenAI 的指南把「每次请求最多 4 次写入」的额度,与大得多的查找历史(最早的两个以及最近的五十个显式标记)区分开来,并且没有写明单次请求可以提供的标记数量上限,因此 Inspect 也不设上限——这与 Anthropic 真正的「每次请求 4 个断点」限制不同。更早的 OpenAI 模型会静默保持该模型原有的隐式缓存,而不会发送(会被拒绝的)显式字段。当一次本应支持显式缓存的请求没有给开头的系统块或开发者块加标记时,Inspect 仍会在该块末尾保留一个检查点(累计覆盖其前面的全部工具定义),这样当后面某个已标记的块发生变化时,稳定的前缀仍有边界可以复用;若调用方自己在该块上加了标记,则优先采用调用方的标记,并抑制这个自动检查点。

用量报告

使用提供方缓存时,模型的 token 用量会报告为 4 个彼此不同的数值,而不再只是通常的输入与输出。例如:

13,684 tokens [I: 22, CW: 1,711, CR: 11,442, O: 509]

所报告 token 数量的前缀含义如下:

  • I:输入 token
  • CW:输入 token 缓存写入
  • CR:输入 token 缓存读取
  • O:输出 token

输入 token 的缓存写入通常更贵(以 Anthropic 为例大约贵 25%),但缓存读取便宜得多(Anthropic 便宜 90%),因此上面的例子在费用和执行时间上都会省下不少。更多细节见 Anthropic 文档。

出处:UK AI Security Institute,Caching,https://inspect.aisi.org.uk/caching.html,MIT License。

Found it useful? Pass it on

WeChat

Scan with WeChat to open it on your phone and forward it.

Subscribe via RSS

Submit a correction