跳到主要内容

vomit:你在终端里看到的,已经不是 Claude 说的话了

老铁
老铁

· 阅读约 8 分钟

GitHub 上有个叫 vomit 的工具,干的事很直接:把 Claude Code 在终端里显示的所有输出截下来,发给另一个本地大模型重新表达或概括,再把改过的文本显示给你看。想看 Claude 到底说了什么,得按 ctrl-o。

我看到这个名字的时候以为是个段子。看完 README 我笑不出来了。它默认做的不是“帮你总结”,而是把一手汇报藏进快捷键后面,让你日常读到的每一条状态说明,都经过一个没有上下文的小模型转述。作者自己在文档里承认,这个本地模型看不到文件、看不到操作,所以可能产生一定程度的幻觉。

那问题就来了:你排障的时候读到的每一行,都已经不是第一手信息。它可能比你没读到原始版本更糟——因为它是被一个不知情的转述者重新表述出来的,而你默认信了。

我理解它为什么会出现。Claude Code 输出长起来的时候是真烦,尤其上下文一乱,它开始把一件简单的事翻过来倒过去说三遍。那种时候人会本能地想找个开关让它“说人话”。

但我想先把一件事说清楚:让输出变短,和让另一个模型在没有上下文的情况下重写输出,是两码事。前者是工程管理问题,后者是往真相外面套滤镜。你以为省了读长文的时间,实际上你连“这到底是什么情况下被生成出来的一段文本”都开始看不清楚了。

这个工具的工作方式,其实不复杂,拆开看:

  1. 它 hook 住 Claude Code 在终端显示的所有输出。注意,是“所有”——不管这段文本是 Claude 读完文件后的结论,还是跑完命令后的状态汇报,它全拦下来。
  2. 它把这段纯文本发给一个本地模型服务,Llama.app、Ollama、Apfel,或者任何兼容 OpenAI API 的本地端点。模型拿到的只有文本,没有文件内容,没有工具调用历史,没有命令执行结果。
  3. 本地模型“重新表达或概括”之后,把这个结果替换进终端。于是你在终端里默认看到的是改写版,按 ctrl-o 才能翻出 Claude 的原话。

这个管线的核心问题是:你的眼睛和 Claude 之间多了一个没有上下文的转述者,而这个转述者被默认放在了你信息获取的主通道上。

“零遥测、无外部依赖、完全本地”这些标签,听起来非常干净。很多人看到这几个字就觉得安心。但“完全本地”不能拆出一个事实:本地小模型不会因为跑在你自己机器上就突然获得上下文。它不知道 Claude 刚才打开过哪个文件,不知道哪条命令失败过,不知道你的 fixture 为什么这么构造。它只能根据一段已经脱了上下文的文本,按照语言模式的概率去补全一个“看起来合理的版本”。

它不是在做总结。它是在根据语言模式重新造句。

我拿一个最小的假设场景来佐证一下这个机制到底会在哪里出问题。假设 Claude 在排障时给了你这么一段:

我已经检查了 accounts/service.py,把查询改成了走 repository 的接口,
并在 tests/test_accounts.py 里补了三个用例。当前有一个用例失败,
错误是 fixture 里传入的 user_id 与 headers 里的不一致。
这个错误在本次改动范围之外,需要你确认 fixture 的构造方式。

如果 vomit 的本地模型拿到这段文本,它没有看过 accounts/service.py 现在的 diff,不知道你项目里的 fixture 长什么样,没有读过 user_id 和 headers 之间的实际关系。它只需要对这段文本做一次“再表达”,就可能输出:

service 的查询改好了,测试也补了。有一个测试失败,
因为你给的 user_id 对不上 headers,需要确认 fixture。

字面意思还在,但变化很大。原本 Claude 说的是“这个错误在本次改动范围之外”,这个限定很重要,它划分了责任边界。本地模型把它简化成一句因果关系,甚至补上了“因为你给的 user_id 对不上”——它凭什么下这个因果判断?它没看过 fixture。它只是按训练数据里“工程师解释 bug”的语言模式补了一个最可能的说法。

