Headroom Phase F 深度解析:PAYG / OAuth / Subscription 三模式认证分类与逐模式压缩策略门控
Headroom 的 Phase F 将「认证模式」提升为一等策略维度:在每个请求进入代理入口时,先通过一个纯函数分类器判定调用方属于按量付费(PAYG)、OAuth 固定额度(OAuth)还是订阅制 CLI(Subscription)三类中的哪一种,再据此门控压缩行为、请求头注入与 TOIN 遥测聚合。读完本文,你将掌握三模式分类器的完整判定规则与源码实现、逐模式压缩策略矩阵的设计原理(为何订阅用户只允许无损压缩、为何要跳过 X-Forwarded-* 头),以及支撑该机制的 Rust/Python 双端一致性测试体系,从而理解一个 LLM 压缩代理如何在不破坏订阅客户端指纹的前提下安全省钱。
一、Phase F 的设计目标:为什么认证模式必须成为策略轴
Headroom 是一个压缩工具输出、日志、文件与 RAG 片段的中间层代理,典型部署方式是让 Claude Code、Codex、Cursor 等编码代理经由它转发到上游模型 API。不同计费方式下的调用方,对代理「能动什么」的容忍度截然不同:
- PAYG(按量付费):调用方按 token 付费,激进压缩直接省钱,可以放开所有优化;
- OAuth(固定额度):调用方使用订阅/IAM 计划(Claude Pro OAuth、Codex Enterprise、Cursor Pro、Bedrock IAM 签名、Vertex ADC),单 token 成本对其不透明,缓存安全性优先——OAuth 作用域绑定
(account, model, session),beta 头漂移会导致凭证失效; - Subscription(订阅 CLI):调用方是 UX 绑定的 CLI/IDE(Claude Code、Cursor、Copilot、Antigravity 等),提供方按请求数限流,且会做程序化指纹检测——代理必须「看起来像」上游代理本身:保留
User-Agent、绝不注入X-Headroom-*内部头、绝不剥掉accept-encoding。
Phase F 的目标文档见 REALIGNMENT/08-phase-F-auth-mode.md,规划为 1 周、4 个 PR:F1 先行落地分类器,F2/F3/F4 在其后并行推进,目标是消除 P5-52~P5-56 五个已知问题,显著降低订阅 CLI 用户的指纹风险。
二、PR-F1:classify_auth_mode 分类器——三模式的判定规则
2.1 判定顺序:最具体信号优先
分类器是一个纯函数:输入 http::HeaderMap(或 Python 侧的 header 映射),输出 AuthMode = Payg | OAuth | Subscription。Rust 实现位于 crates/headroom-core/src/auth_mode.rs,判定顺序(越具体的信号越先命中):
- Subscription UA 前缀 →
Subscription。这是最具体信号:同一个sk-ant-oat*OAuth token 既出现在 Claude Pro(Web)也出现在 Claude Code(CLI)中,只有 User-Agent 能区分二者。CLI 自身的认证模式优先于它碰巧携带的 bearer token 形态; Authorization: Bearer sk-ant-oat*→OAuth(Claude Pro / Max OAuth)。必须排在更宽泛的sk-PAYG 规则之前,因为sk-ant-oat与sk-ant-api共享sk-前缀;Bearer sk-ant-api*或任意Bearer sk-*→Payg(Anthropic / OpenAI API key);Bearer <jwt>(三段式,以.分隔) →OAuth(Codex / Cursor / Copilot OAuth)。实现只数分段、不校验 JWT;- 存在
Authorization但非Bearer ...→OAuth(Bedrock 的 AWS SigV4AWS4-HMAC-SHA256 ...即属此类;任何其他非 Bearer 方案也按透传优先处理); x-api-key存在 →Payg(Anthropic API key 风格);x-goog-api-key存在 →Payg(Gemini key);- 默认 →
Payg。默认选择 PAYG 的理由是:误把非 PAYG 客户端当 PAYG,最多多压缩一次;而把 PAYG 客户端漏判成保守模式,则是白白少省钱——对开源默认用户后者更糟。
Subscription 的 UA 前缀表在 crates/headroom-core/src/auth_mode.rs#L78-L87 中作为模块级常量维护(claude-cli/、claude-code/、codex-cli/、cursor/、claude-vscode/、github-copilot/、anthropic-cli/、antigravity/)。从源码结构看,把它放在模块作用域而非函数内部有三重考虑:编译器可将切片常量折叠进只读段;后续 PR 可把它换成可配置列表而无需改函数体;新增客户端只需一行编辑。匹配用 str::contains 而非前缀匹配,因为部分 Anthropic CLI 会在自己的 UA 前拼接父代理的 UA。Python 侧的实现 headroom/proxy/auth_policy.py 在同一前缀表基础上还多了 grok/ 一项,并额外提供 CLIENT_UA_MAP 用于识别客户端 harness(claude-code、codex、cursor、zed、aider、droid、opencode、copilot、antigravity、strands 等)。
2.2 Rust 实现的健壮性细节
crates/headroom-core/src/auth_mode.rs#L121-L210 的 classify 函数有若干值得注意的工程决策:
- 从不 panic:非 UTF-8 的
User-Agent或Authorization头只触发一条tracing::warn!事件(auth_mode_classify_unparseable_user_agent/auth_mode_classify_unparseable_authorization),随后落入安全默认Payg,运维可从日志流中发现异常客户端而不影响代理存活; - 不记录头值:
to_str返回与HeaderMap同生命周期的&str,Authorization 值零拷贝读取且绝不进日志; - 性能预算:仅一次 UA 小写化的
String分配,其余全部是零分配的starts_with/contains/split('.').count(),验收标准要求单次调用 <10us,基准测试位于crates/headroom-core/benches/auth_mode.rs; - 稳定字符串格式:
AuthMode::as_str()输出"payg" / "oauth" / "subscription",这是与 Python 端共享的 wire 格式——Python 一致性测试直接断言这些字符串(见 tests/test_auth_mode.py#L161-L165)。
枚举本身派生 Copy + Hash + Eq,注释解释了动机:Copy 是因为该值会在每个请求中穿过几十个压缩决策点,克隆一个 1 字节枚举比跨 await 点持有引用更便宜;Hash 则是为了 Phase F PR-F3 中按租户划分 TOIN 聚合 map。
2.3 双端一致性测试矩阵
Python 移植版位于 headroom/proxy/auth_mode.py,classify_auth_mode 委托给 auth_policy.py 中的纯函数 classify_auth_signals。测试矩阵 tests/test_auth_mode.py 逐条镜像 Rust 侧用例,两端的约定是「必须对每个被覆盖的 header 集合给出相同分类,任何分歧都是 bug」。核心用例包括:
| 场景 | 输入示例 | 期望结果 |
|---|---|---|
| Anthropic PAYG | Authorization: Bearer sk-ant-api03-... |
PAYG |
| Codex/Cursor OAuth JWT | Bearer eyJ...xxx.signature(三段式) |
OAUTH |
| Claude Pro OAuth | Bearer sk-ant-oat-01-... |
OAUTH |
| 真实 OAuth token 形态 | Bearer sk-ant-oat01-...(无 oat 后的连字符) |
OAUTH |
| Claude Code CLI | User-Agent: claude-code/1.2.3 (darwin; arm64) |
SUBSCRIPTION |
| Cursor CLI | User-Agent: cursor/1.0 |
SUBSCRIPTION |
| 空 header | {} |
PAYG(安全默认) |
| Bedrock SigV4 | Authorization: AWS4-HMAC-SHA256 Credential=... |
OAUTH |
其中两个用例暴露过真实缺陷,值得注意:
test_oauth_real_sk_ant_oat01_classified_oauth:真实 Anthropic OAuth access token 是sk-ant-oat01-...(版本号紧跟、oat后无连字符)。早期只匹配sk-ant-oat-的写法会让它们漏过、落入 PAYG,从而在订阅请求上启用激进有损压缩;test_subscription_takes_precedence_over_oauth_token:Claude Code 同时携带claude-code/...UA 和Bearer sk-ant-oat-...token,UA 必须胜出——限流/指纹策略绑定在 CLI 上,而非 token 形态。同一 token 走非 CLI UA 时则应分类为 OAuth。
此外还有防御性用例:非 UTF-8 的 bytes 值 Authorization 头不抛异常且落回 PAYG、header 名大小写不敏感匹配、对每个 UA 前缀参数化的独立分类、以及单次调用 <100us 的 Python 侧性能冒烟(Rust 预算为 10us,Python 因字符串开销放宽一个数量级)。
2.4 请求入口接线
Rust 代理在 crates/headroom-proxy/src/proxy.rs#L419-L480 完成接线:请求进入时调用一次 classify_auth_mode(req.headers()),把结果插入 axum request extensions 供下游各 handler 读取而无需重复分类;同时按 CompressionPolicy::for_mode(auth_mode) 派生策略对象并存入 extensions。入口日志事件 auth_mode_classified 携带 auth_mode 字段与 request_id,可与后续各阶段的结构化日志按 auth_mode + request_id 关联。Bedrock 路径则通过 crate::bedrock::classify_and_attach_auth_mode 单独附着(Bedrock 客户端不带 Authorization 头、签名发生在上游,见 crates/headroom-proxy/src/bedrock/auth_mode_layer.rs)。Python 侧在 headroom/proxy/handlers/anthropic.py 与 openai.py 的请求入口做同样的调用。
三、PR-F2:逐模式压缩策略门控——从分类到策略结构体
3.1 策略矩阵
Phase F 的策略矩阵(见 REALIGNMENT/02-architecture.md §2.4)规定:
- PAYG = aggressive(当前默认行为):全部压缩能力放开;
- OAuth = passthrough-prefer:不自动放置
cache_control断点、不自动注入prompt_cache_key、不使用有损压缩器,只允许无损压缩; - Subscription = stealth:OAuth 的一切约束,外加保留
accept-encoding(绝不剥离)、绝不注入X-Headroom-*、绝不改动User-Agent。
3.2 CompressionPolicy 结构体:集中式策略而非散落的 match
策略的落地实现是 crates/headroom-core/src/compression_policy.rs 中的 CompressionPolicy::for_mode(AuthMode) -> CompressionPolicy。源码注释明确解释了为什么用结构体而不是在每处门控点写 match auth_mode:一是集中化——没有结构体时,逐模式判定会在 E3 cache_control、E4 prompt_cache_key、live-zone 门控、cache_aligner 门控等处重复,调整策略要满仓库找调用点;二是测试面——for_mode 是纯函数,可以直接对结构体做属性测试,而不用搭完整请求 fixture。
当前各模式取值(源码注释中标注为 CONSERVATIVE 默认值,待 bake 遥测后调优):
| 模式 | live_zone_only | cache_aligner_enabled | volatile_token_threshold | max_lossy_ratio | toin_read_only |
|---|---|---|---|---|---|
| Payg | false | true | 128 | 0.45 | false |
| OAuth | false | true(同 PAYG) | 128(同 PAYG) | 0.45(同 PAYG) | false(同 PAYG) |
| Subscription | true | false | 32 | 0.25 | true |
各字段语义(见 crates/headroom-core/src/compression_policy.rs#L27-L78 的模块文档):
live_zone_only:为true时下游变换不得改动缓存标记之后的 live zone 之外的字节。Rust 调度器本身按构造就是 live-zone-only,该字段主要约束 PythonTransformPipeline的CacheAligner/ContentRouter门控,同时保证跨语言一致性测试对字段映射的诚实性;cache_aligner_enabled:为false时 PythonCacheAligner的should_apply必须返回False。注释指出CacheAligner是缓存不稳定投诉的负载级修复点——它历史上会改动已缓存前缀并按 pipeline 实例写_previous_prefix_hash,正是这一点破坏了订阅用户的 prompt cache。对 Subscription 禁用它是 F2.1 的用户可见收益;volatile_token_threshold:低于该 token 数的内容视为缓存稳定。Subscription 保守(32,更早标记 volatile → 保持 prompt 稳定),PAYG 激进(128,容忍更多噪音)。源码明确说明该字段在 F2.2 处于「已接线但未被消费」状态——当前cache_aligner.py里的 volatile 检测器是基于形状而非 token 计数,接线需要超出本次范围的检测器重构;max_lossy_ratio:有损压缩可丢弃原始 token 的比例上限(0.0为禁止、1.0为不限制)。PAYG 上限 0.45,Subscription 上限 0.25。同样标注为已接线未消费,区别于 Python ContentRouter 中调用方驱动的target_ratio参数;toin_read_only:为true时 TOIN 只提供缓存建议、不从此请求写新的模式观察。订阅流量为 prompt-cache 稳定性买单,其压缩事件不应污染全局学习池;PAYG/OAuth 继续写入以维持网络效应。
结构体上还实现了净收益公式(#856):net_mutation_gain(delta_t, suffix_tokens, expected_reads, p_alive) 用 Anthropic 缓存定价常量(写 1.25×、1 小时档 2.0×、读 0.1×,见 crates/headroom-core/src/compression_policy.rs#L133-L144)计算「改动某条消息、使其后所有缓存失效」的期望净收益,配套 break_even_reads 给出盈亏平衡读次数 R = ((w−r)/r)·S/ΔT = 11.5·S/ΔT(5 分钟档)。例如 2K 剪裁落在 50K 热后缀下需要 287.5 次剩余读取才回本(几乎不划算),而 50K 剪裁落在 10K 后缀下 2.3 次读取即回本。tests/test_compression_policy.py 以相同数值断言 Python 镜像,两端任何漂移都会同时触发一致性测试对。
门控测试以 #[test] oauth_matches_payg_today 作为金丝雀:一旦未来 PR 让 OAuth 与 PAYG 分叉,该断言立即失败,强制显式更新——这正是设计意图。订阅侧的门控测试则断言:live_zone_only 为真、cache_aligner_enabled 为假,但 live_zone_compression_enabled() 仍为真——源码注释强调「关闭缓存投诉绝不等于零压缩」,订阅用户依然保留 live-zone 压缩。
3.3 门控的具体落点
按 Phase F 文档,F2 需要修改的位置包括:Rust 的 live_zone_anthropic.rs(auto_place_breakpoints 仅在 auth_mode == Payg 时执行)、live_zone_openai.rs(inject_prompt_cache_key 同门控)、live_zone.rs(有损压缩器仅在 PAYG 下启用,OAuth/Subscription 只走无损路径)、headers.rs(见下文 PR-F4)、以及 proxy.rs 中 accept-encoding 剥离改为条件化(Subscription 除外);Python 侧 headroom/proxy/handlers/anthropic.py 与 openai.py 做镜像门控。crates/headroom-proxy/src/compression/ 下 live_zone_anthropic.rs、live_zone_openai.rs、live_zone_responses.rs 均引用 AuthMode,可确认三端 live-zone 模块都已接入模式参数。验收标准包含一条人工冒烟:真实 Claude Code 会话穿过代理后,上游请求不含任何 X-Forwarded-*,且 accept-encoding 被保留。
四、PR-F3:TOIN 按租户聚合键与订阅凭证加固
TOIN(Token Optimization INsights,headroom/telemetry/toin.py)原本按 structure_hash 做全局聚合。F3 将聚合键扩展为 (auth_mode, model_family, structure_hash) 三元组:
Pattern数据结构新增auth_mode: str = "unknown"与model_family: str = "unknown"字段;- 聚合键改为元组,内存字典按新键重排;
- 旧观察数据在
legacy/前缀下保留并迁移到("unknown", "unknown", structure_hash),在 30 天内逐步废弃,实现优雅降级; - 聚合键变更会使早期推荐失效,需通过部署 CLI 重新发布;
- 推荐文件结构化:按
(auth_mode, model_family)分节的recommendations.toml。
与认证模式直接相关的另一个加固点在 headroom/subscription/tracker.py:把内存中的 _current_token: str(原始 OAuth bearer 存储)替换为 _current_token_id: str(单向哈希 + 末 4 位用于调试),轮询代码改为每次请求使用真实的 Authorization 头而非存储副本,消除 token 泄漏面。对应测试:tests/test_toin_per_tenant.py::test_aggregation_key_includes_auth_mode_model、test_legacy_observations_preserved_under_unknown、test_publish_per_auth_mode_writes_separate_recommendations,以及 tests/test_subscription_tracker_token_hardening.py::test_raw_token_not_stored_in_memory(仓库测试目录中 tests/test_subscription_tracker.py 等订阅跟踪测试覆盖了 tracker 主体行为)。
从聚合维度看,这条改动的意义在于:不同认证模式下同一请求结构的压缩收益/风险特征不同(订阅流量必须保缓存稳定,PAYG 流量追求最大节省),混在一起聚合会让推荐值互相污染——这正是 Phase F 把 auth mode 作为策略轴的同一逻辑在遥测层的延伸。
五、PR-F4:X-Forwarded-* 注入按模式条件化
Rust 代理的转发行头构建逻辑位于 crates/headroom-proxy/src/headers.rs。build_forward_request_headers(crates/headroom-proxy/src/headers.rs#L132-L169)负责:剥离 hop-by-hop 头(RFC 7230 §6.1)、移除 Connection: 列出的头与客户端托管头(host、content-length)、追加 X-Forwarded-For、设置 X-Forwarded-Proto / X-Forwarded-Host、确保 X-Request-Id,并在 strip_internal == true 时剥掉 x-headroom-* 前缀头(INTERNAL_HEADER_PREFIX,大小写不敏感匹配)。
F4 的改动是把这个「总是注入」行为按模式条件化:PAYG → 注入;OAuth → 注入;Subscription → 跳过。风险在于程序化指纹检测——上游提供方一旦在订阅流量上看到代理附加的 X-Forwarded-* 痕迹,就可能识别出非官方客户端路径。相关单测已覆盖内部头剥离(strip_internal_headers_removes_only_internal_prefix、build_forward_strips_internal_when_enabled / build_forward_keeps_internal_when_disabled,见 crates/headroom-proxy/src/headers.rs#L241-L287),模式条件化的集成测试规划在 crates/headroom-proxy/tests/integration_x_forwarded_authmode.rs(payg_adds_xfwd、oauth_adds_xfwd、subscription_no_xfwd)。Python 侧对应策略模块 headroom/proxy/forwarded_policy.py 与测试 tests/test_forwarded_policy.py 覆盖同源行为。
六、阶段验收清单与回滚策略
四个 PR 全部落地后,Phase F 的验收清单(源自 REALIGNMENT/08-phase-F-auth-mode.md 的 acceptance summary):
classify_auth_mode辅助函数可检测 PAYG / OAuth / Subscription;- 逐模式压缩策略门控就位(auto-
cache_control、prompt_cache_key、有损压缩器); - TOIN 聚合键按
(auth_mode, model_family, structure_hash)划分; - 订阅 tracker 不再存储原始 OAuth bearer;
- Subscription 模式跳过
X-Forwarded-*; - Subscription 模式保留
accept-encoding。
每个 PR 的回滚策略都是 git revert 且语义清晰:F1/F2/F4 回滚后所有请求按 PAYG 处理(即 Phase F 之前的现状,PAYG 用户无功能回归,OAuth/Subscription 用户可能看到 scope 拒绝或吊销风险回升);F3 回滚后 TOIN 退回全局聚合,无功能破坏。
七、小结:模式分类作为策略原语的设计模式
Phase F 的核心价值在于把一个「请求元数据判定」沉淀成了贯穿压缩、缓存、头处理与遥测的策略原语,其实现有三个可复用的工程范式:
- 纯函数分类 + 最具体信号优先 + 保守默认:分类器无 I/O、不 panic、<10us,把判定复杂度集中在一个可穷举测试的函数里,而不是散落在各 handler 中;
- 策略结构体替代散落 match:
CompressionPolicy::for_mode让逐模式调参收敛到单点,配合金丝雀测试(如oauth_matches_payg_today)使未来有意的策略分叉无法「静默发生」; - 双端一致性契约:Rust 与 Python 实现共享同一测试矩阵和 wire 字符串格式(
payg/oauth/subscription),在 Python 代理路径尚未退役(Phase H)之前保证行为等价。
对运维者的实际意义:走 API key 的按量客户端获得最大压缩收益;走 OAuth/Bedrock/Vertex 的客户端得到缓存安全优先的透传保守行为;跑 Claude Code / Cursor 等订阅 CLI 的用户则在几乎不可感知的「隐身」模式下工作——压缩继续发生(live-zone 无损路径),但前缀不被改写、内部头不外泄、指纹风险被系统性消除。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00