舍弃今日,只为明朝。我喜欢痛苦,因为痛苦意味着,生命中那些不完美的地方正在被修补。
本文系笔者在阅读 《OpenAI Codex 最佳实践》 的基础上,补充了部分个人心得。以话题列表的方式展开。
Codex 不是 Chatbot,而是 AI Agent。不要把它当作临时性的对话助手,它就像是一名小组成员,一位中级软件工程师,需要时间来培养。在初始阶段,他对项目、代码、任务一无所知,随着慢慢了解和提升,处理起需求来也会更加得心应手。
我现在更习惯把 Codex 看成一个驻留在终端里的初级到中级开发搭档:它擅长 阅读文件、编辑代码、执行命令、总结问题,但要向着什么目标改、是否值得改、改动边界在哪里、是否符合团队规范,最后仍然需要开发者自己把关。只要这个角色定位明确,很多期待落差就会自然消弭。
因此,在与他交流的过程中,要格外注意 Prompt(提示词)的质量,不要问空泛抽象的问题,例如"为什么这个脚本报错"。问题越模糊,对 AI 思考的约束就越弱,得到精确回答的概率就越低。
因此,我想讨论的第一个话题是 ------ 如何撰写高质量的提示词。
GCCO ------ 高质量 Prompt 的写作公式
AI Agent 背后的大模型,掌握了人类几千年历史以来全部信息,其认知储备远超地球上任何一个自然人。这固然是好事,他无所不知,无所不晓。不论我们问什么问题,都能得到答案。但能力太过强大、知识太过丰富,没有边界的 AI 就像一把双刃剑,这在一些场景下并非是好事。如果提问者的问题不够明确,很容易把 AI 引导到错误的方向上越走越远,不仅无法完成正常的任务,还会空耗 token,造成时间和金钱的双重损失。
在这个时候,尽量把 AI 当成一个初出茅庐的实习生/新员工,他具备一定的逻辑思考能力、学习能力、信息挖掘能力,但需要我们为其明确目标及上下文,制定约束条件,说清楚希望 AI 用什么方案、技术、工具来完成任务。
GCCO ------ 目标、上下文、约束、输出
这里推荐一个提示词框架:GCCO,是四个英文单词的首字母缩写:
- Goal/目标 :你想要实现的功能、完成的构建是什么?如果任务再复杂一点,还可以额外补一行
Non-goals,明确说明这次不处理什么。 - Context/上下文 :说明相关资源,例如相关文件、目录、文档、错误信息。可以使用
@filename的形式在 CLI 中引用具体文件。 - Constraints/约束:必须遵守的规则,例如项目架构要求、编码规范、安全限制、代码风格。
- Output/输出:输出格式的要求,例如所使用的语言、要达到的效果、需要通过哪些测试、是直接修改代码还是先提供待审核的方案。
Android 开发场景下的 Prompt 对比(好的 vs 坏的)
小技巧:使用
@filename让 AI 只关注相关文件,而不是扫描整个仓库。这样能够显著减少 token 消耗,降低答非所问的概率,防止过度思考、上下文爆炸。
对于 Android 工程,尤其建议把下面几类目录排除在主要上下文之外:构建产物、自动生成代码、第三方缓存、图片和视频资源、历史归档脚本。它们要么无助于解决当前问题,要么非常消耗 token。
| 场景 | 坏的 Prompt | 好的 Prompt | 为什么好 |
|---|---|---|---|
| 实现新功能 | "写一个 Android 图片同步模块。" | Goal :实现 PhotoSyncManager,用于同步表盘图片到手表。 Context :项目为 Android Kotlin + MVVM。已有模块 DialRepository、BleTransferManager。 Constraints : - 使用 Kotlin Coroutine - 同一时间只允许一个同步任务 - 使用 Flow 通知 UI 状态 Output : - 支持 FIFO 队列 - 支持 cancel(dialId) | 明确目标、架构和完成条件,避免 AI 随意设计 |
| 修复 Bug | "帮我修复这个 crash。" | 应用在同步表盘图片时出现 crash。 Stacktrace :java.lang.NullPointerException at PhotoSyncManager.kt:134 Relevant file :@PhotoSyncManager.kt Goal :找出 root cause 并修复。 Constraints:不要改变 API 行为。 | 提供 stacktrace 和文件,AI 才能定位问题 |
| 代码优化 | "优化这段 Kotlin 代码。" | 请优化下面 Kotlin 函数:kotlin<br>fun checkPhotoFileChange(...)<br> Goal :降低时间复杂度。 Constraints : - 保持函数签名不变 - 避免 O(n²) - 使用 Set/Map 优化查找 |
明确优化目标,否则 AI 可能乱改 |
| 重构代码 | "重构这段代码,让它更好。" | Goal :重构 PhotoSyncManager。 Problems : - 同步逻辑与 UI 耦合 - 并发任务没有控制 Constraints : - Repository 层负责业务逻辑 - ViewModel 只负责状态 Expected architecture:ViewModel → UseCase → Repository | 告诉 AI 为什么重构以及目标架构 |
| 设计模块 | "设计一个 BLE 文件传输模块。" | Goal :设计 BLE 文件传输模块。 Environment :- Android App ↔ Watch RTOS- BLE MTU = 247 Requirements : - 支持断点续传 - 支持进度回调 - 支持取消 Output format:1 类图2 核心接口3 Kotlin 示例代码 | 需求完整,AI能做系统设计 |
| 新增 API | "写个 API 获取手表配置。" | Goal :实现函数 getWatchDialConfig()。 Input :watchId Output :DialConfig Constraints : - suspend function - 运行在 Dispatchers.IO- 返回 sealed Result 类型 | 避免 AI 随意定义接口 |
| 调试问题 | "为什么我的代码卡顿?" | Context : 用户在进入 DialPreview 页面时出现卡顿。 Observed : - UI thread blocked 200ms - Glide decode bitmap Goal:分析可能原因并提出解决方案。 | 提供观测信息才能分析 |
Windows + WSL/Ubuntu 环境整体架构示意
我比较推荐的工作架构是:Windows 11 + Android Studio(Windows) + WSL2 Ubuntu+ Git(WSL)+ Codex CLI(WSL)。

