先说结果。我们拿开源库 python-humanize/humanize 的真实 issue #239 做实验,用 codex exec 非交互跑了一次:
| 项目 | 结果 |
|---|---|
| 修复前(全量测试) | 2 failed, 599 passed, 24 skipped |
| 修复后(全量测试) | 601 passed, 24 skipped |
| Codex 改动 | 1 个文件、1 行。源码改动与上游 PR #240 一致(上游另外加了 6 条测试,本文只加了 2 条) |
| 耗时 | 246 秒 |
| 模型 | gpt-5.6-sol(通过 AI Code With 接入) |
| Token | 共 19 次模型请求,输入累计 517,604(其中缓存命中 484,608),输出 4,572(含推理 987) |
过程中踩了三个坑,下文写了每个坑的现象和解决办法。
适合谁
- 已经在用 Codex CLI,想把"修 bug + 跑测试"交给它、又拿不准效果的开发者;
- 想在 CI 或脚本里用
codex exec做无人值守修复的人; - 想知道一次真实修复要花多少 token 的人。
准备工作
- Node.js 16+(
@openai/codexpackage.json 里 engines 写的是>=16),安装:npm i -g @openai/codex(本文实测版本 codex-cli 0.162.1) - Python 3.9+、git
- 一个 AI Code With API Key(登录/注册控制台后创建,接入说明见 AI Code With 的 Codex CLI 接入文档)
第 1 步:选一个真实 Bug
issue #239 描述的问题:humanize 4.11.0 里 naturalsize(1.123456789) 返回 1 Bytes,升级到 4.12.0 后变成了 1.123456789 Bytes。
检出修复合并之前的提交,也就是 PR #240 合并提交的父提交:
git clone https://github.com/python-humanize/humanize.git
cd humanize
git checkout a0602c70bb6e11322107b51114333bab7adab021
python3 -m venv ../venv && . ../venv/bin/activate
pip install -e . pytest freezegun pytest-cov
坑 1:只装 pytest、不装 pytest-cov 时,pytest 会直接报PytestConfigWarning: Failed to import filter module 'coverage',测试根本起不来。原因是这个项目的 pytest 配置引用了 coverage,补装pytest-cov就行。
第 2 步:先写失败测试
在 tests/test_filesize.py 的 test_naturalsize 参数表里加两行:
([1.123456789], "1 Bytes"),
([1.123456789, False, True], "1B"),
运行全量测试:
$ python -m pytest -q
FAILED tests/test_filesize.py::test_naturalsize[test_args62-1 Bytes] - AssertionError: assert '1.123456789 Bytes' == '1 Bytes'
FAILED tests/test_filesize.py::test_naturalsize[test_args63-1B] - AssertionError: assert '1.123456789B' == '1B'
2 failed, 599 passed, 24 skipped in 0.92s
先提交测试,之后好单独看 Codex 的 diff:git commit -am "test: reproduce #239"。
整件事能验证,前提是先让测试变红,再让 AI 改代码。
第 3 步:配置 Codex 走 AI Code With
Codex 接第三方 provider,把配置写进全局配置 ~/.codex/config.toml,Key 直接用 experimental_bearer_token 写在 [model_providers.<id>] 里,不用设环境变量:
# ~/.codex/config.toml
model_provider = "aicodewith"
model = "gpt-5.6-sol"
[model_providers.aicodewith]
name = "aicodewith"
base_url = "https://api.aicodewith.ai/chatgpt/v1"
wire_api = "responses"
experimental_bearer_token = "sk-你的Key"
改之前先备份原配置:cp ~/.codex/config.toml ~/.codex/config.toml.bak。如果原配置里有env_key这一行,记得删掉,不要和experimental_bearer_token同时用。本文实验当时是用环境变量传 Key 跑的,写进全局配置后接口、模型都一样。
另一种写法:AI Code With 的接入文档用的是 ~/.codex/auth.json(写入 OPENAI_API_KEY),再在 provider 里设 requires_openai_auth = true,适合日常交互使用。两种写法任选一种,不要混用。
更多字段说明见 Codex config.toml 配置详解。
第 4 步:用 codex exec 非交互修复
提示词原文:
tests/test_filesize.py 里有 2 个失败用例,对应 issue #239:naturalsize(1.123456789) 在 4.12.0 返回 "1.123456789 Bytes",期望 "1 Bytes"(gnu=True 时期望 "1B")。请找到根因,做最小修改修复 src/ 下的代码,不要修改测试。修复后运行 python -m pytest -q 确认全部通过,最后用中文简述根因和改动。
命令:
codex exec --sandbox workspace-write --skip-git-repo-check --json "$(cat prompt.txt)" \
< /dev/null > codex-run.jsonl
坑 2:第一次运行没加< /dev/null。在脚本或后台环境里,Codex 打印Reading additional input from stdin...之后就一直挂着,10 分钟没有任何输出,最后只能手动结束。非交互运行时,记得把 stdin 接到/dev/null。
第 5 步:Codex 做了什么
从 --json 日志看,它依次做了这几件事:
- 读
src/humanize/filesize.py和测试文件; - 用
git blame和git log -p查历史,发现旧实现用%d格式化,后来改成 f-string 时丢了取整语义。这次改动来自上游提交fb61d5a("Update pre-commit (#226)",2025-01-07); - 做最小修改:
if abs_bytes < base:
- return f"{bytes_}B" if gnu else f"{bytes_} Bytes"
+ return f"{int(bytes_)}B" if gnu else f"{int(bytes_)} Bytes"
这处源码改动和上游维护者在 PR #240 里的改动一致。
坑 3:Codex 在沙箱里执行python -m pytest时报command not found(exit 127)。它的 shell 是bash -lc登录 shell,没有继承我激活的 venv,而workspace-write沙箱默认又禁网,装不了 pytest。它的处理是改用标准库解析测试参数表,逐条断言(128 条通过),并在总结里如实说明全量 pytest 没跑成。
解决办法:在提示词里写明测试命令的绝对路径,比如 ../venv/bin/python -m pytest -q。不管怎样,合并前都要自己再跑一遍测试。第 6 步:自己验证
$ python -m pytest -q
601 passed, 24 skipped in 0.92s
用了多少 token
turn.completed 事件给出的用量:
{"input_tokens":517604,"cached_input_tokens":484608,"cache_write_input_tokens":0,"output_tokens":4572,"reasoning_output_tokens":987}
几点说明:
- 51 万输入 token 是 19 次模型请求的累加,单次最大约 3.4 万;
- 缓存写入是 0;
- 输入里 94% 命中缓存。Codex 每次请求模型都会重发上下文,所以这类任务的输入大部分能命中缓存。
常见报错
| 现象 | 原因 | 处理 |
|---|---|---|
| Reading additional input from stdin... 后卡住 | 非交互环境下 stdin 没关闭 | 命令末尾加 < /dev/null |
| 沙箱内 python: command not found 或没有 pytest | 沙箱 shell 不继承 venv,且默认禁网 | 提示词里写 venv 的绝对路径 |
| Failed to import filter module 'coverage' | 项目的 pytest 配置依赖 coverage | pip install pytest-cov |
| 401 Unauthorized | Key 错误,或 ~/.codex/config.toml 里的 Key 没填对 | 见 Codex 401 排查 |
| 长时间无响应或超时 | 网络或上游超时 | 见 Codex 超时四类排查 |
经验总结
- 先写一个红的测试,Codex 才有明确的目标和验收标准;
- 提示词里写清"最小修改、不要改测试",本次 Codex 照做了;
- 它说"测试通过"不能直接当真。
--json日志里每条命令、退出码和 token 都有记录,看完日志再自己复跑一遍。