然后你带着这句话去查 fixture。查错方向,浪费十几分钟,最后按一下 ctrl-o 才发现 Claude 原话根本没下这个结论。这就是把一手信息藏起来、塞给你二手转述的代价。更恶心的是,这种代价是默认发生的。你不是在特殊场景里主动选择了透明地总结一次,你是把日常输出信道整个交给了它。

我在不少项目里见过这种反射动作。输出烦了,套一层“让它好读”;配置烦了,再套一层“自动生成配置”;错误多了,再套一层“自动修错误”。每一层都是因为不想解决上一层的问题。最后桌子上摆一排工具,就是没有一个能让你搞清楚系统到底在干什么。一个被层层滤镜包起来的系统,看起来是顺滑了,实际上你已经失去了对真相的直接感知。这不是提效,这是给烂地基刷漆。

Claude Code 输出长,是信息管理问题。上下文里塞了一堆无关文件,CLAUDE.md 里写了好几套互相矛盾的要求,每个子任务没有明确的汇报边界,模型自然就会长。你不去管这些,反而套一个本地小模型在输出端“精简”,就像水管漏了拿毛巾捂住。表面上不漏了,水还在墙里渗。

要解决输出长这件事,顺序应该反着来:

  1. 先把上下文管住。Claude Code 每次自动读进去的东西你清不清楚?哪些目录该排除,自动加载的文件数量能不能控制,这些是基本功。上下文不干净,后面全是白搭。
  2. 再把沟通密度写清楚。直接在自己的系统配置里要求状态汇报保持几行以内,排障时才列出具体文件和证据。这是你给 AI 的工程约束,不该是另一个 AI 替你猜出来的语言风格。
  3. 前两步做完了,再考虑要不要引入第二个模型做总结。就算用,它至少得能拿到同一份上下文、能标注不确定的地方,而不是黑箱重写。达不到这两条的摘要工具,不该被放在默认输出信道上。

这个顺序反了,就是本末倒置。

我知道有人会说,一个玩具而已,你较什么真。但问题恰恰在于它不只是在玩具场景里跑。它已经把“默认显示”这个位置占了。你日常用 Claude Code 时,每一行你读到的汇报都可能不是 Claude 说的原话,而是一个被作者明确标注“可能产生幻觉”的本地模型转述出来的。这种东西你拿来图一乐可以,把它放进日常信息通道,不是较真不较真的问题,是你对一个做高置信度错误的东西说了“行,我默认信你”。

工具作者在文档里写的那句话,在我看是整个项目最有信息量的一句:“本地大语言模型只能看到 Claude 试图传达的内容,无法访问操作或文件。”翻译成工程语言:转述者不知道刚才发生过什么,但它被允许用自己的话告诉你刚才发生了什么。而且你还得按一个快捷键才能绕开它。

这是信任链断裂。

当一个工程师开始默认接受二手转述,还忘了原始版本藏在哪个快捷键里,这时候退化的不是“读得少了”,是判断力。判断力的基础是你能摸到接近事实的一手信息,然后自己权衡。一手信息被藏起来,二手信息成了默认,你的每一次判断都被架在幻觉概率更高的文本上。时间长了,你连“这段到底是 Claude 说的还是 vomit 说的”都会分不清。到那时候再想回到直接读原始输出,你的阅读惯性已经不适应那个密度了。

所以我的态度很明确:输出长了,就管上下文、管系统提示、管模型选择,这是工程师的分内事。用另一个没有上下文、会幻觉的本地模型把输出重写一遍,再把原始版本藏进 ctrl-o,这不是提效,这是在你和真相之间加了一道不会替你负责的滤镜。

别把一手汇报藏起来。至少别把它藏成默认。先把“我读到的还是不是 Claude 说的话”这个问题想清楚,再去装任何让你“说人话”的工具。想不清楚,你不是在被工具服务,你是在吃一个叫“清晰”的二手幻觉。

老铁
老铁

把每个技术现象拆到原理、再上升到工程价值观,崇尚基础功、反浮躁。

查看主页 →