首页
/ caveman cacheengine:独立式提示词缓存规划器与 Provider 原生 Wire 编译引擎详解

caveman cacheengine:独立式提示词缓存规划器与 Provider 原生 Wire 编译引擎详解

2026-09-06 14:30:43作者:房伟宁

caveman 仓库中的 cacheengine 是一个零运行时依赖的提示词前缀缓存引擎:它不启动任何网关进程,不访问网络、数据库或控制面,仅以纯函数方式接受 provider 请求的 wire 字节,规划“正收益”的缓存断点并直接改写请求体,使其命中 Anthropic、OpenAI、Bedrock、Gemini 的原生 prompt cache 机制。读完本文,你将理解它的 capability-driven 规划器如何计算 break-even(盈亏平衡)复用次数、如何用 Scope/Epoch 守护前缀漂移、如何为 OpenAI 风格亲和键做租户不透明分片,以及它“绝不猜测、绝不铸美元、不确定就回传原字节”的整套正确性不变式与验证手段。

设计定位:零运行时依赖的缓存引擎

模块文档 cacheengine/CLAUDE.md 开宗明义:cacheengine 是“capability-driven planner plus provider-native wire compiler”(能力驱动规划器 + provider 原生 wire 编译器)。运行时不需要网关进程、网络、数据库或控制面。engine.go 保持 provider/model 无关;独立的 wire 编译器与 profiles.go 负责绑定当前各 provider 的契约;通过 Driver/profile resolver 两个接缝可以新增 provider,而无需改动规划器本身。可选的 live replay I/O 只属于 cachebench 子包。

模块导入路径为 github.com/JuliusBrussee/caveman/cacheengine(见 cacheengine/README.md),源码以 Business Source License 1.1 发布:源码可见,Change Date 之前不属于 OSI 开源;第一方自托管生产允许,第三方托管/托管式/嵌入式服务使用需要商业授权(见 cacheengine/LICENSELICENSING.md)。

一个关键保证是:Optimize 全程不做任何 provider 调用。它接受并返回 wire 字节,因此代理、SDK、sidecar 或本地进程都能直接内嵌这个引擎。从源码结构看,核心生产依赖图只复用了仓库内的 JSON splice、cache guard、catalog/cost 与 YAML 几个平台包(README 称共六个非标准库包);Anthropic 与 Bedrock 的行为由 parity 测试与既有网关转换逻辑锁定,但生产路径不导入任何网关运行时。

模块布局

CLAUDE.md 的 Layout 一节给出了完整的文件级地图,逐条继承如下:

文件/目录 职责
types.go 公开的 capability、plan、result、driver、observation 契约
engine.go stable-prefix 边界、break-even 数学、volatile/drift 守护、按 Scope 分片的 affinity key
native.goopenai.gowire_anthropic_bedrock.go 严格的内建 JSON 抽取与 wire 编辑;生产图不导入任何网关适配器,parity 测试将独立版 Anthropic/Bedrock 行为与那些适配器对比
profiles.go 内建模型阈值、TTL、经济学参数、归因
raw_usage.go provider 缓存计数器归一化;不做美元换算
cmd/cache-experiment 仅离线转换/经济学 fixture,零 provider 调用
cachebench/ + cmd/cachebench 严格 97% 请求/token 门槛、语义等价检查、有界公共语料导入、trace 导出、provider 观测回放
cmd/cache-replay 可选 live 回放:精确 trace 重建、provider HTTP 鉴权/SigV4、发送前全 trace 等价、绝对时间有界并发、任务验证器协议、私有留存证据、不重试
cachebench/scripts/ 哈希钉住的 LMCache 下载与 parquet 转 JSONL 流式辅助脚本;PyArrow 只是可选基准工具,绝非运行时代码

核心契约:从 Capability 到 Plan

规划器认识的是“能力数据”而不是 provider 名字。核心类型全部定义在 cacheengine/types.go

四种缓存控制语义(Mode),见 types.go#L11-L16

  • ModeUnsupported:provider 无缓存能力,直接放行;
  • ModeImplicit:provider 隐式管理缓存,引擎只观测不干预;
  • ModeAffinity:引擎通过亲和路由键(affinity key)提升同一前缀落在同一缓存条目上的概率;
  • ModeExplicit:引擎可以向请求体写入显式断点/缓存控制字段。

