1. 引言

2026 年的今天,AI 编程助手已经从「能补全几行代码」进化到「能理解整个代码库、参与架构讨论、自动生成测试」的阶段。在众多工具中,ChatGPT Plus / Pro 订阅所附带的 Codex 能力,是很多程序员每天都会用到的生产力工具。

但很多人的用法还停留在「把报错信息贴进去问一下」的层面。这篇文章我想分享一套更系统、更实战的用法:如何用 ChatGPT Plus / Pro + Codex 完成一次完整的代码审查与重构工作流。整个过程包含真实案例、可复制的 Prompt、具体的操作步骤,以及我在实践中踩过的坑。

本文写于 2026-08-28,所有操作基于当时最新的 ChatGPT 界面与 Codex 功能。文章不涉及任何充值或广告内容,只讲技术本身。

2. 准备工作:环境与前置条件

在开始之前,先确认你的环境满足以下条件:

  • 一个 ChatGPT Plus 或 Pro 订阅账号,且已开通 Codex 功能。
  • 本地安装 Git,并已初始化一个代码仓库。
  • 准备一个真实的项目。本文以 Python 项目为例,但整套流程对 Java、Go、TypeScript 同样适用。
  • 建议开启 Codex 的「代码库感知」能力(Codebase Awareness),这样它能读取你仓库中的多个文件,而不是只盯着你粘贴的那一段。

2.1 为什么选择 Codex 而不是普通对话

ChatGPT 普通对话模式适合问答,但 Codex 是专门为代码任务设计的。它的优势在于:

  • 可以读取本地文件系统,理解项目结构。
  • 支持在沙箱环境中执行命令、运行测试。
  • 能生成 diff 格式的修改建议,方便你 review。
  • 与 Git 集成更紧密,可以直接查看提交历史。

3. 实战案例:一个需要重构的旧模块

为了演示完整流程,我准备了一个真实的旧代码片段。这是一个用户服务模块,功能是加载用户配置并做权限校验。代码能跑,但存在明显的问题。

# user_service.py
import json
import os


def load_user_config(user_id):
    path = os.path.join("configs", user_id + ".json")
    if not os.path.exists(path):
        return None
    with open(path, "r") as f:
        data = json.load(f)
    return data


def check_permission(user_id, action):
    config = load_user_config(user_id)
    if config is None:
        return False
    if action in config.get("permissions", []):
        return True
    return False


def get_user_name(user_id):
    config = load_user_config(user_id)
    if config is None:
        return "unknown"
    return config.get("name", "unknown")

这段代码的问题很明显:

  1. 每个函数都重复调用 load_user_config,没有缓存。
  2. 文件路径拼接用字符串加法,跨平台有隐患。
  3. 权限校验逻辑写死,无法扩展。
  4. 没有类型注解,可读性差。
  5. 没有异常处理,文件损坏时会直接崩溃。

接下来,我会用 ChatGPT Plus / Pro + Codex 来完成审查和重构。

4. 第一步:用 Codex 做代码审查

4.1 初始化 Codex 会话

在项目根目录打开终端,启动 Codex:

codex

如果你是第一次使用,它会引导你登录 ChatGPT 账号并授权本地访问权限。授权后,Codex 会扫描当前目录,建立代码库索引。

4.2 发起审查请求

在 Codex 交互界面中,输入以下 Prompt:

请审查 user_service.py 这个文件。重点关注:
1. 代码重复与可维护性
2. 潜在的安全问题(如路径遍历、注入)
3. 异常处理是否完善
4. 性能问题(如重复 IO)
5. 可测试性

请按严重程度分级输出问题清单,并给出每个问题的具体行号和修改建议。

Codex 会读取文件并给出结构化的审查结果。下面是我实际得到的结果摘要:

审查结果:

[严重] 路径遍历风险(第 4 行)
  user_id 直接拼接到文件路径中,恶意输入可读取任意 JSON 文件。
  建议:校验 user_id 格式,或使用白名单映射。

[中等] 重复读取配置文件(第 8、17、25 行)
  每个函数独立调用 load_user_config,同一请求周期内多次 IO。
  建议:引入缓存或依赖注入。

[中等] 缺少异常处理(第 9 行)
  JSON 解析失败会抛出未捕获异常。
  建议:捕获 json.JSONDecodeError 并返回默认值。

[轻微] 无类型注解(全文)
  建议:补充类型注解,提升可读性与 IDE 支持。

4.3 审查结果的价值

