用代码生成模型写了差不多一年之后我最深的感受不是“它什么都会”而是“它特别容易被问偏”。同样一段代码我甩一句“帮我优化一下”和给出完整边界条件的提问得到的产出根本不像同一个工具。后来我把高频场景整理成一张提问急救卡遇到问题直接套模板、再把模板串联起来Codex 的输出稳定到可以拿去做代码评审。这篇文章就把这张卡完整拆开7 个常用模板、每个模板的话术和适用时机再加上组合写法和一个能照抄的实战流程。适合那种已经和 Codex 聊过几轮、但总觉得它在“给我想要的”和“给我一个像样的东西”之间反复摇摆的程序员。1. 同样的需求为什么 Codex 有时候像换了个人先说一个高频场景你粘贴一段刚写完的业务函数说“帮我理理逻辑”。Codex 大概率会给你加注释、改几个变量名、把 if 嵌套改成早返回。看起来挺努力但你要的可能是“把这段逻辑重构成策略模式”或者是“这个函数在延迟场景下不稳定想改成异步”。两件事被一句话包进去了模型只能挑一个“平均答案”来猜。这不是 Codex 理解力不行是提问里缺少坐标。1.1 一个模糊询问的解剖“优化一下”这四个字在不同人嘴里有完全不同的含义。我问过几个同事同样面对一段处理订单状态的代码甲想的是减少嵌套、让每个分支提前 return乙想的是把状态判断抽成独立的映射表丙想的是把整个流程改成事件驱动。三个人如果都用“帮我优化这段代码”来提问Codex 只能从代码里自行推断一个最保险的方向最后给出的结果对三个人来说都是“四不像”。所以模糊询问的代价不是“输出质量差”而是“输出质量不可预测”。你可能拿到了一个结构漂亮、但方向完全错误的方案。更麻烦的是当你试图纠正它时之前的错误方向已经污染了对话上下文Codex 会在错误的架构上打补丁比第一次就给清楚预期的成本高得多。1.2 给 Codex 的三个坐标目标、边界、格式经过几十轮测试我把编程类问题的必要信息压缩成三个坐标目标你到底想得到什么是更快的代码、更清晰的模块还是更全的测试。目标最好是可验证的例如“P99 延迟降低 30%”“去掉重复订阅”而不是抽象的“性能好一点”。边界哪些东西不许动。这是最容易忽略的一项不说不许改公开接口Codex 就可能把save(user)改成persist(user, forceTrue)让调用方全部报错。格式输出呈什么结构。是不需要解释直接给代码还是先给方案再给代码或是给一段带风险说明的改动清单。格式约束能把一次长回复变成你可以直接使用的交付物。这三个坐标就是后面所有模板的骨架。每个模板都只是把这三个坐标变成了不同的固定话术你不需要每次从头构思怎么组织语言只需要填空。2. 急救卡背后四个比模板更底层的概念模板是表层的壳真正让模板起作用的是下面四个概念。理解了这四样你才能自己改模板、拼模板而不是死记硬背。2.1 上下文不是贴得越多越好而是贴得越准越好很多人的直觉是“上下文越多Codex 越懂我”其实不全对。上下文窗口固然是有限的但注意力也是会散的。你把整个项目的五个模块文件全粘进去然后在最后写一句“重点改第三个模块”模型会被前面大量无关声明干扰尤其在长对话里指令越靠后、越容易被忽略。我现在的做法是只粘贴和当前任务直接相关的代码片段并在片段前加一句“下面是参考代码重点看process_refund这一个函数”。如果代码有依赖就补一小段简化版的数据结构定义而不是贴整个类型文件。这样 Codex 的注意力会集中在你要它操作的那一小块区域上。还有一种常见失误把上下文当成“给模型补知识”粘进去一段和任务无关的业务描述。描述本身不重要重要的是“你希望模型注意到什么”。上下文的价值不在字数在定位。2.2 角色让模型切换到不同的专业视角很多人把角色设定当成玄学其实它是一种有效的输出调节器。同一段代码你让 Codex 扮演“初学者导师”和“资深代码审查员”得到的讲解深度和批判性会完全不同。角色不是让模型真的“变成”什么人而是给它的语言分布提供一个方向。我在急救卡里常用的角色有两种“你是一名刚接手这个模块的开发者”——适合讲解场景会强制模型从零解释而不是默认你已经懂。“你是一名有多年经验的代码审查者”——适合重构和优化场景会让模型更愿意挑毛病、更重视边界条件。角色尽量贴近任务本身不要写“你是一个无所不知的超级 AI”那只是占字数没有调节作用。角色描述得越具体模型的回答风格就越贴近你需要的场景。2.3 约束必须明确告诉模型“不许碰什么”人有一个毛病只喜欢说“我要什么”不喜欢说“我不要什么”。Codex 是概率生成模型如果没有反向约束它会在可能的改动空间里挑一个最“自然”的方向走而这个方向经常不是你想要的。常见的约束项有保持公开接口不变不要新增第三方依赖不要改变异常类型和抛出位置不要修改与当前任务无关的代码块如果必须牺牲某条约束先说明再做而不是直接执行。约束不是越多越好关键是约束项要和目标对齐。如果目标是重构内部分支逻辑那“保持接口不变”就是硬约束“不要动注释”这种细节约束反而会限制模型发挥。在模板里我会把约束放在“任务描述”之后、代码粘贴之前位置固定避免模型读着读着忘记。2.4 输出格式让回复长成可以直接用的样子很多失败的 Codex 对话问题出在输出格式上是“散文式”的。它写了一大段推理、分析、假设然后把代码埋在中间你复制出来还要手动清理前面的废话。这不是模型懒是你没告诉它怎么组织回复。在模板的最后我都会加一个“输出格式”小节。比如先给两行动改设计说明再给完整代码块最后列一个风险点清单。格式约束还有一个额外的好处它强迫模型在生成代码之前先“走一遍方案”减少那种上来就改、改了半截发现不兼容的情况。格式这层约束虽然简单却是所有模板里性价比最高的一项。3. 7 个模板逐个拆解什么时候用、怎么填、输出长什么样下面这七张卡覆盖了我日常写代码时 80% 的 Codex 使用场景。每张卡的格式我都简化成了填空式的文本你可以直接复制到提示框里替换占位符。3.1 模板一重构手术这个模板用在“结构不佳但行为正确”的代码上目标是让模型在保持行为不变的前提下做结构优化。你是一名资深开发工程师。 背景{这段代码所属模块的一句话说明} 任务重构下面代码目标是{减少嵌套 / 拆分大函数 / 消除重复分支}。 约束保持公开接口不变不要改变运行时行为不要引入新依赖不要修改测试已覆盖的逻辑。 代码 {代码} 输出格式 1. 改动设计说明2-3 行 2. 重构后的完整代码 3. 改动后可能存在的风险点。为什么这个模板特别强调“先给设计说明再给代码”因为我发现一旦模型先写代码它往往会陷入局部优化改到一半才发现某个私有函数的作用是什么。让它先写设计说明等于逼它在生成具体代码前先建立全局结构输出质量会明显下一个台阶。使用时机代码能跑、测试也过但你想让下一个人更容易接手或想缩小某个函数的职责范围。如果你不确定自己想改成什么样可以先把这段代码丢给讲解模板模板四弄明白结构之后再来重构。3.2 模板二报错定位这个模板用在“有异常、有堆栈、但不确定根因”的场景。它的核心是不允许模型只给一个“拍脑袋修复”。我在{具体操作场景}遇到了异常 {堆栈或报错信息} 相关代码 {代码} 我期望的行为是{正常行为} 请按以下顺序回答 1. 最可能的 3 个根因按概率排序 2. 针对第 1 个根因给出最小修复补丁 3. 解释这个修复为什么不会被相邻模块影响。这里有三个关键设计“3 个根因”不是让模型凑数而是逼它列出不同假设你可以用代码逻辑快速排除不合理的而不是只盯着一个答案“针对第 1 个根因”防止模型一次性给出三个补丁导致修复范围失控“为什么不会被相邻模块影响”是让模型自己检查一下改动范围很多幻觉修复在这一步会被模型自己推翻。使用时机测试挂了、线上报错、或者 Codex 生成了代码但运行报了一片红。注意堆栈信息要完整不要只贴“报错了”三个字模型不是占卜师。3.3 模板三测试用例补全这个模板专门用来补测试尤其是当你没时间整理边界条件时。函数签名{签名} 行为说明{一两句话描述功能} 需要覆盖的场景正常路径、{边界值、异常、空值、重复调用}。 请用{测试框架}生成测试用例。 输出要求 1. 先给用例清单包括“输入、期望输出、覆盖点”三列 2. 等我确认清单没有遗漏后再输出完整测试代码。 在测试代码中用 mock 模拟外部依赖不要发起真实网络或数据库连接。为什么要分两步输出因为测试代码通常很长一次性生成后如果覆盖点不对你要在一大片代码里找漏项。先让模型输出用例清单你用业务逻辑检查一遍再让它补齐代码这个“先清单后代码”的节奏能省下不少纠偏时间。使用时机模块已经重构完、想补回归测试或者“这个函数行为很怪但不知道哪里怪”时用这个模板生成一批边界测试来反推行为。3.4 模板四代码讲解这个模板用来读旧代码、交接代码、或者理解一段别人写的“天书”。下面这段代码是我需要接管的模块里的核心部分。 请你以一个没接触过这个模块的工程师身份讲解。 我重点关注 - 入口点和调用链 - 核心数据结构的流转路径 - 如果我要新增一个功能最应该修改的位置 - 当前实现里最可能出问题的点。 代码 {代码} 输出结构 1. 入口与调用链说明 2. 核心数据结构说明 3. 要改功能时先动哪个位置 4. 风险点清单。 不要逐行解释代码先给整体脉络。这个模板的特点是“限制模型逐行读”。逐行讲解看起来内容多但对你理解模块毫无帮助你需要的是一张“地图”。加了“不要逐行解释”之后模型的输出会从流水账变成结构化的阅读地图。使用时机接手新模块、看开源代码、或者下一步打算重构但还没完全看懂现状。讲解完通常可以无缝衔接模板一让 Codex 直接基于“它刚给出的地图”做修改。3.5 模板五性能诊断这个模板用在“慢、但不知道慢在哪”的场景。它最大的作用就是阻止模型凭感觉优化。性能现状{接口/函数} 平均耗时 {数字}疑似瓶颈在{数据库查询 / 大量对象创建 / 锁竞争 / 无缓存}。 代码 {代码} 约束 - 不要凭直觉改先给出“如何确认瓶颈”的具体验证方法 - 优化目标{例如P99 从 500ms 降到 200ms} - 只允许改函数内部逻辑不修改调用方协议。 输出格式 1. 可疑点列表每个点说明为什么可疑 2. 每处需要补充的监控日志或基准测试 3. 最小改动方案。我以前犯过的错误是直接让 Codex“优化一下性能”它主要以启发式的方式比如把 list 换成 set、加缓存开始改但完全不确认实际热点。现在的模板先要“可疑点列表”和“验证方法”相当于让模型先写一份诊断计划再动刀。这个思路和真实性能优化的流程是一致的先测量、再假设、再验证、最后优化。使用时机接口在压测中明显慢或者线上监控看到耗时异常。如果你已经有明确热点比如一条 SQL 慢直接把这个热点代码粘进去并在背景里写清楚瓶颈位置效果更好。3.6 模板六跨语言迁移这个模板不仅用于换语言也用于从旧框架迁移到新框架。它的关键在于“语义不变风格变”。把下面 {源语言} 代码迁移成 {目标语言} 代码。 迁移要求 - 外部行为必须一致 - 遵循目标语言的惯用写法不逐行翻译 - 公开接口语义保持不变 - 如果两种语言在错误处理、并发模型、资源释放上有差异用注释标出给你改动点。 代码 {代码} 输出格式 1. 语义映射表源语言概念 → 目标语言实现 2. 完整的迁移后代码 3. 迁移过程中可能遗漏的边界问题。如果不加“语义映射表”模型经常直接逐行翻译产物在语法上正确但在目标语言里非常别扭。比如把 Python 的for循环翻译成 Go 的for循环而不是思考“这里该用 range 还是迭代器”。语义映射表能强制模型在生成代码之前先做一层“意图对齐”迁移结果会自然很多。使用时机项目换技术栈、把一次性脚本变成正式服务、或把一个语言的库函数移植到另一种语言。3.7 模板七接口与文档生成这个模板用来生成可以交给别人的维护文档而不是那种“每行旁边加注释”的伪文档。用下面代码生成维护文档阅读对象是另一位后端工程师。 输出要求 - 所有公开方法都要有参数含义、返回值、可能抛出的异常 - 提供一个最小可运行的使用示例 - 不要虚构代码中不存在的字段或行为 - “生产注意”类上下文只写代码里能看出的部分不写环境相关的数据。 代码 {代码}这个模板里最重要的约束是“不要虚构代码中不存在的字段或行为”。模型的补全能力很强可能给你补出一个实际不存在的配置项或者假设某个依赖有某种行为。这条约束能明显降低文档里的幻觉率。使用时机接口写好了但没写注释、要交接模块、或者要把一个内部函数暴露成对外 API 前先补文档。4. 组合写法让模板产生“112”的三种编排方式单张急救卡只能处理单一任务真实开发里的任务往往是复合的先要读代码、再重构、再补测试、最后写提交说明。这时候就需要把模板串成流水线。组合的关键不是在一个提问里塞进所有模板而是控制每个阶段的输出让上一轮的结果变成下一轮的输入。4.1 串联编排讲解→重构→测试最常见的串法适合“接手一段不熟悉的代码并改进它”。流程用模板四讲解代码拿到一张“结构地图”把讲解结果里最关键的、你最难接受的部分抽出来用模板一重构把重构后的函数用模板三补测试。每一步之间你可以人工检查输出是否符合预期再决定下一步是否继续。这个“人在环上”的节奏比一次性问“帮我看懂然后重构然后加测试”要可靠得多。模型一旦在一个回复里阶段太多后面的阶段往往只做表面功夫测试代码会漏掉重要分支。4.2 并联编排一次处理多个独立代码块当几个代码块互不依赖、且你确认它们彼此没有隐式耦合时可以让 Codex 在一个回复里分别套不同模板。下面有三个独立任务请用空行分隔分别输出结果 1. 对函数A用重构模板目标是减少嵌套保持接口不变。 2. 对函数B用测试模板补边界测试测试框架用 unittest。 3. 对函数C用文档模板生成公开方法说明。 各自独立输出不要合并成一段代码。这种写法适合“批量维护多个工具函数”这类场景。但要记住并联任务不要超过三个超过之后模型会在输出中间相互串味A 任务的约束被带到 B 任务上甚至代码块之间出现复制粘贴。我实测下来两到三个是安全区再多就分多轮。4.3 接力编排用上一轮的输出作为下一轮的上下文这是最优雅也最容易被忽略的写法。Codex 在同一会话里会记住上下文但对话太长之后前面的细节会逐渐弱化。你可以把上一轮输出的“精华摘要”手动补回下一轮提示里让上下文更精确。举个例子第一轮用模板四讲解模块输出“入口点 main_loop数据流 A→B→C风险点 B 段修改全局状态”第二轮开始重构时不是直接说“继续改”而是说“基于你刚才提到的风险点B 段修改全局状态。现在重构 B 段保持 A 和 C 的调用方式不变”。这种方式让模型不需要重新回顾上百行代码只需要在你给的精简摘要上工作。本质上和“上下文不是越多越好”的原则是一致的只给当前真正需要的上下文下一个指令的质量会更高。4.4 什么时候不要组合组合不是万能钥匙。有两类场景我坚决不组合破坏性操作必须单独验证。比如“删除某段逻辑并替换成新方案”我会先用模板二分析风险再单独发一个带“只输出方案、不要执行代码”的重构请求人工确认后才执行。根因未明时的重构不要组合。报错场景里如果你还没弄懂问题原因就直接拿去重构很容易把错误的根因当成“需要消除的味道”给重构掉。先排错再谈重构。组合的目的是让人全程只做“决策”而不是做“翻译”但决策的前提是你拥有每个阶段的可视化检查点。跳过检查点的组合等于把控制权全部交给了模型。5. 完整实战从一段旧代码到重构、测试、提交说明一次跑通最后一个章节我把前面所有内容串起来。假设我在处理一个纯内存的事件总线模块它的注册、去重、触发逻辑耦合在一起重复订阅会触发多次回调而且emit过程里修改订阅列表容易造成顺序问题。下面是原始代码class EventBus: def __init__(self): self._subs {} def subscribe(self, event, fn, onceFalse): if event not in self._subs: self._subs[event] [] self._subs[event].append((fn, once)) def unsubscribe(self, event, fn): if event in self._subs: self._subs[event] [x for x in self._subs[event] if x[0] ! fn] def emit(self, event, *args, **kwargs): if event not in self._subs: return for fn, once in list(self._subs[event]): fn(*args, **kwargs) if once: self.unsubscribe(event, fn)看起来不长但已经有两个真实隐患重复订阅会被反复触发emit在遍历过程中如果某个回调内再次触发emit迭代器可能错乱。5.1 第一轮背景注入与代码讲解我会先用模板四把这段代码丢进去下面这段代码是我刚接手的某个通知模块里的核心。 请以一个没接触过该模块的工程师身份讲解。 我重点关注入口点、数据流、修改风险点。 输出结构入口与调用链、核心数据结构、最可能出问题的点、如果要加功能先改哪里。 代码 {class EventBus...}Codex 会指出“订阅是按追加顺序保存的重复订阅没有去重”、“emit遍历时先复制了list但如果回调里再触发同类型emit外层列表可能变化”。这段输出就是第二轮的输入摘要。5.2 第二轮带约束的重构基于第一轮的风险点发第二个提示基于刚才的讲解结论重构这个 EventBus。 目标是 - 重复订阅变成幂等即同一 handler 对同一 event 只注册一次 - emit 触发前先复制订阅快照保证回调里再触发 emit 不会打乱当前遍历 - 把订阅与触发逻辑拆分清楚避免 subscribe 和 emit 互相掺和。 约束公开接口 subscribe/unsubscribe/emit 保持不变不引入第三方依赖不改变默认行为。 输出格式先给设计说明再给完整代码最后给行为变化风险。这样写的好处是Codex 在重构前已经拿到第一轮的地图不需要重新分析代码结构。它直接基于“重复订阅去重”这个约束在subscribe里加一次if handler in existing的判断在emit里复制快照后遍历副本还会提出把“快照复制”做成一个私有函数来保证可读性。5.3 第三轮用测试模板锁住行为重构完成之后立刻用模板三补一组测试。提示针对上一轮重构后的 EventBus用 unittest 生成测试用例。 覆盖点 - 同一 handler 重复 subscribe 多次emit 时只调用一次 - onceTrue 的 handler 触发一次后自动移除 - emit 触发顺序与注册顺序一致 - unsubscribe 之后不再触发。 先给用例清单确认后再给代码。不要真实连接外部依赖。这一轮看似简单实际上是整个链路里最容易出岔子的地方。如果跳过测试直接进入提交信息阶段你很可能把“重构后行为等价”当成事实结果第二天就被回归测试打脸。测试模板在这里是最便宜的安全网。5.4 第四轮生成提交说明最后把前面三步的结论合并让 Codex 输出一份有结构的提交信息基于上述重构和测试生成一个 git 提交说明。 标题refactor(event-bus): 拆分订阅与触发逻辑修复重复订阅问题 正文需要包含背景、改动点、行为影响、测试情况。 不要发挥不要写我没有提到的功能。“不要发挥”是我后来才加上的。早期我经常让 Codex“顺便写一下后续优化建议”结果提交信息里突然出现一大堆没有实现的计划提交上去造成误导。加了这条约束提交信息才真正变成“这次改动的客观记录”。6. 让模板失效的几个细节我实际踩过的坑与调整模板不是万能咒语很多看起来合理的提问方式会在细节处翻车。这里列几个我反复踩过、后来调整过来的点。6.1 上下文堆太满指令反而被稀释有一阵子我为了让 Codex 更“懂”业务会把整个服务模块的全部代码都贴进去。结果是重构请求被淹没在几百行无关代码里模型改了一个完全不相干的工具函数我要的重构反而没发生。后来我在上下文里加了一句“下面这些代码只是背景不要改动它们真正要修改的是其中的process_refund函数”情况立刻改善。上下文不是越多越好而是“无关注释”越少越好。6.2 一个提问里塞了四个任务模型只认真做最后一个“重构这段代码顺便加注释、补测试、再给个性能优化建议”——这是我早期经常发的复合句。Codex 每次都会非常认真地执行最后一个任务前面的任务只给个半成品。后来我养成了拆轮的习惯一个提问只承担一个主任务。想加测试就再发一条想加注释就再发一条。初看是多花了几轮对话实际上每轮产出都可直接用总时间是省着的。6.3 只说要什么没说“不许碰什么”重构前不声明“公开接口不能变”Codex 非常喜欢顺手美化函数签名比如把subscribe(event, fn, onceFalse)改成attach(event, handler, single_useFalse)。从模型角度看这是“命名优化”从你的角度看是“所有调用方都崩了”。现在我的每个重构模板里都固定一行“保持公开接口不变”不依赖模型自觉。6.4 拿到结果直接定稿不做交叉验证模型生成的重构代码经常在核心路径上很漂亮但边界条件上有小裂缝漏掉一个空值判断、少处理一个异常分支、把某段不在粘贴范围内的依赖假设成另一种行为。所以我现在的流程固定是“模型输出 → 先跑测试 → 再人工做一遍 diff review”。这和我用 senior 工程师写的代码是同一个流程只不过 Codex 变成了一个输出速度极快但需要审稿的队友。6.5 连续口语化修改不如重新发一次结构化提问当 Codex 的输出不对很多人会在后续消息里打补丁“等等这里不对那个也别改了还是用之前那种方式吧……”这样来回几轮后上下文会充满互相矛盾的指令模型会在“新指令”和“旧指令”之间左右横跳最后给你一个比第一次更乱的版本。我现在遇到偏差会直接把前一轮可接受的部分复制出来加上新约束重新完整发一次模板。这看起来浪费实际是让模型在一个干净上下文里工作纠错准确率最高。急救卡的最终目的从来不是让你把思考外包给模型而是让你更快地拿到可审查的草稿然后把精力留给真正需要人判断的地方架构选择、边界处理、业务取舍。模板帮你稳定下限你的理解决定上限。
阅读完成 · 觉得有帮助?