Headroom 基准测试指南:压缩性能、准确率验证与可复现的评测方法
Headroom 的核心承诺是"压缩上下文但不损失准确率"。本篇技术文章以仓库中 wiki/benchmarks.md 为骨架,完整讲解三类评测结果——压缩性能、HTML 抽取准确率、QA 准确率保持——以及 token 级 F1 等评测方法学,并基于仓库源码(headroom/evals/、headroom/transforms/、benchmarks/)说明每个指标是如何计算与验证的。读完之后,你可以自行在本仓库中复现全部基准数据,并判断 Headroom 在自己的工作负载下是否值得引入。
评测总览:两个正交的问题
一个上下文压缩方案必须同时回答两个问题:
- 压缩了多少:Token 节省比例、压缩延迟;
- 准确率是否保持:压缩后 LLM 对同一上下文还能否给出同样的答案。
Headroom 的评测围绕这两个问题展开,全部可以从仓库中复现。关键结论先行:在 Scrapinghub 文章抽取基准上,Headroom 的 HTMLExtractor 达到 98.2% Recall、94.9% 压缩率(F1 0.919,trafilatura 基线 0.958),且在 QA 任务上抽取后的内容准确率不降反升。
压缩性能:compress() 在不同内容类型上的表现
官方文档标注的测试环境为 Apple M 系列 CPU,headroom v0.5.18,每个测试对真实工具输出调用 compress()。完整数据如下:
| 内容类型 | 原始 token | 压缩后 | 节省 | 比例 | 延迟 |
|---|---|---|---|---|---|
| JSON 数组(100 项) | 3,163 | 297 | 2,866 | 90.6% | 1ms |
| JSON 数组(500 项) | 9,526 | 1,614 | 7,912 | 83.1% | 2ms |
| Shell 输出(200 行) | 3,238 | 469 | 2,769 | 85.5% | 1ms |
| 构建日志(200 行) | 2,412 | 148 | 2,264 | 93.9% | 1ms |
| grep 结果(150 处命中) | 2,624 | 2,624 | 0 | 0.0% | <1ms |
| Python 源码(约 480 行) | 2,958 | 2,958 | 0 | 0.0% | <1ms |
| 合计 | 23,921 | 8,110 | 15,811 | 66.1% | 5ms |
两个值得注意的 0% 行:
- grep 结果与 Python 源码压缩率为 0——它们本身就是紧凑的结构化格式。SmartCrusher 只压缩 JSON 数组;代码走 passthrough 路径以保留正确性;
- 延迟是
compress()SDK 调用的耗时,不包含完整代理链路的往返时间。
从源码看:compress() 与默认管线
表格中的"压缩后"数字来自 compress() 这一个函数 API:无需代理、无需配置,传入 messages 即返回压缩后的 messages 与 tokens_saved、compression_ratio 等指标。从 headroom/compress.py 的管线初始化可以看到默认管线结构:
CacheAligner → ContentRouter
- CacheAligner 稳定请求前缀,使上游 KV/prompt cache 能命中;
- ContentRouter 按内容类型路由到具体压缩器——JSON 走 SmartCrusher,代码走 CodeCompressor,文本走 Kompress(ONNX 模型压缩)。
这也解释了表格中"为什么只有部分行有压缩":路由层按内容类型决定走哪个压缩器,紧凑格式直接透传。另外,compress() 内部有明确的保护逻辑:CompressConfig.min_tokens_to_compress 默认 250(低于该长度的消息不动)、protect_recent 默认 4(最近 4 条消息不压),并且在 token 数出现膨胀时直接回退原始消息(inflation guard,见 headroom/compress.py)——这与文档"短消息不压缩,因为开销大于收益"的表述一致。
准确率基准
HTML 抽取(Scrapinghub Article Extraction Benchmark)
- 数据集:Scrapinghub Article Extraction Benchmark(HuggingFace 上的
allenai/scrapinghub-article-extraction-benchmark),181 个带 ground truth 正文的 HTML 页面; - 基线:trafilatura,0.958 F1。
| 指标 | 数值 | 含义 |
|---|---|---|
| F1 | 0.919 | 与 ground truth 的 token 级重叠 |
| Precision | 0.879 | 抽取内容中相关的比例 |
| Recall | 0.982 | ground truth 内容被覆盖的比例 |
| Compression | 94.9% | 平均体积缩减 |
对 LLM 应用而言 Recall 是关键指标——98.2% 意味着几乎全部正文内容被保留;Precision 的轻微下降(带进一些额外内容)并不会伤害 LLM 准确率。
该基准的实现在 headroom/evals/html_oss_benchmarks.py 中:
evaluate_scrapinghub_benchmark()逐样本调用HTMLExtractor().extract(html, url=...)(抽取器位于 headroom/transforms/html_extractor.py),对每个样本计算 F1 与压缩率后取均值;- 结果对象
ExtractionBenchmarkResult内置基线对比属性:matches_baseline(F1 与 0.958 相差 0.02 以内)和beats_baseline(F1 超过基线),方便 CI 中做回归判定; - 对应的可执行测试在 tests/test_evals/test_html_oss_benchmarks.py:
test_extraction_f1_quick(10 样本)、test_extraction_f1_medium(50 样本,要求 F1 > 0.85)、test_extraction_f1_full(全部 181 样本,标记为@pytest.mark.slow,要求 F1 > 0.90),以及test_compression_achieved(要求平均压缩率 > 50%)。整个模块用pytest.importorskip("trafilatura")守卫——trafilatura 未安装时自动跳过。
本地复现:
pip install "headroom-ai[html]" datasets
pytest tests/test_evals/test_html_oss_benchmarks.py::TestExtractionBenchmark -v -s
JSON 压缩(SmartCrusher)
- 测试:100 条生产日志条目,关键错误位于第 67 位;
- 任务:找出错误、错误码、解决方案与受影响数量。
| 指标 | 基线 | Headroom |
|---|---|---|
| 输入 token | 10,144 | 1,260 |
| 答对题数 | 4/4 | 4/4 |
| 压缩率 | — | 87.6% |
SmartCrusher 的保留策略是:前 N 项(承载 schema/结构信息)、后 N 项(新近性)、全部异常项(error/warning)与统计分布。仓库中还提供了一个公平的三方对比基准 benchmarks/compression_benchmark.py,在"截断(保留前 N 项)"、"LLM 摘要"、"Kompress(ModernBERT 本地推理)"与"Headroom SmartCrusher"四种方案上,用带 ground truth 问题的日志/文件搜索/时序指标三类场景同时度量 token 节省与答题准确率,并记录 LLM 摘要的额外成本。其中 Headroom 侧的配置示例为:
config = SmartCrusherConfig(
enabled=True,
min_items_to_analyze=5, # 至少分析 5 项才触发统计压缩
variance_threshold=2.0, # 异常判定阈值
max_items_after_crush=20, # 压缩后最多保留 20 项
preserve_change_points=True, # 保留变化点(趋势拐点)
)
crusher = SmartCrusher(config)
QA 准确率保持
| 指标 | 原始 HTML | 抽取后 | Delta |
|---|---|---|---|
| F1 | 0.85 | 0.87 | +0.02 |
| Exact Match | 60% | 62% | +2% |
抽取有时会提高准确率:去掉 HTML 结构噪音后,LLM 反而更能聚焦相关内容。
对应实现在 evaluate_qa_accuracy_preservation():将 QA 数据集的上下文包进一个带 <nav>/<footer> 噪音的最小 HTML 骨架,对原始 HTML 与抽取内容分别调用同一个 answer_fn 作答,再对比 F1 与 exact match。"准确率是否保持"的判定标准写得很明确:accuracy_preserved = avg_f1_ext >= avg_f1_orig - 0.02(抽取后 F1 不低于原始 F1 减 2 个百分点即算保持)。测试类 TestQAAccuracyPreservation 使用 OpenAI 的 gpt-4o-mini 作为答题函数,且仅在设置了 OPENAI_API_KEY 时执行(否则 skip)。
方法学:指标是怎么算的
Token 级 F1
Precision = |predicted ∩ ground_truth| / |predicted|
Recall = |predicted ∩ ground_truth| / |ground_truth|
F1 = 2 * (Precision * Recall) / (Precision + Recall)
实现上先分词再统计词频交集:Counter 求取两侧 token 计数的按量截断交集(多出的重复词不计),分别除以预测/真值 token 总数得到 P/R。核心函数 compute_f1() 见 headroom/evals/html_oss_benchmarks.py。
此外,通用评测指标库 headroom/evals/metrics.py 提供了更全的工具集:compute_exact_match、compute_f1、compute_bleu、compute_rouge_l、compute_semantic_similarity(基于 sentence-transformers 的余弦相似度)以及综合判定函数 compute_answer_equivalence(exact match / F1 ≥ 0.7 / 语义相似度 ≥ 0.85 / 双方都包含 ground truth,四者居一即判"等价")。值得注意的实现细节:该文件的分词器是 CJK 感知的——中日韩连续字符段会被切成重叠的双字 bigram(单字则保留 unigram),否则中文这类无空格语言在 token 级 F1/Recall 上会退化成"整串全对或全错"的判定。
压缩率
Compression = 1 - (compressed_size / original_size)
94.9% 压缩意味着输出只有原始大小的 5.1%。
局限性:Headroom 不压缩什么
不会压缩的内容
- 短消息(< 300 token)——处理开销大于节省;
- 源码——默认原样透传以保证正确性(除非启用 tree-sitter AST 压缩);
- grep/搜索结果——本身已是紧凑结构化格式;
- 图片——按固定 token 成本(约 1,600 token)计入,不作为文本压缩;
- 系统提示词——为保持前缀缓存兼容性而保留。
已知的开销来源
| 开销来源 | P90 延迟 | 说明 |
|---|---|---|
| Token 计数 | 16ms | 压缩前后各跑一次 tiktoken |
| Tree-sitter AST 解析 | 886ms | 大代码文件开销显著 |
| Kompress ONNX | 576ms | CPU 上跑 ML 推理做文本压缩 |
| 内容检测(Magika) | — | ML 分类内容类型 |
从源码结构看,这些开销对应管线中各阶段:token 计数服务于节省统计与 inflation guard,Magika 服务于 ContentRouter 的类型路由,Kompress 的 ONNX 推理只作用于文本型内容,而 tree-sitter 只在大代码文件启用 AST 压缩路径时出现。
何时价值最大 / 何时价值有限
价值最大:
- 积累了大量工具输出的长 agent 会话;
- JSON 密集型工作流(API 响应、数据库查询)——见压缩性能表中 JSON 行;
- 构建/测试输出——见 Shell/Build log 行;
- 多工具 agent——每次调用的节省随工具结果累积而复利。
价值有限:
- 短对话——小 payload 下开销可能超过节省;
- 纯代码读写会话——代码走透传;
- 单轮请求——没有累积上下文可压。
复现全部结果
以下命令均在仓库根目录执行:
# 安装评测依赖
pip install -e ".[evals,html]"
# 运行全部评测
pytest tests/test_evals/ -v -s
# 单次压缩冒烟测试
python -c "from headroom import compress; print(compress([{'role':'user','content':'test'}]))"
# 本地代理模式基准(无 API 调用)
python benchmarks/proxy_mode_benchmark.py --turns 12 --show-real-harness
# 回放本地 Claude Code 转录(无 API 调用)
python benchmarks/claude_session_mode_benchmark.py --workers 1
# 在同一本地 Claude 转录语料上对比两个 git ref
python benchmarks/claude_session_branch_compare.py --left-ref upstream/main --right-ref HEAD --recent-turns-per-session 200 --workers 1
# 确定性的 cache-bust 证明用例
python benchmarks/synthetic_token_cache_bust_report.py
# 完整的本地报告包
python benchmarks/cache_validation_bundle.py --workers 1 --output-dir benchmark_results/cache_validation_bundle_full
# 本机私有审查时可带上真实内容摘录
python benchmarks/cache_validation_bundle.py --workers 1 --include-content
各脚本的定位:
benchmarks/proxy_mode_benchmark.py —— 在同一合成对话上对比 token 与 cache 两种代理模式:token 模式压缩率应更高;cache 模式保持前轮前缀稳定,在 prefix-cache 复用充分的长会话中可能胜出。--show-real-harness 只打印用 Claude Code 复跑同一对比的可选步骤,默认不调用任何 API。
benchmarks/claude_session_mode_benchmark.py —— 回放 ~/.claude/projects 下的本地转录,分别以 baseline、token、cache 三种模式重放,估算 raw token、cache read/write token、计费 input/output 成本,并在两种假设下比较 prompt 窗口占用:
- 假设一:cached token 计入模型上下文窗口;
- 假设二:cache read 不计入模型窗口。
注意事项:输出写入 gitignored 的 benchmark_results/;脚本对内存使用刻意保守,全语料回放建议 --workers 1;由于只使用转录中可见的消息(隐藏的 Claude Code 系统/工具 schema 不在本地 .jsonl 中),数字是对比性估算而非精确的供应商账单复刻。
benchmarks/claude_session_branch_compare.py —— 在隔离的 worktree 中针对两个 git ref 各跑一次真实本地会话回放,用于同一转录切片上的 PR vs main 对比。产物:
- 各 ref 的回放输出:
benchmark_results/branch_compare/<label>/ - 合并对比报告:
benchmark_results/branch_compare/
benchmarks/synthetic_token_cache_bust_report.py —— 确定性 cache-bust 证明:强制 token 模式在第二轮回溯性改写上一轮工具结果(触发缓存击穿),而 cache 模式保持稳定。用它验证模拟器能区分:
token:history rewrite + cache bust;cache:无改写 + 无击穿。
benchmarks/cache_validation_bundle.py —— 组合生成可复现的本地报告包,内容涵盖真实会话回放汇总、仅本地的处理后真实输入/输出摘录、合成 token 击穿证明与合成长文压力测试。默认输出对分享是脱敏安全的(真实报告摘录转录内容、manifest 路径均被 redact),加 --include-content 才在本机私有审查时保留内容摘录。产物结构:
index.html/index.md:顶层汇总与链接;bundle_manifest.json:运行时元数据 + 语料指纹;real/:完整真实会话回放报告;real_processed/:真实转录的处理前后摘录;synthetic_token_bust/:最小显式 cache-bust 证明;synthetic_long_suite/:长确定性改写/TTL 场景。
检查点(checkpoint)作用域限定在 bundle 输出目录内,并按所选语料打指纹,避免过期运行结果污染新结果。
小结
Headroom 的评测体系覆盖三层:单函数 compress() 的压缩率与延迟(按内容类型分列)、抽取/压缩后的 LLM 准确率保持(token 级 F1、exact match、QA 保留率),以及代理模式级别的缓存稳定性证明(token vs cache 模式)。所有数字都可通过仓库内的 pytest 与 benchmarks/ 脚本复现;局限部分也如实给出了不压缩清单与 P90 开销来源——在决定是否为特定工作流启用 Headroom 前,建议先按其"何时价值最大"清单对号入座,再跑一轮本地回放基准确认收益。
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 StartedRust0625
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