这一步的价值在于:Codex 不是简单地「找 bug」,而是按严重程度分级,并给出可执行的修改建议。你可以逐条确认,而不是盲目接受。

5. 第二步:基于审查结果进行重构

5.1 让 Codex 生成重构方案

审查完成后,我继续输入:

基于你的审查结果,请重构 user_service.py。要求:
1. 使用 dataclass 封装用户配置
2. 增加模块级缓存,避免重复 IO
3. 补充类型注解
4. 增加异常处理
5. 保持对外函数签名不变(load_user_config / check_permission / get_user_name)
6. 输出完整的重构后代码

Codex 会生成重构后的代码。下面是我得到的结果:

# user_service.py (重构后)
import json
import os
from dataclasses import dataclass, field
from functools import lru_cache
from typing import Optional


@dataclass
class UserConfig:
    user_id: str
    name: str = "unknown"
    permissions: list = field(default_factory=list)


def _safe_path(user_id: str) -> Optional[str]:
    """校验 user_id 并返回安全的配置文件路径。"""
    if not user_id or not user_id.isalnum():
        return None
    return os.path.join("configs", f"{user_id}.json")


@lru_cache(maxsize=128)
def load_user_config(user_id: str) -> Optional[UserConfig]:
    path = _safe_path(user_id)
    if path is None or not os.path.exists(path):
        return None
    try:
        with open(path, "r", encoding="utf-8") as f:
            data = json.load(f)
        return UserConfig(
            user_id=user_id,
            name=data.get("name", "unknown"),
            permissions=data.get("permissions", []),
        )
    except (json.JSONDecodeError, OSError):
        return None


def check_permission(user_id: str, action: str) -> bool:
    config = load_user_config(user_id)
    if config is None:
        return False
    return action in config.permissions


def get_user_name(user_id: str) -> str:
    config = load_user_config(user_id)
    if config is None:
        return "unknown"
    return config.name

5.2 人工 review 重构结果

这里要特别强调:不要盲信 AI 生成的代码。我 review 后发现几个问题:

  1. lru_cache 会缓存 None 结果,如果配置文件后来被创建,缓存不会失效。对于这个场景可以接受,但要注意。
  2. _safe_pathisalnum() 校验,会拒绝包含连字符的合法 user_id。需要根据业务调整。
  3. 权限校验仍然依赖 action in permissions,如果权限体系复杂,建议引入策略模式。

我把这些问题反馈给 Codex,它给出了改进版本。这种「人机协作」的循环,才是 AI 编程的正确姿势。

6. 第三步:生成单元测试

6.1 让 Codex 生成测试

重构完成后,下一步是补测试。我输入:

请为重构后的 user_service.py 编写 pytest 单元测试。要求:
1. 覆盖正常路径、异常路径、边界条件
2. 使用 tmp_path fixture 模拟配置文件
3. 测试 check_permission 和 get_user_name 的返回值
4. 不要 mock lru_cache,直接测试真实行为

Codex 生成的测试代码:

# test_user_service.py
import json
import pytest

import user_service


@pytest.fixture
def config_dir(tmp_path, monkeypatch):
    """创建临时配置目录并指向 user_service。"""
    target = tmp_path / "configs"
    target.mkdir()
    monkeypatch.setattr(user_service, "os", __import__("os"))
    # 注意:这里需要让 user_service 使用 tmp_path
    # 实际项目中建议通过环境变量或参数注入路径
    return target


def test_load_user_config_normal(config_dir):
    user_id = "alice"
    (config_dir / f"{user_id}.json").write_text(
        json.dumps({"name": "Alice", "permissions": ["read", "write"]}),
        encoding="utf-8",
    )
    config = user_service.load_user_config(user_id)
    assert config is not None
    assert config.name == "Alice"
    assert "read" in config.permissions


def test_load_user_config_missing(config_dir):
    assert user_service.load_user_config("nobody") is None


def test_load_user_config_invalid_json(config_dir):
    user_id = "bob"
    (config_dir / f"{user_id}.json").write_text("{invalid", encoding="utf-8")
    assert user_service.load_user_config(user_id) is None


def test_check_permission_allowed(config_dir):
    user_id = "alice"
    (config_dir / f"{user_id}.json").write_text(
        json.dumps({"permissions": ["read"]}), encoding="utf-8"
    )
    assert user_service.check_permission(user_id, "read") is True
    assert user_service.check_permission(user_id, "delete") is False


def test_get_user_name_unknown(config_dir):
    assert user_service.get_user_name("ghost") == "unknown"

6.2 运行测试并修复问题

在 Codex 沙箱中运行:

