
当下, AI 编程助手已经变成开发人员必须拥有的工具了, 大家能够从自动补全代码功能使用到生成最小可行性产品这个方面去使用它, 它的实际能力是完全没有疑问的。但是你是否曾经碰到了这样一种状况就是虽然用的是同样的模型, 但是别人用起来的感受好像是增强了力量一样, 而你自己生成的代码内容却是总是存在着一些不够到位的地方。许多人认为这是因为人工智能不够聪明, 但是在读完工程总监 Addy 写的那篇叫做《程序员提示词实战指南》的文章之后, 你将会明白一个令人心痛的真相: 人工智能产出的质量, 有百分之九十是由你的提示词的质量所决定的。绝大多数开发者现在已经形成了一种习惯, 这种习惯是基于某个特定模式的搜索思维。具体来说, 他们会把一些关键词丢进去, 然后满心期待出现奇迹, 结果往往让他们失望不已。然而在当今的人工智能时代, 这个情况已经发生了变化, 所以我们每个人都必须对大脑里的认知框架进行一下升级和调整, 以便更好地适应当前的发展需求。不妨把人工智能AI 当作一个技艺非常高超, 并且阅读量极广的“资深实习生”, 只不过这个人对你所在的项目背景情况是完全不了解的。人工智能这个玩意儿, 它可不是那种能够揣度你心思的大师, 要是没有你把相关的背景情况给补充完整, 它简直就是两眼一抹黑, 什么也看不见, 你要是问得模模糊糊、不清楚不楚, 它就会还给你一些看起来没错但没啥用的废话, 可如果你能把方向引导好, 它是有可能给出既优美又让人惊讶的解决方法的。所以说, 这个叫提示词工程的事情, 它已经就不再是那种只是让东西变得更好的锦上添花的操作了, 而是变成了现代的程序员必须要拥有的、那种实打实的硬技能。为了让你能够掌握这项技能, 本系列文章会放弃那些不着边际的理论方面的内容而是从实战的角度出发, 帮助你系统地掌握高效提问的技巧。我们将会涵盖以下核心场景。1.2.3. 关于代码重构, 这里有一份提示词指南, 这是本篇文章所讲述的主要内容。4. 从零构建新功能的提示词指南5. 编程提示词避坑指南之前我们其实已经介绍过关于这个高效提示词的底层逻辑, 所以现在呢, 就让我们正式开启这种实战模式, 也就是这篇叫做第三篇的关于代码重构括号里面是空的然后接着是提示词这样一个指南。我们现在进入第二个实战模式, 也就是对代码进行重构的操作。代码重构, 说白了就是, 在不动它现有功能的那些情况之下, 把它收拾得更加整洁起来, 变得更加高效一些, 也要更加符合那些地道的编写代码的习惯才行呀, 这个活儿可是 AI 助手们特别擅长去做的。毕竟, AI 模型阅读过海量的优秀开源代码, 这使得它成为了一个天然的“代码整容医生”。可是想要发挥出它的全部威力, 你就不可以只是扔下一句话叫做“优化一下”, 因为 AI 并不知晓你心目当中的那个所谓的“好代码”到底具备着什么样的具体特征和样子。高效重构这个事情, 它的核心要点就在于, 要通过使用提示词来定义出所谓最佳实践的那些具体标准。以下是驱动 AI 进行高质量重构时提示词的三个关键支点1. 明确重构目标如果把话仅仅是局限于说出一句“重构这段代码”, 这就类似于去到理发店, 然后对着理发人员说出要帮我剪短一点这样的一种诉求, 这显然是一种太过随意的行为了。你必须把目标进行拆解, 并且最终要落实到具体的技术指标上面去。你这样说话, 难道是想让代码变得更加容易阅读吗? 又或者你心里头想着的是要减少程序的复杂程度? 再不然, 难道你是盼着去提升程序运行的性能表现? 还有可能, 你是打算变换一种编程的手法风格, 又或者是想要更换一个第三方的工具库使用?那些表现非常糟糕的提示词, 它们通常都采用了一种模式, 就是简单地说一句: “请对这段代码做出改善和提高。”。好提示词模式请把这个函数重新搞一下, 让它的可读性变得更好, 也让它更容易被维护下去, 具体的做法是把里面那些重复出现的代码给减少掉, 并且要把变量名改成更清楚地表达意思的名字。请对算法运行期间的处理效率实施优化措施, 原因是因为在针对具备大规模数据量的场景进行运算的时候, 该算法的执行速度过于迟缓。当你明确确定了那个具体的目标, 这个模型就清楚明白地知道了应当朝着哪一个确切的方向去施加力量或者集中精神了。假如你明确表示自己在乎性能表现, 那么它就有可能会去更换一个效率更高的排序方法, 又或者是添加缓存手段来帮忙若是你着重强调程序需要具备较高的可读性, 它就可能把体积庞大的函数拆解分成更小的若干单元, 又或者补充上必要的代码注释以便他人阅读。2. 锁定技术上下文按照同样的这种逻辑来讲, 在不同版本的框架里头所对应的那些所谓的地道的写法的方面, 那真的是存在着非常大的差别的其中最核心、最应该去做的那一点事情就是把自己所属的情况给说明白, 也就是说要明确地告知对方你所使用的具体是什么编程语言以及你所依赖的是哪一个具体的框架体系。按照同样的逻辑进行推演, 那么在 Node.js 这个环境里面, 还有在 Deno 这个环境里面, 情况可能会变得完全不一样另外, 如果具体到 React 里面的类组件这一种形式, 再结合函数组件这种形式来看的话, 差别就更大了。当前的技术组合是 React 18。现在需要把这段以前使用的 Class 组件进行改动, 改成用 Hooks 来实现。在这个过程中, 要注意让渲染的逻辑变得更合理, 千万不要出现不必要的重新渲染的情况。如果你不去把版本指出来, 那么人工智能就可能会出现情况, 它很可能会拿去使用五年之前的那种语法规范, 然后最终所写出来的代码就是属于不能互相兼容的代码。3. 要求自我解释重构这件事情, 它不单单是对代码进行修改, 同时也是大家一个非常好去学习的时机和机会。请你把那份代码重新整理一下, 给出更新后的版本, 同时详细地列出你具体进行了哪些方面的调整, 并对为什么选择这种新的写法而舍弃原来的旧写法这一理由做出解释。这不仅可以让你快速检查一下代码方面的事儿, 另外还可以防止那个人工智能在旁边悄悄地改动业务的逻辑, 从而避免出现问题。简单来说, 让人工智能来解释相关的情况, 就是一种类似安全带那样的东西, 这就如同让人工智能对自己的重构这一类的工作内容进行一次代码级别的核查操作。4. 通过进行角色扮演, 把标准给拔高。前面我们就说过, 让AI来扮演专家这个角色是非常有好处的。在你进行重构工作的时候, 你完全可以这样说:这个提示词的模板内容是: 你是一位资深的专家, 按照最佳实践和现代标准对这段代码进行重构。这种设定往往能够炸出更有深度的改进。而不仅仅是表面上的修修补补。这是因为AI会努力去贴合专家的人设。有一个被很多人熟知的经典案例, 是安排人工智能来担任导师这个角色的。你是一名在软件开发领域拥有很久工作经历的人, 也就是大家所说的开发者, 你正在给一个刚开始学习编程的年轻人做指导人员。请你去编写那个关于函数注释的东西, 也就是用小括号括起来的部分, 然后把原来的代码拿来进行一次重新编写, 让它变得更好一些, 这个过程叫做优化。在进行这些操作的时候, 你需要给出非常细致和详细的解释说明内容, 这样对方才能听懂。在一些示例当中, 这种把 AI 当成老师来看待的做法, 甚至会让 AI 主动地去挑选那些更加合适的数据结构, 并且提供出那种比较简洁的、只用一句话就能写出来的代码, 以此来替换掉那个原来写得特别啰嗦的循环结构。02 案例实战: 一个是烂提示词, 另一个是好提示词。我们现在面对一个场景, 这个场景里存在一个Node.js函数, 这个函数的作用是先去串行调用两个接口, 然后在做完这些之后呢, 还得用一个非常低效的嵌套循环去合并数据。原始代码async function getCombinedData(apiClient) { // 问题1: 串行请求慢 const users await (await apiClient.fetch(/users)).json; const orders await (await apiClient.fetch(/orders)).json; const result ; // 问题2: 嵌套循环O(n*m) 复杂度 for (let user of users) { const userOrders orders.filter(o o.userId user.id); result.push({ user, orders: userOrders }); } return result; }第一轮的时候, 那个指令弄得非常含糊不清, 然后我们进行了重新组织。把上面的那个函数对象, 给弄出一个新的版本来。人工智能系统给出的回应, 这里做一个模拟处理。好的, 这是那个经过调整之后的版本。async function getCombinedData(apiClient) { // 并行获取用户和订单 const [usersResponse, ordersResponse] awaitPromise.all([ apiClient.fetch(/users), apiClient.fetch(/orders) ]); if (!usersResponse.ok || !ordersResponse.ok) {thrownewError(Failed to fetch data);}const [users, orders] awaitPromise.all([usersResponse.json(),ordersResponse.json()]);// 按 userId 索引订单以便高效查找const ordersByUser {};for (const order of orders) {if (!ordersByUser[order.userId]) {ordersByUser[order.userId] ;}ordersByUser[order.userId].push(order);}// 合并数据return users.map(user ({user,orders: ordersByUser[user.id] || []}));}人工智能技术确实把请求模式更改为了并行处理, 同时也应用了 Map 方法来进行优化。然而在错误处理的环节, 它能够自行决断, 把源自两个不同接口的报错信息给合并了起来, 最终形成了一种统一的错误提示, 也就是被称为 Data Fetch Error 的数据获取错误。我们来好好说, AI 有时候可能蒙对了关于性能优化的事儿, 但是它很有可能会在没有经过允许的情况下, 擅自把错误处理的逻辑给改了, 这一点是我们必须注意的, 我们需要像在抽取卡片一样去检查由 AI 生成的代码内容, 这是因为发出的指令不够清晰、目标不是特别明确, 所以就会带来一些让人无法掌控的负面影响和副作用。第二轮, 也就是面向目标去进行重构的那个阶段。用户对上面的那个函数进行重构操作, 目的是为了把那些重复出现的代码部分去掉, 同时还得想办法让执行的效率变得更高一些。具体约束为了避免出现重复的 users 数据以及对数据进行获取的逻辑处理, 也许可以考虑使用一个辅助函数来进行解决, 或者是选择把两次的获取操作合并为一步来完成处理。如果说是可以做到这样的状况的话, 那么就尝试着去并行地获取这两个列表。要保留每个请求的独立错误处理, 这样我们就能知道具体是哪个调用出现了失败的情况。对数据合并那一部分进行改进, 使用更高效的结构来处理查找工作, 而不是使用嵌套循环的方式。请提供经过重构后的代码内容, 并且在代码里面加上注释来解释你做出的那些修改动作。人工智能系统给出的回应, 这里做一个模拟处理。async function getCombinedData(apiClient) { // 1. 并发请求提升响应速度 const [usersRes, ordersRes] awaitPromise.all([ apiClient.fetch(/users), apiClient.fetch(/orders) ]); // 2. 独立错误检查 (遵从指令) if (!usersRes.ok) thrownewError(Failed to fetch users);if (!ordersRes.ok) thrownewError(Failed to fetch orders);const [users, orders] awaitPromise.all([usersRes.json(), ordersRes.json()]);// 3. 构建索引 Map空间换时间const ordersMap orders.reduce((map, order) {(map[order.userId] || []).push(order);return map;}, {});// 4. O(n) 复杂度合并return users.map(user ({user,orders: ordersMap[user.id] || []}));}这一段的评论, 是对那个回答的点评。那一个回答, 可以说是完美地命中了所有的目标。它的代码, 变得更加干净了, 运行的速度, 也更加快了。它还听话地, 保留了独立的错误信息。AI的解释方面, 也是逐一地, 对应了我们提出的要求。这, 就是所谓的“把重构定义清楚”的这个效果吧。我们做的事情是, 我们不仅告诉 AI 它要去做什么事情, 我们还告诉它具体应该怎么去做, 要保留哪些内容, 要优化哪些部分。--这个事例给了我们一个极其深刻的警示, 其核心内容在于表明, 当你的内心对于所期望达成的最终效果拥有了非常清晰且明确的认知时, 那么你务必、并且是一定要采取实际行动, 把这一情况明确无误地书写记录出来。人工智能确实能够非常擅长去执行我们发出的各种指令, 然而它自身并不具备那种可以直接看透人类内心的魔法般的能力。当你要处理那些极其复杂的代码的时候, 最好是把你的具体需求像列出一份清清楚楚的愿望清单一样给列出来, 这种做法所带来的最终效果, 绝对是比你仅仅只丢下一句模糊不清的“优化一下”这样的话要好上足足一百倍以上的。相关领域社区里的大家伙们的实际使用经验也一次又一次地反复强调并指出, 如果你所使用的提示词是呈现出结构化的模样并且带有非常明确的目标指向的话, 那么这便能够有效且显著提升最终所获得的输出结果的质量水平。03 进阶的部分内容就是关于重构的所谓的高超手段, 接下来要说的第一个点是去打听还有没有其他可以替代的方法。人们也许会认为AI的第一版重构方案是可以使用的, 但是很多人心里会有好奇心想知道是否还有其他的写作方法存在。你不妨可以去问一下别人这个问题。这个重构的方案, 它的优点确实是比较明显的。不过, 我们不妨换个角度重新考虑一下这个设计方式。例如说在使用函数式编程思路的时候, 我们可以多去调用那些数组自带的方法来操作数据, 尽量把常规的循环语句给减少掉。另外呢, 也可以去想象这样一个情况, 如果是采用了递归这种结构来实现功能, 而不是坚持用循环的方式来反复执行, 这会让整个的代码逻辑变成怎样的一个形态。这种情况就好比是跟同事搞头脑风暴, 这种做法能够起到帮你拓宽思路的作用。在经过一系列讨论之后, 从众多想法当中选出最让你感到满意的那个来作为最终的结果。2. 进行验证, 以及进行测试。你使用人工智能工具生出来的那段代码, 在正式投入使用之前, 一定不可以直接去上线部署, 它存在一种可能性, 就是会引入那种非常细微、不好发现的错误程序缺陷, 特别是当你没有在给它的指令提醒里面把各种必要的约束条件说清楚说明白的时候, 这种情况就变得尤为危险。以我们在上面的那个例子作为参照, 假如原先的代码是有意地把错误现象进行分开式的记录与日志操作处理, 而人工智能这边却选择把这些内容给全部地合并到一起去处理的了, 那么这个行为就属于是一个错误的缺陷。你需要作为人类去进行审查。你可以提出这样的要求: 在开始重构工作之前。请为原始的函数编写三个单元测试。要让重构完成之后的代码能够通过这些相同的测试条件。这是一个非常强有力的保障措施, 其作用在于确保进行代码结构重组的过程中绝对不会导致原本正常的业务逻辑发生崩溃。3. 分步重构要是函数的量非常大, 或者你打算修改的地方特别多, 那就不要想着凭借一个人一次的尝试就能够把全部的事情都处理完成。比方说, 先把情况描述为让人工智能去执行重构这一动作, 其目的是为了提升代码的可读性, 具体来说就是进行变量重命名或者是将庞大的函数拆解为更小的部分, 在确认这一切操作都没有引发任何错误之后, 再接着进行下一轮的对话, 此时向它发出指令, 要求其对那个特定的算法实施优化行为, 通过这样一种分步骤进行的方式, 既能够有效防止因为一次性塞入过多模型指令而导致其处理能力过载的情况发生, 同时也便于使用者对每一次修改产生的结果进行单独且细致的查验与核对。4.边重构边学习我再次强调了使用人工智能的解释这个功能。假如说你看到了一个你以前从来没有使用过的方法, 比如说创建 Map 这种操作, 那么请你仔细地阅读一下代码里面给出的解释说明。这样子的话, 你原本简单的一次提问, 就可以转变成为一堂小型的技术学习课程了, 从而帮助你掌握那些最好的实践方式。--到目前为止, 我们已经把调试也就是修复旧的那段代码这一件事, 还有重构也就是修改旧的那一段代码那另一件事, 都处理妥当。接下来, 这是非常合乎逻辑的、顺理成章的一个步骤, 这个步骤就是让人工智能技术来帮助我们去编写新的功能模块, 去生成那些全新的代码文件。我们要好好地看一下具体应该通过怎样的方式来撰写这类用于引导人工智能的工具提示词, 才能使得最终的结果达到最为有效的状态。在进入新功能的实际运用之前, 因为要便利你随时进行复习, 所以特意整理出了一份叫作《Vibe提示词入门速查表》的东西。建议你去收藏并保存一下, 等到写作时卡壳的时候, 可以随时随地翻看: 。请长按图片下方那块地方, 这样就能把高清版本给保存了下来。就是最近那个文章的单子。