Skim - 给 coding agent 准备的 AST 感知上下文压缩器
AI coding agent 的上下文问题,不只是“窗口够不够大”。很多时候,模型已经能塞进大量文件,却仍然会被实现细节、日志噪声、重复 diff、完整测试输出分散注意力。真正稀缺的是可用注意力:agent 需要知道模块边界、函数签名、失败断言、关键错误和改动范围,而不是每次都读完整源码和完整终端输出。
今天推荐的 dean0x/skim 正是为这个问题做的 Rust CLI。它把“给 agent 看代码”这件事拆成一组上下文优化动作:用 tree-sitter 解析源码结构,按不同模式保留架构、签名或类型;压缩测试、构建、lint、package manager 和 git 输出;还可以通过 hook 重写常见命令,让 agent 在不改变工作习惯的情况下少消耗 token。GitHub 页面当前显示项目约 26 stars、2 forks,主要语言是 Rust,许可是 MIT;npm 和 crates.io 上的包名都是 rskim,当前版本为 2.10.0。
项目概览
| 属性 | 详情 |
|---|---|
| 仓库 | dean0x/skim |
| 定位 | AI coding agent 的上下文优化与输出压缩 CLI |
| Stars | 约 26 |
| Forks | 2 |
| 主要语言 | Rust |
| 许可 | MIT |
| 包名 | rskim |
| 当前版本 | 2.10.0 |
它不是普通的 cat 替代品
Skim 最容易理解的入口,是把一个源码文件变短。比如你让 agent 读一个 TypeScript service,它未必需要每一行 validation、循环和错误包装;很多任务只需要知道有哪些函数、参数是什么、返回值是什么、类之间如何连接。Skim 的默认 structure 模式会保留函数、类、类型、import 等结构,把函数体折叠成占位。
这和单纯截断文件不同。截断会丢掉尾部内容,也不会理解语言结构。Skim 的思路是先解析 AST,再按目的选择保留层级。README 当前列出 17 种语言支持,包括 TypeScript、JavaScript、Python、Rust、Go、Java、C/C++、C#、Ruby、SQL、Kotlin、Swift、Markdown、JSON、YAML、TOML。对代码文件,它可以在 full、minimal、pseudo、structure、signatures、types 等模式之间切换;对 JSON/YAML/TOML 这类配置文件,则提取结构而不是伪造“函数签名”。
这点对 agent 很实用。你可以先让模型看 structure 模式理解架构,再在需要修改具体逻辑时回到原文件局部。上下文不是越少越好,而是先把探索阶段和编辑阶段分开。
命令输出压缩是更容易落地的价值
源码压缩很有用,但我更看重 Skim 对终端输出的覆盖。AI agent 经常浪费上下文在这些地方:
cargo test或pytest输出一大段通过用例,只需要失败断言。tsc或cargo build把 warning、路径、堆栈混在一起,只需要错误摘要和定位。git diff给出大量未变上下文,只需要改动函数和必要边界。npm install、pnpm、pip、cargo audit输出很多进度和噪声,只需要依赖冲突或漏洞。
Skim 提供了 skim cargo test、skim pytest、skim vitest、skim jest、skim go test,也覆盖 cargo build、cargo clippy、make、tsc,以及 eslint、ruff、mypy、golangci、prettier、rustfmt、biome、black、gofmt 等 lint/format 工具。它的设计不是只做正则剪切,而是尽量先结构化解析,失败时降级到 regex,再失败才 passthrough。
这种降级策略很重要。开发工具输出格式并不稳定,完全依赖结构化 parser 很容易在边缘场景坏掉;但完全靠原样输出,又会吞掉大量 token。Skim 至少把“尽量压缩,必要时保留原始信息”的策略放进了工具里。
skim init 把节省上下文变成默认行为
README 里还有一个很适合 agent workflow 的设计:skim init。它会安装 hook,让 PreToolUse 阶段把常见命令改写成 skim 版本,例如把 cat、head、tail、cargo test、vitest、git diff 改成对应的压缩命令。
这和要求人类每次记得输入 skim 不同。真正的 agent 工作流里,问题常常不是“有没有更好的命令”,而是 agent 默认会不会调用。把命令重写放进 hook 层,可以让上下文优化发生在 agent 平时调用工具的路径上。
当然,这也意味着要谨慎。命令重写不应该改变语义或隐藏关键输出。Skim 的 guardrail 声称会保证压缩输出不会比原始输出更大,但使用者仍然应该先在低风险仓库里观察:失败日志是否保留了足够细节、diff 是否没有漏掉关键上下文、测试失败时是否还能定位。
AST-aware git diff 比普通 diff 更适合 agent
skim git diff 是我觉得最有代表性的功能之一。普通 diff 以行和 hunk 为单位,适合人类 reviewer,但对 agent 来说经常不够稳定:它可能看到局部变更,却不知道这个 hunk 属于哪个函数、是否还有同文件其他相关签名、函数边界在哪里。
Skim 的 git diff pipeline 会尝试用 AST 渲染改动函数,保留完整函数边界和 +/- 标记;--mode structure 还可以把未变函数作为签名加入上下文。这样 agent 看到的是“这个函数发生了什么变化,以及同文件里还有哪些接口”,而不是纯粹的行片段。
这对提交前自检尤其有用。Agent 改完代码后,往往需要回答三个问题:
- 我到底改了哪些函数或类型?
- 这次 diff 有没有因为局部上下文太少而误判?
- review 时需要保留多少未变代码才能看懂影响?
AST-aware diff 不会替代完整 review,也不会替代测试,但它可以让 agent 的自检输入更像“代码结构”而不是“文本碎片”。
Heatmap 和 search 把历史信号也纳入上下文
Skim 还不止做压缩。skim heatmap 会从 git history 里提取 churn hotspot、blast radius、fix risk、bus factor 和 module health 等信号。它可以按 sprint、最近 N 次提交、最近若干天或完整历史窗口计算,也能用 --insights 输出更短的阈值化结论。
这类信息很适合在 agent 开始修改前使用。一个文件如果经常和另一个目录一起改,或者最近 fix commit 密度很高,agent 就不应该只看当前文件内容。它需要知道“这个地方在历史上是不是容易出问题”“有哪些文件总是跟它一起变”。
skim search 则提供 AST-aware search index,并支持 --hot、--cold、--risky、--blast-radius FILE 这样的排序和过滤。普通全文搜索回答“哪里有这个词”,Skim 想多回答一层:“和这个文件历史上一起变化、同时又相关的地方在哪里”。这对大型仓库的上下文选择很有帮助。
和 repomix、code graph、日志压缩工具的区别
如果把 Skim 放在现有工具里比较,它并不完全等同于 repomix 这类 repo 打包工具,也不等同于 code graph memory server。它更像是一层 agent 输入过滤器。
repomix 更适合把一个仓库整理成可投喂模型的文本包。code graph 工具更关注符号、调用和跨会话记忆。Skim 的优势在于它覆盖了 agent 每天都会碰到的“即时输入”:文件、目录、diff、测试、构建、lint、包管理器、日志、git 状态。它不一定要成为唯一上下文来源,而是可以作为更靠近 shell 的压缩层。
这也是它适合小团队尝试的原因。你不需要先引入复杂服务或数据库。README 给出的安装路径包括 npx rskim、npm install -g rskim、cargo install rskim 和 Homebrew。先拿几个大文件、一次失败测试、一段 git diff 试一下,就能判断它是否减少了噪声。
需要保留的怀疑
Skim 的 README 写得很积极,也列出了大量 benchmark 和 token reduction 数字。作为早期小众项目,最好把这些数字当作项目作者的测试基线,而不是对所有代码库的保证。不同语言、不同代码风格、不同测试框架输出格式,都会影响压缩质量。
我会特别关注三类风险:
- 语义缺失:结构模式隐藏函数体后,agent 可能错过实现里的副作用、异常路径或性能细节。
- 输出误裁剪:测试和构建日志压缩如果漏掉环境信息,可能让 debug 方向变窄。
- 命令重写边界:hook 自动改写命令很方便,但团队需要明确什么时候要看原始输出。
所以,Skim 更适合作为默认探索层,而不是最终事实来源。让 agent 先看压缩版快速定向,然后在要编辑、debug 或 review 的关键路径上回读原始文件和原始日志,是更稳妥的用法。
适合谁尝试
Skim 适合这些场景:
- 你经常让 AI agent 阅读中大型仓库,探索阶段 token 消耗很高。
- 你想让测试、构建、lint、git diff 输出更适合 agent 读取。
- 你希望命令行工具能自动压缩上下文,而不是每次手动整理日志。
- 你的项目语言在 Skim 的 17 种支持语言范围内。
- 你愿意先用它做辅助层,并在关键问题上回到原始输出验证。
如果项目很小,或者你只偶尔让 agent 看单个文件,Skim 的收益可能不明显。但只要团队已经开始频繁使用 Claude Code、Codex、Cursor、Gemini CLI 或其他命令行 agent,终端输出噪声就会变成一个真实成本。
小结
dean0x/skim 是一个很值得关注的小众 Rust 工具。它抓住了 agent workflow 里一个朴素但重要的问题:上下文窗口变大以后,输入质量仍然很关键。让模型看完整代码和完整日志,不等于让它更理解任务。
Skim 的价值在于把“压缩上下文”做得更接近工程现场:AST-aware 源码变换、测试/构建/lint 输出压缩、git diff 重写、历史 heatmap、搜索排序、hook 集成。它还很早期,需要验证和边界意识,但方向是对的。未来的 coding agent 不只需要更多上下文,也需要更少噪声、更强结构和更明确的注意力焦点。