最近给一个 AI 代码助手做数据管线被仓库的 git log 折磨得不轻。一个不算大的项目两三千个 commit原始日志拉出来接近 10 万 token。prompt 还没组织完上下文窗口先顶到了天花板。后来换了个思路用 rtk 这种工具做前置处理同样的历史数据压到 2% 左右模型该知道的提交意图、影响文件、变更趋势一样没少token 成本骤降。这个叫 rtk 的工具在开源社区已经拿了 8 万星属于那种看着不起眼、实际极能打的类别。它的核心定位不是“压缩日志”而是“token 代理”——在代码仓库和大语言模型之间加一层预处理把模型真正需要的信息挑出来把不需要的噪音丢掉。这篇文章我想把它拆开聊聊git log 到底为什么这么费 token98% 是怎么压出来的以及这种工具真正适合用在哪些场景。如果你也在做 AI 辅助编码、代码评审、仓库问答或者 API 成本优化这内容大概率能对你有用。1. rtk 是什么为模型“预先消化”仓库内容1.1 被 git log 一路“吃掉”的 token先看一个真实感受。我之前处理某跨平台系统的提交历史仓库不算大也就 2200 多个 commit。直接跑git log --all --stat输出文本量是 460 多 KB换算成 token 大概在 10 万上下。再想带一点 patch 细节进去轻松破 15 万。也就是说你只是想让它帮忙总结一下最近一个月哪些模块在持续重构模型却被迫先吞下一整本“仓库流水账”。问题就出在 git 的原始输出是按人类阅读习惯设计的。完整 40 位哈希、作者名加邮箱、时区时间、merge 信息、分级缩进、全部路径……这些对模型理解“代码发生了什么变化”几乎没有帮助却在每一个 token 上烧钱。我当时的第一个想法是用--formatoneline之类的参数去精简。确实能降一些但从 10 万降到 6 万左右依然不够。因为单纯格式化去掉的是“样子”不是“冗余”。真正费 token 的是大量中间 commit 的重复信息、merge 分支的交叉陈述以及所有那些和问题无关的琐碎历史。这时候我才意识到需要一个从语义层面做减法的工具而不是一个格式美化器。1.2 “token 代理”这个定位不要理解成网络代理rtk 官方把自己的能力叫“token 代理”。这里说的代理不是网络代理也不是转发网关而是一个“内容代理”的概念在你把仓库内容交给模型之前它先替你“读一遍、懂一遍、做一遍取舍”最后只把模型真正需要消费的那部分知识整理好交出去。就像你请了一个非常熟悉代码库的助理让 TA 看完原始日志帮你写一份摘要你再拿这份摘要去开会而不是直接把仓库 Git 仓库的完整 log 拍在会议桌上。这也是它和普通压缩工具最本质的区别。普通压缩是“用更少字节表达同样信息”rtk 这类工具是“挑出有价值的信息再组织成更省 token 的形态”。它允许丢东西丢掉的是模型不需要的元数据、重复描述、低信息熵的文本。从这个角度看它输出的不是一个小的 log 文件而是一份为特定任务准备的上下文片段。实际用下来rtk 的输出风格非常“给模型读”——紧凑的字段标识、短哈希、归一化日期、省略可推断路径、聚合相似提交。乍看有点奇怪但塞进 prompt 之后模型的理解效率反而比杂乱原文更高。2. 压掉 98% 的底层逻辑git log 的冗余到底藏在哪2.1 原始 git log 里的“安静冗余”要理解它能压掉 98%得先搞清楚一个没有被处理过的 git log 到底在 token 上有多浪费。我拆几个最容易吃 token 的点。第一是完整哈希。每 commit 的 40 位 SHA 会被当作一整段长字符串输入 tokenizer它不是一个高频词往往会被拆成十来个 token。你仓库里 2000 个 commit光哈希就浪费掉好几万 token。而实际上git 世界里 7 到 12 位短哈希就可以唯一标识绝大多数提交模型读代码时也完全不需要 40 位全值。第二是作者元信息和时间格式。Author: Zhang San zhangsanexample.com加Date: Mon Sep 23 21:45:12 2024 0800这类完整表达lin 在压缩格式里就变成ze 2024-09-23甚至3d ago。老格式里全部都大写的月份名、时区偏移量、星期几模型不需要知道token 却照常收。第三是 merge 提交的重复。一整个分支合回主干git log 会输出类似于Merge branch feature/foo into develop后面跟着一系列已经被各自记录的 commit。对这些低频信息压缩逻辑完全可以只写一行“merged 23 commits from feature/foo”语义基本不留损失。第四是路径的重复前缀。一个 monorepo 项目里几十个文件路径都带packages/service/src/main/java/com/company/module/这种长前缀。如果一条条全部展开token 数量会非常可观。rtk 的做法是折叠公共前缀改成相对路径加分组统计。把这些加到一起你就会发现真正承载语义的部分commit message 的主题行、变更的文件集合、变更幅度可能只占原始输出的 2% 到 5%。其余全是“包装材料”。这 98% 不是没信息而是对模型理解代码这个问题没有用的信息。2.2 压缩三板斧截断、去重、结构化rtk 的压缩策略归纳起来就三件事理解了这三点很多同类工具的原理你也都能看懂。第一板斧是截断。短哈希、归一化时间、压缩作者格式、去掉归并提交里的重复内联记录。这一层是纯粹的格式瘦身就像把一篇文章里的字体、行距去掉只留下文字本身。第二板斧是去重。把语义上重复的提交合并成一条聚合记录。比如连续的fix typo、update docs、style: lint这类小提交在按主题聚合后可以合并为一行N commits: chore/style updates。这个动作其实模拟了人读日志时的自动归类习惯你不会把 30 个fix lint一条一条全看一遍模型同样不需要。第三板斧是结构化。把长段的自然语言描述转换成字段化的紧凑格式。比如一条提交记录从自然语言段落变成r:a1b2c3 3d zh: fix login race condition F: auth/login.go auth/session.go S:42 -17这样一个记录行同时保留了变更模块、文件影响、增删行数和核心意图。模型读到的是完全可解析的信息而不是需要自己从散文里提取的无序序列。2.3 为什么能压到 98%而不是“删掉了 98% 的信息”有人听到 98% 会担心这是不是把信息都删光了不是。要区分“信息量”和“原始文本量”。log 原始输出里大量 token 花在重复性的、可推断的、与当前问题无关的内容上。98% 的压缩率压缩的是那些不值得模型消费的“展示型文本”而不是语义。我能给出的判断依据是把未压缩的 git log 和 rtk 压缩后的输出同时丢给模型让它分别回答“最近登录模块改了什么”二者的回答质量几乎一致。但未压缩版本消耗的 token 是压缩版本的 50 倍而多出的那 49 倍基本都在“认真阅读”作者、日期和哈希。当然压缩也意味着策略选择。rtk 选择保留的是提交主题、关键文件路径、增删行数、提交者简写和相对时间。它放弃的是完整哈希、完整姓名、日志正文附带的冗长描述、以及重复性的归并信息。这套取舍不是万能的所以要看场景选用后面我会展开说什么地方不合适。3. 8 万 star 背后的设计取舍3.1 优先保留什么信息熵视角一个工具能在开源社区拿到 8 万 star说明它踩中的不是小众需求而是普遍存在的痛点。但 star 多不意味着它的实现有多玄妙反而在于设计取舍非常清晰。从信息论视角看git log 这种文本里不同部分的“信息熵”差异极大。提交主题行通常是开发者手工写的信息熵高值得保留自动生成的 merge 信息、重复的路径前缀、完整的哈希值信息熵低可以删除或缩写。rtk 做的事情本质上是一个“熵过滤”高熵语义留下低熵格式抛弃。它甚至不会尝试去解读代码内容因为那超出了“代理”的职责范围它只做物流层面的整理。这也解释了为什么它能在压缩和处理质量之间取得平衡。它不追求像抽象总结那样重新生成语言而是保守地保留最高信息密度的原始字段。代价最小可信度最高因为输出里的每一个事实都来自仓库本身。3.2 和 RAG 的互补不是替代品很多人第一次接触这类工具会拿它和 RAG 检索增强生成比。我一开始也这么想过后来实践证明它俩根本不是同一层的东西。RAG 解决的是“从大规模知识里捞取和问题相关的一小段”核心是检索管道是 embedding、向量库、相似度计算。rtk 解决的是“让一段已知上下文以最低成本被模型消化”核心是压缩与结构化管道是内容解析和格式重排。实际工作流里它们往往是串联关系。比如在做一个仓库问答系统时先用 rtk 把仓库的提交历史和变更记录压缩成库再对压缩后的文本做切分和 embedding。这样索引体积变小检索效率和准确率还会提升因为喂进向量库的已经是高信噪比的文本而不是塞满完整哈希和邮件地址的原始日志。这也是它拿 8 万 star 的原因之一它不是替代某个已有环节而是插在现有 AI 工程链路里几乎任何用到仓库文本的项目都能接上这么一层。3.3 心智模型的转换把人读的 log 转成模型读的 contextrtk 最让我觉得有价值的一点是想明白了一个问题git log 是给“人”设计的而 prompt 是给“模型”设计的。两者看似都是文本但消费方式完全不同。人看 git log会扫两眼作者、扫一眼日期、重点读提交说明。模型不需要“扫”这个动作它会把所有可见 token 视作信息一视同仁地加权处理。因此那些对人类来说无害的冗余对模型来说就是实打实的注意力噪音——既烧钱还会模糊真正重要的内容。转换心智模型之后你再看 rtk 的输出格式就顺眼了。每条 commit 都是一个紧凑的记录块按时间、模块、频率组织字段稳定便于模型快速定位。它不是在“美化”一份日志而是在“编译”出一个模型友好的上下文格式这思路本身就值回票价。4. rtk 真正适合哪些场景4.1 AI 代码评审把 PR 浓缩成一段可消费的上下文做 AI 辅助代码评审时最头疼的不是分析逻辑而是怎么把一场评审需要的信息塞进 prompt。一个中等规模的 MR涉及 20 个文件、50 多个 commit原始 diff 加完整提交日志动辄 5 万 token。你已经想好要让模型关注登录模块和状态处理逻辑但 prompt 里却塞着一堆无关文件的历史演进。用 rtk 处理之后MR 上下文变成这样一个是变更文件清单及各自增删行数一个是相关 commit 的紧凑列表还有一个是跨文件的公共路径折叠。三个部分加起来 1000 token 出头模型读得快关注点也容易聚焦。我实际做过对比测试。同一个 PR一份是原始上下文一份是 rtk 压缩上下文让模型各自评估并发风险和代码结构问题。压缩版本反而在细节准确率上稍高因为它没有被无关提交的噪声干扰评审建议更加具体。“少即是多”这个说法在 AI 代码评审里体现得很充分。4.2 自动生成 CHANGELOG 和 release notes靠 git log 自动生成 changelog 是很多团队的常规需求但直接用原始 log 跑出来的 changelog 质量一直不太行原因还是噪声太大。几十个 fix、style、chore 混在一起模型很难提炼出真正面向用户的变更要点。rtk 的聚合能力在这里很好用。它把同类型提交按主题聚类比如“这一版有 14 个 fix 提交集中在鉴权模块”这让模型在生成 changelog 时能快速抓主干。你不需要让模型逐条浏览所有提交它只要基于这些聚合信息就能产出结构良好的 release notes效率和准确率都更高。4.3 大仓库问答与检索增强生成的预处理在大型 monorepo 里做“问仓库”这类功能一个很大的成本瓶颈是如果你要把仓库的提交历史、目录结构、负责人信息做成 AI 可查资源直接全文索引存储和检索开销都难以控制。有人做过估算一个 5000 commit 的仓库光 git log 原始文本就有 1 MB 还多转成 embedding 又放大很多倍。rtk 的优势在于它能把语料先压到原来的 2% 左右再进入后续的切分、embedding、索引流程。代价是丢失掉一些细节信息——但在仓库问答这个场景里用户问的通常是“这个模块最近为什么频繁改动”或“谁负责登录模块”需要的就是趋势和归属不是逐字节的 commit 原文。这里给出的建议是做 RAG 预处理时可以考虑双索引策略。一份是 rtk 压缩后的摘要索引负责回答趋势性、结构性、归属类问题一份是原始全文的关键词索引负责需要精确引用原文的场景。两者配合成本和精度兼顾得很稳。4.4 CI 流程中稳定控制 prompt 成本如果你的 AI 工作流已经跑在 CI 里比如每次 push 后自动做代码 review、自动补 commit message、自动检查提交规范那 token 成本的稳定性是一个必须面对的问题。原始 git log 的长度完全取决于仓库历史规模prompt 成本时高时低预算非常难做。rtk 这类压缩层的价值在于它把输入长度拉到一个可预测的范围内。不管仓库历史是 100 条还是 2000 条 commit经过压缩后上下文尺寸都是同一量级。这让下游的 prompt 模板、token 预算、超时控制都变得容易设计。CI 管道里的 token 消耗不再是“开盲盒”而是变成一笔可预算的成本。4.5 微调语料的噪声过滤做模型微调或数据集构造时如果用 git 历史作为训练语料原始日志里的噪声会直接影响训练质量。完整哈希、邮件地址、merge 信息这些无意义字符串会干扰模型学习“提交信息与代码变更之间的对应关系”。把 rtk 作为数据预处理工具可以把真实 commit 历史转成干净的训练样本。它的输出格式本身就是模型友好的指令-响应对很适合直接构造微调数据。相比手工清理这能省下大量数据处理的时间。4.6 一句话警告这些场景不应该上 rtk任何工具都有边界。rtk 这类激进压缩策略放在下面这些场景里可能会帮倒忙场景不建议原因逐行精确代码审计压缩后丢失完整链路无法定位具体代码行合规审计与作者归属追溯完整作者、时间、哈希是审计元数据不能被缩写包含大量二进制文件的仓库文本压缩对二进制 diff 没有意义需要完整保真输出的场景压缩是有损策略不适合追求无损的流程极大规模 monorepo 一次性全量读取单次全量压缩仍可能超上下文需配合分片策略记住一个判断标准如果你的下游任务要求“每个字节都可追溯”那压缩工具就不合适如果下游任务是让模型“理解发生了什么”那 rtk 这类工具几乎总是能帮你省钱省心。5. 实操用 rtk 压一个真实仓库的完整过程5.1 安装与首条命令rtk 这类工具通常以命令行方式分发安装方式也不复杂。由于不同版本的包名和子命令会有差异最稳妥的起点是先看--help不过使用逻辑是相通的。以我这边常用的一套命令为例# 安装 npm install -g rtk-cli # 查看帮助确认当前版本支持哪些子命令 rtk --help # 压缩 git log生成紧凑上下文 rtk log --path /path/to/repo --depth 1000 --no-merges --format compact # 压缩两个版本之间的变更摘要 rtk diff --from HEAD~10 --to HEAD --stat # 输出到一个文件方便后续塞进 prompt rtk log --path /path/to/repo --output context.txt这里--depth 1000表示只看最近 1000 条提交--no-merges是跳过归并提交--format compact选择紧凑输出模式。如果你用的 rtk 版本命令名不一样不用纠结一般都会有log、diff、export这类子命令来覆盖核心能力。我第一次跑的时候还犯过一个低级错误直接在仓库根目录跑rtk log结果工具提示找不到.git目录。后来才发现它读取的是当前目录下的 git 元数据需要在仓库目录内执行或者用--path显式指定。5.2 参数怎么选depth、merges、hash、stat参数选择直接决定压缩质量和信息保留之间的平衡下面是我自己试出一组比较好用的组合按任务类型区分任务类型推荐参数理由AI 代码评审--no-merges --compact-hash --stat聚焦文件变更跳过归并噪声CHANGELOG 生成--no-merges --aggressive允许聚合相似提交提炼主干仓库问答索引--depth 2000 --compact保留更长历史但用紧凑格式控制 token提交规范检查关闭--aggressive保持完整主题行需要完整提交信息来校验规范审计场景不启用压缩使用原生输出保留完整元数据可追溯如果你拿不准就先用默认参数跑一遍然后在输出文件上估算 token可以用分词工具或直接看文件大小估算除以 4 左右。如果输出明显超过你的 prompt 预算再打开--aggressive或调低--depth。要注意的是--aggressive这类超级压缩模式会把更多小提交合并成聚合条目代价是单条 commit 的细节变少。对趋势分析来说是好事但如果你要精确定位某个具体提交做了哪几行改动就不该开这个开关。5.3 把 rtk 接进 CI 和 AI 工作流的三种姿势第一种姿势最简单就是在 prompt 构建前先调用一次 rtk把生成的文件塞进变量context$(rtk log --path . --depth 500 --no-merges --format compact) prompt请根据以下变更历史分析登录模块的稳定性趋势\n$context第二种是作为 CI 的一个前置步骤把压缩后的上下文输出成缓存文件后续多个 job 共享避免每个 job 都重新跑一遍压缩逻辑。我见过不少项目把这一步放到构建阶段的早期这样后面所有依赖上下文的 AI 步骤都能省下重复解析的时间。第三种是做成一个后端 API 的中间层。你的服务收到“某仓库某时间范围变更”的请求时先调用 rtk 生成紧凑上下文再传给大模型。这样接口层不感知仓库内部结构也比较容易做缓存和限流。5.4 token 成本估算一张表算清楚省了多少我用一个真实项目做过对比。项目情况是2300 个 commit15 个活跃分支90% 的提交集中在后端服务目录。以下是不同处理方式下的估算 token 量处理方式输出形态估算 token备注原始git log --all --stat完整历史完整元数据约 102,000最费量级git log --oneline精简一行式提交列表约 51,000半折但信息贫乏git log --format自定义可读性增强仍保留大量字段约 38,000依赖自配格式rtk 默认压缩紧凑字段短哈希约 3,100含提交主题和文件改动rtk 加--aggressive高度聚合格式约 1,900适合趋势总结从 10 万量级到 2 千量级压缩率确实能达到 98%。这里面要特别注意我说的 token 数是估算值不同 tokenizer 的切分策略不同实际数字会有浮动但数量级差距是确定的。如果你要自己算节省的成本公式很简单节省的 token 原始 token - 压缩后 token。假设你的模型输出价格是每百万 token 3 美元一次代码评审原本文本输入就要 0.3 美元用 rtk 后只要 0.01 美元左右。一天跑 100 次 CI一个月的差别就很可观了。6. 常见问题与排错记录6.1 压缩后“信息丢失”怎么办有段时间我在做提交规范检测发现经过压缩后某些提交的主题行被截断了。后来才明白--aggressive模式会把主题行按长度截断以换取更小的输出对规范性检测这种需要完整主题的场景来说属于丢了重要的信息。解决办法是区分场景。规范检测这种任务不要在压缩参数里开--aggressive同时把主题行长度阈值调大或者直接用--format compact而不是更极端的模式。压缩参数必须和下游任务匹配这是我从这个坑里得出的第一条经验。如果你的任务确实需要完整保留每一条 commit 的提交信息又希望省 token可以优先压缩的是元数据部分哈希、作者、时间、路径前缀而完整保留主题行。很多 rtk 版本支持对字段进行独立控制建议花点时间研究一下字段配置而不是一律套用默认参数。6.2 --no-merges 不是所有场景的银弹我最初习惯开--no-merges因为归并提交对分析一般没太大价值。但在一个分支策略管理比较严格的项目里merge 提交往往记录了 feature 分支接入主干的关键时间点和冲突情况跳过它之后模型的趋势分析就缺了一块。现在我的选择标准是如果只需要“谁改了什么”--no-merges没问题如果还要分析“这些改动在什么时间点以什么方式合入主干”那 merge 提交其实提供了额外的结构化信息留着更好。它不会增加太多 token因为归并提交通常只有一行主题。6.3 自研脚本和 rtk 的边界在哪有些团队会觉得自己写一个awk加正则的日志清洗脚本也能做到类似效果。理论上确实可以但实际要维护的东西比想象中多得多。自研脚本通常只能做格式层面的精简比如截断哈希、删掉作者名、折叠空行。而 rtk 这类工具真正的价值在于语义聚合、文件公共前缀分析、跨提交模式识别这些都需要对 git 对象结构做解析不是几行正则就能稳定实现的。另外还要考虑不同操作系统的 git 差异、国际化时间格式、非 UTF-8 提交信息等边角问题自研方案很容易在这里翻车。我的建议是一次性处理、需求高度定制、只跑一次的脚本可以自行实现长期在 CI 里跑、需要稳定输出结构的场景直接用成熟工具更划算。6.4 日志很短的小仓库有必要上 rtk 吗如果你现在的仓库只有几十个 commit原始 git log 也就 1 万 token 以内那确实不需要专门引入一个工具。可以直接用git log --oneline --stat手动组织一下 prompt 就够用。但如果你预计仓库会持续增长或者你同时在处理多个仓库那么提前把 rtk 集成到流程里是有价值的。因为这不仅仅是在省 token更重要的是让你的 prompt 模板保持稳定。一次配置之后所有仓库都走同一套压缩逻辑再大的历史都不需要担心 prompt 结构被撑爆。工具的复利效应在仓库成长后会越来越明显。最后分享一点实践心得就个人体验来说rtk 这类工具最打动我的不是它省了多少 token而是它让我重新审视了“喂给模型的上下文到底需要什么”。在没有压缩概念的时候我习惯把所有信息一股脑塞进去总怕漏掉什么。实际上模型在信息过载环境下的表现并不好它会像人一样被无关细节带跑。把上下文压到刚好覆盖关键信息的范围不仅是降成本也是在提升回答质量。动手做这一步之后我的 AI 代码评审输出里不相关建议明显减少很多问题的分析也更集中了。如果你打算在项目里引入这类工具我的建议是先不要追求极端压缩率从默认参数开始先跑一个真实仓库看看输出形态再根据任务调整字段配置。数据管线里多一层处理肯定会有调试成本但相比每次调用都多花几十倍的 token 成本这个前置投入相当划算。后续你还可以在这个基础上继续扩展比如拿压缩后的历史做仓库健康度分析、自动生成周报甚至训练一个“读提交历史”的小模型。顺着这个方向玩下去能做的事比想象中多不少。