Codex 费用优化:搭 repomix 与 markitdown 把 Token 消耗降到三成
上个月我收到 Codex 的账单第一反应是以为自己被谁刷了卡。排查了一圈发现既没有死循环也没有异常的调用就是正常用了两周Token 消耗比我预估的高了快一倍。后来我把每次会话的输入输出拉出来对了一遍才意识到问题根本不在多问了几个问题而是上下文的重复装载和输入噪音频频发生。这篇文章要说的两个开源项目就是专门针对这两类浪费做优化的一个负责把代码库压缩成一份干净、紧凑的 Prompt另一个负责把 PDF、Word、Excel 这类文档转成不掺水的 Markdown。两者配合我实测下来 Token 消耗能压到原来的三成左右。如果你平时用 Codex 处理仓库级任务或者经常往里面塞各种文档这两个工具应该都能帮上忙。为了让你能判断哪个环节最该改我先不急着上项目而是把 Codex 的 Token 消耗账目拆开给你看。1. 先算清楚Codex 的 Token 究竟花在了哪里1.1 三笔容易忽略的 Token 开销Codex 和普通聊天对话不一样。普通对话里你发一条、模型回一条Token 消耗基本就是内容本身的长度。Codex 是智能体agent模式它会自己分析任务、决定要读哪些文件、执行哪些命令、观察输出、再决定下一步。这意味着同一个会话里它会反复发送当前累积的上下文。第一次开销在上下文重发。每执行一步Codex 都可能把之前的对话历史、文件内容、命令输出重新发一遍模型才能记得前面发生了什么。上下文里有 1 万 token每走一步就要为这 1 万 token 付一次钱。走 50 步光是重发就有 50 万 token 的消耗。这一步是乘法效应步数越多越吓人。第二次开销是无效输入。很多人喜欢直接把 PDF、Word、PPT 里的内容复制粘贴给 Codex或者让 Codex 自己打开一个巨大的文件去读。PDF 的排版噪音、Word 里的隐藏标记、Excel 的空行列、代码文件里大段注释和空行这些东西都会原封不动变成 token。你花的是全额的钱买来的却是模型理解上的负担。第三次开销是错误往返。输入越脏、上下文越乱Codex 的理解就越容易跑偏。跑偏一次它就会多读几个文件、多试几种方案甚至把问题改坏了再改回来。每一步都在消耗 token而且这种消耗是不可预测的账单爆炸往往就发生在这。1.2 真正的大头上下文重复装载我在排查自己的账单时最受触动的不是哪一步特别贵而是同样的代码被读了多少次。举个例子一个中型项目里有个utils.py大约 800 行。Codex 为了实现一个功能先后 6 次主动读取了这个文件每次读取约 6000 token。光这一个文件的重复读取就占了 36000 token。更麻烦的是Codex 在读取文件之后会把内容留在上下文里。哪怕后面已经不需要utils.py的细节了只要对话历史没有截断它就会一直占着位置。就像你租了个大仓库进了货不清理仓库越堆越满租金越来越贵。所以省 Token 的核心思路不是少问问题而是让每一次输入都更精准。把项目里真正有用的部分提前整理出来一次性放入上下文把文档里的排版噪音剥离掉只留干货。这两件事做好了Codex 就不需要自己东翻西找也不需要带着一堆垃圾信息跑完整条流程。1.3 省钱三板斧的逻辑输入净化、输出控制、渠道优化顺着上面的分析省 Token 无外乎从三个方向下手。输入净化把塞进上下文的内容变少、变干净。这是今天两个项目的核心战场。输出控制通过限制任务范围、约束回答格式减少模型多写废话。比如让 Codex 只输出 diff不要长篇解释。渠道优化如果你的 Codex 版本支持自定义模型端点把它接到更便宜的模型渠道上同样的问题花更少的钱。这个属于配置层面的优化不是今天的主角。输入净化最容易被忽视因为它需要前置功夫——也就是在向 Codex 提问之前先把材料处理好。多数人习惯直接把原始仓库、原始文档丢给 Codex等于把处理成本全部变成了 Token 费用。下面这两个开源项目就是帮你把这道前置功夫自动化。2. 项目一repomix把整个仓库压成一份喂给 Codex 的精准 Prompt2.1 它是干什么的为什么它能省 Tokenrepomix 是一个把代码仓库打包成单个 AI 友好文件的命令行工具前身叫 pack。你只需要在项目根目录执行一条命令它就会遍历整个仓库剔除掉不需要的文件生成一个包含文件树和核心代码的紧凑文件适合直接作为上下文喂给大模型。这个词你可能在 GitHub 上见过它是目前社区里把代码库转 Prompt这件事做得最完整的工具之一。它能自动读取.gitignore默认跳过node_modules、dist、.git这类几乎不可能对任务有帮助的目录还能自己估算 token 数。为什么它能省 Token因为 Codex 在无人干预的情况下探索代码库是非常耗 Token 的。它要自己列目录、猜哪个文件有用、逐个打开再排除。如果仓库里有 500 个文件其中 400 个跟任务无关Codex 也得先花时间和 Token 确认这些无关。而 repomix 是把所有文件压缩成一份带结构的文本你只需要看一眼 Token 统计就知道这份材料大概要花多少钱。后面不再需要反复读文件一次放进上下文就行。2.2 安装与三分钟上手安装很简单Node.js 环境是必需的。# 用 npx 直接跑不需要提前安装 npx repomix # 或者全局安装用起来更顺手 npm install -g repomix在项目根目录直接运行cd /path/to/your-project repomix默认会在当前目录生成一个repomix-output.txt里面是所有代码的拼接体。命令行结束时会打印一行统计类似Codebase analysis complete. Total files: 132 Total tokens: 48,320 Total size: 156.3 KB这一步非常关键。Token 统计直接告诉你这份材料的重量如果超过预期就该考虑加大忽略范围或者换一种打包方式而不是直接把它塞给 Codex。你还可以指定输出格式我用得最多的是 Markdown 和 XML# Markdown 格式适合人类阅读也很适合放进 Codex 提示词 repomix --style markdown --output-file codebase.md # XML 格式结构化更强程序解析更友好 repomix --style xml --output-file codebase.xml2.3 让输出更省的配置组合ignore、compress、模板只看默认行为还不够。repomix 真正比我以前用的粗暴拼接工具强的地方是它支持精细的包含和忽略规则。我第一次用它的时候直接把整个仓库打包结果一个中型项目出来 20 万 token根本喂不起。后来调整了策略用--include和--ignore只保留相关部分repomix \ --include src,scripts,docs \ --ignore **/*.test.js,**/*.spec.js,docs/archive/** \ --compress \ --style xml \ --output-file packed.xml解释一下各参数的含义--include只打包src、scripts、docs三个目录。--ignore跳过测试文件和历史归档文档。--compress这是另一个省 Token 利器。它会删除代码里的注释和多余空行并做一定的压缩处理。对于注释特别多的老项目这一项能把体积再压掉 30% 左右。--style xmlXML 格式在边界处理上更清晰Codex 分辨代码块和结构信息更不容易出错。这些规则也可以固化到配置文件里一劳永逸。在项目根目录创建repomix.config.json{ ignore: { useGitignore: true, custom: [ **/*.min.js, dist/**, coverage/**, docs/archive/** ] }, output: { style: xml, filePath: packed.xml, showLineNumbers: false }, tokenCount: { encoding: o200k_base } }我用o200k_base做编码估算是因为 OpenAPI 最新的模型大多基于这个编码体系估算出来的数字更接近真实计费。如果你用的是别的模型可能需要根据模型去调整否则会有偏差。2.4 和 Codex 配合的推荐工作流工具再好也要用对流程。我现在处理一个已有的仓库任务时基本遵循这个套路先用repomix打包一份全量概览看一下项目规模。根据任务范围决定是喂全量概览还是用--include只打包相关模块。如果仓库里注释多开启--compress。把生成的repomix-output.md作为第一条消息的背景信息发给 Codex并在提示词里明确说明代码上下文见附件后续不需要再探索仓库结构。整个会话里只围绕具体任务提问避免让 Codex 反复读取文件。用这种办法Codex 的开销模型会变得非常可预测。它不需要为了找一个小函数而翻遍整个仓库因为所有小函数都已经在上下文里了而且是经过精心筛选的。有一点要提醒不要为了数据好看就盲目开--compress。压缩会把注释全部删掉而有些注释本身就是重要的业务逻辑说明。如果这份代码里充满了为什么要这么写的注释压缩之后 Codex 可能完全看不懂这种非直观的写法接下来你要为它的错误理解付出远超省下来的 Token。压缩是一笔交易你得清楚自己在交易什么。3. 项目二markitdown别让文档里的排版噪音烧掉你的预算3.1 文档输入是 Token 黑洞很多人忽略一个问题Codex 的上下文不只是代码还有需求文档、接口文档、数据分析报告。这类材料往往以 PDF、Word、Excel 的形式存在。直接把 PDF 内容复制粘贴给 Codex会发生什么首先是页眉页脚。每一页都可能重复出现公司名、文档名、页码10 页文档就是 10 次重复。然后是分页符和断行。PDF 的文本提取经常在行尾断裂一段完整的描述被拆得七零八落。还可能有目录、水印、嵌入的图片说明。这些全是 token但全都没用甚至有害。Codex 需要花额外的推理能力去理解这个脏数据能不能看懂还是两说。我做过一个对比。同样是 10 页的 PDF 需求文档直接从 PDF 阅读器复制出来的文本约 6800 token里面有大量页眉、页脚和断裂行用 markitdown 转成 Markdown 之后只剩 3100 token而且标题层级、列表、表格都保留了下来。花一半的钱买到一份结构更清晰的材料这笔账怎么算都划算。3.2 安装与支持范围markitdown 是微软开源的工具GitHub 上目前热度很高。它支持的格式相当全PDFWord.docxExcel.xlsxPowerPoint.pptxHTMLCSV、JSON、XML图片可选用 OCR 识别文字音频可选用转录服务转文字安装用 pip# 安装全部依赖包括 OCR、音频转录等 pip install markitdown[all] # 如果只需要处理常见文档 pip install markitdown命令行就可以直接用markitdown requirements.pdf requirements.md markitdown 数据说明.xlsx 数据说明.md markitdown 产品介绍.pptx 产品介绍.md我看到不少朋友只会用命令行其实它的 Python API 也很有用。想批量处理一堆文档的时候写个小脚本非常轻松from markitdown import MarkItDown from pathlib import Path md MarkItDown() for path in Path(docs).glob(*.pdf): result md.convert(str(path)) output_path Path(output) / (path.stem .md) output_path.write_text(result.text_content, encodingutf-8)3.3 一个直观的对比试验我拿一份真实的数据分析需求文档做过试验下面是处理前后的对比。对比项PDF 直接复制粘贴markitdown 转换后Token 估算68003100包含内容页眉页脚、页码、断裂行、目录噪音标题层级、干净段落、Markdown 表格Codex 后续纠错往返次数3 次1 次那次任务是让 Codex 根据需求文档生成数据分析代码。直接粘贴版让 Codex 把统计周期理解错了因为原始 PDF 里那一段文本被分页符切开后半段跑到了第二页模型读的时候漏了一半。后面胶着了两轮才修正。转换版一次就答对了而且生成代码的质量明显更高。这就是文档类 Token 黑洞的可怕之处表面上看只是多花了点输入钱实际上因为脏数据导致的错误理解还会带来额外的输出 token 消耗。输入浪费和输出浪费叠加在一起才是账单爆炸的真正原因。3.4 markitdown 在 Codex 流里的两个正确用法用法一先转格式再贴内容。任何文档在进入 Codex 上下文之前先经过 markitdown 转成干净的 Markdown。这个习惯一旦养成处理文档的 Token 消耗基本能下降一半。文件太大的话还可以把多个 md 文件合并成一个再手动删除明显无关的章节。用法二配合 API 调用做自动预处理。如果你是用 Codex CLI 或脚本方式调接口可以在代码里先调用 markitdown 做转换再把转换结果拼进 prompt。这样整个流水线就自动化了不需要每次手动复制粘贴。我还习惯把转换后的 Markdown 文件提交到仓库里形成一个docs/md/目录。这样以后任何人要用这些文档都直接拿转换版本不用重新踩一遍原始格式的坑也算一劳永逸。4. 组合拳一次真实项目里两个项目联用省了多少4.1 场景预设接手一个历史仓库 三份需求文档前面分开讲了两个项目各自的用法现在把它们放到一个真实的场景里演示。假设你要接手的项目情况如下一个历史仓库约 1.2 万行代码分布在 420 个文件里。有 3 份需求文档分别是 PDF 格式的《功能规格说明书》、Word 格式的《接口文档》、Excel 格式的《数据字典》。任务基于这些文档让 Codex 在仓库里实现一个新的查询接口。如果按老办法直接让 Codex 自己去探索流程可能是这样的Codex 先列目录读 README、读配置、读源码一段一段探索。它分不清哪些文件跟新接口有关会把大量无关文件也读一遍。读到 PDF 需求文档时又因为格式噪音产生理解偏差来回试错。整个流程下来300k 到 400k Token 是很正常的数字取决于模型在仓库里迷路多久。用两个工具联动流程完全变了。4.2 操作顺序与 Token 估算第一步用 repomix 打包代码部分。但要控制范围不要把仓库全部打包repomix \ --ignore **/*.test.js,db/migrations/**,docs/old/** \ --compress \ --style markdown \ --output-file codebase.md去掉迁移脚本和测试文件之后420 个文件压到 290 个打包结果约 64k token。这一步做完Codex 就不再需要自己去探索仓库了。第二步用 markitdown 转三份文档markitdown 功能规格说明书.pdf spec.md markitdown 接口文档.docx api.md markitdown 数据字典.xlsx data_dict.md cat spec.md api.md data_dict.md docs_combined.md三份文档合并后约 8.5k token。加上代码包 64k总共约 72.5k token。这里面还包含我第一条消息里的任务描述我习惯再留一点余量按 80k 算。第三步把两份材料一起放进 Codex 的第一条消息并给它明确指令代码上下文和文档上下文都在上面直接基于这些内容实现功能不要去仓库里找其他文件不要重复读取。最终单次任务的 Token 消耗大约在 85k 到 100k 之间几乎腰斩再腰斩而且整个过程中 Codex 迷路的概率大大降低。我用一套差不多的办法跑了几天基本上把原来让 Codex 自由探索的三分之一到四分之一用量做到了同样甚至更好的结果。4.3 如果还想更省模型路由的思路输入精简到一定程度之后还想继续省钱就要看模型渠道侧了。如果你的 Codex 版本支持自定义模型端点把它接到成本更低的模型渠道上Token 单价会直接降下来。这一点社区里已经有很多朋友在实践也有很多 Codex 接入其他模型的教程。这块涉及的内容比较杂而且不同版本的 Codex 配置方式变动蛮大我就先不展开了。如果你感兴趣可以自己去搜关键词Codex 自定义端点核心思路就是通过环境变量或配置文件把 Codex 的请求指向你希望调用的模型 API 地址。要注意的是不同模型对工具调用的支持程度不一样跨模型使用之前最好先做一轮小规模验证。5. 配套的心得与踩坑记录5.1 repomix 输出过大的切割技巧打包出来的文件如果太大不要急着喂给 Codex。先看命令行打印的 Token 统计超过目标就调整策略。一种办法是缩小范围只打包任务相关的模块。比如任务是修复登录模块的 bug那就--include src/auth,src/utils把无关的支付、订单代码全部丢在外面。另一种办法是把一个大包拆成多个小文件分批喂。比如先给 Codex 一个整体概览文件树 核心入口文件等它提出具体问题再把对应模块的完整代码追加进去。这种做法能把单次请求的上下文控制住避免一次性投入过多 Token 却用不上。我踩过的坑是一开始图省事全量打包一个超大仓库结果 repomix 生成了 18 万 token 的文件我硬塞给 Codex。任务进行到一半Codex 开始遗忘早期内容回答质量明显下降反而要重开会话。后来才明白省 Token 不等于不花 Token而是把每一个 Token 都花在刀刃上。合理分片让 Codex 在每一个会话里只看它真正需要的内容比一次性给全量高效得多。5.2 扫描版 PDF 与乱码文档要小心markitdown 对普通 PDF 的转换效果很好但有一个明显的软肋扫描版 PDF。这类文件本质是图片没有文本层。markitdown 拿到这种 PDF读不出任何文字转出来要么是空白要么只有 OCR 出来的零星乱码。解决办法是先用 OCR 工具把扫描件识别成文本再用 markitdown 或者手动整理成干净文本。常见的开源方案有 PaddleOCR 等识别中文效果也比较可靠。但 OCR 本身有误识别率越专业的术语越容易出错。处理完之后稍作人工校对再喂给 Codex。另外Excel 转出来的 Markdown 表格可能非常长尤其是有几十个 Sheet 的工作簿。建议在转换之前先把真正需要的 Sheet 单独拆出来或者写脚本按 Sheet 名筛选只保留核心内容。否则一个数据字典转出 5000 行表格它也变成一个巨大的 Token 负担反而违背了省 Token 的初衷。5.3 压缩是技术更是取舍不能省的 Token 别省这是我最想强调的一点。很多朋友用repomix --compress之后看到 Token 数刷一下降下来非常兴奋。但压缩不是免费的。代码里的大段注释往往是业务规则的最佳说明尤其是那些为什么不用方案 A 而用方案 B的注释。这些内容被删掉以后Codex 可能会基于代码表象得出一个完全相反的结论然后给出一个技术上正确、业务上错误的方案。你省下了输入 Token却要为多轮纠错付出更多的输出 Token 和宝贵时间。同理某些看似冗余的上下文比如项目的整体架构说明、模块之间的依赖关系对 Codex 理解任务至关重要。这种 Token 属于基建投入该花就花。我现在的原则是无关内容坚决不喂相关内容压缩可以但核心逻辑和业务说明一条不动。5.4 把省 Token 变成日常工作流的最后建议最后分享几个我从实践中养成的习惯也算给这篇文章收个尾。第一把 repomix 和 markitdown 固化成固定的前置步骤而不是想起来才用。我给自己的工作目录写了一个简单的打包脚本一条命令完成代码打包 文档转换 Token 统计每次开新任务前先跑一遍心里大概有数知道这次任务要花多少预算。第二在提示词里明确告诉 Codex上下文已经齐了不需要再探索仓库。这句话真的能省很多 Token因为它直接切断了 Codex 因为不确定而启动的主动探索行为。第三如果被 Codex 的登录态问题困扰过比如 token 失效、验证流程卡住直接用 API Key 方式运行 Codex CLI 会省心很多。我自己的使用体验是 API Key 方式的会话状态更可控配合自定义模型端点也更灵活。这可能涉及不同人的使用习惯你可以自己试试看哪种方式顺手。第四也是最重要的省 Token 不是目的让 Codex 更快地给出高质量结果是目的。所有压缩、忽略、切割的动作都应该围绕帮助 Codex 更好理解任务来设计。如果一个操作让 Codex 的理解变差了不管它省了多少 Token都不值得做。这两个开源项目给我带来的最大改变不是账单数字变小了而是我对 Codex 的每一次使用都变得有掌控感。我知道喂进去的是什么、花了多少、预期的产出是什么而不是月底看账单的时候一脸茫然。如果你也在被 Codex 的 Token 消耗困扰建议从 repomix 和 markitdown 开始先跑通一个只涉及单模块和单文档的任务再慢慢扩展到整个仓库级工作流。这套方法不会让你的 Codex 变聪明但会让你花出去的每一分钱都更值。