四级归因(Attribution)none / organic / affinity / causal。它回答的是“一次 provider 确认的命中能证明什么”。例如 Gemini 的隐式缓存命中是 organic——它提升了缓存表现,但永远不能归因为引擎因果所致;只有显式写入断点且 provider 确认命中的场景才是 causal

四种决策(Decision)apply(已改写 wire 体)、observe_only(仅观测)、pass_through(放行原字节)、new_epoch(显式开启新的冻结前纪元)。

Profile 结构(types.go#L68-L85)携带 IDProviderModeAttributionMinPrefixTokensMaxBreakpointsEconomicsKnownWriteMultiplierReadMultiplierTTLRollingRoutingKeyMaxRPMPerKeyOptimizerID 等字段。Segment 表示有序 prompt 前缀的一个组成部分,其中 Stable 是调用方拥有的事实——在一个 epoch 内可能变化的内容绝不允许被标记为 stable。

通用规划器示例

README 给出的最小嵌入方式(完整继承,可直接编译运行):

engine := cacheengine.New(cacheengine.Config{})
plan, err := engine.Plan(cacheengine.PlanRequest{
    Scope:         "org/project",
    Epoch:         "conversation-42",
    ExpectedCalls: 8,
    Profile: cacheengine.Profile{
        ID: "provider-cache-v1", Mode: cacheengine.ModeExplicit,
        MinPrefixTokens: 1024, MaxBreakpoints: 4,
        EconomicsKnown: true,
        WriteMultiplier: 1.25, ReadMultiplier: 0.10,
        RoutingKey: true,
    },
    Segments: []cacheengine.Segment{
        {Name: "tools", Content: toolBytes, Tokens: 1800, Stable: true, Cacheable: true},
        {Name: "live", Content: userBytes, Stable: false},
    },
})

ExpectedCalls 的语义必须精确理解:它指“在 provider 缓存条目保持温热(TTL 内)预计共享该前缀的调用次数”,不要把跨越缓存过期间隙的终身总调用数填进来。经济学字段使用输入费率单位(一次单位 = 一个按全输入费率计费 token),从不猜测美元。token 数未知时,安全转换仍可用,但经济学标记为 unavailable。

NativeRequest 面向 provider 原生请求(types.go#L187-L209):除上述字段外还有 ProviderModelRegionEndpointBodyRuntimeModeAuthModePrefixTokens(应优先来自 provider 计数,为零时转换仍可行但阈值/经济学资格未知)、StableSegments(自定义 provider 绕过内建 envelope 抽取)与 Profile(仅对注册了自定义 Driver 的 provider 允许按请求覆盖,内建编译器拒绝 per-request 能力覆盖)。官方示例见 cacheengine/example_test.go

result, err := engine.Optimize(context.Background(), cacheengine.NativeRequest{
    Scope: "org/project", Epoch: "conversation-42",
    Provider: "openai", Model: "gpt-5.6", Endpoint: "/v1/responses",
    Body: requestBody, PrefixTokens: providerCount,
    ExpectedCalls: 8, RuntimeMode: "optimize", AuthMode: "payg",
})
upstreamBody := result.Body // 所有不安全/不支持路径返回原始字节

Break-even 数学:只选正收益断点

规划器核心在 cacheengine/engine.goPlan 的入口校验、前缀抽取、波动检测、经济学计算见 engine.go#L102-L221。断点候选的逐段递推逻辑在 breakpointCandidatesengine.go#L359-L416):

  1. 按序对 stable 段做 length-prefixed 帧化(appendFrame,name 与 content 各 4 字节大端长度前缀),累计 token 数;

  2. 每个位置要求 ExpectedCalls >= 2(少于两次复用没有意义),且累计 token 数达到 profile.MinPrefixTokens 下限,否则记录 belowMinimum 并跳过;

  3. 经济学已知时计算净收益(输入费率单位):

    net = cumulativeTokens * (calls - WriteMultiplier - (calls-1) * ReadMultiplier)

    直觉是:写一次缓存多付 WriteMultiplier 倍费率,之后每次读取只付 ReadMultiplier 倍费率。若 net <= 0 则记为 negativeEconomics 并跳过;

  4. 更长的前缀不允许拥有更高的预期复用次数(longer prefix cannot have higher expected reuse),违反即报错;

  5. 净收益为正的段生成带 PrefixSHA256 的候选断点;连续相同 ExpectedCalls 的候选只保留最深处一个。

盈亏平衡调用数由 breakEvenCallsengine.go#L418-L428)线性搜索:最小的 calls(2 起,上限 10000)使 calls - WriteMultiplier - (calls-1)*ReadMultiplier > 0。以 Anthropic 典型 1.25/0.10 倍率为例,第 2 次调用即净收益转正,所以断点几乎总能入选;经济学未知时 breakEvenCalls 返回 0,绝不猜测。

候选超过 MaxBreakpoints 时,limitBreakpointsengine.go#L430-L444)按净收益降序选前 N 个,再按原始顺序排序,保证选中的是“最赚钱”的边界且 wire 顺序不乱。

ModeImplicit(如 Gemini),Plan 会把所有断点的净收益清零、EconomicsBasis 置为 provider_managed_unattributed,并把决策改为 observe_only——引擎从不把 provider 自主管理的缓存算作自己的功劳。

Stable Prefix、Epoch 与漂移守护

CLAUDE.md 的不变式规定:“Epoch 意味着一个冻结的 stable 前缀;字节变化必须走 StartEpoch;静默前缀漂移直接放行。”实现上:

  • stablePrefixengine.go#L323-L348)只接受开头连续的 Stable && Cacheable 段,遇到第一个非 stable 段即止;段名唯一、非空、长度受限,且帧化总字节数必须低于 MaxStablePrefixBytes(默认 64 MiB),超限在复制/拼接之前拒绝。
  • 前缀摘要(SHA-256)连同 Scope/Epoch/ProfileID 组成的 epoch key 交给 cacheguard(来自 shared/platform/cacheguard)做漂移检查:如果同一 epoch 下前缀字节与冻结记录不一致,返回 WarningPrefixDrift,规划器将其翻译成 ReasonPrefixDrift 并放行原始字节,不尝试“追着漂移走”。
  • 显式开启新纪元用 StartEpochengine.go#L224-L266):它拒绝波动内容进入稳定纪元(volatile content cannot start stable epoch),并返回 DecisionNewEpoch
  • cacheguard.DetectVolatile 检测前缀中的易变内容(时间戳之类);引擎另有一个 LRU 式 prefixSafetyCacheengine.go#L498-L533)缓存“已知安全”前缀摘要(容量 8192),避免对同一稳定前缀反复跑波动检测。

StartEpoch 也用于 compaction 场景:agent 历史每 64 轮压缩一次时开启新纪元,其冷写入计入分母(见下文 cachebench)。

Scope 与亲和键分片

不变式要求“Scope 必填,且在生成 provider 可见路由键之前被哈希”;内建 profile 显式绑定唯一 provider。分片与路由键生成在 engine.go#L446-L472

  • keyShard:当 ExpectedRequestsPerMinute 超过 profile.MaxRPMPerKey(内建 OpenAI profile 为 15)时,分片数 count = 1 + (RPM-1)/MaxRPMPerKey,再被 MaxKeyShards(默认 64,可配 1..1,000,000,见 types.go#L143-L163)封顶,触顶时警告 routing_key_shard_cap_reached。分片号由 PartitionKey(缺省回退 Epoch)的 SHA-256 取模得到,同一 partition/epoch 内路由键保持稳定。
  • routingKey:对 scope + 0x00 + profileID + 0x00 + prefixSHA256 + 0x00 + shard 做 SHA-256,取前 16 字节十六进制。tenant 名称、epoch、前缀内容都不出现在键中,只以摘要形式参与哈希——这就是“租户不透明、按负载分片”的 affinity key。

请求身份、段名、profile ID、路由元数据全部有长度上限并拒绝控制字符(validIdentity,见 cacheengine/validation.goengine.go#L268-L302 的校验调用)。

Provider 原生 Wire 编译:Optimize 全流程

Optimizenative.go#L18-L185)是引擎的总入口,按序执行一串 fail-closed 闸门,任何一关不通过都返回拷贝后的原始字节并给出明确原因(原因常量见 types.go#L38-L55):

  1. 字节上限:Body 超过 MaxRequestBytes 直接报错;
  2. 身份校验(validNativeIdentity),失败记 malformed_request
  3. RuntimeMode == "record"record_mode 放行;AuthMode 非空且非 paygnon_payg 放行;
  4. 内建 provider(anthropic/openai/bedrock/gemini)必须提供 ModelEndpoint,且端点在白名单内(native.go#L187-L200):Anthropic /v1/messages;OpenAI /v1/chat/completions/v1/responses;Bedrock converse/converse-stream/invoke/invoke-with-response-stream;Gemini generateContent
  5. 请求体必须是唯一键 JSON 对象(严格流式解析器 inspectUniqueJSONObject,深度上限 512,重复键、非对象根、尾随字节全部判 malformed);
  6. body 内 model 字段与 request.Model 不一致 → profile_mismatch
  7. caller-managed 检测cacheMarkerAtnative.go#L395-L409)识别各 provider 的既有缓存控制标记——Anthropic 的 cache_control(tools/system/messages content 路径下)、OpenAI 的顶层 prompt_cache_key/prompt_cache_options 与内容块上的 prompt_cache_breakpoint、Bedrock 的 cachePoint/cache_control、Gemini 的顶层 cachedContent。只要发现调用方已自行管理缓存,引擎即让路:caller_managed。CLAUDE.md 的不变式“调用方缓存字段永远优先”由此落地;
  8. profile 解析:内建 provider 不允许按请求注入 Profile(否则 profile_mismatch),由 defaultProfile 解析后经 builtinProfileCompatiblenative.go#L238-L258)逐字段核对模式、归因、断点数、TTL、Rolling、RoutingKey、OptimizerID,任何一项偏离即拒;
  9. 未提供 StableSegments 时,用 nativeStablePrefixnative.go#L339-L393)从请求体抽取稳定前缀:provider、model 加各 provider 的稳定字段(Anthropic 的 tools+system、OpenAI 的 tools/instructions、Bedrock 的 toolConfig+system、Gemini 的 systemInstruction+tools),再拼接对话序列开头的连续 system/developer 消息;
  10. 交给 Plan;决策非 apply 即止步;
  11. 按 provider 编译 wire 体,输出为空、超限、优化器 ID 非法或与原体完全相同,都回退为 transform_unavailable 放行。

各 provider 的内建行为(完整继承自 README 表格):

表面 行为 归因上限
Anthropic 复用既有 stable tool/system 断点;新增滚动顶层 automatic caching 因果级 provider 观测;独立版美元保持为零
OpenAI GPT-5.6 家族 作用域亲和键 + 1 个稳定断点与最近 3 个显式断点;body 中无安全可标记块时退化为仅亲和 因果级 provider 观测;仓库内已验证账本扩展尚未构建
早期 OpenAI provider automatic caching 之上的作用域亲和键 仅亲和
Bedrock Anthropic Claude 复用 catalog 门禁的 stable 点并追加滚动 message 检查点 因果级 provider 观测;独立版美元保持为零
Gemini 观测 provider 隐式管理缓存,不改写 body organic,永不归因引擎
未知 provider 精确放行 不可用

OpenAI 断点标记策略值得细看(openai.go#L41-L106):显式模式保留“1 个稳定锚点 + 最近 3 个可缓存消息块”共最多 4 个 prompt_cache_breakpoint: {"mode":"explicit"} 标记。GPT-5.6 显式模式不做“无法标记前缀就回退自动缓存”——保留上一轮滚动标记能让第 N+1 次请求读取第 N 次写入的前缀,同时最多只新增一次滚动写入。字符串 content 会被转成 content block 数组再加标记,这一步是 wire 等价的(CLAUDE.md 不变式:OpenAI 的 string-to-content-block 转换仅当显式断点语法要求时才使用)。标记按索引降序执行插入,确保每次替换都不使更早 span 失效。

AnthropicapplyAnthropicnative.go#L260-L272)先复用既有稳定断点,再用 jsonsplice.AppendObjectFields 在顶层追加 cache_control: {"type":"ephemeral"}(字段已存在则不动),返回两个优化器 ID:anthropic-cache-breakpointscave-cache-anthropic-rolling-v1

BedrockappendBedrockRollingnative.go#L290-L337)按端点区分:converse 系在最后一条消息 content 追加 {"cachePoint":{"type":"default"}};invoke 系把最后一条消息的文本内容块加上 cache_control: {"type":"ephemeral"}(字符串 content 先等价转为 block)。

若 OpenAI 显式模式未能写入任何断点,结果会把归因从 causal 降级为 affinity 并记 affinity_fallbacknative.go#L179-L183)。成功应用时 ClaimBasis = "inferred"VerifiedSavingsUSD 恒为 0——CLAUDE.md 不变式“managed gateway 拥有唯一经核验的记账方法”由此体现。

内建 Profile 与模型阈值

defaultProfileprofiles.go#L12-L70)按 provider 分发,阈值数据全部落在 profiles.go

Provider 判定条件 模式/归因 最小前缀 最大断点 TTL 其他
Anthropic catalog 具备 prompt_cache 能力 explicit / causal 按模型 512–4096(anthropicMinimumprofiles.go#L181-L193 4 5 分钟 Rolling,无路由键
OpenAI GPT-5.6 家族 模型名 gpt-5.6/gpt-5.6-* 前缀(profiles.go#L176-L179 explicit / causal 1024 4 30 分钟 Rolling + 路由键,15 RPM/key
其他 OpenAI catalog 具备 prompt_cache_key 能力 affinity / affinity 2048 1 5 分钟 Rolling + 路由键
Bedrock catalog 中 anthropic.claude-* 模型具 prompt_cache 能力,且端点为 converse/invoke 系(profiles.go#L105-L138 explicit / causal 按模型 1024–4096(bedrockMinimum 4 5 分钟 Rolling
Gemini catalog 具备 explicit_cache 能力 implicit / organic gemini-2.5: 2048;gemini-3: 4096;其余 0(profiles.go#L207-L217 1 Rolling;经济学未知
其他 无 profile(返回 false → 放行)

注意 openAIExplicitModel 刻意保持狭窄:旧模型拒绝显式缓存字段,官方契约只点名 GPT-5.6 家族;未来家族需要 profile 数据或显式调用方覆盖,而不是猜测请求。

经济学倍率不是写死的:cacheMultipliersprofiles.go#L149-L171)优先从 catalog 价格数据推导(CacheWritePerMillion / InputPerMillionCacheReadPerMillion / InputPerMillion,支持按 Region 取价),无定价数据时回退到保守默认(1.25/0.10,OpenAI 亲和路径写倍率为 1)。模型能力数据来自 shared/platform/catalog,价格来自 shared/platform/cost

缓存计数器归一化:永不“铸美元”

响应侧证据由 cacheengine/raw_usage.go 负责,对应 CLAUDE.md 布局中“provider cache-counter normalization; no dollar minting”。NormalizeRawCacheUsageraw_usage.go#L166-L268)将各 provider 官方计数器映射为统一的 UsageObservation

Provider 读取字段
OpenAI input_tokens_detailsprompt_tokens_details(二者必有且仅有一个)中的 cached_tokenscache_write_tokens
Anthropic cache_read_input_tokenscache_creation_input_tokens,并与 cache_creation.ephemeral_5m/1h_input_tokens 明细交叉核对,矛盾即失败
Bedrock cacheReadInputTokenscacheWriteInputTokens
Gemini cachedContentTokenCount(回退 total_cached_tokens

未知 provider、重复键、负数/小数计数器、OpenAI 双字段歧义、Anthropic 总额矛盾,一律 fail-closed 返回不可用。Observetypes.go#L257-L280)把归一化结果与 NativeResult 组合成 Observation:区分 hit/write/miss/unavailable,AttributedToEngine 仅在“引擎确实应用了优化器且 profile 归因为 causal”时为真。ObserveRawCacheUsage 额外覆盖 OpenAI GPT-5.6 的 cache_write_tokens——旧版共享响应归一化器可能不暴露它。ExtractProviderUsageraw_usage.go#L25-L120)更进一步,从完整非流式响应抽取 usage 对象并绑定 provider 计数的输入 token 分母(Anthropic/Bedrock 的总量 = 未缓存 + 缓存读 + 缓存写),溢出、重复键、缺失总量全部失败关闭。

CacheObserved 字段专门区分“观测到零/未命中”与“响应里根本没有缓存计数器”,避免把缺失当未命中。

扩展新 Provider:Driver 与 Profile Resolver

CLAUDE.md 与 README 给出同一契约:提供能力 profile 加 Driver,规划器保持不变;内建 profile 必须显式绑定 Provider;Driver 收到选定的断点,无法安全编译时必须返回原字节且不带任何优化器 ID

engine := cacheengine.New(cacheengine.Config{
    ResolveProfile: func(r cacheengine.NativeRequest) (cacheengine.Profile, bool) {
        return acmeProfile, r.Provider == "acme"
    },
    Drivers: map[string]cacheengine.Driver{
        "acme": acmeWireDriver,
    },
})

Config 的完整语义(types.go#L143-L163):MaxKeyShards 默认 64(有效显式值 1..1,000,000);MaxRequestBytesMaxStablePrefixBytes 默认各 64 MiB(显式值 1 字节..1 GiB),二者都在复制/拼接之前拒绝超限;ResolveProfile 非 nil 时替换内建查找;Drivers 的键经小写/去空格归一化后必须唯一。生产构造应使用 NewCheckedengine.go#L54-L56)在构造期暴露配置错误;遗留的 New 保留单返回值 API,但同样保存配置错误并使所有操作失败关闭。Resolver 与 Driver 回调可能并发执行,必须自身并发安全。自定义请求必须提供 StableSegments(否则 no_stable_prefix),自定义 Driver 输出不得超过配置的请求体上限,优化器 ID 接受与身份字段同样严格的校验(native.go#L224-L236)。

正确性不变式汇总

CLAUDE.md 的 Correctness invariants 一节是理解这个模块设计哲学的总纲,逐条列出并给出源码落点:

  1. 原始字节存活:malformed、unsupported、caller-managed、record、non-PAYG、volatile、drifting 或不可转换的请求,一律原样放行(native.go#L49-L91 的闸门链);
  2. 永不重排或改写语义内容:只追加 provider 原生缓存控制字段;OpenAI 的 string-to-content-block 转换是 wire 等价的,且仅当显式断点语法需要时使用(openai.go#L136-L167);
  3. Scope 必填并先哈希:provider 可见路由键只包含摘要;内建 profile 显式绑定唯一 provider(builtinProfileCompatible);
  4. Epoch = 一个冻结 stable 前缀:字节变化要求显式 StartEpoch;静默前缀漂移放行;
  5. ExpectedCalls = TTL 内复用:未知 token 数或缓存经济学保持 zero/unavailable,绝不猜测;
  6. 独立版结果分级:应用后的结果为 inferred,放行/仅观测结果为 noneVerifiedSavingsUSD 恒为零;已核验记账方法归 managed gateway 所有;
  7. 自定义 Driver 在不确定时:返回原字节与零优化器 ID;
  8. 公开边界:永不导入 cloud/...

“总能命中缓存”不可能是字面保证:provider 最小前缀、TTL、并发、容量、精确前缀变化、不支持的模型与有机缓存都可能导致未命中。引擎的职责是最大化合格的稳定前缀,并且在无法行动时返回明确原因——15 个 Reason* 常量(types.go#L38-L55)就是这个承诺的词汇表。

产品边界上(README),cacheengine 是“provider 提示词前缀规划器”:只做元数据级请求转换,provider 仍然运行模型并报告缓存计数器。它不存储/回放模型响应,也不管理自托管 KV 内存——后者属于 exact/semantic response cache 与 self-hosted KV cache 两类完全不同的产品,正确性边界不同。README 明确拒绝“市场最佳”类声明,因为那需要同人群 live 计数器、任务质量验证、延迟与竞品对比。

验证:测试、Fuzz 与 cachebench

CLAUDE.md 的 Proof 一节给出完整验证命令(原文含 cd public,对应原单仓目录;本仓库布局中 Go module 位于仓库根,含 go.mod,在根目录直接执行即可):

go test -race ./cacheengine/...
go vet ./cacheengine/...
go test ./cacheengine -run '^$' -fuzz '^FuzzOptimizeMalformedBuiltinsPassThrough$' -fuzztime=5s
go test ./cacheengine/cachebench -run '^$' -fuzz '^FuzzAgentCorpusJSONLFailClosed$' -fuzztime=5s
go test ./cacheengine/cachebench -run '^$' -fuzz '^FuzzObservationJSONLFailClosed$' -fuzztime=5s
go test ./cacheengine/cachebench -run '^$' -fuzz '^FuzzTraceJSONLFailClosed$' -fuzztime=5s
go test ./cacheengine/cachebench -run '^$' -fuzz '^FuzzVerificationCommandOutputFailClosed$' -fuzztime=5s
go test -run '^$' -bench BenchmarkOptimizeOpenAIExplicit -benchmem ./cacheengine
go run ./cacheengine/cmd/cache-experiment
go run ./cacheengine/cmd/cachebench
go run ./cacheengine/cmd/cache-replay -help

Fuzz 目标的名字本身就说明立场:FuzzOptimizeMalformedBuiltinsPassThrough 验证畸形输入必须穿过引擎而字节不变,四个 cachebench fuzz 目标验证所有外部 JSONL 解码器 fail-closed。

cachebench 子包回答一个具体问题:cacheengine 能否在一个持续使用工具的 agent 上维持至少 97% 缓存命中,同时不掩盖冷启动、compaction、语义变更、非法 usage 或不支持的 provider 行为? 零参数运行 128 请求/provider × Anthropic/OpenAI/Bedrock/Gemini,负载携带 8,192 个声明稳定 system/tool token、增长的 user/assistant 工具调用与工具结果历史,每 64 轮做一次计划内 compaction(开新纪元,冷写入留在分母里)。主门槛(完整指标契约见 cacheengine/cachebench/README.md):

request_hit_rate = cache_read_tokens > 0 的请求 / 所有合格请求
token_hit_rate   = sum(cache_read_tokens) / sum(合格 prompt 前缀 token)

两者均 ≥ 目标值、每 provider 最小样本数达标、质量通过率 100%、模型可见等价失败为零、非法样本为零;速率绝不排除计划内冷启动、TTL 过期、compaction 或前缀失效。低于 provider 最小前缀的请求记 inelig 而非 miss;Gemini 隐式命中保持 organic,进入 attributed_token_hit_rate 之外的通道。

失败演练(期望 FAIL,退出码 1):

go run ./cacheengine/cmd/cachebench \
  -providers anthropic -turns 128 -step 6m -target 0.97

(每个 Anthropic 请求间隔超过 5 分钟 TTL,所有后续请求冷启动。)程序门控失败退出 1,非法输入/配置退出 2,全部 provider 过门才退出 0。

公共语料方面,cachebench 导入 CC-BY-4.0 的 LMCache Agentic Traces(钉住 revision 与 LFS 哈希,有界留存内存,解码上限默认各 1 GiB 且超 16 GiB 失败关闭)。钉住的保守模拟结果存档于 cacheengine/cachebench/results/lmcache-agentic-traces-2026-08-10.json:24,880 请求、24,706 个 OpenAI 缓存合格请求,96.89% 请求命中率、95.76% 估算 token 命中率,严格 97% 门槛整体 FAIL——README 如实记录这一失败,因为每会话一次冷纪元在数学上就把请求命中上限压到 96.92%。这就是该模块“不掺假证据”文化的缩影:模拟报告与 provider 观测报告永不混同,simulation 与 live 证据是两份独立报告。

cmd/cache-replay 提供可选 live 回放:精确 v3 trace 重建、opt-in 鉴权调用(provider HTTP 鉴权/SigV4)、首次真实调用前完成全 trace 优化与模型可见等价、绝对时间有界的并发 worker(调度漂移过大即失败)、外部任务验证器协议、私有留存证据、自动重试为零。零网络 preflight 示例:

go run ./cacheengine/cmd/cache-replay \
  -trace /tmp/cachebench-openai.jsonl \
  -max-requests 128 \
  -max-declared-billed-tokens 5000000 \
  -allow-ungrounded-timing \
  -allow-estimated-token-budget

生产 trace 省略降级开关;live 执行另需 -execute -accept-live-cost -output <新私有目录> -verifier-command <路径>。provider 计数的计费基准由调用方自证,计费 token 上限是预检约束而非实际 token/美元保证。完整凭证、评分器 wire 契约、失败语义与留存产物布局见 cacheengine/cachebench/REPLAY_PROTOCOL.md

小结

cacheengine 展示了一种与“AI 网关”截然不同的缓存工程路径:把缓存收益问题分解为能力建模(Profile)、收益计算(break-even 输入费率单位)、字节级安全(严格唯一键 JSON、wire 等价编辑、全路径原字节存活)与证据分层(inferred/none、organic/affinity/causal、verified 美元恒零)四个正交层,再用 fuzz、parity 测试、严格 97% 门槛基准与钉住语料的诚实 FAIL 报告逐层验证。对需要在代理、SDK 或本地进程中直接内嵌 prompt 缓存优化的开发者,它提供的是可审计的机制与可复制的验证命令,而不是一个需要整条控制面基础设施的“黑盒网关”。进一步阅读可从 cacheengine/README.mdcacheengine/CLAUDE.md 与测试文件 engine/planner 相关的 planner_test.gowire_parity_test.go 入手。

登录后查看全文
热门项目推荐
相关项目推荐