Squelch — 噪音更少,token 更省

编程代理读到的东西大多是命令输出,而命令输出大多是噪音:围绕着唯一失败的那个测试的数百行 PASSED、安装时每下载一个软件包就一条进度条、构建时每个文件一行 Compiling、git 的对象计数器。模型每一轮都会把这些全部读一遍,而它们全都计入上下文窗口和账单。

Squelch 会在模型读取之前去除这些噪音。它保留代理据以行动的内容——错误、失败、警告、摘要——其余的则略去。它适用于每一个代理(Claude Code、Codex、Kimi Code、Grok、omp),机器内无需安装任何东西:你 Mac 上的代理服务器会精简每个请求所携带的命令结果,就像个人数据保护替换个人数据一样。Squelch 按机器设置(在设置编辑器中即工作区),默认关闭;各字段的说明请见设置 → Squelch。

致谢: Squelch 仿照 rtk(Rust Token Killer,github.com/rtk-ai/rtk,Apache-2.0),它通过在你的电脑上改写代理的 shell 命令来做到同样的事。这个构想、按命令类别的过滤策略,以及“节省的 token”报告(rtk gain)都来自 rtk;Bromure 的过滤器是自己的,改在代理服务器中运行,因此无需 hook 就能覆盖每一个代理。

开启它

有两种方式,都立即生效——代理的下一个请求就会被精简,无需重启任何东西:

  • 在会话的标题栏中,点按 Squelch 图标(token 数之后、三条逐渐变短的线),然后在弹出窗口中切换开关。
  • 在机器的设置中,选择模型下的 Squelch,勾选在模型读取之前,去除命令输出中的噪音,然后点按存储。

若要让它成为新机器的默认值,请在 Bromure → 设置…(默认值模板)中开启它。

它去除什么

Squelch 会查看一段输出来自哪个命令——一串命令中真正干活的最后一个命令,会穿过 sudo、timeout、env 和 VAR=value 这些前缀——并应用该类别的过滤器:

类别命令(示例)略去始终保留
测试pytest、jest、vitest、mocha、go test、cargo test、swift test、xcodebuild test、npm test、dotnet test、rspec、phpunit每个通过的测试一行、进度点、编译进度失败、traceback、断言差异、摘要
安装npm/pnpm/yarn/bun install、pip/uv/poetry、apt、brew、cargo fetch、go mod download、docker pull下载、解包和“already satisfied”的行、进度条、弃用通知错误、冲突、结果行
构建cargo build、swift build、xcodebuild、make、cmake、gradle、mvn、tsc、docker build每个文件的编译行、xcodebuild 的步骤块、make 进出目录的信息、再次打印的同一个警告每一个错误和警告,连同其源码片段
gitgit push、pull、fetch、clone、status、commit对象计数器、(use "git add"…) 提示、冗长的 create mode 列表分支、ref、冲突、文件
日志docker logs、kubectl logs、journalctl只有数字(时间戳、id)不同的连续行——保留第一行并附上次数任何不同之处
搜索grep、rg、ag、git grep超长行(压缩过的文件)的尾部每一个匹配项及其位置
其他一切—终端转义序列、重绘的进度行、进度条、连续出现六次以上的同一行其余部分

提到错误、失败、警告、panic 或超时的行,无论匹配哪个模式,都绝不会被略去。

卸载(pip uninstall、uv pip uninstall、npm remove、brew uninstall、apt remove…)不算安装:它打印的是被移除项目的列表,因此只会得到“其他一切”的通用清理。

有些输出永远不会被改动,因为代理把它当成内容本身来读——通常是要从中复制到编辑里:cat、head、tail、sed、less、jq、awk、diff、git diff、git show、git log、git blame(不论前面接了什么选项:git --no-pager diff、git -C repo log)、gh pr diff、gh api、hg diff、curl、python -c 之类。代理自己组出的管道(pytest -v | tail -40)也不会改动:它已经选好要看什么了。代理自身文件工具(Read、Edit、Grep 工具)的结果也永远不会被改动——只处理 shell 命令。

小于约 300 字节、或缩减不到 10% 的输出,会原封不动地通过。

模型看到什么

精简过的输出最后会有一行,说明略去了什么以及如何获取全部内容:

FAILED tests/test_api.py::test_retry_budget - assert 2 == 3
========================= 1 failed, 120 passed in 4.12s =========================
[Bromure Squelch left out 120 noise lines (passing tests 120). Run the command again prefixed with BROMURE_FULL_OUTPUT=1 to see all of it.]

当代理需要完整输出时,它会在命令前面加上 BROMURE_FULL_OUTPUT=1 再运行一次——这对 shell 无害,而 Squelch 会让该命令的输出完整通过。

只有代理的模型会看到精简后的文字。代理自己的对话记录、聊天视图和你的终端都保留完整输出。Squelch 逐字符串修改请求,其余每个字节都保持代理发出时的样子,而且同一段输出永远以同样方式精简,因此一轮又一轮重发的对话能保住它的提示缓存。(在对话进行中开启或关闭 Squelch,会让之前的轮次改变一次,因此下一个请求会缓存未命中。)

查看节省了多少

每个会话的标题栏会显示 Squelch 在该对话中节省的量(节省 12K)。点按即可打开弹出窗口:

  • 此对话——节省的 token、被略去的命令输出比例、发给模型的命令输出有几个,以及其中几个被精简。
  • “…”全部(整台机器)——同样的信息,覆盖机器上的所有对话。
  • 来源——节省最多的命令(pytest、npm install、…)。
  • 最近两周——每天节省的 token。

机器的 Squelch 设置窗格会显示完整的命令列表和同一张图表。

token 数与 rtk 一样以字符数 ÷ 4 估算——流程中没有分词器,所以节省的比例是可靠的,绝对数字则是近似值。每段命令输出只计算一次,也就是请求第一次携带它的时候,即使代理每一轮都会重发整段对话——因此长会话的实际节省量比显示的数字还大。

节省量按机器保存在 ~/Library/Application Support/BromureAC/squelch/ledger.json(按对话、命令、类别和日期,保留最近 90 天)。在胖客户端(连接到另一台 Mac 的 Mac、iPhone 或 iPad)上,数字来自运行该机器的服务器,而弹出窗口中的开关会在那里开启或关闭 Squelch。

限制

  • 仅限机器。 Squelch 位于每台机器所有 AI 流量都会经过的代理服务器中。原生机器(运行 Bromure Sidecar 的 Mac)会把其代理的流量直接发送到提供方,因此 Squelch 在那里不适用。
  • 靠模式,不靠判断。 过滤器能识别常见工具的输出格式。少见的测试运行器或自定义的构建脚本,只会得到通用清理(转义序列、进度条、重复行)。
  • 请求中没有指名的命令。 当 Codex 的某一轮在服务器上接续之前的一轮时,结果可能会在没有产生它的那个调用的情况下到达。Squelch 会把它对应到模型在回复中预告的调用;从未见过其调用的结果——例如 Bromure 重启之后——则保持原样,因为单凭文字无法区分一次测试运行和一次对测试日志的 cat。