用Codex干活的人都经历过这种场面:项目背景你讲得清清楚楚,结果它改出来的东西跟你心里想的完全是两回事。你越说越急,它越改越离谱,最后只能自己推翻重来。我刚开始用的时候也这样,一度怀疑是工具不行。后来复盘了几次才明白,问题多半出在问法上——不是Codex不聪明,是我把提示词写成了聊天灌水。这篇就聊聊我整理了大半年的Codex提问急救卡:7个常用模板,加上一套组合写法,专治那种“说完需求但没说清楚”的毛病,尤其是代码解释、Bug排查、重构优化这几个高频场景。
Codex这类工具的本质是“对话式编程助手”,它能读你的仓库、跑命令、改文件、拆解多步任务。但它毕竟不是读心术,你的每一句话都会被当成需求说明书来解析。问得模糊,它就猜着做;问得具体,它才有机会给你靠谱的结果。下面这套急救卡,理论上的依据很简单:把“这个代码怎么写的”变成“这个代码在什么约束下怎么写的”,把“帮我修个Bug”变成“复现路径+预期行为+实际行为+嫌疑范围”。
1. 为什么要准备一张Codex提问急救卡
1.1 Codex的工作方式决定了提问质量
Codex和普通聊天式AI不一样的地方在于,它被设计成可以在一个真实项目里工作。你给它一个任务,它可以先读代码、跑测试、看报错日志,然后直接改文件或者执行命令。这意味着它接收的不仅是你的文字,还包括它从项目里自己扒出来的上下文。这个能力是好事,也是麻烦——如果它自己扒的上下文不够,或者你给的任务描述有歧义,它就会基于猜测开始干活。
举个最常见的例子。你说“把这个列表优化一下”,它对“优化”的理解可能是换一种排序算法,也可能是删掉多余字段,还可能是加个缓存。没有边界、没有验收标准、没有相关文件指向,它就只能碰运气。而Codex这类模型有一个很典型的脾气:只要你没明确说“先别动”,它就会自作主张地动手。所以我的经验是:提问之前先想清楚,Codex需要知道“你是谁视角”、“项目里哪块代码相关”、“任务边界在哪”、“输出形式是什么”。这四点齐全了,它会像换了个人一样稳。
1.2 急救卡到底是什么
急救卡不是一个魔法咒语,而是一套固定结构的提示词片段。每次遇到典型任务,我直接把对应模板粘进去,替换几个占位符,省得每次都从零组织语言。好用的模板应该满足三个条件:结构可复用、占位符清晰、输出约束明确。我这里整理了7张卡,覆盖了日常开发里最高频的需求:理解旧代码、写新功能、修Bug、重构、写测试、审代码、补文档。
2. 七张急救卡:常用模板逐张拆解
先说明一下,这些模板不是要求你一字不改地抄。用多了以后完全可以按自己习惯调整,但核心结构建议保留,因为我试下来,去掉任何一块,输出质量都会明显下降。每张卡我都会给你模板、示例和几个踩坑点。
2.1 卡1:解释代码模板,让Codex当你的贴身讲解员
接手一个老项目最头疼的事,就是打开一个几百行的函数,完全看不懂它在干什么,又不敢随便动。这时候直接用模板1,比干瞪眼高效十倍。
先看文件:<文件路径> 用<角色>的视角,讲清楚<某个函数/类/模块>到底在做什么。 要求: 1. 不要大段贴原文,用普通人能听懂的话解释; 2. 按执行顺序拆成步骤; 3. 标出输入、输出和关键副作用; 4. 指出这里最容易踩坑的点。角色我一般会填“后端架构师”或“刚接手这个模块的新人”,效果完全不一样。填“新人”会让它默认你是零基础,解释得特别细;填“架构师”它会跳过基础概念,直奔设计和隐患。实际用的时候,为了理解代码我会同时跑两遍:先当新人听一遍逻辑,再当架构师听一遍潜台词。这样对一个陌生模块的理解速度,基本可以压缩到十分钟以内。
这里要补一个经验:如果Codex开始贴大段代码,说明你忘了说“不要贴原文”。模型有很强的惯性,你让它解释代码它就本能地先复制一段再说,加了约束之后才会真正去“讲人话”。我在模板里把这条固定写死,一次都没再犯过。
2.2 卡2:代码审查模板,让Codex当第二个Reviewer
每次提交MR之前,让Codex先当一轮独立审查者,能拦住不少低级问题。我用的模板是把规范拆成“安全、性能、可读性、边界条件”四个维度,再要求它给问题分级。
审查文件:<文件路径> 重点检查:<安全/性能/可读性/边界条件,按需保留> 按严重程度分三类输出: - 严重:可能导致Bug或安全事故; - 建议:影响代码质量但不致命; - 风格:可改可不改,非硬性。 每个问题需要给出:具体位置、为什么是问题、建议改法。 最后输出一个“如果这个PR只能改三处,优先改哪三处”的排序。这个模板的后半段是关键。“只能改三处”这个约束非常有用,它逼着Codex做优先级判断,而不是给你列二十条问题让你眼花。我以前用普通审查提示词的时候,它会输出一堆“可以考虑提取一个函数”之类不痛不痒的废话,看完了等于没看。加上这个排序之后,至少能快速定位到真正要命的两个问题。
还有一个技巧。审查完代码后,我会追问一句“有没有漏网的问题”,因为有研究结论说让AI在输出之后追加一轮自我质疑,能多发现不少边缘情况。实测下来,第二轮的命中率确实不低,尤其是在并发、空值处理这些方向上。
2.3 卡3:Bug排查模板,治标之前先让Codex给方案
很多人让Codex修Bug,上来就是一句“这个报错了,帮我看下”,然后把报错往对话框一贴。Codex其实能做到的远不止这个。它可以自己跑命令、翻日志、写个临时脚本复现问题。但前提是,你得给它一条明确的排查路径。
复现步骤: 1. <第一步> 2. <第二步> 3. <第三步> 预期行为:<我期望的返回结果/页面状态> 实际行为:<实际出现的返回结果/报错信息> 相关文件:<最可疑的文件路径,没有就写“不确定,先帮我定位”> 嫌疑方向:<如果你已经有怀疑的点,直接写> 请先输出排查计划,再动手验证,不要跳步。我遇到过不少开发者,连“相关文件”都懒得填,就让Codex全仓库找。Codex虽然能全仓库找,但效率低到你怀疑人生,而且它还容易跑到无关模块里瞎猜。与其赌它的检索能力,不如你花十秒钟定位一下最近的改动文件。追问一句“把报错栈里的调用链读一遍,定位哪一层最可疑”,比我筛一遍日志还快。
这个模板最重要的词是“先输出排查计划”。加了这四个字之后,Codex会先给你一个思路清单,你确认方向对了再说“动手”。这能避免一种很蛋疼的情况:它按自己的歪思路改了一通代码,结果把别的功能带崩了。
2.4 卡4:功能实现模板,把需求变成一份可执行的小方案
新功能开发的时候,我最怕的不是Codex不会写,而是它写出来的东西想当然。你说“加个导出Excel功能”,它能给你引入三个你从没用过的依赖库。模板4就是用来堵这些口的。
在<模块>中新增一个<功能>。 输入:<数据格式/调用方> 输出:<返回值/落盘路径/页面效果> 需要处理的边界情况: - <空数据> - <网络异常> - <重复提交> 技术栈与约束: - 当前项目已使用<什么框架/依赖>,不允许引入新库; - 遵循<项目现有风格/接口命名规范>; - 需要自动补充<单元测试/注释/接口文档>。这段提示词的神奇之处在于,你不说“不允许引入新依赖”,它十有八九会给你装一个方案,然后你就得陷入依赖地狱。一旦明确说“按现有技术栈实现”,它反而会在你项目的代码里找你用过的工具函数,复用已有实现,代码一下子变干净了。
边界情况这个部分我习惯多写两条,因为Codex默认只会处理“输入-输出”的正常路径,空数据、超时、并发冲突这些它经常想不起来。你可以让它自己再补一轮“还有什么边界情况我漏了”,结合老开发的经验判断要不要采纳。像金额计算、时间换算、状态流转这些业务里最容易出鬼的边界,宁可多让Codex列一轮。
2.5 卡5:重构优化模板,让Codex先交方案再动手
重构比新代码更危险,原因很简单:改坏了好歹能回滚,但改了API签名导致一堆调用方全挂,就不是回滚能解决的事了。所以我的重构卡里有一条硬性规定,就是“先给方案,确认后再动手”。
重构<文件/函数>。 目标:<提升可读性/抽公共逻辑/优化长函数> 约束: - 对外接口保持不变,调用方代码不用跟着改; - 现有测试允许运行但不要修改测试预期来适配新实现; - 不引入新依赖。 请先输出重构计划,包括改动点、影响面、风险点,我会确认后再让你动手。加不加这个约束,输出效果天差地别。不加的时候,它可能会一口气把整个文件重写一遍,你根本没法Review每行改动。加完之后,它先输出的计划通常会是“抽出某个函数、把这段逻辑改为提前返回、把魔法数字提成常量”这样的清单,你有机会把那些你不同意的方案提前毙掉。
另外,重构过程中我强烈建议要求Codex“每改十行就停下来让你看一眼进度”。这虽然会多几轮对话,但对大文件来说特别稳。你想想,让它一口气改两百行,中途思路跑偏你根本察觉不到,等它改完你再读一遍的时间,都够手动重写一遍了。
2.6 卡6:测试编写模板,让测试真的有价值而不是凑覆盖率
让Codex写测试,经常会出现一种“覆盖率高但一坨废话”的结果——全是assert(1+1==2)那种用例,对逻辑保障毫无意义。模板6的核心是逼它写边界和异常路径。
为<文件/函数>补单元测试。 测试框架:<jest/pytest/go test 等,按项目来> 覆盖用例要求: 1. 正常路径:传正常参数,验证输出; 2. 边界路径:空值、超长输入、临界值、负数、极端时间; 3. 异常路径:抛出错误的情况。 其他约束: - 测试不能联网,不依赖真实数据库,必要时用mock; - 每个用例开头写一句“本用例验证什么”; - 保留已有测试风格,不修改业务代码去凑测试。“不修改业务代码去凑测试”这句是我加了很久才加的。Codex有一种惯性,遇到难写的单测它就想改业务代码逻辑来让测试好写,这会破坏现有行为。加上这句,它就会老老实实去mock环境,而不是动生产代码。
还有一点,“每个用例写目的”看起来多此一举,但对维护相当有价值。三个月后你回来看测试文件,每一个用例想干嘛一眼就懂,不用再猜当初写的人是不是脑子被门夹了。
2.7 卡7:学习与文档模板,让Codex帮你把经验沉淀下来
最后一个模板是用来补文档的。程序员都烦写文档,但Codex不烦。关键是你要它按你的项目实际情况来写,而不是输出一些放之四海皆准的空话。
以<角色>的视角,解释<某个概念/模块>。 要求结合实际代码举例,示例从我项目的<文件路径>里面找。 生成一份简洁备忘,包含: 1. 一句话定义; 2. 核心流程或原理; 3. 使用时的常见坑; 4. 最小可运行示例。我第一次用这个模板是想给团队写一份支付状态机说明。以前这种东西我自己写,先看代码、再画状态转移、再核对每个分支,能磨一下午。后来用这个卡,让Codex先读了支付模块代码,再让它按“新人视角”整理状态机文档,半小时搞定初稿,我再把把关,直接能用。注意这里有个顺序问题:一定要先让它读代码再生成文档,不然它写的是虚构的状态流转,跟项目的实际情况对不上。
3. 组合写法:模板不是孤立的,拼起来才是完整工作流
3.1 五段式组合公式
前面7个模板是“底料”,但实际工作中,我们很少只用一张卡。比如你让Codex写一个新功能,写完之后它顺手就能做代码审查、补测试、甚至写个提交信息。这不靠“换个提示词”,而是靠组合。
我常用的一套组合公式是五段式:角色词、上下文、任务、边界、输出格式。具体展开就是:
角色:你是一名<领域>专家。 上下文:项目是<项目名>,请先读取<相关文件>。<关键背景信息> 任务:完成<任务描述>。 边界:只允许改动<范围>;不允许<行为>;必须遵守<项目约束>。 输出:先输出<方案/计划>,确认后再执行;最终产出<代码/测试/文档>。这套公式和单张急救卡的区别在哪?急救卡是“针对一种任务类型的标准问法”,而五段式是“一张万能外壳”。你把第2节的任意模板嵌入到“任务”这一段里,就能把模板1和模板6、模板4和模板2随意组合。Codex输出的不是一坨孤立的代码,而是一条完整的操作链。
我举个例子。你接手一个订单模块,对里面的结算逻辑两眼一抹黑。正确做法不是直接说“帮我重构结算逻辑”,而是先上卡1解释代码,让Codex把结算流程讲清楚;等它讲完,你再用卡5的重构模板,并且把“边界”设为“接口保持不变、只改实现”;重构完了顺手用卡6补测试、卡2做一轮自查。四次提问,每问一次Codex的理解都比上一次深,输出质量一次比一次好。这跟我直接丢它一个“重构掉这个文件”的结果,完全是两个等级。
3.2 模板之间的常见搭配方式
哪些模板经常放在一起?我列几个实际用着顺手的组合:
- 卡1 + 卡7:临时接手的模块,先理解再沉淀成团队文档。
- 卡4 + 卡6:实现新功能的同时补单测,相当于一次交付两块产物。
- 卡2 + 卡5:先让Codex审查现有代码,再根据审查结果重构。这两个组合起来特别顺,因为审查输出的问题清单,恰好就是重构计划要处理的清单。
- 卡3 + 卡2:修完Bug后让Codex自查一遍,防止修了A坏了B。
- 卡7 + 卡5:先让它写一份现有实现说明,再让它在说明基础上提重构方案。文档还能变成后续改动的基准线。
组合的时候有个原则:一次对话只做一件事。很多人会把“帮我改这个,然后更新文档,再跑个测试”塞进一句话。Codex虽然能多任务,但每多一个任务,它就会稀释注意力,最后哪个都没做到位。我的习惯是,一个任务完成后我确认一下,再开始下一个任务。虽然对话轮次多了,但返工率低很多,总时长反而会更短。
3.3 让组合更稳的小技巧:追问式修正
就算用了模板,Codex也不可能一次到位。但比直接换一个提问更有效的,是“追加式修正”。比如它输出的方案里有个设计你不喜欢,不要生气,直接说:
方案里第2点有问题。不要返回错误码,改成抛异常,抛出的异常类型也按现有Exception子类来。其余部分保留,重新输出完整方案。这种“指定位置+指定方向+保留其余”的追问法,比说“你重新来一遍”稳定得多。Codex对局部修正在大多数情况下都能精准响应,而且不会把其他已经正确的地方也改掉。这里有个经验,追加的修正信息一定要带上“为什么”——不需要太长,一句“因为调用方统一用exception-handler处理”就够了。模型有了原因,才能选对后续的实现倾向。
4. 实战过程:用提问急救卡跑完一个真实小任务
光讲模板比较抽象,我拿一个真实场景完整走一遍组合写法。背景是一个积分系统,我给它起的代号就叫“某积分服务模拟项目”。需求是给积分账户增加“过期积分自动清零”的定时批量任务,要求不引入新的框架,沿用现有Spring定时器风格,同时不能影响当前的手动积分调整功能。
4.1 第一步:先用“解释卡”校准上下文
我没有上来就让Codex写代码。我先把积分账户相关的文件和过期规则的代码路径找出来,然后粘了卡1的模板:
角色:以一名熟悉该积分服务的后端工程师视角。 先看文件:src/main/java/com/sim/points/Account.java 和 src/main/java/com/sim/points/PointRecord.java 任务:讲清楚积分账户的有效期字段、状态流转和积分扣减逻辑,重点说明“过期”概念在现有代码里是怎么表示的。 要求:用讲人话的方式拆步骤,标注出涉及定时任务或批次处理的现有代码位置。Codex读了代码以后,给我输出了一段解释:账户的过期时间存在Account表里,PointRecord记录了每一笔积分的入账时间和到期时间,但没有一个统一任务对过期积分做处理,最终“过期”只体现在查询展示层的过滤条件里。这个结论很关键——它告诉我,这不是写一个定时器的事,还要统一“过期”定义,否则清理任务跟查询逻辑会数据口径不一致。
这一步的价值就在这里。如果我直接让Codex实现“自动清零”,它大概率会写一个每天扫一遍、把过期积分减掉的定时任务,但不会意识到展示层的过滤条件也要跟着改。先解释再实现,相当于让Codex在动手前先建立了对这个模块的心智模型。
4.2 第二步:用“功能实现卡”落地任务
搞懂现有逻辑后,我再上卡4,并在边界里明确了两件事:定时任务沿用项目里已有的@Scheduled风格,不引入XXL-Job之类的中间件;清理过程必须往流水表“PointRecord”里插一条“过期失效”类型的记录。
任务:在src/main/java/com/sim/points/下面新增一个过期积分清理任务。 输入:每次触发时,扫描Account表中所有“存在未失效积分”的账户。 输出: 1. 把过期的积分标记为失效状态; 2. 向PointRecord插入一条“过期清零”记录; 3. 更新账户的可用积分余额。 边界:只允许改动points包下的代码;不得影响手动调整积分的接口;不允许引入新依赖。 输出:先给设计方案,列出要新增的类、方法签名和SQL大概思路,确认后再写代码。Codex先给了方案:新增一个ExpiredPointsCleaner类,内部一个@Scheduled方法,每分钟或每天凌晨跑一次,用一条SQL查出所有“到期时间小于当前时间且未失效”的积分记录,然后逐账户批量更新余额并写流水。方案合理,我确认之后它开始写代码,还问我要不要配置cron表达式。我让它配成每天凌晨2点,错开业务高峰。
这一步下来,新增的代码大概是这么几块:一个定时任务类、一个批量查询的Mapper方法、一个把积分置为失效的状态更新逻辑、一条流水记录插入逻辑。整体六十多行,用的是项目现有的Mapper和事务注解风格,没有多出一个新依赖。这就是“边界写清楚”带来的最大好处。
4.3 第三步:用“测试卡”补防护网
功能写完以后,我接着用卡6让它补单元测试。我给它的关键信息是:测试不能连数据库,需要用mock把Mapper层挡掉。它给出来一组用例:
- 正常路径:账户名下有10笔积分,其中3笔过期,清掉后余额扣减正确;
- 边界路径:账户名下没有任何过期积分,任务执行后账户不动;
- 异常路径:批量更新时有一笔更新失败,事务回滚,流水没有多余记录。
其中“事务回滚”那个用例,它还真用了Mockito去模拟Mapper抛异常,然后断言流水表没有插入记录。这个用例如果是在没写模板的情况下让它生成,八成又变成了“传两个数,assert一下”。
4.4 第四步:用“审查卡”再兜一层底
代码和测试都有了,最后用卡2做一轮Review。它挑出两个问题:一是批量扫描时没有对查询结果做分页,如果账户量大会一次性加载太多;二是流水插入和余额更新虽然在一个事务里,但定时任务本身没做“执行中幂等”控制,如果上一次任务还没跑完又触发下一次,可能导致重复扣减。这两个问题都在点子上,我让它补充了分页参数和基于账户ID的锁串行控制,然后重新跑了测试。
整个需求做完,我只动手改了配置文件和几个业务说的口径,代码块全部是Codex写的。但注意,关键决策都是我确认的——包括“过期”口径统一、定时时间错峰、幂等控制方案。模板不会替你思考,它只是让你的思考能准确传达给Codex。
5. 常见问题与排查技巧实录
用这套急救卡的时候,大家可能会遇到下面几个高频问题。我把踩过的坑和对应的调整方法一起列出来,比光给模板更实用。
5.1 Codex答非所问,输出一套“正确的废话”
如果你发现Codex输出的内容逻辑完美、语句通顺,但完全没解决你的问题,多半是上下文给得不到位。它不知道你的项目里到底有什么,就只能凭通用知识生成一篇“看起来对”的东西。解决办法不是骂它,而是回到模板,把“相关文件”“报错信息”“复现步骤”这些字段补全。一旦它真的读取了指定文件,答非所问的概率会直线下降。
5.2 Codex生成的文件路径是错的
这是用CLI版最容易撞上的问题。你让它改“utils.js”,它可能自己新建一个同名或者类似名字的文件到别的目录。这里要对模板加一句“不要新建文件,直接在<已有文件路径>上修改”。这是我吃过亏的地方:有一次它新建了一个文件,我提交之后CI直接崩了,因为它把旧文件里的导出给覆盖了依赖关系。
5.3 Codex一股脑改了一堆你不想改的东西
不加“只允许改动范围”时,Codex经常顺手把相邻逻辑也改掉。修复方案是边界约束写死:只允许改动哪些目录或文件、不允许删除某些函数、不允许修改公共接口。只要边界够硬,它的克制程度会超出你预期。
5.4 长任务跑到一半,逻辑开始不一致
任务超过一定复杂度后,Codex可能忘记前面自己给过的方案前提。比如前半段设计说用A方案,后半段代码却按B方案写了。这是模型的上下文窗口和注意力机制决定的,不必大惊小怪。做法是“切成小步”:一次只让它处理一个函数或一个步骤,每完成一步就总结当前状态再继续。组合写法里的“确认后再执行”就是为这个准备的。
5.5型错误或编造不存在的API
Codex偶尔会引用一个项目里根本不存在的类和方法,尤其是它没仔细看文件的时候。遇到这种情况,我一般不是让它“检查一下”,而是直接问“你刚才引用的这个方法是哪个类里的?在项目里的路径是什么?”它如果答不上来,就说明它在编。然后你让它先grep定位真实存在的函数签名,再重新生成。
5.6 权限和安全问题
Codex可能会主动建议一些有风险的命令,什么rm -rf、清库、强制推分支,虽然有权限体系兜底,但习惯上我还是坚持一个原则:它给出的命令先阅读一遍,确认没问题再手动执行,不要直接放权。尤其在处理生产数据相关的脚本时,宁可多花一分钟看命令,也不要在几百次对话里赌它永远聪明。
结尾
讲了这么多,最后再说一点个人体会。我最早用Codex的时候,总想着一句话把需求说清楚,结果反复返工。后来接受了一个事实:它不是聊天对象,而是一个“理解力中等偏上但执行力很强”的实习生。实习生要的是明确文档,不是情绪。你给他越结构化的指令,他越能发挥能力。急救卡和组合写法,本质上就是把你脑子里的需求翻译成“模型爱读、且不产生歧义”的格式。要说技巧,无非是固定结构、填好上下文、收紧边界、确认后再动手。把这几个习惯养成了,Codex能帮你赶出不少活,而且质量比你手忙脚乱写完再改要高得多。