- Windows 负责图形化 IDE、模拟器、浏览器和日常办公软件。
- Android Studio 负责查看代码、人工 review、断点调试和最终提交。
- WSL Ubuntu 负责 Node、npm、Git、Java 命令、Gradle 命令以及 Codex CLI。
- Codex 负责读写局部目录、执行命令、生成补丁、分析报错和整理任务进度。
这样做的核心思路,是把 IDE体验 和 命令行执行环境 拆开。Android Studio 继续运行在 Windows 上,因为它在图形界面、模拟器、设备调试、性能分析等方面体验更成熟;Codex 则运行在 WSL 的 Ubuntu 里,因为 Agent 对 Linux 的终端、脚本、权限模型、包管理器和文件系统操作支持更稳定。
两者各用所长,组合起来比全都堆在 Windows 原生环境里更顺手。
项目代码应该放在 Windows 还是 Ubuntu 文件系统中?
虽然运行在同一台电脑上,但 Windows、Ubuntu 是相互隔离的操作系统,WSL 在其中作为桥接,供两者访问对方的文件系统。因此,在实践中,我们面临两种选择:应当把项目代码放在哪一个文件系统,是 Windows,还是 Ubuntu?
Windows、Ubuntu 文件系统目录的对应关系
| 项目代码所处文件系统 | Windows 项目目录 | Ubuntu 项目目录 |
|---|---|---|
| Windows | D:\Projects\... |
/mnt/d/Projects/... |
| Ubuntu | ~/Projects/... |
\\wsl.localhost\Ubuntu\home\lei\Projects\... |
小技巧:在 Ubuntu 命令行里,通过命令
explorer.exe .可以打开 Windows 资源管理器窗口,窗口地址栏里记录了对应 Windows 文件系统的路径。如下图:

