关于 Distil
Distil 是为编码 Agent 提供上下文压缩与测量的工具,可将工具输出折叠为可恢复句柄,并按原始字节展开。它还可比较不同压缩方式对费用和 Agent 后续决策的影响。
主要功能
- 01可逆压缩工具输出
- 02按需还原原始字节
- 03审计压缩对费用与决策的影响
- 04代理多种编码 Agent 流量
- 05提供 Python 与 TypeScript 库
- 06通过 MCP 提供展开工具
适用场景
- 01减少重复工具输出占用的上下文
- 02检查压缩是否改变 Agent 后续行动
- 03比较不同压缩器的费用影响
- 04让 Agent 按需取回完整工具输出
MCP 相关
Distil 可作为 MCP 服务,为 Agent 提供压缩自身输出及按需取回精确原始内容的工具。README 也说明,Cursor 等客户端的 MCP 输出可由其钩子压缩。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
3收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| text | string | 是 | 要压缩的原始文本,按原样传入——请勿预先摘要或截断,否则恢复的原文会有损失。 |
详细介绍
Distil 衡量编码 Agent 的上下文工具实际花费——
以每个已解决任务的美元成本和决策变化为指标;涵盖任意压缩器、提供商自带的上下文压缩,以及 Distil 自身的压缩。
uv tool install distil-llm && distil setup
其他安装方式(curl、Homebrew、pipx、Windows):选择适合你的安装方式
distil wrap -- claude # run your agent through distil (or let `distil setup` make it always-on)
distil savings # what it saved you, from your own traffic
distil doctor # if something looks off
distil audit --compressor anthropic-context-editing --cap-usd 1 # did it change what your agent does, and what it cost? (opt-in, capped)
distil audit report # helped, hurt, or can't tell yet, per compressor
Distil 也能压缩内容(默认无损,可还原每个字节),并用同样的指标衡量该压缩器。
当前测量结果(2026-10-06;每项数据均链接到对应产物)
- 在短编码任务中,没有证据表明任何压缩器能省钱。 SWE-bench Lite,共 298 项任务,使用相同模型和评分器:Distil 与不压缩的成本持平(每个已解决任务 $0.0393 vs $0.0387)。RTK 看起来每项任务便宜 20.7%,直到我们发现它的实验组读取了其他实验组的提示词缓存;按冷启动重新定价后,结果为 −6.5% [−13.1%, +0.1%],未达显著水平。Selective Context 和 Anthropic 上下文编辑都没有降低成本。Headroom 尚未在该基准上运行。排行榜 →
- 长会话:结论尚不明确。 一项包含 7 项任务的长时程试点(中位数为 63–69 步)显示,Distil 和 RTK 均未带来成本差异;在没有失败尝试的 6 项任务中,Distil 的成本比原方案高 9.7%。运行结果 →
- 原因。 一个离线模拟器在未见过的运行中,复现提供商账单的误差在 2.5% 以内。模拟结果显示,无损策略带来的成本变化不到 0.2%;有损压缩只有在 Agent 不会为了弥补被删去的内容而增加步骤时,才能省钱。下一步是通过实时 A/B 测试进行测量。模拟器 → · RTK 看起来更便宜的原因 →
- 在维护者本人按量计费的 Claude Code 流量中(2026 年 9 月,共 13,191 次请求),扣除 Distil 自身开销并计入缓存费用后,估计账单减少了 8.3–9.2%(来源,方法)。这是基于相同轨迹的估算:它假设 Agent 的行为保持不变,而这正是上文 A/B 测试需要验证的。
为什么这些测量值得信任
- 不会破坏提示词缓存。 Distil 绝不会重写提供商仍在缓存中的字节;只有缓存过期后,较早的上下文才会发生变化。我们曾发布过一次导致此问题的版本,测量了它造成的代价,并将这条规则设为强制不变量。缓存约定 →
- 每个被压缩的字节都可恢复。 distil 会将折叠掉的内容保存在本地存储中,并为 Agent 提供
distil_expand工具,以便在任务进行中取回精确的原始内容。摘要的工作原理 → - 基于真实账单进行测量,并附上凭据。 节省金额按请求统计,并根据提供商实际计费的
usage进行校准;每个请求都会写入一份可供验证的哈希链凭据。同一套测试框架也会运行其他所有压缩器;当它发现自己的正面对比测试存在缺陷时,也发布了修正结果。测量方式 →
它还会告诉你何时压缩反而有害。 影子模式会在原始上下文和压缩后的上下文上重放部分请求,并报告每种压缩模式造成的差异;当摘要的危害上限超出预算时,代理会将自身限制在无损模式。将同一检查直接用于提供商时,发现 Anthropic 的上下文清除在 40 个案例中有 37 个改变了 Agent 的下一步操作,且所有旧工具结果都被清除(keep=0,合成语料库)(研究)。
深入了解:distil 会检查什么,以及将这些检查用于提供商自身的压缩时发现了什么 ↓
功能
-
评估你的上下文工具 —
distil audit会将你自己的请求样本限制在指定数量,并按指定压缩器(distil、Anthropic 上下文编辑、OpenAI 压缩、Headroom)的处理方式重放,报告有帮助 / 有害 / 暂无法判断的结果,以计费金额和 Agent 的下一步操作为衡量依据(ADR 0024)。离线运行时,SWE-bench 结果评估框架会按每个已解决任务的花费为任意方案评分,并隔离各方案的提示词缓存;结果见排行榜。 -
包装你的 Agent — 提供 18 种预设:
distil wrap -- <agent>,支持aider·claude·codex·gemini·copilot·goose·grok·kilo·kimi·vibe·opencode·openhands·qwen·cline·cn·crush·droid·omp。零配置,无需更改代码。distil wrap --list会列出所有目标、对应机制以及所使用的提供商格式。 -
运行代理 — 将任何
base_url客户端指向它。支持 Python、TypeScript,以及任何语言和框架。提供同步代理、异步代理和独立网关,三者的提供商覆盖范围相同:Anthropic Messages、OpenAI Chat Completions 和 Responses API、Azure OpenAI,以及 GeminigenerateContent。 -
作为库调用 — 在你自己的 Agent 循环中使用
from distil import compress_messages。 -
为你的 Agent 提供召回工具 — MCP 服务:压缩自身输出,并可按需获取完全一致的字节内容。
-
框架钩子 — LangChain · LangGraph · LiteLLM · Agno · Strands · AutoGen · LlamaIndex,在进程内运行,无网络跳转;还提供 ASGI 中间件,可用于托管自有 LLM 端点的任何 Starlette/FastAPI 应用,以及适用于 Vercel AI SDK 的 npm 包。
-
代理无法触及的地方 —
distil setup --hooks:Claude Code、Cursor(MCP 输出)、Gemini CLI 和 Codex CLI 通过各自文档说明的工具后钩子压缩工具输出。订阅版仅支持无损压缩,除非添加--digest;每个摘要都可通过distil expand <handle>还原。 不使用代理,不会触碰凭据。distil quota显示它能为你腾出的限流窗口。钩子 → -
从源头调整 Shell 输出 —
distil sh -- <command>(选择启用,ADR 0026)会原样保留测试运行或git status的每条失败、错误和摘要行,并将通过测试的冗余输出折叠到distil expand句柄后;distil hook install --shell可让 Claude Code 使用它。在 SWE-bench Lite 记录中,测试运行很少见,因此它只会移除 0.06% 的 bash 输出,并默认不启用。Shell → -
所有提供商使用相同机制 — 在 Anthropic Messages、OpenAI Chat 和 Responses,以及 Gemini 上均支持原样重新获取、冷点淘汰、编辑引用保护和普查;OpenAI 和 Gemini 按量计费,因此节省金额和
distil audit不再将其计为 0 美元;distil savings的假设重放现在也会处理 Codex CLI 和 Gemini CLI 会话,以及 Claude Code 会话。兼容性矩阵 → -
VS Code Copilot Chat — 它的 BYOK 自定义端点可以指向 distil 代理:
distil setup --vscode。 -
保留文本原样 — 提示词或工具输出中的
<distil:keep>…</distil:keep>永远不会被压缩。 -
保持 MCP 工具搜索开启 —
distil wrap -- claude会让 Claude Code 保持 MCP 工具搜索开启;否则 Claude Code 会在代理后关闭该功能,因此未使用的连接器会继续延迟加载,而不是每轮都随请求发送。已在 1.54.0 上进行实时验证(2026-09-25):每个请求的tools_deferred均为 4–5,工具负载为 9,733 个令牌,提示词缓存读取正常。(ADR 0013) -
真实代码骨架 —
pip install 'distil-llm[code]'会为 Go、Rust、Java、C/C++、Ruby 和 TS/JS 添加 tree-sitter 解析支持。代码骨架 → -
查看运行情况 — 实时状态行、会话剖析、逐请求标头、OTel 追踪、Prometheus 指标。
uv tool install distil-llm && distil setup # detects your agent + billing, wires everything
不确定你需要哪种方式? 回答两个问题,选出适合你的模式 → — 通俗易懂,提供诚实的节省范围,不讲术语。
◉ 实时 · 根据 公开 git 分支上的自愿参与统计测得,绝非估算
| ⚡ 获取节省 2 分钟,无需配置 uv tool install distil-llmdistil setup | 🔬 查看证据 真实测试框架 基准测试 ↓ · 论文 与其他方案对比 |
立即使用 · 作为库使用 · 集成 · 安装 · 为何值得信赖 · 完整文档 → · llms.txt
AI Agent:请阅读 /docs/llms.txt,了解 distil 是什么以及如何调用它的精简机器可读摘要。
🧩 将它用作库
自己构建 Agent?在消息列表所在的位置压缩消息——无需代理,也无需网络跳转:
from distil import compress_messages, expand_handle
result = compress_messages(messages) # OpenAI/Anthropic-style dicts
print(f"{result.saved_pct:.1f}% smaller")
response = client.messages.create(model=..., messages=result.messages)
original = expand_handle(result.handles[0]) # byte-exact, any time, any process
工具结果会获得可逆摘要;用户和系统文本只进行无损转换;模型自身的轮次绝不会被改写。句柄可跨进程和重启解析,因此由代理生成的摘要可以在这里还原,反之亦然。verbatim=True 会完全禁用摘要。
之所以命名为 compress_messages/expand_handle,而不是 compress/expand,是因为 distil.compress 和 distil.expand 是模块——如果顶层导出使用相同名称,其解析结果就会取决于无关的导入顺序,有时指向函数,有时指向模块。
也支持 TypeScript——使用 npm 包中的 compress(messages),其结果与 Python 引擎逐字节一致。完整参考:库 API → · 可运行示例:python_library.py · js_library.ts。
维护框架? docs/INTEGRATING.md 只有约 20 行和四条规则——我们更希望集成代码留在你的仓库,而不是我们的仓库中。
🔬 distil 会检查什么,以及发现了什么
有东西正在改写 Agent 的上下文。
Distil 会衡量这让你付出了什么代价。
你的提供商现在会默认在服务端为你编辑上下文窗口——清除旧工具结果、总结历史记录——却不告知你做了哪些更改。
Distil 能回答唯一重要的问题:Agent 仍然会做出相同的事吗?
|
我们对提供商进行了测试。 Anthropic 的默认上下文编辑保留规则( |
Distil 也会以可逆方式压缩 Agent 每轮都会重新发送的工具输出、日志和历史记录。
它是唯一自带认证证书、对抗性门槛,并且敢于拒绝输出某个数字的上下文操作。
60 秒快速了解
无法验证的压缩,只是对 Agent 行为的猜测。
Distil 的构建原则是让每个环节都可验证,也允许验证结果为否。
证明与来源
上述每项声明都可验证,交付这些内容的供应链也同样可验证。每个版本都附带 PEP 740 证明,让你能够确认构建来自此代码库的 CI,而非遭到入侵的笔记本电脑;每个版本都附带 CycloneDX SBOM,让你了解其中包含哪些内容;OpenSSF Scorecard 每周都会针对代码库本身运行。恶意输入测试路径有明确文档记录,而非想当然:请参阅威胁模型和安全白皮书,了解涵盖和不涵盖的内容;在部署中使用它处理恶意输入之前,请自行运行 distil validate,以此作为部署门槛。
为什么值得信赖 📊
在 SWE-bench Lite 上,已发布的路径成本持平,任务成功率相差约 2 个百分点——在 n=300 时,统计上无法区分。
修复 shell 搜索后进行了两轮测试,distil-served 与纯 Claude 的结果:204/299 对比 210/299(−2.0 个百分点,95% CI −5.5..+1.5;成本 $7.18 对比 $7.18),以及 213/298 对比 218/298(−1.7 个百分点,95% CI −5.1..+1.7;成本 $8.44 对比 $8.52)。尚未证明在预注册的 5 个百分点界值下满足非劣效性;长期会话试点(7 项任务)的结果尚无定论。其他所有压缩器均以相同方式在排行榜上评分。报告:低强度 · 中等强度。
研究配置(E8–E14,SWE-bench Verified)见研究页面。它们不是已发布的实现路径,因此这里不会将其中任何一项作为该路径的结果引用。
Distil 的优势——看特性,不看形容词
Headroom 一栏直接对照公开的 headroom-ai 0.37.0 源码;截至 v0.37.0,2026-09-04;其中每一行都引用了该版本中的 file:line。陈述事实,不用形容词;对于它真正擅长的地方,我们也会如实说明。
| 特性 | Distil | Headroom 0.37.0 (2026-09-04) |
|---|---|---|
| 逐请求行为检查 | 配对 A/A′/B 回放、未截断的差值、bootstrap CI、单一报告下限 | 代码库中没有影子或双发路径;accuracy_guard="strict" 会在 /healthz 和 /stats 中回显,但没有任何逻辑会据此分支 |
| 恢复被折叠的内容 | 基于内容寻址的存储 + 面向 Agent 的 distil_expand,字节完全一致,并经门控验证 | TTL 缓存(SQLite、1800s、1000 条 FIFO),没有完整性或往返检查 |
| 无法恢复的有损路径 | 无——每个会输出存根的服务(代理和网关)都会注入并响应 distil_expand | 四种:OpenAI 聊天流式传输、ChatGPT 身份验证下的 Responses、Gemini 流式传输、Bedrock |
| 节省量数值 | 先计数,再根据提供商计费的 usage 进行校准 | 回退到 chars/3.5 |
| 面向编码 Agent 的精确引用保证 | 根据 shell 命令读取来源信息,而不只是工具名称;引用丢失率从 39.3% 降至 16.2% | 该工具不具备此特性 |
| 缓存约定 | 仅限后缀、缓存单调递增,并作为不变量强制执行 | 提示词缓存回放确实很强(overlay_cached_prefix)——是真正的工程成果 |
| 对抗性门控 | CI 中包含 COMA 级测试集;两个未能干净通过的案例已公开 | 未随产品发布 |
| 降级曲线 | 测量每个阶梯档位,离线且免费 | 仅支持单点配置 |
| 已发布的默认行为 | 执行压缩 | 模式为 cache——在 Bedrock 上完全绕过,在 OpenAI 上仅冻结 |
这是离线令牌节省量,不代表成本或任务成功结果:在同一语料上于 2026-09-04 重新运行,并预加载 Headroom 模型后:distil:令牌减少 52.9% / 成本减少 58.7% / 决策等效率 100% / 通过,而 Headroom:1.7% / 2.0% / 81% / 未通过。在读取→编辑→重新读取的编码工作负载中,Headroom 的令牌减少量达到 35.6%,而 distil 的摘要减少量按设计为 0.0%——这正是实现精确引用保证所付出的代价;此页面列出了两个数字,并已提交原始输出。
🚀 立即使用
四条命令。 distil --help 仅显示这些命令;distil --help-all 显示其余命令。
uvx --from distil-llm distil savings # what your agent costs you now — no install, read-only
uv tool install distil-llm
distil setup # detects your agent + billing, wires the status line, tells you what's next
distil wrap -- claude # run your agent through distil
distil savings # spent, saved, daily graph, what to fix next
distil doctor # if anything looks wrong
distil setup 会检测你的环境(Claude Code · Codex · Gemini CLI;按量计费还是订阅制)。也可以直接包装你的 Agent——无需配置,无需更改代码:
# Claude Code on a metered API key — saves real $$:
distil wrap --expand -- claude
# Claude Code on a Pro/Max subscription — flat-rate, ToS-safe (trims context, not $):
distil wrap --lossless-only -- claude
# Codex, Gemini CLI, aider — same pattern; env var auto-selected per agent:
distil wrap --expand -- codex # → OPENAI_BASE_URL (routing unverified: codex-rs reads openai_base_url from its config)
distil wrap --expand -- gemini # → GOOGLE_GEMINI_BASE_URL
distil wrap --expand -- aider # → OPENAI_API_BASE
distil wrap --list # every target, its mechanism, and the agents it can't reach
# Headless too — print mode, CI, and Agent SDK scripts route the same way:
distil wrap -- claude -p "summarise this diff"
distil wrap -- python my_agent_sdk_script.py
使用 Cursor、Cline 编辑器扩展、Windsurf、Zed、Warp 或 Amp?(Cline CLI 不同——
distil wrap -- cline可以接入它。)它们都没有提供distil wrap可以设置的基础 URL 接口——有些根本没有这样的选项,有些选项在结构上无法指向 localhost(Warp 在自己的服务器上运行 Agent,并拒绝私有地址)。运行代理并在工具自身的设置中将其指向代理:docs/IDE-AGENTS.md 列出了所有这些工具,以及核实相关说法时参照的页面和日期。VS Code Copilot 扩展 完全无法重定向,该页面明确说明了这一点,以免你白费时间——GitHub Copilot CLI 是另一款工具,wrap可以接入它。
每个可识别的 Agent 都会自动选择正确的环境变量和上游服务——无需 --env-var 或 --upstream 标志。13 款通过环境变量进行路由(aider / claude / codex / gemini / copilot / goose / grok / kilo / kimi / vibe / opencode / openhands / qwen);5 款完全没有环境变量接口,会通过 wrap 为当前会话管理并在退出时还原的配置文件进行路由(cline / cn / crush / droid / omp)。启动时会打印 preset: <agent> detected → <VAR>。显式指定的标志始终优先。
设为默认 — 不用再输入 distil wrap
厌倦了每次都输入 distil wrap? 只需设置一次,即可设为默认:
distil default # adds a managed shell alias so `claude` always routes through distil
distil default --undo # remove it anytime (backed up before any change)
它会检测你的 Shell(zsh / bash / fish / PowerShell)和计费模式,将正确的配置行写入 Shell 实际读取的 rc 文件,并告知你检测到的内容。想要覆盖所有 SDK(而不只是你输入的 Agent)?distil default --always-on 会运行持久代理服务——功能强大,但它会固定 ANTHROPIC_BASE_URL,因此这台机器上的所有客户端都会经过同一个本地进程。
过去,这种固定设置会造成单点故障:代理哪怕只宕机一秒,都会导致会话因 ConnectionRefused 错误而失败,而错误信息显示的是提供商名称,不是 distil。现在不会了。服务监督程序(launchd/systemd)负责管理监听套接字,因此发生崩溃或重启时,连接会排在内核积压队列中,而不是被拒绝——客户端会等待约一秒,而不是直接失败。distil default --always-on 还会在配置任何内容之前,验证服务确实已注册并正在提供服务;如果没有,就拒绝进行任何配置。
如果你需要退出,而 distil 已经卸载,运行 sh ~/.distil/uninstall.sh 即可,仅使用 sh 移除固定设置、服务和 Shell 配置块。
然后观察你的实际流量带来的真实节省——经过测量,而非估算:
distil savings # billed spend vs saved, daily graph, top fixes (--since 7d / --all / --json)
distil leaderboard # cumulative tokens + $ saved, from the local ledger
distil dashboard # live terminal TUI — token-trim + decision-equiv bars, Ctrl-C to exit
distil dissect # per-session deep-dive: savings, digest inventory, anomalies (--html/--serve)
用你的实际流量验证。 --shadow 会对部分请求执行两次(压缩版和完整版本),并比较 Agent 选择的下一步操作:
distil wrap --shadow 0.1 -- claude # wrap + shadow 10% of requests
distil shadow-stats # live decision-equivalence rate
诚实说明适用范围:这衡量的是下一步操作的等效性——它是一个代理指标,并不代表任务成功(E7 显示,在激进的有损压缩下,这种等效性无法完全保持)。Distil 会安全地回退到完整上下文。
能省钱吗? 对于按量计费(API 密钥)——能减少 Token 数量:在维护者的流量中,账单约减少 9%。在较短的 SWE-bench 任务中,测得净成本不变;长会话试点(7 项任务)的结果尚无定论。有损压缩是否划算,取决于 Agent 是否会采取额外步骤,下一次线上 A/B 测试将对此进行测量。对于固定费用的订阅制,没有按 Token 计费,因此节省的是限流额度空间:每轮 Token 更少,就能在达到时间窗口限制前进行更多轮对话(
distil quota可实时显示)。
💡 Distil 有何不同
你不需要字节级等价,而是需要决策等价:让你的 Agent 在压缩后的上下文中采取相同的行动。这可以衡量,也可以认证。
- 有门控,而非想当然 — 仅当每个请求的决策变化检查在预算范围内时,才会提供有损模式;若无法证明这一点 → 使用完整上下文。目前尚未证明任务级非劣效性(SWE-bench Lite:−1.7 分,95% CI −5.1..+1.7)。
- 能够报告损害的估算器 — 实时检查采用配对统计量,
1{A=B} − 1{A=A'},并提供 bootstrap 95% CI,且不将结果限制为零。旧的比率估算器只要运气好,就会恰好显示 100%,完全无法表示损害。现在,一个报告下限同时控制状态行、证明账本、shadow-stats、普查数据流和公开仪表板——低于下限时会显示低于报告下限,而非一个讨喜的数字。 - 字节精确的引文得以保留,因此
Edit仍然有效 —Edit(old_string=…)会对 Agent 先前读取的字节进行字面匹配;若对该读取内容进行摘要处理,编辑就会悄然无效,而 Agent 仍会报告成功。来源依据 shell 命令(cat、head、sed -n)判定,而不只是工具名称——这是名称规则从未覆盖的工具结果总量的 33.6%。这会牺牲节省量,而变更日志对此明码标价,而不是将其隐瞒。 - 经对抗性门控,并如实说明两项命中问题 —
distil validate --adversarial会通过代理所用的同一公开路径运行 7 个 COMA 类案例。可信/不可信预算隔离是结构性的:任何地方都不存在块之间共享的保留预算,并在 CI 中通过相等性断言验证。我们公开而非掩盖的两项结果:去重诱饵确实会折叠真实错误行(靠可逆性挽救);诱饵判定泛滥则是一个真实且未缓解的节省量拒绝服务——该块的节省量为 0.0%。 - 测量整个调节范围,而不只是默认值 —
distil bench --curve会报告每个档位的节省量、事实召回率、可见召回率、丢失事实和可逆性,离线运行且免费。 - 可自行运行的任务级界限 —
distil certify-trajectories会根据你匹配的评估结果,界定压缩可能导致多少个可解任务失败。在我们自己的 SWE-bench 运行中,该界限目前仍未达到 5 分的边际要求。 - 可逆,而非有损 — 将摘要存放在句柄后,保留原文,并向 Agent 提供
distil_expand工具。放心压缩。 - 保留答案,折叠噪声 — 按内容类型制定的保留策略会固定每类内容的关键行(日志的通过/失败判定、回溯的堆栈帧、差异的块标题);重复的近似错误信息会去重,而在运行结果为绿色时,去重会进一步加强,因为这些噪声并未导致失败。
- 感知查询——保留你实际询问的那一行 — distil 是一个代理,因此它能在同一个请求中同时看到 Agent 的意图(其 tool_use 参数及最新提问)和输出。与搜索内容匹配的行(grep 命中、配置值、SHA)即使出现在任意输出中也会被固定——这是附加操作,不影响可逆性和证书。事后压缩器无法获得这种查询与输出的配对信息。它还具备语义能力,并且始终启用:一个零依赖桥接层——词形分析、精选技术同义词映射和字符三元组模糊匹配——会固定那些能回答查询、但与查询没有共同词语的行。询问“重试限制是多少?”时,它会保留
max_attempts = 5;询问“连接超时是多少?”时,它会保留deadline_ms。另外两层从你自己的流量中成长,而非来自随产品发布的内容:关联关系由 distil 从其不含内容的扩展飞轮(哈希对、--expand会话)中学习;学习所得的相关性模型只有在你标注的数据上,其留出集召回率超过词法基线后才会晋升——晋升之前,实际运行的恰好就是词法层 + 桥接层。也可以提供一个可选的分布式向量表(纯 Python 余弦相似度;不随产品提供)。每一层都是附加的——只会扩大保留范围,因此不影响可逆性和证书——而且无需嵌入或模型即可运行。 - 固定费率套餐下也能无损处理 — 订阅/无损模式不只是原样输出:它会压缩 JSON、折叠重复片段,并将表格形式的工具输出折叠为紧凑且自描述的表格(符合服务条款,不做有损摘要)。近期工具输出保持字节精确。请明确其规模:无损节省取决于内容形态,而在 distil 自己的评估语料中——没有 JSON,也没有重复行——节省量为 0.00%(E15b)。
- 准确查看发生了什么 —
distil dissect会将一次封装会话转换为报告:按模型/机制统计的节省量、摘要清单、计费使用量校准、各路径延迟,以及一份能自动捕捉静默故障的值得关注异常清单。 - 效果会累积 — 扩展和匹配到的失败会教会策略应该保护什么(仅使用特征签名,绝不使用内容),并且只会让策略更加保守。
- 重读只为变化部分付费,而非为重读部分付费 — 编码 Agent 会不断重读同一个文件(在 2,489 个测量会话中,占读取的 51.4%),但几乎从不在相同偏移处读取,因此块级去重无法奏效。Distil 按行匹配:新读取内容与仍在上下文中的较早读取内容共有的连续行会变成可逆引用,其余内容保持字节精确,最新读取内容则绝不触碰。它在精确引文保证的范围内运行——这是唯一能从 distil 承诺原样保留的内容中重新获得节省量的转换——同时也保持安全,因为
Edit的old_string只需在转发载荷中的某处以字节精确形式存在。→ ADR 0010 - 流式传输,仿佛它并不存在 — SSE 按块中继;保留 TTFT——包括可恢复摘要,它会进行推测式流传输,只在流中途遇到实际的
distil_expand调用时拦截,并在不缓冲整个轮次的情况下插入恢复内容(可逆层不会增加 TTFT)。
**保真等级:**无损(
--verbatim)· 可逆(按需可恢复字节 — 默认)· 有损(其他所有工具)。Distil 的可逆等级受其逐请求决策变更检查限制,且恢复面向 Agent——模型会在任务中途展开内容(Headroom 提供检索功能,没有此类限制)。两者都没有证据表明能在任务结果上节省成本。
⚡ 无需 API 密钥,亲自验证这些数据
别盲目相信上面的表格。distil bench 会在捆绑的 8 个领域语料库上离线重新认证节省效果 和 决策等效性,只需几秒——这与 CI 中运行的检查相同。我们如何评估,以及为什么没有任务成功率变化数据的压缩率毫无意义,已记录在 docs/EVALUATION.md 中,其中也包括我们自己的负面结果:
uvx --from distil-llm distil bench # certify savings + quality across 9 domains, in seconds
distil verify # byte-fidelity: every compression is exactly reversible
distil validate # adversarial real-path gate: invariants on hostile inputs
distil retention # fact recall: what stays visible vs expand-recoverable
distil retention --dataset hotpotqa # graded against a PUBLIC benchmark's ground truth
distil fidelity # state probes: artifact state, overclaim, continuation
CI 中共有五项检查:bench(语料库上的非劣效性)、verify(字节保真度)、retention(事实级召回率)、fidelity(状态探测,见下文),以及 validate——它会用 对抗性 输入(超大内容/Unicode/嵌套/格式错误/标记注入/看似机密的内容)测试压缩器,并断言可逆性、变大时拒绝压缩、近期内容精确保留、故障时放行以及不含内容的遥测在每种情况下都成立。设置最后这项检查,是因为单元测试套件全绿的同时,真实流量中仍不断出现问题;validate 这一对抗性层正是为捕获这些问题而设。
召回率还不够,下面的案例足以证明这一点。 一段轨迹在第 2 轮创建 net/scratch_bench.py,并在第 4 轮将其删除。压缩掉第 4 轮后,所有路径标记仍然存在——字符串召回率显示为 100%——但此时 Agent 会误以为文件仍然存在,并据此制定计划。distil fidelity 会将工具调用汇总到文件状态台账中,并评估 最终状态,区分 lost(路径消失——Agent 能察觉缺失)和 stale(路径仍在,状态有误——Agent 会确信错误信息并据此行动)。在该案例中:字符串召回率为 100%,状态保真度为 0%。
它还报告了召回率看不到的另外三项:过度断言("approximately 4200 ms" → "4200 ms"——数值保留了,不确定性却消失了)、延续性(Agent 是否仍知道接下来要做什么?)以及错误传播(第 k 轮的损失是否会在第 k+n 轮表现为行为变化?)。门禁只针对静默失败——CI 运行 --max-silent 15——因为明显的损失已经由 retention --max-lost 负责,而对同一回归设置两道门禁会让人看不清究竟是哪项属性出了问题。界限依据的是实测值,而不是零:Tier-1 摘要会将带保留句柄的模糊表述隐藏起来,并在 171 条主张中有 9 条丢弃限定语,因此将门禁设为零,就等于断言压缩器并不具备的属性。此外,distil suite 还会评测十二项公开基准测试,其答案由其他人编写——包括 BFCL,它会压缩工具架构,并检查黄金调用所需的每个名称——函数和每个参数——是否都保留下来。在 91.4% 的节省率下,distil 保留了黄金调用所需的所有名称(原始数据)——但这些名称都不可见:架构位于恢复句柄之后,只需一次 distil_expand 即可展开。测试套件会显示这一差距(visible → true support: bfcl 0%→100%),而不只是展示那个讨喜的数字,因为如果读者以为模型能看到一个实际上必须先展开的架构,那么即便每个数字单独看都正确,也会造成误导。名称按标识符匹配——带引号的 JSON 词元,允许转义——而非按散文匹配:通用匹配器曾意外地将 85 条黄金记录中的 11 条计为匹配('a' 匹配到了 "tool-schemas" 中的内容)。BFCL 确实命名 a、b、c 的 15 条黄金记录会被排除并计数,因为一个单字母词元既无法诚实地计为匹配,也无法诚实地计为失败。每一行都标记为 rich 或 thin 负载,因为没有可压缩内容的基准测试只是对照组,而非证据;只评测对照组的运行会以状态码 1 退出。它不需要 API 密钥,也不产生费用,因此已接入 make gate 和 CI 门禁任务,而不是在发布前运行。完整的方法说明,包括这些探测发现我们自己的语料库有哪些问题,见 docs/EVALUATION.md §6;如何运行所有评测,见 docs/RUNNING-EVALS.md。
召回率,以及一个你可以亲自核验的数字。 上述三道门禁都是用我们的语料库对照我们的判定标准进行评测的——虽然严谨,但你无法自行核验。distil retention --dataset hotpotqa 则对照由他人编写的真实答案进行评测(HotpotQA 的黄金支持句,夹在 8 段干扰段落中),并与一个针对同一案例、按 distil 自身节省率调优的截断基线进行比较:
| HotpotQA,n=100(原始数据) | 节省率 | 答案召回率 | 黄金句召回率 |
|---|---|---|---|
| distil(可逆) | 14.3% | 100.0% | 100.0% |
| 截断 @ 匹配节省率 | 14.1% | 91.6% | 82.7% |
distil retention 还会将召回率拆分为可见(位于模型面前)和可恢复(只需一次 distil_expand,并通过句柄的恢复字节验证)。在该语料库上,真实召回率为 100%,丢失数为 0;与有损方式相比,可逆方式带来的召回率优势为 23.1%——这是全部 9 个领域的平均值,每个领域各计一次(原始数据)。这里特意采用宏平均:按事实加权的平均值为 62.3%,但它由探测数量最多的领域决定;曾经有一个 HTML 样例在压缩器完全没变的情况下,就让这个数字波动了 50 多个百分点——这就是护城河,体现为测量结果,而非争论。distil retention --live 会对你自己的流量报告相同的指标;计量器只存储计数,绝不存储内容。
它还发现了一个真正的漏洞。 召回测试工具首先发现的不是回归问题,而是能力缺失:distil 对 HTML 工具结果的压缩率为 0.0%——缩小后的标记只有一行,因此无行可折叠。使用抓取或浏览器工具的 Agent 只能为 <script>、<style> 和导航栏等内容支付全额成本。现在,Wikipedia 文章和 Python 文档页面的大部分内容都能被压缩,且 0 条事实丢失。(在两个页面上进行了测量;该次运行的输出未提交,因此此处不提供压缩百分比。)
可逆性是有损提取器无法提供的:精确的原始内容会保留在句柄后,因此启发式判断失误时,只需调用一次 distil_expand,而不是丢失内容。
具体来说,每一层能够证明什么:每次提交的门禁会针对已提交语料库中的离线确定性预言机,评估决策等价性(速度快、免费、每次推送都会运行——但数据是合成的)。每晚运行的 live-cert 作业会使用真实模型重新认证相同轨迹(distil certify --runner anthropic),并设置预算上限和硬性 --max-live-calls 上限,确保无人值守运行绝不会在不知情的情况下产生费用。上述实证结果(SWE-bench n=500,实时正面对比 n=200)由真实模型评估;仅凭每次提交的徽章并不能证明这一点。
谁来评估实时运行。 自 1.56.0 起,默认的实时认证器为 claude-sonnet-5-5,并使用 effort=low(--effort 是 certify、eval、benchmark、frontier 和 conformal 的标志)。这是通过基于真实 τ-bench 流量进行的预注册配对模型迁移评估选出的:它通过了所有门禁,包括相较于 claude-opus-4-8,质量下限不低于 −5 分;每个案例的成本还低了 57.5%。上文较早的实时结果由 claude-opus-4-8 评估,仍按此标注。
选择或迁移实时认证器。 评估器本身也是一个变量,因此更换评估器应基于测量结果作出,而不是简单地切换标志。使用 --model 按运行指定模型(用于 certify 时,在 --runner anthropic 下覆盖轨迹的模型),并使用 --effort low|medium|high|xhigh|max;默认值为 claude-sonnet-5-5 和 low。若要让新模型通过相对于现有模型的资格认证,请使用相同案例,并在留出的轮次上进行配对比较:
python benchmarks/model_migration_eval.py --fetch-tau-bench # pinned, sha256-verified real traces
python benchmarks/model_migration_eval.py --cases real --flow .claude/hillclimb/decision-equivalence-real \
--variant baseline --model claude-opus-4-8 --reps 4 # incumbent
python benchmarks/model_migration_eval.py --cases real --flow .claude/hillclimb/decision-equivalence-real \
--variant v5 --model <new-model> --effort low --reps 4 # candidate
python benchmarks/model_migration_eval.py --status # cross-variant table
python benchmarks/model_migration_summary.py # paired CIs -> benchmarks/results/model-migration/summary.json
实时运行会产生费用;先添加 --fake oracle,离线检查配置是否正确。门禁、表格及其他命令: 模型迁移(docs/ab.html#model-migration)。决策记录:ADR 0020(默认认证器)和 ADR 0021(服务路径认证)。
编码流量中的一项未解决风险。 已认证的 distil 策略只摘要最新的工具输出,在真实 SWE-agent 轨迹上节省 2.6% 的 token;服务适配器则会摘要所有更早的工具输出,节省 52.6%,因此大部分实际提供的字节都未经认证。现在,distil certify --strategy served 会评估真实适配器,其首个结果并非通过:启用恢复后,在留出的编码决策中,它有 78.0% 能保留下一步操作;两次内容相同的未压缩调用则为 94.1%。这是否会导致解决的任务变少,要由 SWE-bench 结果评估来验证(规范,benchmarks/swebench_outcome/);在全部 300 个 SWE-bench Lite 任务上(报告),两个 Agent 均使用提示词缓存时,distil 服务版 Agent 在 299 个配对任务中解决了 201 个,普通 Agent 则解决了 210 个:相差 −3.0 个百分点(95% CI −6.4 至 +0.4,McNemar p = 0.12)。这并未证明其在预注册的 5 个百分点界值内不劣,而且该结果取代了此前一轮勉强通过的 100 任务测试。服务版的成本还高出 12.4%,步骤数多出 29.9%。离线重放压缩过程揭示了原因:distil 摘要了 Agent 大部分 shell grep 输出,也就是它用来定位内容的索引;于是 Agent 又重新搜索、读取,而不是调用 distil_expand。distil 已会原样保留 Grep 工具的输出,但通过 bash 执行的同一搜索却不会;现在两者都会保留。修复后重新运行 distil 测试组(报告),惩罚消失:相较普通版本,步骤数增幅从 +29.9% 降至 +3.1%,成本则降至持平。但任务成功率仍未得到证明:299 个任务中解决了 204 个,普通版本为 210 个(相差 −2.0 个百分点,95% CI −5.5 至 +1.5),仍略超界值。更高投入下的第二轮测试(报告)也显示出相同趋势。对于编码 Agent,应将服务路径视为成本持平,但任务成功率尚未得到验证;在长会话中,一项 7 任务试点的结果尚无定论(运行记录)。方法、表格和重跑命令:模型迁移;所有使用的数据集及其来源和固定版本:EVALUATION.md §6.9。
domain trajectory $ saved distil aggr pruned
---------------------------------------------------------------------------
ops/sre sre-disk-incident 32.8% PASS FAIL 615
coding coding-bugfix 25.5% PASS FAIL 736
support support-refund 32.6% PASS FAIL 765
research research-synthesis 25.7% PASS FAIL 809
data-analysis data-analysis-sql 18.1% PASS FAIL 965
devops devops-rollback 22.8% PASS FAIL 857
finance finance-reconcile 24.9% PASS FAIL 1014
web-research web-research 89.8% PASS FAIL 428
agent-worklog agent-worklog 35.3% PASS FAIL 891
---------------------------------------------------------------------------
aggregate: distil cuts $0.24052 -> $0.12400 (48.4% cheaper) reversibly; 7080 tokens causally prunable.
GATE: PASS — every trajectory certified non-inferior; aggressive rejected on all.
为什么值得信任? token 节省量很容易造假——在低压缩率下测量质量,却在高压缩率下宣传节省量。Distil 不会这样做:准确率和压缩率在同一批轨迹上测量,无法通过非劣效检验的策略不会发布。
distil certify --strategy distil # VERDICT: PASS (100% decision-equivalence) distil certify --strategy aggressive # VERDICT: FAIL (mean diff −1.0, blocked)
distil eval 会绘制已认证压缩前沿——一条展示节省量与质量关系的曲线,其中每个点都带有认证判定,可找出有损压缩开始导致决策减少的临界点。没有竞争对手发布过的产物:benchmark.html。
📊 证据
三项结果,均可复现,且均已发布并注明注意事项:
-
与真实的
llmlingua/headroom-ai正面对比(来自benchmarks/gen_realworld.py的固定种子 120 轮语料,由claude-opus-4-8评分;2026-07-05,distil 1.10.1 对比 llmlingua 0.2.2 和 headroom-ai 0.27.0):节省 83.2%,决策变化率为 0%,速度快约 1,000 倍(无需加载 ML 模型,而竞品需要本地运行 Transformer 推理)。实时代理行为由tests/test_live_certified_equivalence.py固定为通过认证的策略;唯一经审查的差异是一个近期内容例外机制,会原样保留最新的工具结果轮次(Agent 需要其最新输出逐字节准确)。自 1.45 版起,该例外机制仅适用于提供商尚未缓存的内容——以客户端的cache_control断点为锚点;对于会隐式缓存的提供商,则完全取消该机制。按对话末尾回溯计算的例外范围会随着对话增长而向前滑动,导致已缓存内容在后一轮被改写,重计费的前缀成本高于摘要节省的成本。→ 基准测试 -
E7(SWE-bench Verified): 激进的有损压缩会让任务成功率骤降(52% → 16%)——单步证书无法迁移到多轮场景。可逆层级则经受住了考验(56% 对比 52%)。我们发布这一结果,因为它是真实的。→ E7
-
SWE-bench Lite,已发布路径(n=300,运行两次): 成本持平,任务成功率相差约 2 个百分点(−2.0 个百分点,95% CI −5.5..+1.5;−1.7 个百分点,95% CI −5.1..+1.7)——无法在统计上区分,且未证明在 5 个百分点的界限下满足非劣效性。→ 报告。研究配置(E8–E14,SWE-bench Verified)见研究页面,并非已发布路径。
-
与其他压缩器正面对比(SWE-bench Lite,298 项任务;长时程试点,7 项任务): 成功率见排行榜;RTK 是唯一被证明在成功率上满足非劣效性的组别;在移除该轮次中共享提示词缓存这一混杂因素后,没有任何组别被证明成本更低(RTK 每项任务 −6.5% [−13.1%,+0.1%],不显著)。长时程试点未显示成本差异。→ 成本混杂因素 · 原因
完整方法、McNemar 检验和逐实例数据:docs/PAPER.md · PDF。
📡 查看实际效果
基于你自己的流量测量,不做估算,数据绝不离开你的设备:
- 每个请求:
x-distil-*响应头(tokens-saved、mode、compressible-tokens、expanded)。 - 每台机器:
distil leaderboard(使用--html生成页面)。 - 影子模式:
distil proxy --shadow 0.05会报告实时决策变更率,并能感知流式传输。 - 你仍在浪费的部分:
distil discover会汇总近期会话,并按影响排序,找出仍在产生开销的项目——每个请求都要重新发送的工具/MCP 定义、定义随每轮请求一同发送却从未调用的 MCP 服务、从未进入摘要层级的会话、不断变化并导致重复计费的缓存前缀、服务提供商尚未折扣的重新折叠开销,以及不断变长的系统提示词。每项操作都会列出每周可节省的令牌数和金额、该数字的计算依据,以及可采取操作的命令或设置。它会在最佳会话旁边显示每个会话节省量的中位数和 p10/p90,因此不会把最佳情况误当成典型情况;同时采用你自己的账本测得的费率——只有当这台机器从未运行过相应模式时,才会回退到已发布的基准比率,并在对应行中明确说明。无法测量的检测器不会输出结果,因此“没有建议”意味着确实没有可推荐的内容,而不是没有进行检查。 - **整个组织:**将
distil proxy作为边车运行,并设置一次ANTHROPIC_BASE_URL;所有客户端都会通过它路由。 - 社区:可选择加入的普查(
distil census on)会分享仅包含数字的汇总数据——同意前,可用distil census show预览确切的载荷;冻结的架构见TELEMETRY.md。默认情况下仍不会发送任何内容。
仪表板、状态栏插件、联邦排行榜:部署与可观测性。
🔌 适用于所有 SDK
一个代理。让任何遵循 base_url 的客户端指向它——Python、TypeScript 或任何语言——即可获得具备缓存感知能力的可逆压缩,无需修改代码。
distil proxy --upstream https://api.anthropic.com # localhost:8788
// JS/TS: npm i distil-llm → helper so you don't hardcode the URL
import Anthropic from "@anthropic-ai/sdk";
import { distilBaseURL } from "distil-llm";
const client = new Anthropic({ baseURL: distilBaseURL() });
| SDK / 框架 | 修改方式 | 示例 |
|---|---|---|
| Anthropic SDK (Py/TS) | base_url="http://127.0.0.1:8788" | examples/python_anthropic.py · examples/js_anthropic.ts |
Claude Agent SDK / claude -p(无头模式) | distil wrap -- <cmd> 或 ANTHROPIC_BASE_URL | examples/python_claude_agent_sdk.py |
| OpenAI SDK(Chat + Responses) | base_url="http://127.0.0.1:8788/v1" | examples/python_openai.py |
| Vercel AI SDK | createAnthropic({ baseURL: '…:8788' }) — 或在进程内使用:wrapLanguageModel({ model, middleware: distilMiddleware() }) | examples/js_vercel_ai_sdk.ts |
| LangChain (py/js) · LangGraph | anthropicApiUrl / base URL · pre_model_hook | examples/js_langchain.ts |
| LiteLLM | api_base="http://127.0.0.1:8788" | examples/python_litellm.py |
| Google Gemini | --upstream https://generativelanguage.googleapis.com | examples/python_gemini.py |
Codex · aider · OpenCode · Qwen Code · 任何 base_url 客户端 | distil wrap -- <agent>(会为各 Agent 选择正确的变量)或 OPENAI_BASE_URL | — |
任何支持 Anthropic / OpenAI / Gemini 线路格式的工具都能使用——该代理与框架无关,因此 CrewAI、AutoGen、LlamaIndex、Agno、Strands、Bedrock 等都可以通过将客户端的 base URL 指向 distil 来接入,无需其他改动。
更倾向于在进程内使用?直接包装客户端——同样无需修改调用位置:
from distil.adapters.anthropic import wrap
client = wrap(anthropic.Anthropic()) # compresses the request, keeps the cache warm
(OpenAI——Chat Completions 和 Responses API——以及 Gemini 都通过代理接入:distil wrap -- codex,或将 OPENAI_BASE_URL 指向代理。只有 Anthropic SDK 提供进程内客户端包装方式。)
框架钩子(无需代理,也无需网络跳转)——对于自行管理消息列表的 Agent 框架,可在消息所在位置进行压缩:
| 框架 | 钩子 | 示例 |
|---|---|---|
| LiteLLM | distil.integrations.litellm.compress(kwargs) | examples/python_litellm.py |
| LangChain | distil.integrations.langchain.compress_messages(msgs) | — |
| LangGraph | pre_model_hook=pre_model_hook()(在模型节点执行前压缩图状态) | examples/python_langgraph.py |
| Agno | distil.integrations.agno.compressed_model(model) | — |
| Strands | distil.integrations.strands.compressing_hook() | — |
| LlamaIndex | DistilNodePostprocessor()(节点后处理器)· DistilLLM(llm) · compressing_tool(fn) | integrations.html#llamaindex-page |
LangChain / LangGraph — langchain-distil
已列入 LangChain 自己的社区中间件集成。如果你从那里过来,这就是要安装的包:
pip install langchain-distil
from langchain_distil import compress_messages, pre_model_hook, as_runnable
msgs = compress_messages(msgs) # compress a message list in place of the call
graph = create_react_agent(..., pre_model_hook=pre_model_hook()) # LangGraph: before the model node
chain = as_runnable() | llm # or drop it into a chain (lazy langchain-core import)
工具和函数消息会获得可逆的 Tier-1 摘要,人类和系统消息采用无损的 Tier-0 处理,而助手消息绝不会被改写——模型自己的措辞不由 distil 擅自修改。每个摘要都能按字节精确还原。无法使用恢复工具时,可传入 verbatim=True,仅使用 Tier-0。
这是对上表钩子的轻量封装,因此继承了同一条经过认证的压缩路径——不会重复实现任何功能。distil-llm 是依赖项;无需手动同时安装两者。
🎟️ 订阅 — 节省限额窗口,而非账单
使用固定费率的 Pro/Max 套餐时,没有按 Token 计费的账单可供削减,因此 distil 显示的金额只是估算值。限流窗口却不是估算的:花在 40 KB 测试日志上的 Token,会占用配额,导致下一个任务可用的配额减少。
代理在这里帮不上多少忙。Anthropic 的消费者条款(§3,第 7 项)限制使用订阅凭据自动访问,因此 distil 会在此类场景中有意运行 --lossless-only,而这对大多数流量几乎毫无节省(在 distil 自有语料上的节省为 0.00%,E15b)。你的账户不值得为了几个百分点冒险。
PostToolUse Hook 是另一种机制——一种有文档说明的第一方扩展点。Claude
Code 会在自己的进程中、模型读取工具输出前,对其进行压缩:
distil hook --install # writes ~/.claude/settings.json (idempotent, preserves your other hooks)
distil hook --selftest # verify the schema adapters — a live mismatch is SILENT
distil quota # the window it buys back
$ distil quota
Subscription quota (the currency a flat-rate plan actually spends):
five_hour [########............] 43.0% used resets 2026-08-16 15:49Z
seven_day [....................] 4.0% used resets 2026-08-23 07:59Z
单次会话观察,并非基准测试:在一个任务上进行了一次实时配对 A/B 测试,两组都正确作答,读取的 tool_result 减少了 −38.6%,cache_creation 减少了 −67.4%,按成本加权后减少了 −68.3%
(原始数据);另外五个可验证任务的结果也一致,达到 5/5 (原始数据)——足以发现明显退化,但不足以验证具体比率。关键的是,cache_read 并未大幅下降——Hook 每次只会看到一次结果,无法改写历史记录,因此压缩从机制上就是只追加,提示词缓存也能保留。
无法节省的场景。 Tier-0 会压缩 JSON 并合并连续重复行,因此节省效果取决于内容结构:冗长的 JSON(npm/pip/kubectl/terraform)可节省 28–33%,重复日志行最高可达 99%,而唯一行日志、散文、git log 和 git diff 则为 0%。在 distil 自有评测语料上的节省为 0.00%——该语料没有 JSON,也没有连续重复项。我们仍公布这一结果,因为只引用有利的样例,正是我们批评他人时所说的夸大宣传。
其他 Agent:Gemini CLI 的
AfterTool可以间接影响输出(正在评估);Codex CLI 的 Hook 只能观察,并且会拒绝重写输出,因此在上游就被阻止。
🧠 MCP 服务 — 为你的 Agent 提供一个召回工具
Distil 提供 Model Context Protocol 服务,让 Agent 可以压缩自己的工具输出,并在之后取回完全相同的字节。零依赖(通过 stdlib 使用基于 stdio 的 JSON-RPC,无需 SDK),完全本地运行——内容不会离开你的设备。
只需一行即可添加:
claude mcp add distil -- distil mcp
Claude Desktop · Cursor · Windsurf · VS Code — 所有平台使用相同的 JSON 配置
{
"mcpServers": {
"distil": { "command": "distil", "args": ["mcp"] }
}
}
还没安装 distil?直接从 PyPI 运行,无需安装:
{
"mcpServers": {
"distil": { "command": "uvx", "args": ["--from", "distil-llm", "distil", "mcp"] }
}
}
配置文件位于 ~/Library/Application Support/Claude/claude_desktop_config.json(Claude Desktop,
macOS)、.cursor/mcp.json(Cursor)或 .vscode/mcp.json(VS Code)。编辑后请重启客户端。
验证服务是否已启动——无需客户端:
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | distil mcp
三个工具
| 工具 | 功能 | Agent 会在何时使用 |
|---|---|---|
distil_compress(text) | 返回精简摘要和一个 8 位十六进制句柄;在本地存储原文(加密,0600) | 某个工具返回了大量内容,逐字传递会造成浪费 |
distil_expand(handle) | 返回精确的原始字节,而非摘要 | 摘要遗漏了它现在需要的细节:一行内容、一个值或一个堆栈帧 |
distil_savings() | 根据本地账本累计的 Token 数/金额节省情况 | 你想问“distil 帮我省了多少?” |
每个工具都带有注解(readOnlyHint、idempotentHint、openWorldHint: false),因此,行为良好的客户端无需从说明文字中猜测,就能知道 distil_expand 是安全、可重复的离线读取操作。
这是回溯路径,而非节省路径。 MCP 服务不会压缩 Agent 的流量——
distil wrap -- <agent>会透明地完成这项工作,无需调用工具。MCP 服务补充的是另一半:任何 Agent,包括未经过封装的 Agent,都可以对上下文中看到的句柄调用distil_expand,取回原文。句柄会跨会话和进程保留,并在DISTIL_RESTORE_TTL_DAYS指定的天数后过期(默认为 14)。
🗜️ MCP 压缩器 — 缩减其他服务的工具和结果
带子命令的 distil mcp 是一个透明代理,位于你其他 MCP 服务的前端,可供 Codex、Cursor、Gemini CLI、opencode、Claude Desktop、Windsurf 和自定义 Agent 使用。(Claude Code 自带的工具搜索已会延迟加载未使用的工具——详见 ADR 0017。)
distil mcp wrap -- npx -y @modelcontextprotocol/server-filesystem ~/work # one server
distil mcp serve --config mcp.json # every stdio server in an mcpServers file
distil mcp install cursor # route Cursor's servers through distil (…--undo restores byte-exact)
distil mcp watch # per-tool: tokens before→after, unlocks, fetches, expands
各级别定义明确:L0 无损模式规范化(已启用),L1 抽取式摘要,L2 延迟加载,在获取工具架构后展示实际工具(而非始终使用通用的 invoke),L3 在 L2 基础上加入根据使用情况学习到的固定项,R 可恢复的结果摘要,并提供 <server>_expand 工具(使用 --results)。预注册准确性协议的首次实测运行(claude-haiku-4-5,每个级别 1,000 个工具任务)验证了所有级别:工具及参数选择正确率从原始工具列表的 91.2% 提升至 L0–L3 的 92.1% / 95.4% / 96.3% / 95.4%,而 R 针对结果的问题回答正确率为 99.5%,原始结果为 99.7%。在复现模型完成运行前,L1–L3 和 R 均保持为可选功能。由于短索引未命中提示词缓存,L2 在此次运行中的计费高于原始模式。详情见 docs/mcp.html。
📦 按需安装
初次使用? 运行 uv tool install distil-llm,然后运行 distil setup——它会为你完成配置并提供引导(见立即使用)。想先看看它的实际效果?运行 distil bench,约 10 秒即可通过认证门槛测试,且无需 API 密钥。下方矩阵用于选择安装格式——其中的每种格式都是替代方案,而非必需项。
安装注意事项与故障排除(包名称、旧版 Python 错误、过时的镜像)
⚠️ 唯一需要注意的地方——名称。 PyPI 上的软件包名为
distil-llm,但命令名是distil(裸名称已被占用)。因此,运行pipx install distil-llm后,使用distil …。pip install distil安装的是其他软件包。
🔧 遇到
Could not find a version that satisfies the requirement distil-llm (from versions: none)? 这个软件包确实已发布到 PyPI——出现此错误意味着你的pip/pipx使用的 Python 版本低于该软件包要求的最低版本,因此 pip 会过滤掉所有发行版。Distil 现在支持 Python 3.9+(macOS 附带的版本),使用当前版本即可顺利安装;如果你在非常旧的 Python 上仍遇到此问题,可以让 uv 为你安装 Python:uvx --python 3.12 --from distil-llm distil bench(或uv tool install --python 3.12 distil-llm)。运行python3 --version查看当前版本。 🔧 拿到的是旧版本(例如0.25.1),而不是最新版本? 公共 PyPI 始终提供最新版本(pip index versions distil-llm会列出这些版本)。如果拿到的是较旧版本,说明你的pip/pipx没有从公共 PyPI 解析——几乎总是因为过时的内部镜像(尚未同步最新版本的 Artifactory / CodeArtifact / Nexus——发布后不久很常见),或者 constraints 文件 /pip.conf中设置了<1.0版本固定。诊断并修复:pip index versions distil-llm # 只显示到旧版本?→ 你的索引/镜像已过时 pip config list ; env | grep -i pip # 查找 index-url 或 PIP_CONSTRAINT 固定 # 立即解除阻碍——强制使用公共 PyPI: pipx install --pip-args="--index-url https://pypi.org/simple/" distil-llm # (或者,如果必须使用镜像,请联系平台团队同步 distil-llm;上游已有此包)
| 格式 | 命令 | 前置条件 |
|---|---|---|
| 单行安装程序 | curl -LsSf https://dshakes.github.io/distil/install.sh | sh · Windows:powershell -ExecutionPolicy ByPass -c "irm https://dshakes.github.io/distil/install.ps1 | iex" | 无——如果缺少 uv,会先安装,然后执行下一行 |
| uv 工具 | uv tool install distil-llm → distil setup | uv——自动配置 Python 3.9+ |
| 零安装 | uvx --from distil-llm distil bench | uv——自动配置 Python 3.9+ |
| 隔离式 CLI | pipx install distil-llm → distil bench | Python 3.9+(否则使用 pipx install --python python3.12 distil-llm) |
| Homebrew | brew install dshakes/tap/distil | Homebrew |
| Docker | docker run ghcr.io/dshakes/distil:latest bench(或 docker build -t distil .) | Docker |
| 单文件 | make pyz → python dist/distil.pyz bench | Python 3.9+ |
| 在 venv 中 | pip install distil-llm(在已激活的虚拟环境中) | Python 3.9+ |
| Node / JS / TS | npx distil-llm wrap -- <agent> · npm i distil-llm,用于 baseURL 辅助函数 | Node 18+(通过 uv/pipx 调用 Python) |
导入包和 CLI 名称为
distil;PyPI 发行包名为distil-llm(distil这个名称已被占用——因此uvx/pip必须引用distil-llm,而不是distil)。Distil 是一个 CLI:请隔离安装(pipx/uv/brew/Docker),因为现代 macOS/Linux 会阻止系统范围的pip install(PEP 668)。**Node / JS / TS:**使用npx distil-llm wrap -- <agent>(npm 包会调用 CLI),或使用npm i distil-llm获取distilBaseURL()辅助函数,以便将任意 SDK 指向代理——也可以直接自行设置base_url。
🧰 速查表
| 目标 | 命令 |
|---|---|
| 设置 + 引导式介绍(从这里开始) | distil onboard |
将 distil 设为默认(无需在每个会话中使用 wrap) | distil default · 撤销:distil default --undo |
| 移除 distil 留下的痕迹(卸载前) | distil offboard · 同时清除数据:distil offboard --purge |
| 诊断设置(账本、影子、代理自检、连线) | distil doctor |
| 将节省状态行接入 Claude Code | distil setup(紧凑片段:DISTIL_STATUSLINE=minimal) |
| 查看实际节省额的累积情况 | distil leaderboard · 实时 TUI:distil dashboard |
| 退出时显示会话摘要(令牌、费用、影子、可恢复性) | distil wrap 自动打印 — 使用 DISTIL_NO_LEDGER=1 可选择退出 |
| 深入分析单个会话(节省额、异常) | distil dissect(--html / --serve) |
| 查看仍可节省的部分 | distil discover(--since 7 / --json) |
| 在真实流量上实时验证决策等效性 | distil wrap --shadow 0.1 -- claude → distil shadow-stats |
| 在你自己的领域进行认证 | distil research ingest --input prod.jsonl --out ./mycorpus → distil research conformal --corpus ./mycorpus |
| 从任何 Agent 中恢复已消化的细节(MCP) | distil mcp |
| 自我改进的保留策略 | distil research learn / distil research online |
| 在源头调整测试运行的输出 | distil sh -- pytest -q · Claude Code:distil hook install --shell |
| 根据 Claude Code / Codex / Gemini CLI 记录查看 distil 本可节省的费用 | distil savings(无需安装:uvx --from distil-llm distil savings) |
| 开发者侧研究和 CI 检查门禁(基准测试、认证、验证、校验等) | distil research <command>(distil research --help) |
状态栏 — 所有状态使用同一种格式:
distil · <live> · total ▼<lifetime>。
状态 显示内容 含义 保存中 distil · ⬢ digest · ▼12.0K · 40% smaller · $0.31 · total ▼27.0M · de 99%正在压缩(模式标签: ⬢ digest·◇ lossless·▪ verbatim;de= 决策等效性)监视中 distil · ✓ on · waiting for a large read · total ▼27.0M已启用,但尚无大型内容 — 节省量来自大型文件/命令输出 空闲 distil · ✓ on · total ▼27.0M已设置并启用,近期没有流量 未路由 distil · off — session not routed · total ▼27.0M此会话的请求直接发送给提供方 — 使用 distil wrap(或始终启用的环境变量)启动,以进行压缩绕过中 distil · ⚠ wrapped, agent bypassing proxy · total ▼27.0Mwrap 已启动,但 3 分钟以上没有请求到达其代理 — Agent 固定使用了自己的端点。修复方法:重启 wrap。 这种情况主要出现在 claude.ai-subscription(OAuth)会话中;通过自定义基础 URL 路由这些请求的方式在上游没有文档说明,而且会话偶尔会忽略该设置。如果问题持续存在, scripts/soak-report.sh会收集证据
de段显示实时决策等效性证据:累计达到 50 个 A/B 样本 + 30 个 A/A 样本后,会显示 ✓/⚠/✗ 比率(A/B = 压缩内容与原始内容对比;A/A = 将同一请求 重放并与自身对比 — 作为抽样噪声基线);采集期间显示de n/50。 默认情况下,影子采样已启用,采样率为 2%(--shadow 0可禁用;--shadow 1.0会对每个请求采样 — 以约 3 倍的令牌开销在几分钟内验证等效性,然后将采样率 调回默认的 2%)。测量结果 — 2026-09-15,构建版本 1.53.0rc1,配对估算器(签名 v5)。 实时 样本现已达到报告门槛:398 个 A/B 样本和 399 个 A/A 样本。请按模式 阅读:digest 有 102/206 次一致,自我一致性为 113/206 — 低 5.3 个百分点,超出 5% 的限额 — 而仅使用 lossless 时为 109/192,对比 109/193(约为 0)。状态栏 显示合并后的数值
⚠de 97.5% (398),它是两种模式的平均值,不能代表任何一种 模式的结论;distil shadow-stats会显示各模式及其区间。重放使用热状态运行 — 399 次中有 399 次未固定温度 — 因此请关注配对差值,而非 53.0% 的原始一致率:A/A 组包含相同的运行间噪声,差值会将其抵消。产物:benchmarks/results/shadow-live-2026-09-15.json。 此前的两项读数仍保留在记录中:签名 v3/1.13.0 的数值(116 个采样请求中为 100%,A/A 为 31/31)已撤回 — 1.51.1 的变更日志发现,所有带有先前thinking块的重放都因签名错误而失败,使样本偏向于少数不含该块的轮次 — 而 1.51.1 的读数(44 个 A/B、11 个 A/A、原始一致率 81.8%,低于门槛,未配对估算器)保存在benchmarks/results/shadow-live-2026-09-04.json。
▼= 节省的令牌数 ·total= 累计值 ·de= 决策等效性(累计达到 50 个 A/B + 30 个 A/A 影子样本后给出结论)。想让状态栏与 git/当前工作目录/模型共存?设置DISTIL_STATUSLINE=minimal→distil ▼7.8K · 27M total。使用固定费率订阅时,美元金额仅为名义值,并会自动隐藏(DISTIL_SUBSCRIPTION=0/1)。
🎚 压缩模式——通俗说明
通常无需自行选择。distil onboard 会检测你的计费方式,并为你设置合适的模式——它会将模式写入配置,让每次会话都能正常运行。你也可以传入标志,为特定会话覆盖该设置。
- digest(默认)——Distil 会将较长的内容(大文件、命令输出、之前的步骤)缩短为简短摘要,并可在 AI 需要时立即恢复完整原文。节省最多,而且内容并未真正消失——原文会被保留并自动恢复。大多数人直接使用此模式即可。
- expand——与 digest 一样会缩短内容,但 Distil 还会为 AI 提供一个“显示完整版本”按钮,让 AI 可以自行点击。适合长时间自主运行的 AI(例如长时间编码会话)。如果你按使用量付费(API 密钥),系统会自动选择此模式。
- lossless-only(也称为
--safe)——谨慎模式:Distil 只会裁减能够完美还原的内容(例如多余空格),绝不生成摘要。节省较少,但完全不会丢失任何细节。如果你使用每月固定订阅,系统会自动选择此模式。 - verbatim——最轻度的处理:只整理格式,不做其他改动。节省几乎可以忽略。想要查看或审计实际发送的内容时可使用此模式。
技术细节如下:
| 模式 | 功能 | 节省幅度 | 安全性 | 自动选择条件 |
|---|---|---|---|---|
--expand | Digest + 注入 expand 工具,让模型按需恢复内容 | 最大 | 有损但可恢复 | 按量计费 / API 密钥(PAYG) |
(default) digest | 仅进行 Tier-1 摘要——不注入工具 | 高 | 可通过 RestoreStore 还原 | 未传入标志 |
--lossless-only / --safe | 仅进行无损转换——不生成摘要,不注入工具 | 较少 | 不会丢失任何无法恢复的内容 | 订阅 / 固定费率 |
--verbatim | 仅规范化空白和 JSON | 最少 | 最保守 | 调试 / 审计 |
订阅用户不应强制使用 --expand;该模式会突破无损安全边界。需要重新读取代码时?无论使用哪种模式,都可以添加 --session-delta。
🧠 工作原理
两种技术带来了大部分收益——它们针对的是 Agent 工作循环中真正耗费资金的部分,而不是看起来耗费资金的部分。
① 缓存感知压缩——最主要的杠杆
每一步都会重新发送不断增长的上下文。使用提示词缓存时,缓存读取的成本约为新输入的 1/10,因此真正的成本来自缓存未命中,而非上下文大小。Distil 会保持前缀的字节稳定(规范化 schema,并将时间戳/UUID 等易变字段移出前缀),只压缩易变的尾部内容。
朴素的重新压缩虽然发送的 token 更少,却比完全不压缩更贵,因为它每轮都会改写缓存前缀。Distil 不会这样——这正是大多数工具忽略的关键所在。
- 转发字节前缀重放 — 这套机制的另一半是 客户端:它每轮都会改写自己的历史记录,却不改变模型读取的任何 token:
cache_control断点向前移动,SDK 加上index字段,字符串变成文本块。离线测量显示,以往每轮在每个提供商上都要重写整个前缀(转发字节完全相同的比例为 0%)。现在,Distil 会重放上一轮转发的字节,覆盖最长的规范化相等前缀——适用于的各种改写形式下均达到 100%,每个请求耗时约 0.13 ms。它恢复的是字节,不是决策,因此精确引用保证仍优先于缓存命中。每个请求都会记录重放停止的原因(replay_stop:held、client、distil、marker、cold、untracked),便于判断缓存写入是否发生在窗口内,以及应归因于哪一方。默认启用;使用--no-prefix-replay可退出。→ ADR 0011 - 冷点重新压缩 — 旧字节唯一能免费更改的时机,是某轮请求到达时,提供商的缓存条目已经过期(空闲 5 分钟;如果客户端请求了
ttl: "1h",则为 1 小时)。这一轮本就会重写整个前缀。因此,distil 会在此时将较早的工具输出替换为可通过distil_expand恢复的存根,之后每轮都原样转发这些存根,让较小的前缀被缓存。只有在 distil 自己的时钟能确定缓存已过期时才会执行。如果某条 lineage 是 distil 从未见过的、请求仍在处理中,或两个对话共用同一个 lineage key,distil 都不会采取任何操作。精确引用读取、最新几轮内容以及模型已展开的内容均不会被触碰。凡是运行可恢复摘要的地方都会启用此功能(目前为 Anthropic)。使用--no-cold-point或设置DISTIL_COLD_POINT=0可退出。目前尚未测量实际运行中的节省效果:必须先通过 rc 稳定性测试和 A/B 测试。→ ADR 0014 - **工具定义会原样转发,这是有意为之。**在实际流量中,请求的
tools数组占计费输入很大一部分,但它位于缓存前缀的开头,几乎全部按缓存读取费率计费。只有很小一部分可以在不改变模型可调用工具的前提下移除。因此,无损架构压缩带来的收益太小,不值得承担影响前缀的任何风险。测量脚本为benchmarks/tool_schema_share.py;数据和重新评估条件见 ADR 0012。如需降低工具开销,请移除不使用的连接器;distil discover会按成本对它们排序。 - 保持 Claude Code 自带的 MCP 工具搜索启用。Claude Code 会延迟加载 MCP 工具定义,只有模型搜索某个工具时才会加载;但只要
ANTHROPIC_BASE_URL指向非一方主机,它就会关闭此功能——因此通过代理时,以往每轮都会附带所有连接器的完整架构。现在,distil wrap -- claude会为子进程设置ENABLE_TOOL_SEARCH=true(已导出的ENABLE_TOOL_SEARCH=false仍优先),distil default --always-on只会在 Claude Code 的设置中尚未配置该项时添加它,而 distil 会原样转发defer_loading/tool_reference块。已在线验证(2026-09-25):一个调用了 MCP 工具的 Claude Code 包装会话,在每个请求中都记录了延迟加载的工具,缓存读取正常,且无失败。distil discover会列出出现在 20 个以上请求中但从未调用过的 MCP 服务。→ ADR 0013distil cache会显示它是否正常工作,并且会刻意混用两种数字:缓存读取和写入量来自提供商自己的usage——这是关于费用的真实数据;而前缀漂移则是 distil 根据其发送的稳定区块的无内容哈希,对原因进行的自我诊断。没有测量数据支撑的诊断只是猜测,因此它绝不会只打印其中一项。在一个实时的三轮会话中,第三轮会在系统提示词前添加会话 ID,这两项数据各自独立地相互印证:哈希标记出的那一轮,正是提供商为重新创建上下文而重新计费 15,819 个 token 的那一轮。仅仅变长的轮次——也就是对话照常发展——不算漂移,因为每个正常轮次都会触发的警告,只会让人将它关闭。如果没有经过代理的请求,它会以非零状态码退出,而不是打印一个令人安心的零值。完整说明,包括我们刻意不提供的一项缓存功能及其原因,请参阅 docs/CACHE.md。
② 因果 / 反事实剪枝——发现引擎
评估并非附带的标尺,而是一个发现引擎。移除一个上下文区块并重放后,决策是否发生变化?从未改变任何决策的区块,可以证明能够安全删除。
distil prune
# doc-0 PRUNE (causally inert) # speculative retrieval, never cited
# obs-0 keep (changed a decision) # carries the decision-driving signal
🎓 证书(DERC)
门控回答的是 “这种策略在我的语料上是否不劣?”。决策等效风险证书回答的是实际运行中的问题:“在我选择的风险预算(例如决策变化率 ≤5%)下,压缩程度最高能到什么水平,同时还能保证这一点适用于我的真实流量?”
distil conformal --corpus ./mycorpus --alpha 0.05 --delta 0.05
# ✔ CERTIFIED 'lossless' → 57.4% savings; decision-change ≤ 5.0% at 95% confidence (Learn-Then-Test)
每份证书都会注明对其进行评估的判定器。 证书是证据,而没有说明证据由什么产生,就算不上证据——因此,Certificate.grader 会由运行器盖章,并显示在保证说明中。默认的离线门控由确定性合成判定器评估,而非模型,并会原样说明:Graded by: deterministic (synthetic DECISION: oracle — NOT a model)。真实模型的证据来自 distil certify --runner anthropic,其证书会注明对应的运行器。数字来自哪个层级一目了然,因为数字本身就会标明这一点。
这是保形风险控制(Learn-Then-Test / CRC——分布无关、有限样本),而不是启发式阈值。唯一关键的注意事项:该保证要求满足可交换性(校准流量 ≈ 线上流量),且是关于该分布的边际保证——出现漂移时请重新校准。完整理论和引用请见:概念 · docs/PAPER.md。
一个风险预算,以及会据此采取行动的告警。 证书、实时漂移告警和证明账本都读取同一组固定常量 distil.conformal.BUDGET_ALPHA / BUDGET_DELTA(决策变化率 ≤5%,置信度 95%),因此不会出现一个界面显示完好无损,而另一个界面却判定超出预算的情况。distil certify 的 TOST 裕量(CERT_MARGIN,2 pp)也在同一位置设置,并固定为比预算更严格的值。当影子模式下的配对判定使 anytime-valid e-process 超出预算时,代理会从下一条请求开始停止有损压缩:仅使用 Tier-0,不生成摘要,不调整输出。每台机器恰好只有一个 e-process:每个代理都会在文件锁保护下,将刚刚生成的判定纳入其中,因此重启、热切换和并行包装都不会对相同证据重复检验。暂停状态会在重启后保留,并写入回执链。该状态是全局的,而非按会话划分,因此新的 distil wrap 无法悄悄恢复上次运行已证明有害的操作;长时间运行的代理会在 30s 内获知其他进程触发或解除的暂停状态。状态行会显示为 ⚠ drift hold,wrap 退出摘要和 distil stats 中也会用直白文字显示(BREACHED … compression held at lossless-only)。要解除暂停,请运行 distil calibrate,然后运行 distil reset --drift-guard。此操作只会影响告警,不会影响你的节省总量。告警默认启用;如需在超出预算后继续压缩,请设置 DISTIL_NO_DRIFT_GUARD=1(告警仍会显示)。多租户网关特意不受此机制约束(ADR 0016)。这是 1.53.0rc1 之后新增的功能;与所有默认启用的变更一样,它仍须通过 rc 浸泡测试。
🏔 轨迹级证书
DERC 认证的是步骤;这份证书认证的是任务。我们的 E7 实验,以及 2024–26 年的 Agent 压缩研究文献表明,逐步保真度可能达标,但端到端成功率却会骤降。因此,distil 还会认证用户真正感受到的层面:将评估套件运行两次(完整上下文与压缩上下文),输入匹配后的结果,即可获得一个无分布假设的界限,说明压缩可能会让你失去多少原本可以解决的任务:
distil certify-trajectories outcomes.jsonl --alpha 0.05 --delta 0.05
# each line: {"task_id": "...", "full_success": true, "compressed_success": true}
# → With confidence 95%, compression degrades at most 5.0% of tasks the full
# context would have solved (observed 0.5% over 200 matched trajectories).
样本量不足时,它会拒绝颁发证书;并在证书本身中说明其可交换性假设。它还会与实时、任意时刻有效的漂移警报(上文的 distil/drift.py)配合,告知你——并在代理中采取行动——实时流量何时发生了足以使证书失效的变化。(trajectory_risk.drift_monitor 是仅供研究使用的同类模块,不在请求处理路径上。)结果引导策略(distil.compress.guideline)旨在保护被压缩后会导致任务失败的内容类别,但目前还没有任何数据输入其中——record_trajectory_outcome 尚无调用方,distil doctor 也会指出这一点。
🧩 包含内容
40 多项已交付能力,全部真实可用(没有存根):感知缓存的成本引擎、因果剪枝、TOST 门控 + 保形证书、代理 + Anthropic/OpenAI/Gemini 一流适配器(Chat Completions、Responses API 和 Gemini generateContent)、MCP 服务、LiteLLM/LangChain/LangGraph 钩子、按 Agent 提供的封装预设、会话结束时打印的 Proof Ledger、多租户网关(含已签发密钥和速率限制)、恢复存储的静态加密、学习型保留模型、输出压缩,以及可选的 Rust 热路径核心(通过 maturin 从源码构建;已发布的 wheel 运行纯 Python 引擎,API 相同)——核心没有任何运行时依赖。
🔒 安全与部署
- 默认仅监听本地主机 — 代理绑定到
127.0.0.1,且只转发到唯一配置的上游(无 SSRF)。 - 不记录机密信息/正文 — 永不记录请求正文和凭据。
- 按认证模式进行限制 — 检测到订阅/OAuth 会话后,自动选择
--lossless-only(Tier-0 原样保留:无 Tier-1 摘要占位符、无工具注入——符合提供商服务条款);默认情况下,distil wrap -- claude是安全的,无需设置标志。即使如此,显式指定--expand也可启用可恢复摘要(你已授权恢复工具,因此不会不可逆地丢失任何内容——issue #28)。如果未注入 expand 工具,Agent 就无法恢复占位符,因此--lossless-only会直接保留原文。 - 静态加密 —
~/.distil/restore/中的摘要原文使用 HMAC-SHA256-CTR 加密(先加密后认证,带DSTL1标头,密钥权限为chmod 0600),防止备份/同步泄露以及在共享文件系统上被其他用户读取。同 UID 攻击者若能同时读取数据文件和密钥文件,则明确不在防护范围内(参见THREAT_MODEL.md)。旧版明文文件会透明加载。设置DISTIL_NO_ENCRYPT_AT_REST=1可选择退出;句柄会在DISTIL_RESTORE_TTL_DAYS后过期(默认值为 14)。不会向上游转发任何数据。 - 可用于运维 — 每个入口点都提供无需认证的
GET /distil/health存活探测(绝不会访问会产生费用的上游);网关每 30 秒将统计数据检查点写入磁盘(崩溃安全,不仅在正常关闭时写入);DISTIL_DEBUG=1会显示故障时自动放行的压缩路径所忽略的所有信息。 - 升级会应用于正在运行的会话 —
distil wrap会在由 wrap 管理的套接字上,将代理作为子进程进行监控;磁盘上出现新版本(pipx/pip 升级)时,wrap 会热切换到新的工作进程——端口不变,进行中的流由旧进程完成,Agent 无需重启。切换前会进行健康检查,并支持自动回滚:升级出错时,旧工作进程会继续提供服务。适用于 POSIX;运行kill -USR1 <wrap pid>可强制切换,设置DISTIL_HOT_SWAP=0可选择退出。在 Windows 上,wrap 仍使用历史上的线程内代理(无法无缝切换),并会在版本不匹配时发出警告;升级会在下次会话中生效。 - OpenTelemetry GenAI Spans(可选启用) — 运行
pip install 'distil-llm[otel]'后,每次代理调用都会发出一个 GenAI 语义约定 span(gen_ai.request.model、gen_ai.usage.input_tokens),以及 distil 自有的指标:distil.tokens.original与distil.tokens.compressed、distil.compression.ratio、distil.shadow.sampled,以及用于按会话关联 trace 的distil.session.id——你现有的 OTel 后端可以准确查看压缩对每个请求的影响。不安装额外依赖时,这只会进行一次布尔值检查,开销为零;OTel 出错也绝不会中断请求路径。同样的数据也会导出为 OTel 计数器(distil.requests、distil.tokens.baseline/.sent/.saved),记录位置与 span 属性的插桩位置相同,因此 trace 与指标不会出现不一致;并且计数器会在检查 span 之前记录,因此即使关闭 trace 采样也能正常工作。 - Prometheus 端点(网关) —
GET /distil/metrics提供标准文本格式的指标(distil_tokens_saved_total、distil_dollars_saved_total、distil_compression_ratio,等等),使用标准库实现,因此抓取路径不会增加依赖,也不会因导入而失败。时间序列按租户标记,因此该端点与/distil/stats受完全相同的管理权限门控:本地使用时,在回环地址上开放;绑定到任何非回环地址时,则必须提供--admin-token,否则会拒绝请求。这一门控至关重要——未经认证、带有租户标签的/metrics正是 LiteLLM 信息泄露 类问题;我们对此进行了直接测试(未经认证时返回 403,令牌错误时返回 401,并测试标签注入和指标输出中不含机密信息)。完整参考:docs/adoption.html#metrics。 - 视觉 — 重复截图不再按全价计费 — 一张 1024×1024 的图片约为 1,400 个输入 token;如果 Agent 会截取 UI 或轮询仪表盘,那么只要该内容块仍在上下文中,每一轮都会产生这笔费用。Distil 只省略字节完全相同的重复项,并将其替换为可恢复的引用:首次出现的图片和每张不同图片都保持原样,不会重新编码或缩小尺寸,而
distil_expand会按字节精确还原原始source。URL 来源绝不会被视为重复项——同一个 URL 出现两次并不能证明像素相同。常见替代方案是调整尺寸,这种做法必然有损且无法验证;本方案已通过对照实时视觉模型进行认证,决策等价率达 100%(A/A 下限为 100%,TOST p<0.0001),认证文件随软件包一同发布,并注明自身适用范围。运行distil certify --strategy vision --runner anthropic,即可为你自己的工作负载进行认证——你自己的结果比我们的结果更有参考价值,即使结果未通过也是如此。设置DISTIL_VISION=0可禁用此功能。完整参考:Techniques § Vision。 - 供应链加固 — 发布版本附带 PEP 740 Sigstore 证明(通过 PyPI 可信发布生成)、每个 GitHub 发布版本都包含 CycloneDX SBOM,并且每周在
main上运行 OpenSSF Scorecard。如果 PyPI 未针对刚发布的版本报告证明包,发布任务就会失败,因此这项说明不会变成不实信息。自 1.19.0 起的每个发布版本都已验证。无需相信我们的说法:运行curl -s https://pypi.org/integrity/distil-llm/<version>/<filename>/provenance(注意这是 integrity API——/pypi/<pkg>/<ver>/json不包含 attestations 字段,从那里读取会产生错误的否定结果),或运行uvx pypi-attestations verify pypi --repository https://github.com/dshakes/distil pypi:distil_llm-<version>-py3-none-any.whl。 - Kubernetes — 多租户网关的 Helm chart 位于
packaging/helm/distil-gateway:默认要求身份验证、以非 root 用户运行且 rootfs 只读,并包含 PDB、HPA、将出站流量限制为 DNS + 443 的 NetworkPolicy,以及 ServiceMonitor 和告警规则。随附 Grafana 仪表板,CI 会针对 distil 实际发出的指标交叉检查每个面板和告警。 - SSO / RBAC — 网关除了接受自己的
dsk-密钥外,也接受 OIDC bearer token,并设有三个按顺序排列的角色(viewer<operator<admin)。JWS 验证仅使用标准库;RS256 需要[oidc]extra,若未安装,则会拒绝 RS256 token,而不是在未经验证的情况下接受。 - 审计跟踪 — 每次身份验证成功、拒绝、触发速率限制以及密钥签发/撤销,都会追加到
$DISTIL_HOME/audit.jsonl(0600、JSONL、由 flock 保护)。使用distil gateway audit读取,或通过--json直接发送到 SIEM。和 distil 写入的其他所有内容一样,不包含内容:只记录标识符和结果,绝不记录提示词文本、工具输出或原始密钥。 - 逐请求回执——第三方可核验的团队审计日志 — 代理处理的每个请求都会追加一条不含内容、哈希链式回执(token 数量、模式、签发的句柄、句柄是否仍可解析;绝不包含提示词或补全文本)到
$DISTIL_HOME/receipts.jsonl(0600)。哈希链会轮转:活动文件达到分段大小后,会逐字节封存到receipts-segments/,并在其旁写入一个小型检查点——包含分段 ID、行数、首尾回执哈希,以及基于该分段计算的 RFC 6962 形状 Merkle 根。下一条回执会链接到已封存分段的末尾哈希,因此历史记录始终构成一条链。distil receipts会验证所有内容;--segment N会根据检查点验证一个分段,而无需读取其他分段;--checkpoints会打印检查点记录(以及每条记录的 sha256),以便固定保存到团队信任的位置;--prove <request-id>会为一条回执生成 Merkle 包含证明——只需向审计员提供一条回执,无需提供整份日志。--check-proof proof.json --checkpoint-hash <sha256>仅凭证明和该固定值,即可证明回执的内容、分段和位置;单独使用--root <hex>只能证明其属于该树,不能证明其位置;若未固定任何值,验证就是循环论证,程序会明确说明。分段功能出现前写入的哈希链也能原样通过验证,并会在首次轮转时不作修改地成为分段 0。信任边界会明确说明,而非含糊带过:任何能写入~/.distil的人都能同时改写分段和检查点,因此应将检查点哈希固定保存在他们无法访问的位置。 - 密钥有效期 —
distil gateway keys issue --tenant acme --expires-in-days 90可为密钥设置有限有效期,并在每次查找时强制执行;keys list会分别显示active/expired/revoked状态,因此突发的 401 不会让人误以为发生了实际上并未发生的撤销。未设置有效期的密钥会一直有效,因此现有部署无需作任何更改。
有关拓扑结构(本地 sidecar、容器 sidecar、共享网关),请参阅部署与安全;有关适合审查的数据处理与合规摘要,请参阅安全白皮书;如需报告漏洞,请参阅 SECURITY.md。
✅ 我们不会妄称
-
自校准的 Token 计数——离线启发式估算在方向上准确;压缩比例始终精确。distil 是一种代理,因此它会读取每个响应中提供商实际返回的
usage.*,并据此学习系统性校正(不涉及内容,不联网),自动针对你的模型和内容组合校准绝对计数。流量足够后,排行榜会显示“已根据你的计费用量校准(N 个请求,±X%)”;在此之前显示的是原始启发式估算(恒等映射,因此不会产生偏差)。若要精确计算每个字符串的 Token 数,仍可使用--tokenizer anthropic。 -
默认运行器是确定性替身(带有真实标注结果的离线门禁)。非循环评估会使用真实模型为真实 Agent 执行轨迹评分——验证框架。
-
**确保评分可信:**采用多数投票(单个样本会让评分器的噪声看起来像决策变化)、使用同系列评分器,并使用
distil_expand恢复循环对可逆层进行评分。 -
不伪造权重——keep-model 是真正的逻辑回归分类器(留出集准确率为 96.4%,F1 为 0.98;已提交的
metrics.json可通过python -m distil.codec.learned重新生成,且字节级完全一致,并固定了随机种子)。可选的 Transformer 编解码器在软件包中不附带检查点——演示检查点附在 v0.1.0 发布版本中;用于生产则意味着要用你自己的轨迹重新训练(distil train-transformer)。 -
**外部基准测试发现了我们自己的门禁漏掉的缺陷。**75 次 Agent 运行依据 API 自身的用量字段进行评分,结果发现
wrap --expand在 15 项编码任务中只完成了 6 项,而裸用 Claude Code 完成了 13 项——有 7 次运行没有向磁盘写入任何内容,却报告成功。四个原因已全部在 1.49.0 中修复,每个原因都由回归测试覆盖,并验证了没有对应修复时测试会失败。报告(包括它不能证明什么)见此处。测试套件通过,并不能证明工作已经完成。
刻意打造的非平台
Distil 是上下文工具的裁判,并配有一款同样接受门禁检验的压缩器,而非上下文套件。我们拒绝了所有无法纳入认证范围的功能:
| 相邻功能 | 我们的立场 |
|---|---|
| 持久化记忆/知识图谱 | 不在范围内——有损存储与字节级可逆背道而驰。 |
| 托管式语义缓存 | 不在范围内——我们让提供商的提示词缓存发挥作用,而不是再增加一个有损缓存。 |
| 编辑器/Copilot 身份验证 | 不在范围内——Distil 位于传输链路上或进程内;绝不代理凭据。 |
我们确实采用的功能(通过了门禁):可插拔的显著性评分器,用于保护实体;缓存前缀可观测性;以及框架钩子。
🎯 账单的两面
Distil 同时压缩输入/上下文(全面压缩)和输出——调整生成端的冗长程度(按量付费,通过 distil output-savings 测量),并提供可逆的输出重入摘要,让过去冗长的回答不再在历史记录中按全价计费。详情:输出与 I/O。
调整会改变模型自己的措辞,因此不会仅仅因为有人输入了一个标志就启用——只有证据表明应该启用时才会启用。在按量计费的会话中,--shape-output auto 为默认设置:只有当实时配对影子判定达到共享报告门槛(50 个 A/B + 30 个 A/A)、伤害界限处于 distil certify 测试所用的同一 ±2pp 范围内,且压缩对回复长度的实测影响在节省侧不包含零时,才会运行调整。任何一项不满足,调整都会关闭,并打印原因、将原因存入会话清单,且在 distil dissect 中显示。此门槛仅读取在关闭调整时测量的影子记录,因此调整绝不会因为自身生成的较短回复而持续启用。在订阅或 OAuth 会话中,调整始终关闭——distil 不会修改统一费率提示词。
🔬 可复现的评估与论文
每个数字都可以通过随附的语料库复现(distil bench,无需密钥)。非循环论证的证明工具会使用真实模型评估真实 Agent 轨迹(τ-bench / SWE-bench):benchmarks/PROVE.md。编译后的论文、LaTeX 源文件及所有已提交结果:docs/PAPER.md · docs/paper/ · 论文 PDF。分步指南:复现这些数字 →
别再为重新发送 Agent 根本不会读取的上下文付费。
pipx install distil-llm && distil bench
约 10 秒内验证 9 个领域的节省效果——无需 API 密钥,无需运行时依赖
开始使用 → · 接入你的 SDK · 查看证明 · PyPI
⭐ 如果 distil 为你节省了令牌
点个星,就能让下一位工程师发现可证明的节省效果,而不是有损的猜测——而且
distil stats --badge 会生成可分享的徽章,展示你自己测得的数据,
供你与星标一起展示。这枚徽章和这个仓库,就是全部的营销团队。
🤝 参与贡献
欢迎提交 PR——请参阅 CONTRIBUTING.md。唯一重要的规则是:新的压缩策略必须通过 make gate(在所有领域均不劣于基准,且可按字节还原)。门禁不通过,就不能合并。这一句话就概括了全部理念。
自行运行评估——每项门禁都免费且可离线运行:请参阅 docs/RUNNING-EVALS.md。
💬 社区与支持
- 问题、想法、错误报告 → 提交 issue。每个问题都说明文档还有尚未补齐的内容。
- 看看谁在节省令牌 → 实时、自愿加入的采用情况看板——精确的社区总数,不作预测,且从设计上不含内容。
- 关注发布动态 → 发布版本更新频繁;
pip install -U distil-llm(或uv tool upgrade distil-llm)可获取最新版本。
许可证
Apache-2.0 · “效力不减,用量更少。”
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。