pytest test_user_service.py -v

Codex 会执行测试并报告结果。如果测试失败,它会分析失败原因并给出修复建议。这一步的价值在于:测试驱动 AI 编程,让 AI 生成的代码有验证依据。

7. 第四步:用 Git 管理 AI 修改

7.1 让 Codex 生成提交信息

重构和测试都通过后,需要提交到 Git。我让 Codex 帮忙生成规范的提交信息:

请为以下改动生成一个符合 Conventional Commits 规范的提交信息:
- 重构 user_service.py,引入 dataclass 和缓存
- 新增 test_user_service.py 单元测试
- 修复路径遍历安全隐患

Codex 输出:

refactor(user-service): 重构用户配置加载并补充单元测试

- 使用 dataclass 封装 UserConfig,提升类型安全
- 引入 lru_cache 减少重复文件 IO
- 增加 user_id 格式校验,修复路径遍历风险
- 补充异常处理,避免 JSON 解析崩溃
- 新增 pytest 单元测试,覆盖正常与异常路径

7.2 手动执行 Git 操作

注意:Git 提交操作建议手动执行,不要完全交给 AI。因为提交信息需要你确认,而且 AI 可能误操作。手动执行:

git add user_service.py test_user_service.py
git commit -m "refactor(user-service): 重构用户配置加载并补充单元测试"

8. 进阶技巧:让 Codex 理解整个代码库

8.1 跨文件重构

上面的例子只涉及单个文件。实际项目中,重构往往涉及多个文件。Codex 的代码库感知能力可以处理这种情况。

例如,我输入:

我在项目中新增了 UserConfig dataclass,请找出所有直接调用 load_user_config 并手动访问字典键的地方,改为使用 UserConfig 属性访问。

Codex 会扫描整个仓库,列出所有受影响的文件,并逐个给出修改建议。你可以用 git diff 查看每个文件的改动,确认无误后统一应用。

8.2 让 Codex 解释历史提交

Codex 还可以帮你理解历史代码。输入:

请查看 git log 中最近 5 次提交,总结这个模块的演进脉络,并指出可能引入回归风险的提交。

这对于接手旧项目非常有帮助。

9. 注意事项与常见坑

9.1 不要盲目接受 AI 代码

AI 生成的代码可能有逻辑错误、安全漏洞或性能问题。每一行代码都要 review。尤其是涉及权限、支付、数据删除等敏感逻辑时,更要谨慎。

9.2 注意上下文窗口限制

Codex 的上下文窗口有限。当项目很大时,它可能「忘记」之前的对话内容。建议:

  • 把大任务拆成小步骤。
  • 每个步骤聚焦一个文件或一个模块。
  • 关键信息(如函数签名、数据结构)在 Prompt 中重复强调。

9.3 保护敏感信息

不要把生产环境的密钥、密码、Token 粘贴给 AI。Codex 的沙箱虽然隔离,但数据可能被用于模型训练(取决于你的订阅条款)。建议:

  • 使用脱敏数据。
  • 在本地用环境变量管理密钥。
  • 涉及商业机密时,使用私有化部署方案。

9.4 版本兼容性

AI 生成的代码可能依赖较新的库版本。在集成到项目前,先确认依赖版本兼容。例如,dataclasses 在 Python 3.7+ 才可用,如果你的项目还在用 Python 3.6,就需要调整。

10. 完整工作流总结

下面用一张流程图总结本文的完整工作流:

有异议

通过

启动 Codex 会话

发起代码审查

审查结果确认

追问并澄清

生成重构方案

人工 review 重构代码

生成单元测试

运行测试

测试通过?

反馈失败原因给 Codex

生成 Git 提交信息

手动执行 Git 提交

这套流程的核心是:AI 负责生成和迭代,人类负责决策和把关。两者配合,才能既快又稳。

11. 结语

ChatGPT Plus / Pro + Codex 不是「自动写代码的机器」,而是一个「随叫随到的资深结对程序员」。它擅长快速生成初稿、发现盲点、批量处理机械性工作,但最终的架构决策、安全把关和业务理解,仍然需要你来完成。

希望这篇文章能帮你把 Codex 用得更顺手。如果你有自己的一套 AI 编程工作流,欢迎在评论区分享交流。

Logo

葡萄城是专业的软件开发技术和低代码平台提供商,聚焦软件开发技术,以“赋能开发者”为使命,致力于通过表格控件、低代码和BI等各类软件开发工具和服务,一站式满足开发者需求,帮助企业提升开发效率并创新开发模式。

更多推荐