方案一:只保留一份项目代码,放在 Ubuntu
出于简化操作的考虑,当考虑电脑上只有一份项目代码时,建议把它放在 Ubuntu 中。原因如下:
- 文件系统性能差异 :WSL 访问 Windows 文件系统走的是
9P协议桥接,每次文件操作都要通过 WSL bridge 进行传输,导致 Gradle 构建过程中读写速度降低。注意此时要把 gradle cache 配置在 Linux 环境下,不要放在 Windows。 - Codex CLI 的性能依赖文件扫描:频繁扫描 repo、diff 文件、搜索代码、建立上下文,这些都需要进行大量的文件操作。
- Linux 工具链兼容性更好 :很多工具都默认假设
POSIX filesystem,例如 ripgrep、git、node、python、make。
这种方案下的目录结构如下所示:
plaintext
/home/lei/
├── workspace/
│ ├── android/
│ │ ├── app-main/
│ │ ├── component-user/
│ │ └── demo-playground/
│ ├── backend/
│ └── scripts/
├── notes/
├── sandbox/
└── .codex/
方案二:主代码仓放在 Windows,Codex 只操作小范围 workspace
把主开发仓库放回 Windows 本地,Codex 就不要直接操作这份仓库,只通过手动复制粘贴的形式,将小范围目录文件复制到 Ubuntu 系统,供 Codex 阅读和编辑。
这样的好处是避免频繁的跨文件系统读写,降低性能损耗。但同样也有缺点,就是 Codex 只能编辑,无法直接运行整个项目。
方案三:将 Codex 安装在 Windows 侧,代码仓库也位于 Windows,压根不适用 Ubuntu 系统
这个方案从根源上规避了 Windows 版 Android Studio 对 WSL 项目构建/索引时的额外耗时。但 OpenAI 官方目前对 Codex CLI 的表述是:Windows 支持仍属 experimental,最佳 Windows 体验仍建议使用 WSL workspace。 因此这种做法有一定的风险。
某些脚本、shell 工具、grep/sed/find/xargs、权限语义、sandbox 行为,不如 Linux/WSL 一致。如果编码过程中大量依赖 Linux 工具链,则 Windows 环境很容易产生不支持命令的问题。
根据 第一优先级目标 不同,可供选择的策略如下:
| 第一优先级目标 | 安装环境 | 优点 | 代价 |
|---|---|---|---|
| Android Studio 构建/索引/调试体验稳定 | 方案三 代码放 Windows 目录 + Codex 原生装在 Windows | Codex 访问项目不跨文件系统。Git、Gradle、JDK、SDK、adb 都在 Windows 侧,链路简单 | Codex CLI 的 Windows 支持目前仍偏实验性。某些脚本、shell 工具、grep/sed/find/xargs、权限语义、sandbox 行为,不如 Linux/WSL 一致 |
| Codex / Linux 工具链 / shell 自动化 | 方案一 代码放 Ubuntu 文件系统 + Codex 在 WSL 跑 | 官方推荐,工具链完备 | Android Studio 构建速度下降 |
Codex 的三种使用模式
在日常项目开发里,我把 Codex 的通常使用分成三种模式。
- 信息收集:阅读一个陌生的项目代码时,让 Agent 分析其架构:这个功能在哪个 module?入口 Activity 或 Fragment 在哪里?网络请求链路经过哪些类?某个崩溃最可能和哪几处改动有关? ------ 这个阶段的价值在于让它快速扫清地形,减少手动搜索文件的时间。
- 受控改动 :当已经知道要改什么时,就需要把范围压到最小,例如"只修改
feature-loginmodule 下的 ViewModel 和对应测试,不动 UI 层"、"先给我一个补丁方案,不要执行格式化"。这种模式下,Codex 的效率最高,因为目标明确、边界清楚、验证路径也容易定义。 - 排查故障 :可以直接让它 执行测试、接收日志、读取堆栈、定位失败原因,再尝试修复。只要环境准备好,Agent 在"读报错 -> 找代码 -> 改补丁 -> 再运行"这个循环里,速度通常比纯手工快很多。
一个 SOP 流程是:
- 先在 Android Studio 里定位大致问题范围。
- 切到 WSL 终端进入仓库目录。
- 用一句话描述目标,再补充约束条件。
- 让 Codex 总结当前理解和执行计划。
- 确认计划合理后,再让它开始改动和验证。
- 最终回到 Android Studio 做人工 review。
这套流程看起来比 直接一句话让 AI 改完 多了两步,但实际上更稳。因为软件开发的成本并不在于敲出那几行代码,而在于确保改动没有副作用、没有越界、没有破坏团队约定。把 Codex 纳入现有工程化流程,而不是把它当成一个神奇黑盒,才更容易长期用下去。
更进一步的做法,是 把任务拆成多个回合 。比如 第一轮只定位登录状态同步链路,第二轮只修改 ViewModel,第三轮只跑相关单测 。别担心这样会增加沟通成本,这样做并非浪费时间,而是任务拆解,其实际效果往往更好,因为 每一轮上下文都很干净,Codex 更容易做出确定性较强的输出。
一句话总结:不要追求 让 AI 知道整个项目 ,而要追求 让 AI 在当前任务(步骤)上知道得足够多。
开始改代码前,先生成 Plan
这是我认为最值得保留的一个习惯:在 Codex 真正修改代码之前,先让它生成 Plan。
原因很简单。Agent 一旦拿到写权限,就具备 很强的执行能力 ;而执行能力如果缺少计划约束,就很容易出现 "方向不对,越走越偏" 的情况。先做计划,相当于先验证理解是否正确,再决定要不要授权它动手。
一个好的 Plan,AI 至少应该在其中回答四个问题:
- 它理解的问题是什么?
- 它准备检查哪些文件或模块?
- 它预计采取什么修改策略?
- 它打算如何验证结果?
如果计划里已经出现明显偏差,例如它准备修改根本无关的 module,或者打算进行大范围重构,那就应该在这一步及时纠偏,而不是等代码都改完了再返工。
我一般会让 Codex 先输出一个简洁计划,确认后再执行。例如:
| 英文 | 中文 |
|---|---|
| Before editing, summarize the current understanding and propose a step-by-step plan. Do not modify files yet. Wait for confirmation after the plan. | 在开始编辑之前,请先总结当前的理解,并提出一份分步实施的计划。 暂勿修改任何文件。 待计划确认后,再继续操作。 |
这几句话的效果非常好。因为它明确区分了两个阶段:思考 + 执行。对于复杂任务,这种分阶段协作能显著降低误改概率。
Plan 还有一个额外好处,就是便于 review。无论是你自己还是团队成员,只要先看计划,就能快速判断这次改动是否值得继续。如果连计划都说不清楚,那么让它直接提交补丁通常更危险。
Codex任务的中断与恢复
当 token 耗尽时(剩余10%以下),需要将当前任务保存,随后开启新的对话,进行恢复。
我建议把 中断恢复 当成一项正式工作流来设计,而不是等到 token 快见底时才临时抢救。因为 Agent 的上下文不像 IDE 工程状态那样天然持久,一旦会话结束,很多隐含信息就会丢失。
比较稳妥的做法,是在每轮任务接近尾声时,主动让 Codex 生成一份简短的 交接摘要,至少包含以下内容:
- 当前目标是什么。
- 已经完成了哪些修改。
- 哪些文件被改过。
- 哪些测试已经执行,结果如何。
- 还有哪些问题未解决。
- 下一轮最推荐从哪里继续。
如果再工程化一点,可以在仓库里放一个临时文档,例如 notes/codex_handoff.md(工作交接),每次让 Codex 自动更新它。这样即使换模型、换设备、换时间段继续工作,也不会完全依赖记忆。
恢复任务时,不要只说"继续上一个任务"。更好的写法是:
| 英文 | 中文 |
|---|---|
| Continue the previous task with notes/codex_handoff.md | 使用 notes/codex_handoff.md 继续之前的任务。 |
可以把上述流程固化成为 SKILL.md,从而自动化执行。
下文预告
接下来一篇文章将介绍 SKILL.md、AGENTS.md、MCP 这些重要的概念。
本文系笔者在阅读