Codex 第五课:第一个编码任务
从"Hello World"到修复 Bug,再到添加新功能——三个任务带你完整体验 Codex 的编码工作流。
1. 启动 Codex
1.1 打开终端
首先,打开你的终端(Terminal),进入一个空的工作目录:
mkdir ~/codex-playground && cd ~/codex-playground
1.2 启动 Codex CLI
在终端中输入以下命令启动 Codex:
codex
你会看到 Codex 的欢迎界面,类似这样:
╔══════════════════════════════════════╗
║ Codex CLI v0.x.x ║
║ OpenAI's coding agent in terminal ║
╚══════════════════════════════════════╝
Model: o4-mini
Approval mode: suggest (推荐模式)
Type your coding task, or use:
/plan - 规划模式,先制定方案再执行
/help - 查看帮助
/quit - 退出
>
1.3 了解三种审批模式
Codex 有三种运行模式,通过 --approval-mode 或 -a 参数指定:
| 模式 | 说明 | 适用场景 |
|---|---|---|
suggest | 每个操作都需要你确认 | 推荐初学者使用,安全可控 |
auto-edit | 自动执行文件编辑,但运行命令需要确认 | 信任编辑操作时 |
full-auto | 全部自动执行,无需确认 | 完全信任的任务 |
强烈建议初学者使用 suggest 模式,这样你能清楚地看到 Codex 每一步在做什么。
2. 第一个任务:创建 Hello World 脚本
2.1 输入任务描述
在 Codex 的提示符下,输入你的第一个任务:
> 创建一个 Python 脚本 hello.py,打印 "Hello, Codex!" 和当前日期时间
2.2 Codex 分析需求
Codex 会开始分析你的需求。你会看到类似这样的思考过程:
🔍 分析任务...
- 需要创建一个 Python 文件
- 文件名:hello.py
- 功能要求:
1. 打印 "Hello, Codex!"
2. 显示当前日期和时间
- 需要使用 Python 的 datetime 模块
2.3 Codex 生成代码方案
接着 Codex 会提出执行计划:
📋 执行计划:
1. 创建 hello.py 文件
2. 写入以下代码:
代码预览:
┌──────────────────────────────────────────┐
│ 1 | #!/usr/bin/env python3 │
│ 2 | from datetime import datetime │
│ 3 | │
│ 4 | if __name__ == "__main__": │
│ 5 | print("Hello, Codex!") │
│ 6 | now = datetime.now() │
│ 7 | print(f"当前时间: {now}") │
│ 8 | │
└──────────────────────────────────────────┘
3. 运行 python3 hello.py 验证结果
2.4 请求审批执行
在 suggest 模式下,Codex 会请求你的批准:
⚠️ Codex 请求执行以下操作:
操作 1: 创建文件 hello.py
操作 2: 运行命令 python3 hello.py
你是否批准?[Y/n/all]
- 输入
Y— 批准当前操作 - 输入
n— 拒绝当前操作 - 输入
all— 批准本次所有操作,后续不再询问
2.5 用户批准并查看结果
输入 Y 批准后,Codex 会执行操作:
✅ 已创建 hello.py
✅ 运行 python3 hello.py
输出:
┌──────────────────────────────────────────┐
│ Hello, Codex! │
│ 当前时间: 2025-06-28 10:30:15.123456 │
└──────────────────────────────────────────┘
🎉 任务完成!脚本运行成功。
2.6 完整交互流程回顾
让我们回顾一下整个交互过程:
用户 → Codex:创建一个 Python 脚本,打印 Hello World 和当前时间
Codex → Codex:分析需求,确定文件名、功能点、依赖模块
Codex → Codex:生成代码方案
Codex → 用户:展示方案,请求审批
用户 → Codex:批准(Y)
Codex → 系统:创建文件、执行脚本
Codex → 用户:展示执行结果
这就是 Codex 的基本工作模式:分析 → 计划 → 请求批准 → 执行 → 反馈。
3. 第二个任务:修复 Bug
3.1 制造一个 Bug
让我们先手动创建一个有 Bug 的脚本。继续在 Codex 中输入:
> 先帮我创建一个 buggy_math.py 文件,内容如下:
def divide(a, b):
return a / b
def average(numbers):
total = sum(numbers)
return divide(total, len(numbers))
print(average([10, 20, 30]))
print(average([]))
Codex 创建文件后,运行它会报错:
20.0
Traceback (most recent call last):
File "buggy_math.py", line 9, in <module>
print(average([]))
File "buggy_math.py", line 4, in average
return divide(total, len(numbers))
File "buggy_math.py", line 2, in divide
return a / b
ZeroDivisionError: division by zero
3.2 让 Codex 修复 Bug
现在让 Codex 来修复这个问题:
> 修复 buggy_math.py 中的 bug。当传入空列表时,average 函数应该返回 0 而不是报错。同时给 divide 函数添加除数为零的检查。
3.3 Codex 的修复方案
Codex 会展示修复计划:
📋 修复方案:
问题分析:
1. average() 在空列表时调用 divide(total, 0) 导致除零错误
2. divide() 没有对 b=0 的情况做防御性检查
修改方案:
1. 在 divide() 中添加 b==0 的检查,返回 None 或 0
2. 在 average() 中添加空列表检查,直接返回 0
代码预览:
┌──────────────────────────────────────────────────┐
│ 1 | def divide(a, b): │
│ 2 | if b == 0: │
│ 3 | return 0 │
│ 4 | return a / b │
│ 5 | │
│ 6 | def average(numbers): │
│ 7 | if not numbers: │
│ 8 | return 0 │
│ 9 | total = sum(numbers) │
│10 | return divide(total, len(numbers)) │
└──────────────────────────────────────────────────┘
3.4 批准并验证
批准后 Codex 执行修改并运行测试:
✅ 已修改 buggy_math.py
✅ 运行 python3 buggy_math.py
输出:
┌──────────────────────────────────────────┐
│ 20.0 │
│ 0 │
└──────────────────────────────────────────┘
🎉 Bug 已修复!空列表情况现在正确返回 0。
关键观察:Codex 不是简单地"改代码",它会:
- 先分析错误原因
- 理解代码逻辑
- 提出防御性修复方案
- 验证修复后的行为
4. 第三个任务:添加新功能
4.1 提出新功能需求
现在让我们在已有的 buggy_math.py 基础上添加新功能:
> 给 buggy_math.py 添加以下功能:
> 1. 添加一个 median() 函数,计算中位数
> 2. 添加一个 mode() 函数,计算众数(出现次数最多的数)
> 3. 添加一个 describe() 函数,返回一组数据的完整统计信息(最小值、最大值、平均值、中位数、众数)
> 4. 在文件底部添加测试代码,用 [3, 1, 4, 1, 5, 9, 2, 6, 5] 这组数据测试所有函数
4.2 Codex 的工作方式:先阅读代码
这是 Codex 最智能的地方——它不会直接开始写代码,而是先阅读现有代码:
🔍 正在分析现有代码...
当前文件结构:
- divide(a, b) → 除法函数,含除零保护
- average(numbers) → 平均值函数,含空列表保护
新功能规划:
- median() → 排序后取中间值,偶数个取中间两个的平均
- mode() → 统计频率,返回出现次数最多的值
- describe() → 聚合所有统计函数
4.3 Codex 制定计划
📋 实施计划:
步骤 1: 从 collections 导入 Counter(用于 mode 计算)
步骤 2: 添加 median() 函数
- 排序列表
- 奇数个取中间值
- 偶数个取中间两个值的平均
步骤 3: 添加 mode() 函数
- 使用 Counter 统计频率
- 返回出现次数最多的值
步骤 4: 添加 describe() 函数
- 调用所有统计函数
- 返回字典格式的统计信息
步骤 5: 添加测试代码
步骤 6: 运行验证
4.4 Codex 逐步执行
批准后,Codex 会逐步生成代码:
from collections import Counter
def divide(a, b):
if b == 0:
return 0
return a / b
def average(numbers):
if not numbers:
return 0
return divide(sum(numbers), len(numbers))
def median(numbers):
if not numbers:
return 0
sorted_nums = sorted(numbers)
n = len(sorted_nums)
mid = n // 2
if n % 2 == 1:
return sorted_nums[mid]
else:
return divide(sorted_nums[mid - 1] + sorted_nums[mid], 2)
def mode(numbers):
if not numbers:
return None
counter = Counter(numbers)
max_freq = max(counter.values())
modes = [k for k, v in counter.items() if v == max_freq]
return modes[0] # 返回第一个众数
def describe(numbers):
return {
"count": len(numbers),
"min": min(numbers) if numbers else None,
"max": max(numbers) if numbers else None,
"average": average(numbers),
"median": median(numbers),
"mode": mode(numbers),
}
# 测试代码
if __name__ == "__main__":
data = [3, 1, 4, 1, 5, 9, 2, 6, 5]
print(f"数据: {data}")
print(f"个数: {len(data)}")
print(f"最小值: {min(data)}")
print(f"最大值: {max(data)}")
print(f"平均值: {average(data)}")
print(f"中位数: {median(data)}")
print(f"众数: {mode(data)}")
print(f"\n完整统计: {describe(data)}")
4.5 验证结果
✅ 已修改 buggy_math.py
✅ 运行 python3 buggy_math.py
输出:
┌──────────────────────────────────────────┐
│ 数据: [3, 1, 4, 1, 5, 9, 2, 6, 5] │
│ 个数: 9 │
│ 最小值: 1 │
│ 最大值: 9 │
│ 平均值: 4.0 │
│ 中位数: 4 │
│ 众数: 1 │
│ │
│ 完整统计: {'count': 9, 'min': 1, │
│ 'max': 9, 'average': 4.0, 'median': 4, │
│ 'mode': 1} │
└──────────────────────────────────────────┘
🎉 新功能添加完成!所有测试通过。
5. 理解 Codex 的工作方式
通过这三个任务,我们观察到 Codex 有一套清晰的工作模式:
5.1 五步工作流
┌─────────────────────────────────────────────────────┐
│ Codex 工作流 │
│ │
│ ① 阅读代码 ──→ ② 分析需求 ──→ ③ 制定计划 │
│ │ │
│ ▼ │
│ ⑤ 验证结果 ←── ④ 逐步执行 │
│ │ │
│ ▼ │
│ 展示结果给用户 │
└─────────────────────────────────────────────────────┘
① 阅读代码:Codex 会先了解项目结构和现有代码。它不只是看你当次输入的 prompt,还会查看工作目录下的文件、理解代码上下文。
② 分析需求:将你的自然语言描述转化为具体的编程任务。它会识别:
- 需要创建/修改哪些文件
- 需要使用什么语言特性或库
- 有哪些边界情况需要考虑
③ 制定计划:在执行之前,Codex 会列出详细的步骤。这是审查它工作思路的好时机——如果计划不合理,你可以直接拒绝并重新描述需求。
④ 逐步执行:按照计划一步步执行,每一步都是原子操作(创建文件、编辑代码、运行命令等)。
⑤ 验证结果:运行代码确认功能正确,展示执行结果。
5.2 Codex 的"记忆"
Codex 在单次会话中有上下文记忆。这意味着:
- 后续任务可以引用之前的任务:比如"给刚才创建的文件添加功能"
- 它会记住之前的错误:如果某次修复失败,它会记住并调整策略
- 但新会话会从头开始:退出
codex重新进入后,之前的上下文就丢失了
5.3 Codex vs 普通 AI 对话
| 特性 | 普通 AI 对话 | Codex |
|---|---|---|
| 代码生成 | ✅ 生成代码文本 | ✅ 生成代码并写入文件 |
| 运行代码 | ❌ 需要手动复制运行 | ✅ 直接在终端运行 |
| 读取文件 | ❌ 需要你粘贴内容 | ✅ 自动读取项目文件 |
| 安装依赖 | ❌ 无法操作 | ✅ 可以执行 pip/npm 等 |
| Git 操作 | ❌ 无法操作 | ✅ 可以 commit/push |
| 交互确认 | ❌ 无 | ✅ 展示方案等待审批 |
6. 交互技巧
6.1 清晰描述需求
❌ 模糊的描述:
> 写个程序
✅ 清晰的描述:
> 创建一个 Python 脚本 weather.py,使用 requests 库
> 调用 OpenWeatherMap API 获取北京当前天气,
> 显示温度、湿度、天气状况,并用彩色输出
描述越具体,Codex 的输出越符合你的期望。好的描述包含:
- 语言/框架:Python、Node.js、React 等
- 具体功能:做什么、输入什么、输出什么
- 技术偏好:用什么库、什么风格
- 边界条件:如何处理异常情况
6.2 提供上下文
❌ 缺少上下文:
> 修复这个 bug
✅ 提供上下文:
> 修复 api_handler.py 中的 bug。
> 当 POST 请求 body 中没有 "name" 字段时,
> 服务器应该返回 400 而不是 500。
> 期望的返回格式: {"error": "name field is required"}
6.3 使用 /plan 先规划
对于复杂的任务,建议先用 /plan 模式让 Codex 规划:
> /plan
> 帮我创建一个 REST API 项目,包含:
> 1. 用户注册和登录(JWT 认证)
> 2. CRUD 操作的 Todo 列表
> 3. SQLite 数据库
> 4. 完整的错误处理
> 5. 单元测试
/plan 模式下 Codex 只会展示方案,不会执行任何操作。你可以:
- 审查方案是否合理
- 让它调整计划:"把 SQLite 改成 PostgreSQL"
- 确认后再用正常模式执行
6.4 迭代式开发
不要一次给太大的任务。推荐迭代式开发:
第 1 步: > 创建一个基础的 Flask API,有 /health 端点
第 2 步: > 添加 /users 端点,支持 GET 和 POST
第 3 步: > 给 POST /users 添加输入验证
第 4 步: > 添加 JWT 认证中间件
第 5 步: > 添加单元测试
每一步都小而清晰,Codex 的表现会更好,你也更容易控制质量。
6.5 拒绝并重新引导
如果 Codex 的方案不符合预期,不要勉强批准,直接拒绝并给出更清晰的指引:
⚠️ Codex 请求执行以下操作...
你是否批准?[Y/n/all]
> n
> 不要使用全局变量,请用类来封装这些状态。
> 另外,用 logging 模块替代 print 输出。
6.6 利用 Codex 的自纠错能力
如果 Codex 的代码运行出错了,它会自动分析错误并尝试修复:
> 运行一下 hello.py
✅ 运行 python3 hello.py
❌ 错误: ModuleNotFoundError: No module named 'requests'
🔍 检测到缺少依赖,正在修复...
运行: pip install requests
✅ 已安装 requests
✅ 重新运行 python3 hello.py
输出:Hello, Codex! 当前时间: ...
7. 常见问题
Q1: Codex 和 ChatGPT 有什么区别?
ChatGPT 是一个对话助手,它能写代码,但只能把代码以文本形式返回给你。你需要手动复制代码到文件、手动运行。
Codex CLI 是一个编码代理(Agent),它能在你的终端中直接操作文件系统、运行命令、安装依赖。它是"动手干活"的,不只是"出主意"的。
Q2: Codex 会修改我的重要文件吗?
在 suggest 模式下,每个操作都需要你批准。只要你在审批时仔细查看,就不会有意外修改。建议在版本控制(Git)下使用 Codex,这样即使出错也能轻松回退:
git init # 初始化 Git
codex # 使用 Codex
git diff # 查看 Codex 做了哪些改动
git checkout . # 如果不满意,回退所有改动
git add -A && git commit # 满意的话,提交改动
Q3: Codex 支持哪些编程语言?
Codex 底层使用大语言模型,理论上支持所有主流编程语言。实际测试中,以下语言表现最好:
- Python(最擅长)
- JavaScript / TypeScript
- Go
- Rust
- Java / Kotlin
- C / C++
- Shell / Bash
Q4: Codex 能处理多大的项目?
Codex 的上下文窗口有限,对于非常大的项目,它不会一次性读取所有文件。它会:
- 先看目录结构
- 根据任务需求读取相关文件
- 只修改需要改动的部分
如果你的项目非常大,建议在描述中明确指出要修改哪个文件的哪部分功能。
Q5: 网络断了还能用吗?
Codex 需要调用云端的 AI 模型,所以需要网络连接。但你已经创建的文件和已安装的依赖不受影响。
Q6: 为什么 Codex 有时候会"理解错"我的需求?
大语言模型对自然语言的理解虽然很强,但仍有局限性。常见原因:
- 描述太模糊:没有指定语言、框架、具体行为
- 隐含假设:你认为"理所当然"的细节没有说出来
- 技术术语歧义:"cache" 可能是缓存数据,也可能是缓存策略
解决方法:提供更多上下文,或者用 /plan 先看方案再决定。
Q7: Codex 生成的代码质量如何?
Codex 生成的代码通常质量不错,但它不是完美的。你仍然需要:
- 审查代码逻辑是否正确
- 检查边界情况是否处理
- 考虑安全性问题
- 进行代码测试
把 Codex 当作一个高效的编程搭档,而不是可以完全信赖的"自动程序员"。
Q8: 如何让 Codex 效率更高?
几个实用建议:
- 使用项目级别的
codex.md:在项目根目录创建codex.md,写上项目规范、技术栈、代码风格等信息,Codex 每次启动都会读取 - 保持良好的项目结构:规范的目录和文件命名帮助 Codex 更好地理解项目
- 分步发布任务:大任务拆小,每步验证
- 善用
/plan:复杂任务先规划再执行 - 提供示例:如果想要特定风格的代码,给一个示例
8. 本课小结
在这一课中,我们通过三个实际任务完整体验了 Codex 的工作流程:
| 任务 | 技能点 | Codex 展示的能力 |
|---|---|---|
| Hello World | 创建新文件 | 需求理解 → 代码生成 → 运行验证 |
| 修复 Bug | 修改现有代码 | 错误分析 → 防御性编程 → 回归测试 |
| 添加功能 | 扩展代码库 | 阅读上下文 → 增量开发 → 集成验证 |
你已经掌握了 Codex 的基本使用方法。在下一课中,我们将深入学习 /plan 规划模式,让 Codex 帮你规划复杂的项目架构,先"画蓝图"再"施工"。
9. 动手练习
- 练习一:让 Codex 创建一个
calculator.py,实现加减乘除四则运算,支持命令行参数输入 - 练习二:故意在
calculator.py中引入一个除零 Bug,然后让 Codex 修复它 - 练习三:让 Codex 给
calculator.py添加科学计算功能(平方根、幂运算、对数)
完成这些练习后,你就真正掌握了 Codex CLI 的使用!