ChatGPT Plus / Pro + Codex 实战指南(2026年9月2日)

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 结对编程」带来的效率提升。

相关推荐
mit6.82415 分钟前
AI时代的定位与趋势
人工智能
深念Y22 分钟前
Cloudflare Workers AI 服务部署记录
人工智能·语音识别
gsls20080822 分钟前
OpsKat封装MCP:用 Go 标准库把运维 CLI 变成 AI 的“手“
运维·人工智能·golang·mcp
美股研究社27 分钟前
出海合规战,TEMU先胜“一城”
大数据·人工智能·物联网
元岳数字人小元29 分钟前
数字人一体机如何落地?多模态智能交互设备全解析
运维·人工智能·人机交互·交互·源代码管理
学着改变27535 分钟前
2026手持式超声波流量计品牌对比:巡检标定场景性能与续航评测
人工智能·科技·产品运营·能源·材质
qq4078556036 分钟前
2026 最新鼎捷 vs 轻流:生产管理系统功能对比与选型指南
大数据·人工智能·低代码·制造
夜雪一千36 分钟前
如何编写一个数据分析 Skill:完整拆解一个案例
人工智能·语言模型·数据挖掘·数据分析
liliangcsdn36 分钟前
如何对IC时间序列进行汇总统计分析示例
人工智能·算法·机器学习