1. 引言
2026 年,OpenAI 的 ChatGPT Plus 与 Pro 订阅方案,配合 Codex 编程助手,已经成为开发者日常工作中不可或缺的工具组合。很多朋友升级到 Plus 或 Pro 之后,只知道用网页版聊天,却不知道如何把 Codex 的能力真正接入自己的开发流程。
这篇文章不聊充值、不聊账号,只聊技术。我会从模型能力差异讲起,带你完成 Codex 的本地环境配置,然后通过几个真实可运行的代码示例,演示如何用 Codex 完成代码生成、仓库级重构、自动化测试编写,以及如何把它接入 CI/CD 流水线。全文 3000 字以上,所有代码均可直接复制运行。
2. 订阅方案与模型能力差异
在开始写代码之前,先搞清楚你手里的订阅到底给了你什么。ChatGPT Plus 与 Pro 在模型访问权限、上下文长度和速率限制上存在明显差异。
2.1 ChatGPT Plus
Plus 订阅主要面向日常使用,包含以下能力:
- 访问 GPT-5 系列标准模型;
- 中等优先级的推理算力;
- 支持 Codex 云端沙箱的有限使用;
- 标准速率限制。
对于偶尔写脚本、做代码审查的开发者,Plus 基本够用。
2.2 ChatGPT Pro
Pro 订阅面向重度用户,核心差异在于:
- 无限制访问 GPT-5 高算力模式;
- 更高频次的 Codex 任务并发;
- 更长的上下文窗口支持;
- 优先使用最新实验性模型。
如果你每天要处理大量代码任务,Pro 的体验会明显更流畅。
2.3 Codex 是什么
Codex 是 OpenAI 推出的编程智能体,它不只是补全代码,而是能理解整个仓库结构、执行命令、读取文件、运行测试并迭代修复。它运行在云端沙箱或本地环境中,通过自然语言指令完成复杂的工程任务。
下面用一个表格总结三者的定位差异:
| 项目 | ChatGPT Plus | ChatGPT Pro | Codex |
|---|---|---|---|
| 定位 | 日常问答 | 重度推理 | 编程智能体 |
| 上下文长度 | 标准 | 更长 | 仓库级 |
| 代码执行 | 受限 | 更宽松 | 完整沙箱 |
| 适用场景 | 轻量开发 | 复杂推理 | 工程化开发 |
3. 环境准备与 Codex 接入
无论你用的是 Plus 还是 Pro,Codex 的接入方式基本一致。下面以本地 CLI 方式为例,演示完整配置流程。
3.1 安装 Codex CLI
Codex CLI 支持 macOS 与 Linux。打开终端执行:
bash
npm install -g @openai/codex
安装完成后验证版本:
bash
codex --version
如果输出类似 codex 0.4x.x 的版本号,说明安装成功。
3.2 登录认证
Codex CLI 需要登录你的 OpenAI 账号。执行:
bash
codex login
浏览器会自动打开授权页面,登录后回到终端,会看到登录成功的提示。Codex 会自动读取你当前订阅对应的模型权限。
3.3 验证连通性
写一个最简单的测试任务,确认 Codex 能正常工作:
bash
codex exec "用 Python 写一个快速排序函数,并附带单元测试"
Codex 会在沙箱中生成代码并运行测试。如果一切正常,你会看到类似下面的输出:
text
✓ 已生成 quick_sort.py
✓ 测试通过 (4 passed)
4. 用 Codex 生成高质量代码
这一节我们通过实际案例,演示如何用 Codex 完成一个完整的 Python 工具模块开发。
4.1 任务描述
假设我们需要一个「文件批量重命名工具」,要求如下:
- 支持按规则批量重命名目录下的文件;
- 支持前缀、后缀、序号填充三种模式;
- 提供命令行入口;
- 包含完整单元测试。
4.2 使用 Codex 生成
在项目目录下执行:
bash
codex exec "在当前目录创建一个 Python 命令行工具,实现文件批量重命名:支持前缀、后缀、序号填充三种模式,使用 argparse 解析参数,并编写 pytest 单元测试"
Codex 会自动创建项目文件。生成的 renamer.py 核心代码如下:
python
import argparse
from pathlib import Path
def batch_rename(directory: str, prefix: str = "", suffix: str = "", pad: int = 0) -> int:
"""批量重命名目录下的文件。
Args:
directory: 目标目录路径。
prefix: 文件名前缀。
suffix: 文件名后缀(不含扩展名)。
pad: 序号填充位数,0 表示不填充。
Returns:
重命名的文件数量。
"""
target_dir = Path(directory)
if not target_dir.is_dir():
raise NotADirectoryError(f"{directory} 不是有效目录")
renamed = 0
for index, file_path in enumerate(target_dir.iterdir(), start=1):
if not file_path.is_file():
continue
seq = str(index).zfill(pad) if pad > 0 else str(index)
new_name = f"{prefix}{seq}{suffix}{file_path.suffix}"
new_path = file_path.with_name(new_name)
if new_path.exists():
print(f"跳过 {file_path.name}:目标文件已存在")
continue
file_path.rename(new_path)
renamed += 1
print(f"{file_path.name} -> {new_name}")
return renamed
def main() -> None:
parser = argparse.ArgumentParser(description="批量文件重命名工具")
parser.add_argument("directory", help="目标目录路径")
parser.add_argument("--prefix", default="", help="文件名前缀")
parser.add_argument("--suffix", default="", help="文件名后缀")
parser.add_argument("--pad", type=int, default=0, help="序号填充位数")
args = parser.parse_args()
count = batch_rename(args.directory, args.prefix, args.suffix, args.pad)
print(f"共重命名 {count} 个文件")
if __name__ == "__main__":
main()
4.3 运行与测试
Codex 同时生成了测试文件 test_renamer.py:
python
import pytest
from renamer import batch_rename
def test_batch_rename_with_prefix(tmp_path):
for name in ["a.txt", "b.txt", "c.txt"]:
(tmp_path / name).write_text("test")
count = batch_rename(str(tmp_path), prefix="file_")
assert count == 3
files = sorted(p.name for p in tmp_path.iterdir())
assert files == ["file_1.txt", "file_2.txt", "file_3.txt"]
def test_batch_rename_with_padding(tmp_path):
for name in ["a.txt", "b.txt"]:
(tmp_path / name).write_text("test")
count = batch_rename(str(tmp_path), prefix="img_", pad=3)
assert count == 2
files = sorted(p.name for p in tmp_path.iterdir())
assert files == ["img_001.txt", "img_002.txt"]
def test_batch_rename_invalid_directory():
with pytest.raises(NotADirectoryError):
batch_rename("/nonexistent/path")
运行测试:
bash
pytest test_renamer.py -v
预期输出:
text
test_batch_rename_with_prefix ... PASSED
test_batch_rename_with_padding ... PASSED
test_batch_rename_invalid_directory ... PASSED
5. 用 Codex 做仓库级重构
Codex 的强项在于理解整个仓库结构。下面演示如何让它完成一次跨文件的代码重构。
5.1 场景描述
假设你的项目里有一个旧模块 legacy_utils.py,其中大量使用了 datetime.now() 直接获取时间,且函数命名不规范。你希望:
- 统一时间获取方式,改为可注入的时钟;
- 重命名不规范的函数;
- 同步更新所有调用方。
5.2 发起重构指令
在项目根目录执行:
bash
codex exec "重构 legacy_utils.py:将直接调用 datetime.now() 的地方改为可注入的 clock 参数,默认使用系统时间;将 get_timestamp_str 重命名为 get_timestamp;将 format_log_line 重命名为 format_log;同步更新仓库内所有调用这些函数的地方"
Codex 会扫描整个仓库,找出所有引用点并逐一修改。重构后的核心代码:
python
from datetime import datetime
from typing import Callable
def get_timestamp(clock: Callable[[], datetime] | None = None) -> str:
"""返回当前时间的格式化字符串。
Args:
clock: 可注入的时间函数,默认使用 datetime.now。
Returns:
形如 2026-09-02 15:20:21 的时间字符串。
"""
now = clock() if clock else datetime.now()
return now.strftime("%Y-%m-%d %H:%M:%S")
def format_log(message: str, level: str = "INFO", clock: Callable[[], datetime] | None = None) -> str:
"""格式化日志行。
Args:
message: 日志消息。
level: 日志级别。
clock: 可注入的时间函数。
Returns:
格式化后的日志行。
"""
timestamp = get_timestamp(clock)
return f"[{timestamp}] [{level}] {message}"
5.3 验证重构结果
Codex 会自动运行测试来验证重构没有破坏功能。你也可以手动检查所有调用点是否已更新:
bash
grep -rn "get_timestamp_str\|format_log_line" --include="*.py" .
如果没有任何输出,说明旧函数名已全部替换干净。
6. 用 Codex 编写自动化测试
Codex 不仅能写业务代码,还能为已有代码自动生成高质量的测试。
6.1 准备被测代码
假设我们有如下一个订单折扣计算模块 discount.py:
python
from dataclasses import dataclass
@dataclass
class Order:
amount: float
is_vip: bool = False
coupon: float = 0.0
def calculate_discount(order: Order) -> float:
"""计算订单最终折扣金额。
规则:
1. VIP 用户享受 8 折;
2. 普通用户满 100 减 20;
3. 优惠券可与上述折扣叠加,但不能超过订单金额。
"""
if order.is_vip:
discount = order.amount * 0.2
elif order.amount >= 100:
discount = 20.0
else:
discount = 0.0
total_discount = discount + order.coupon
return min(total_discount, order.amount)
6.2 让 Codex 生成测试
执行:
bash
codex exec "为 discount.py 编写 pytest 单元测试,覆盖 VIP、满减、优惠券叠加、折扣封顶等边界情况"
Codex 生成的测试文件:
python
import pytest
from discount import Order, calculate_discount
def test_vip_user_gets_20_percent_off():
order = Order(amount=200.0, is_vip=True)
assert calculate_discount(order) == 40.0
def test_regular_user_over_100_gets_20_off():
order = Order(amount=150.0)
assert calculate_discount(order) == 20.0
def test_regular_user_under_100_no_discount():
order = Order(amount=80.0)
assert calculate_discount(order) == 0.0
def test_coupon_stacks_with_vip_discount():
order = Order(amount=200.0, is_vip=True, coupon=30.0)
assert calculate_discount(order) == 70.0
def test_discount_cannot_exceed_order_amount():
order = Order(amount=50.0, coupon=100.0)
assert calculate_discount(order) == 50.0
def test_vip_discount_with_coupon_capped():
order = Order(amount=100.0, is_vip=True, coupon=100.0)
assert calculate_discount(order) == 100.0
6.3 运行测试并查看覆盖率
bash
pytest test_discount.py -v --cov=discount --cov-report=term-missing
预期输出:
text
test_vip_user_gets_20_percent_off ... PASSED
test_regular_user_over_100_gets_20_off ... PASSED
test_regular_user_under_100_no_discount ... PASSED
test_coupon_stacks_with_vip_discount ... PASSED
test_discount_cannot_exceed_order_amount ... PASSED
test_vip_discount_with_coupon_capped ... PASSED
Name Stmts Miss Cover Missing
-------------------------------------------
discount.py 8 0 100%
7. 将 Codex 接入 CI/CD 流水线
Codex 的能力可以通过命令行集成到 GitHub Actions 中,实现「PR 自动代码审查」和「Issue 自动修复」。
7.1 配置 GitHub Actions
在仓库中创建 .github/workflows/codex-review.yml:
yaml
name: Codex PR Review
on:
pull_request:
types: [opened, synchronize]
jobs:
codex-review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install Codex CLI
run: npm install -g @openai/codex
- name: Run Codex Review
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
codex exec "审查当前 PR 的代码变更,重点关注:1) 潜在的 bug;2) 安全问题;3) 性能瓶颈。输出审查意见。" \
--review \
--git-diff origin/main...HEAD
7.2 自动修复 Issue
你还可以创建一个「Issue 自动修复」工作流,当 Issue 被标记为 bug 时,让 Codex 自动尝试修复:
yaml
name: Codex Auto Fix
on:
issues:
types: [labeled]
jobs:
auto-fix:
if: github.event.label.name == 'bug'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install Codex CLI
run: npm install -g @openai/codex
- name: Codex Attempt Fix
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
codex exec "请修复 Issue #${{ github.event.issue.number }} 中描述的问题,创建修复分支并提交 PR" \
--auto-fix \
--issue-number ${{ github.event.issue.number }}
7.3 工作流示意
下面是 Codex 接入 CI 后的完整工作流:
#mermaid-svg-QhfJOFhtPNlI93Vj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QhfJOFhtPNlI93Vj .error-icon{fill:#552222;}#mermaid-svg-QhfJOFhtPNlI93Vj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QhfJOFhtPNlI93Vj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QhfJOFhtPNlI93Vj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QhfJOFhtPNlI93Vj .marker.cross{stroke:#333333;}#mermaid-svg-QhfJOFhtPNlI93Vj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QhfJOFhtPNlI93Vj p{margin:0;}#mermaid-svg-QhfJOFhtPNlI93Vj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QhfJOFhtPNlI93Vj .cluster-label text{fill:#333;}#mermaid-svg-QhfJOFhtPNlI93Vj .cluster-label span{color:#333;}#mermaid-svg-QhfJOFhtPNlI93Vj .cluster-label span p{background-color:transparent;}#mermaid-svg-QhfJOFhtPNlI93Vj .label text,#mermaid-svg-QhfJOFhtPNlI93Vj span{fill:#333;color:#333;}#mermaid-svg-QhfJOFhtPNlI93Vj .node rect,#mermaid-svg-QhfJOFhtPNlI93Vj .node circle,#mermaid-svg-QhfJOFhtPNlI93Vj .node ellipse,#mermaid-svg-QhfJOFhtPNlI93Vj .node polygon,#mermaid-svg-QhfJOFhtPNlI93Vj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QhfJOFhtPNlI93Vj .rough-node .label text,#mermaid-svg-QhfJOFhtPNlI93Vj .node .label text,#mermaid-svg-QhfJOFhtPNlI93Vj .image-shape .label,#mermaid-svg-QhfJOFhtPNlI93Vj .icon-shape .label{text-anchor:middle;}#mermaid-svg-QhfJOFhtPNlI93Vj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QhfJOFhtPNlI93Vj .rough-node .label,#mermaid-svg-QhfJOFhtPNlI93Vj .node .label,#mermaid-svg-QhfJOFhtPNlI93Vj .image-shape .label,#mermaid-svg-QhfJOFhtPNlI93Vj .icon-shape .label{text-align:center;}#mermaid-svg-QhfJOFhtPNlI93Vj .node.clickable{cursor:pointer;}#mermaid-svg-QhfJOFhtPNlI93Vj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QhfJOFhtPNlI93Vj .arrowheadPath{fill:#333333;}#mermaid-svg-QhfJOFhtPNlI93Vj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QhfJOFhtPNlI93Vj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QhfJOFhtPNlI93Vj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QhfJOFhtPNlI93Vj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QhfJOFhtPNlI93Vj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QhfJOFhtPNlI93Vj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QhfJOFhtPNlI93Vj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QhfJOFhtPNlI93Vj .cluster text{fill:#333;}#mermaid-svg-QhfJOFhtPNlI93Vj .cluster span{color:#333;}#mermaid-svg-QhfJOFhtPNlI93Vj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QhfJOFhtPNlI93Vj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QhfJOFhtPNlI93Vj rect.text{fill:none;stroke-width:0;}#mermaid-svg-QhfJOFhtPNlI93Vj .icon-shape,#mermaid-svg-QhfJOFhtPNlI93Vj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QhfJOFhtPNlI93Vj .icon-shape p,#mermaid-svg-QhfJOFhtPNlI93Vj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QhfJOFhtPNlI93Vj .icon-shape .label rect,#mermaid-svg-QhfJOFhtPNlI93Vj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QhfJOFhtPNlI93Vj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QhfJOFhtPNlI93Vj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QhfJOFhtPNlI93Vj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
开发者提交 PR
GitHub Actions 触发
安装 Codex CLI
Codex 读取变更 diff
是否存在问题?
生成审查意见并评论
输出通过提示
开发者根据意见修改
合并 PR
8. 常见问题与排查技巧
8.1 Codex 无法登录
如果执行 codex login 后浏览器没有弹出,可以尝试:
bash
codex logout
codex login --headless
--headless 模式会在终端直接输出一个授权链接,手动复制到浏览器打开即可。
8.2 任务执行超时
对于大型重构任务,可以增加超时时间:
bash
codex exec "重构任务描述" --timeout 600
单位是秒,上面的命令将超时时间设置为 10 分钟。
8.3 只想让 Codex 读代码不执行
某些场景下你只希望 Codex 分析代码而不实际修改文件,可以加 --dry-run 参数:
bash
codex exec "分析当前仓库的架构,指出潜在问题" --dry-run
8.4 查看详细日志
遇到问题时开启调试日志:
bash
codex exec "任务描述" --debug
9. 总结
ChatGPT Plus 与 Pro 订阅为 Codex 提供了不同级别的算力与上下文支持,而 Codex 本身则把大模型的能力真正落地到了工程实践中。从本文的示例可以看到,Codex 可以完成:
- 从零生成带测试的完整工具模块;
- 跨文件执行仓库级重构;
- 为已有代码自动补齐边界测试;
- 通过 GitHub Actions 接入 CI/CD,实现自动化代码审查与 Bug 修复。
建议你从一个小型项目开始,先让 Codex 帮你写测试,再逐步尝试重构和 CI 集成。用得越深,你会越能感受到「AI 结对编程」带来的效率提升。