目录

《超越感觉编程(真实 Epub 版)》

超越氛围编程

作者:Addy Osmani

版权所有 © 2025 Addy Osmani。保留所有权利。

在美国印刷。

O’Reilly Media, Inc. 出版,地址:141 Stony Circle, Suite 195, Santa Rosa, CA 95401。

O’Reilly 图书可用于教育、商业或销售促销用途。大多数书籍也提供在线版本 (http://oreilly.com)。如需更多信息,请联系我们的企业/机构销售部门:800-998-9938 或 corporate@oreilly.com

第一版修订历史

有关发布详情,请参阅 http://oreilly.com/catalog/errata.csp?isbn=9798341634756

O’Reilly 标志是 O’Reilly Media, Inc. 的注册商标。《超越氛围编程》、封面图片及相关商业外观是 O’Reilly Media, Inc. 的商标。

本书中表达的观点为作者观点,不代表出版商的观点。尽管出版商和作者已尽诚信努力确保本书中包含的信息和说明准确无误,但出版商和作者对所有错误或遗漏不承担任何责任,包括但不限于因使用或依赖本书而造成的损害。使用本书中包含的信息和说明风险自负。如果本书包含或描述的任何代码示例或其他技术受开源许可或他人的知识产权约束,您有责任确保您的使用符合此类许可和/或权利。

本书不作为法律建议。如需法律建议,请咨询合格的专业人士。

979-8-341-63475-6

LSI

前言

我们正处于软件构建方式深刻转变的时代。专业的氛围编程(vibe coding)——与AI协作创建软件的艺术——正在将开发者从代码工匠转变为产品愿景家和编排者。

氛围编程是关于利用AI的能力来处理编码的繁重工作,让开发者能够更多地专注于想法、设计和高层次的问题解决。正如 Andrej Karpathy 所言,这就像”忘记代码的存在”,只需构建——描述你需要什么,让AI填充实现细节。这可以带来数量级的生产力提升,使传说中的”10x工程师” 可能成为100x的现实

本书的目标读者

本书面向三类核心读者。第一类是希望倍增其影响力的经验丰富的开发者和工程领导者。如果你已经编码多年并感受到重复性任务的负担,本书将向你展示如何将平凡的工作委托给AI,同时将你的角色提升为架构师和战略家。你将学会在不牺牲多年职业生涯中形成的质量标准的情况下更快地构建。

第二类是具有产品思维的工程师,他们将代码视为达成目的的手段而非目的本身。如果你对愿景与实现之间的差距感到沮丧,氛围编程可以极大地缩短这一距离。你将发现如何快速原型设计、迭代并交付使用传统方法需要数月时间的产品。

关于AI工具,我发现了一件最违反直觉的事情:它们对经验丰富的开发者的帮助大于初学者。这似乎很矛盾——AI不应该使编程民主化吗?

现实是,AI就像团队中有一个非常热心的初级开发者。他们可以快速编写代码,但需要持续的监督和纠正。你知道的越多,就越能更好地指导他们。

这产生了我所说的知识悖论(knowledge paradox):高级工程师和开发者使用AI来加速他们已经知道如何做的事情,而初学者试图用它来学习应该做什么,结果截然不同。

我观察到高级工程师使用AI来:

与此同时,初学者通常:

第三类是应对AI对其团队和流程影响的工程经理和CTO。你将深入了解如何在一个单个工程师可以完成过去需要团队完成的工作的时代里,构建团队、评估人才并保持代码质量。这里的策略将帮助你在保持工程文化完整性的同时顺利过渡。

你在这里找不到的是编程入门指南。虽然AI使编程更易于访问,但有效地使用它仍然需要来自经验的判断力。将本书视为为那些准备超越传统编程并拥抱软件创建新范式的人提供的高级培训。

预期内容

本书探讨了开发者角色如何演变,从动手编程转向产品工程。这意味着运用人类判断来引导AI,确保质量、架构和用户需求得到满足。我们仍然提供创造力、系统思维和共情能力,将功能性程序转化为优秀产品。AI不会取代我们;它会增强我们——如果我们明智地使用它。

在第一部分中,我将识别氛围编码(vibe coding)擅长的领域:启动新产品、原型设计功能、生成标准的CRUD应用或集成代码——所有这些领域中,速度和模式匹配胜过深度原创性。相反,我也会审视我们对依赖AI仍需谨慎的地方:真正复杂、底层或新颖的算法,AI可能会在这些地方出错。认识到AI当前的局限性可以防止挫折和失败;仍有大量工作只有人类的创造力才能完成。

人的因素仍然是关键。我们确保架构合理、调试棘手的错误,并判断代码质量是否超越”能运行”。关键的是,我们将以用户为中心的思维融入开发——这是AI无法做到的。由我们来确保软件不仅能工作,而且能以有意义的方式为用户工作。简而言之,开发者成为AI输出的策展人和编辑者,始终使其与现实需求和高标准保持一致。

第二部分关注氛围编码的实践方面。采用新工作流程至关重要。“重新生成而非修复”这样的技术提醒我们不要陷入困境——有时重新生成代码比调试更快。并行提示(parallel prompting)让我们同时从多个角度解决问题。我们必须平衡快速迭代与最终改进,确保不会积累难以维护的混乱。模块化AI代码、全面测试和迭代改进等最佳实践有助于在高速开发的情况下保持代码库的整洁和健壮。

随着项目规模扩大,我们必须管理加速流入的代码和潜在的技术债务。AI可能让你的代码仓库充斥代码;只有纪律和良好的工程实践(加上可能的AI辅助重构)才能保持其可维护性。在人员方面,我们将招聘和培训擅长使用AI工具的工程师,重视适应性和系统设计技能。我们还会知道何时退回到传统模式——比如为了长期维护而巩固产品,或处理谨慎胜过速度的关键系统时。

第三部分涵盖安全性和可靠性、伦理,以及一系列使氛围编码成为可能的工具:像Cursor和Windsurf这样的AI增强IDE,它们集成了Anthropic、Google的Gemini和OpenAI的模型,以理解你的整个代码库并在每个环节提供帮助。知道应用哪些工具和模型(Claude的各种变体用于不同任务,ChatGPT用于一般问答)是新开发者技能集的一部分。它们各有优势:Cursor用于交互式编辑,Windsurf用于上下文密集型任务,聊天界面用于头脑风暴和故障排除等。

展望未来,我预计会有更抽象的软件构建方式(通过GUI和更高级别的输入进行”氛围设计”),对通用库的依赖会减少,因为AI会生成更多定制代码,甚至软件会基于AI反馈循环自主演进。在这个未来中,软件领域的成功将严重依赖于人类的创造力、分发能力和利用网络效应的能力,因为编码的暴力破解门槛将非常低。新的用户体验范式可能会出现,由AI的普遍性驱动——从对话界面到自适应UI等等。

在所有这些中,有一个主题突出:人类和AI优势的融合。单独任何一方都不如两者结合强大。AI带来速度、广泛的知识和不知疲倦的执行力。人类带来方向、深度理解和价值观。未来的最佳工作流程是一种共生关系——想象一下将大师级工匠与能够即时获取任何工具或参考资料的超级学徒配对。工匠的专业知识对于创造真正卓越的作品仍然至关重要。

对于阅读本书的开发者:是时候拥抱这些工具和范式了。本书将鼓励你在下一个项目中尝试AI编码助手,练习将问题分解让AI解决部分问题,并培养制作提示和策展结果的技能。但它也会敦促你加倍投入你的独特价值——你设计系统、与用户共情以及做出使软件与现实保持一致的判断的能力。

本书使用的约定

本书使用以下排版约定:

斜体

表示新术语、URL、电子邮件地址、文件名和文件扩展名。

等宽字体

用于程序清单,以及段落中引用程序元素,如变量或函数名、数据库、数据类型、环境变量、语句和关键字。

提示

此元素表示一般注释。

警告

此元素表示警告或注意事项。

O’Reilly在线学习

注意

40多年来,O’Reilly Media一直提供技术和商业培训、知识和见解,帮助公司取得成功。

我们独特的专家和创新者网络通过书籍、文章和在线学习平台分享他们的知识和专业技能。O’Reilly 的在线学习平台为您提供按需访问的实时培训课程、深入的学习路径、交互式编码环境,以及来自 O’Reilly 和 200 多家其他出版商的大量文本和视频资源。如需了解更多信息,请访问 https://oreilly.com

如何联系我们

请将有关本书的意见和问题发送给出版商:

我们为本书建立了一个网页,在那里我们列出了勘误表和任何补充信息。您可以访问此页面:https://oreil.ly/BeyondVibeCoding

有关我们的书籍和课程的新闻和信息,请访问 https://oreilly.com

在 LinkedIn 上找到我们:https://linkedin.com/company/oreilly-media

在 YouTube 上观看我们:https://youtube.com/oreillymedia

第一部分 基础

第 1 章 导言:什么是氛围编程(Vibe Coding)?

AI 正在重塑我们构建软件的方式,引入了从自由形式提示(prompting)到结构化辅助的新编程范式(paradigm)。想象一下,通过简单地描述你想要做什么来编写软件——几乎就像和队友交谈一样——而 AI 将这些想法转化为代码。这就是氛围编程的本质,一种提示优先的探索性方法,你用自然语言描述你想要什么,让大语言模型(LLM)来填补空白。这个术语最近由 AI 先驱 Andrej Karpathy 提出,用来描述这种新的编程方式,开发人员”完全顺应 AI 辅助的氛围”。

在本书中,我将深入探讨氛围编程对专业开发人员的意义,以及它如何与我所说的 AI 辅助工程(AI-assisted engineering)——一种更正式的增强编码过程——进行比较和互补。我将探讨在这个 AI 优先的时代,开发人员的角色如何演变,哪些工具和工作流可以最大化你的效率,以及如何应对让 AI 在你的代码库中自由发挥的独特挑战。我还将研究氛围编程在哪些方面表现出色,在哪些方面遇到困难,以及如何平衡 AI 生成的速度与人类监督的智慧。最后,你应该清楚地了解如何在自己的编码实践中负责任且有效地利用”氛围”——在 AI 时代成为不仅更快,而且更具创造力和影响力的软件产品工程师。

在本章中,我们探讨开发人员的角色如何从为机器编写详细指令转变为通过表达意图(intent)与 AI 协作(见图 1-1)。我们将看到为什么编程中的这种”氛围转变”如此重要,它在高层次上如何工作,以及它带来了哪些机遇和挑战。

图 1-1:编程意图的概念图示。开发人员提供高层次的规范(“意图”),AI 将其转化为代码。这突出了从逐行编写代码到在高层次指导代码生成的转变。

AI 编程谱系:从氛围编程到 AI 辅助工程

在过去的一年里,我观察到开发人员——尤其是中高级 Web 开发人员——在工作流程中接受 AI 的方式出现了有趣的分化。谱系的一端是氛围编程。另一端是我所说的 AI 辅助工程:一种有纪律的方法,在明确的约束下,将 AI 融入软件开发的各个阶段,从设计到测试。这两种方法都利用了强大的 AI,但它们的目标、受众和期望明显不同。在本书中,我将探讨这两个极端及其对现代 Web 开发的意义。

氛围编程方法:通过对话编码

在 vibe coding 中,你利用强大的大语言模型(LLM)作为编程伙伴,让它们处理代码生成的繁重工作,这样你就可以专注于更高层次的目标。正如《商业内幕》的一篇总结所说,vibe coding “意味着使用 AI 工具……来处理编码中的繁重工作,从而快速构建软件。” 正如英伟达(NVIDIA)首席执行官黄仁勋所说,得益于 AI,“最热门的新编程语言”是英语,而不是 Java 或 Python。你不需要手动输入每个函数和错误修复,而是用自然语言与 AI 交互——勾勒出功能、审查建议,并根据 AI 的输出进行迭代。

这种方法代表了从传统编程到 AI 辅助开发的巨大转变。传统编码需要仔细规划、精确的语法,以及经常令人痛苦的调试过程。Vibe coding 颠覆了这一模式:“这不是真正的编码——我只是看东西、说东西、运行东西、复制粘贴东西,大部分情况下都能正常工作,”Karpathy 在接受《商业内幕》采访时开玩笑说,强调了 AI 如何将高层次的指令转化为可工作的代码,而只需最少的手动工作。

开发者从为计算机编写详细指令转变为在 AI 的帮助下编排结果。例如,Karpathy 描述了通过不断接受 AI 的建议来构建 Web 应用:“我总是’全部接受’,我不再阅读差异了……当我收到错误消息时,我只是复制粘贴进去……有时候大语言模型无法修复错误,所以我就绕过它或要求随机更改直到错误消失。” 代码”增长”超出了他通常自己编写的范围,但通过迭代提示和修复,项目很快就完成了。本质上,vibe coding 将编码视为与你的 AI 配对程序员进行的互动对话,而不是独自在语法和堆栈跟踪中艰难前行。目标是速度和探索——以最小的阻力获得可工作的解决方案。

几个趋势汇聚在一起,使 vibe coding 成为可能。首先,现代 AI 编码助手(如 OpenAI 的 Codex、ChatGPT、Anthropic 的 Claude 等)在生成和纠正代码方面变得惊人地出色。在同一篇文章中,Karpathy 指出这”之所以可能,是因为大语言模型……变得太好了”——它们已经消化了 GitHub 代码的大量内容,可以为许多任务生成合理的解决方案。

其次,新的开发者工具已经出现,可以将这些模型无缝集成到编码工作流程中(稍后会详细介绍这些工具)。最后,开发者社区的心态正在演变,越来越信任 AI 协助处理越来越大的工作块。这不再只是增强版的自动补全;而是将整个函数或文件交给 AI。实际上,vibe coding 通常感觉就像拥有无限供应的热心初级开发者来实现你要求的任何东西——只不过他们以云计算的速度工作。

Vibe coding 最令人瞩目的承诺之一是生产力的提升。早期采用者报告说,他们能够比以前快十到一百倍地创建软件功能或原型。例如,Codeium Windsurf 工程师 John Hoestje 思考道:“为什么要成为 10 倍工程师,而你可以成为 100 倍工程师呢?” 这表明,使用正确的 AI 驱动的集成开发环境(IDE),超凡的生产力是触手可及的。像 Windsurf 这样的工具,一个 AI 增强的 IDE,“可以显著加快开发时间,让你实现那 100 倍的生产力。” 虽然 100 倍可能是一个极端场景,但即使是更保守的研究也发现了巨大的收益。

开发者可以在几秒钟内生成样板代码,在眨眼间修复错误,甚至让 AI 编写测试或文档,将过去需要几天的工作流程压缩到几个小时。不再受打字速度或内存的限制,一个配备 AI 的开发者通常可以在一个周末内原型化一个全栈应用程序——这在过去可能需要一个小团队花费数周才能完成。这不仅仅是炒作;正如我在 2025 年 1 月为《务实工程师》撰写的博客文章中指出的那样,调查显示 75% 的开发者已经将某种形式的 AI 整合到他们的工作流程中,许多公司报告开发速度提高了两位数或三位数的百分比。简而言之,AI 配对程序员正在将神话般的”10 倍工程师”变成一个非常真实(且可达到的)100 倍工程师现象。

要理解这有多革命性,让我们看一个具体的例子。一位开发者想要构建一个简单的网页应用,用于统计播客脚本的字数并估算阅读时间。他们不是从零开始,而是打开一个AI驱动的编程环境,向AI描述自己的想法。几分钟内,AI就生成了一个可用的原型。然后开发者说:“把统计计数器改成亮色,并添加PDF导出功能”,AI就相应地更新了代码。结果是一个功能完整的工具,一键部署——所有这些在10分钟内完成。这个真实场景(由一位使用Replit AI的创作者报告)展示了vibe coding如何实现由高层次需求驱动的极快速迭代开发。同样,非工程师也加入进来:同一篇文章描述了一位被裁员的营销人员,没有任何编程背景,使用AI编程助手构建了100个简单的网页工具,这些工具集体登上了Product Hunt榜首。当创建软件的门槛降到如此之低时,我们不仅仅是在提高资深开发者的生产力——我们从根本上扩大了谁能够开发软件。

然而,vibe coding也有严重的注意事项。因为你将太多工作委托给AI,你最终可能得到一个在正常路径下”能用”但隐藏着大量bug或糟糕设计决策的代码。没有可靠的计划或约束,LLM可能会生成缺乏适当错误处理、安全检查或可扩展性的解决方案。事实上,AI生成的代码有时可能是建立在沙子上的:它看起来很稳固,但有隐藏的问题,只有在实际条件下才会暴露出来。我见过这样的案例:开发者以创纪录的速度通过vibe的方式完成了一个完整的功能,却在后来发现代码效率低下且难以维护。这种”纸牌屋”代码在压力下会崩溃。

例如,想象一下要求AI”快速搭建一个用户登录系统”。AI可能会快速生成一个可用的身份验证流程,但也许它使用了简化的加密方法或已知有漏洞的库。如果你在没有深入检查的情况下部署它,你就是在盲目相信一切都是健全的。资深工程师知道这是有风险的:在生产环境中运行的代码必须是被理解和信任的。正如一位专家所说:“通过vibe coding方式构建生产代码库显然是有风险的。我们作为软件工程师所做的大部分工作涉及演进现有系统,其中底层代码的质量和可理解性至关重要。”极端的vibe coding可能会绕过这些质量关卡。

另一个挑战是vibe coding倾向于轻视前期规划。传统软件工程重视为清晰和约束而设计——思考数据模型,选择适当的模式,并至少写出最小化的规格说明。Vibe coding颠覆了这一点:它从没有脚手架开始,通过提示直接投入实现。这可能导致曲折的开发过程。你可能通过提示把自己逼入困境——比如AI选择了你不打算使用的状态管理方法或库,现在你要么引导它回到正轨,要么接受它。没有初始蓝图,最终的架构可能是杂乱无章的。这对于快速的概念验证(proof of concept)来说还好,但在需要一致性的大型代码库中就有问题了。

Vibe coding本质上并不”坏”。事实上,它的出现是编程民主化(democratization of programming)持续进程的一部分。它降低了创建软件的门槛,就像早期的低代码平台或脚本语言所做的那样。一个有明确想法的积极的非工程师可能仅通过vibe就能构建一个简单的应用。对于经验丰富的开发者来说,vibe coding可以是一个强大的头脑风暴工具——它就像伪代码但能立即得到可运行的结果。关键是要认识到它的局限性。没有纪律的速度可能导致脆弱的软件,所以vibe coding需要一个警觉的人在循环中。我经常提醒开发者(和我自己)“vibe coding不是低质量工作的借口”。它应该是解决方案的起点,而不是终点。

AI辅助工程方法:与AI伙伴一起构建结构

在我们的范围的另一端是AI辅助工程——一种更结构化、更有条理的软件构建方式,AI在每一步都作为副驾驶。在这里,开发者仍然牢牢地坐在驾驶座上。AI辅助工程包括在传统软件开发生命周期(SDLC)中使用AI,例如AI驱动的自动补全、聊天、代码迁移、bug检测、测试生成,以及细粒度(函数、模块、组件)和完整代码生成(见图1-2)。

图1-2. 计划优先的AI辅助工程工作流:开发者创建规范,向AI系统提供有针对性的提示,审查生成的代码片段,并将批准的解决方案集成到他们的项目中。

你从一个计划开始(即使是轻量级的),概述你需要构建什么,并预先定义约束和验收标准。然后你以有针对性的方式融入AI工具来加速或增强计划的某些部分。与提示优先的氛围编码相反,我们可以称之为”计划优先”的AI支持开发。这可以正式到像一个迷你产品需求文档(功能的简短PRD),也可以简单到像一个任务清单。关键区别在于,在让AI开始工作之前,你将工作建立在明确的意图和约束之上。

考虑一个React开发者被要求创建一个新的交互式仪表板组件。在AI辅助工程方法中,他们可能会从写下组件的职责和API开始:

仪表板组件显示分析卡片列表,支持按日期范围过滤,并有刷新和导出按钮。它应该从我们的API获取数据(具有适当的错误处理),并且必须遵循我们的设计系统进行样式设置。

这个大纲本质上就是一个规范。开发者甚至可能快速勾画一个数据模型或识别要重用的现有实用函数。只有在那之后,他们才引入AI:例如,使用支持AI的IDE或编码助手根据该描述生成组件的框架。AI可能会提供React组件的初始实现,包含数据获取的占位符和存根事件处理程序。因为开发者提供了清晰的指导,AI的输出更有可能与项目需求保持一致(例如使用正确的设计系统类或调用正确的API端点)。代码不是意外的产物;它是精心设计的请求的产物。

AI辅助工程不会止步于单个组件的代码生成。它以受控的方式渗透到整个开发生命周期中。对于日常编码任务,像GitHub Copilot这样的AI自动补全工具可以在你输入时建议接下来的几行,当你实现已知模式时节省击键次数。例如,当你编写单元测试时,你的AI助手可能会根据函数名自动建议断言。说到测试,一旦功能就位,你可能会使用AI生成测试用例——将组件的规范或代码输入提示中,以获得你应该检查的边缘情况的建议。这个想法是增强工程师的工作,而不是取代它。你仍然在思考逻辑并验证正确性;AI只是减轻了一些繁重的工作。

当涉及到代码迁移或重构时,AI可以是天赐之物。想象一下需要将基于类的React组件转换为带有hooks的现代函数组件。与其全部手动完成,你可以要求AI助手转换代码或至少概述步骤。通过对旧模式和新模式的良好理解,LLM可以生成重构代码的草稿,然后你进行审查和完善。这种结构化的AI使用逐个处理明确定义的任务(例如”将此代码从Redux迁移到React Context API”),而不是给AI一个开放式的”构建任何东西”的任务。

也许AI辅助工程最引人注目的形式是使用AI从详细规范生成完整的迷你应用程序或功能。现在有几个工具允许你输入应用程序的描述,类似于迷你PRD,并返回一个工作代码库或原型。例如,开发者可以提供以下规范:

一个带有React前端和Node.js后端的待办事项列表应用,支持用户认证和实时更新

这个 AI 工具将搭建(scaffold)项目、创建关键组件并设置数据库模式(schema)。

这并非魔法,而是一个勤勉的工程师在启动新项目时可能会做的事情的加速版本(设置目录、选择库、编写样板代码)。重要的是,AI 的创造力受到规格说明中给出的约束条件的限制。结果是一个遵循您提供的需求的最小可行产品(MVP)。有经验的开发者正确对待这个输出时,不会假设它在第一次生成时就已经可以投入生产。相反,他们会将其视为初稿。他们会运行应用程序、编写或重新生成测试来验证每个功能、检查代码是否存在任何不一致或不安全的配置,并根据需要进行优化。简而言之,他们会应用所有常规的工程严谨性——只是通过 AI 从蓝图生成大量代码的能力来加速。

AI 辅助工程的目标与随性编码不同。这里的目标不仅仅是快速获得能用的代码,而是更高效地获得高质量的代码。这是在保持(甚至改善)结果可靠性的同时提升生产力。实践 AI 辅助工程的团队可能会说:“我们希望以两倍的速度交付这个功能,但在我们的标准上零妥协。”

这种方法的受众通常是专业开发者和已经建立了流程(代码审查、测试、部署流水线)且不愿放弃的团队。这些是中高级工程师,他们将 AI 视为工具箱中一个强大的新工具,而非工具箱的替代品。他们可能见过走捷径的后果,因此重视保持软件可维护性的实践。(相比之下,随性编码的受众包括拼凑演示的独立开发者、具有一定编码知识的产品导向人士,甚至是利用 AI 来弥补专业知识空白的相对较新的程序员。)

AI 辅助工程的预期是人类保持对决策的控制,而 AI 提供建议或加速器。代码质量、性能和安全性仍然至关重要,因此每一段 AI 生成的代码都要接受与初级开发者编写的代码相同的审查。将 AI 视为您的实习生,而非您的替代者。您可能会将任务委派给它,但必须审查它的工作。正如您永远不会在没有代码审查的情况下部署人类实习生编写的代码,您也不应该在不理解的情况下部署 AI 编写的代码。这种思维方式将工程纪律置于首要位置。

不同的思维方式,不同的期望

随性编码和 AI 辅助工程是两种截然不同的思维方式。随性编码是自上而下和探索性的:您从一个宽泛的想法开始,通过与 AI 的交互让实现逐渐显现。这有点像即兴爵士乐——结构最少,大量创意即兴空间,您在演奏过程中发现曲子的形态。AI 辅助工程是系统化和迭代的:更像古典作曲,您从一个主题或动机(您的需求)开始,有条不紊地发展它,可能在乐谱的小节内使用一些即兴创作(AI 建议)。两者都能产生”音乐”,但过程和结果类型会有所不同。

对于中高级 Web 开发者来说,您对每种方法的预期是关键。如果您在进行随性编码,您预期会有惊喜。AI 可能会想出一种您自己不会编写的方法——也许它使用了不同的库或您不太熟悉的编程习语。部分吸引力在于从这些惊喜中学习,或快速越过您觉得乏味的事情。但您也需要预期会有小波折。随性编码爱好者应该睁大眼睛意识到他们将对那段棘手的最后阶段负责。魔力是真实的,但不是全面的。

如果您在实践 AI 辅助工程,您的预期会更加谨慎,对于长期项目来说可以说更加现实。您期望 AI 为您节省时间,也许启发一两个解决方案,但不会做您的全部工作。事实上,一个优秀的 AI 辅助工程师可能会在更大的框架内小剂量使用随性风格的提示。例如,在实现一个明确指定的模块时,他们可能会暂时切换到”随性模式”问:“嘿 AI,生成一个快速的实用函数来格式化这些日期”,然后立即切换回工程师模式来集成和检查该函数。这种思维方式是将 AI 视为在您指导下工作的协作者。您将任务分配给它擅长的地方(如样板代码、重复性代码、粗略实现),而您自己处理其余部分(关键逻辑、集成、最终审查)。

这里的期望包括提高生产力,减少机械性错误(例如,AI 不太可能拼错变量名),以及可能更广泛的解决方案搜索空间(AI 可能会建议你没有想到的算法)。但你也需要投入时间进行验证。调试 AI 辅助代码仍然是调试:你运行测试,必要时在调试器中逐步执行代码。不同之处在于,你可能会发现自己在调试 AI 为你编写的代码,这是一种新体验,伴随着学习曲线。第 5 章将详细讨论这一体验。

这两种方法的目标突出了它们之间的根本差异:氛围编程(vibe coding)优化的是短期速度,而 AI 辅助工程优化的是持续速度和可靠性。氛围编程者可能会说:“我需要在今晚之前让这个应用运行起来,看看这个想法是否可行。”AI 辅助工程师则会说:“我需要快速构建这个功能,但它应该足够健壮,能够在我们的代码库中存在多年。”前者只要代码基本能运行就满意;后者关心的是代码是否足够清晰,以便其他人在此基础上继续构建。

这些差异自然会吸引不同的受众。经验较少的开发者或工程学科之外的人可能倾向于氛围编程,因为它降低了入门门槛并提供了即时满足感。我遇到过产品经理和设计师通过氛围提示(vibe prompts)涉足编码,将 AI 几乎当作一个超强版的 Stack Overflow,为他们提供完整的解决方案。另一方面,经验丰富的开发者和工程团队往往更青睐 AI 辅助工程。他们曾因脆弱的代码吃过亏,所以他们从”让我们做对,即使我们使用新工具来加快速度”的立场出发。他们在前期投入更多努力(编写那个迷你 PRD,设置项目结构),以换取长期回报。

在光谱上找到你的位置

人们很容易问:哪种方法更好?事实上,氛围编程和 AI 辅助工程并不是互相排斥的类别:它们代表了光谱的两端,现实世界的工作流程通常会融合两者的元素。开发者可能以一阵氛围编程开始项目,以搭建一些新颖的东西,然后切换到工程模式来巩固它。或者他们可能通常遵循 AI 辅助规范,但偶尔——对于一个微不足道的一次性脚本或一个临时原型——会说:“你知道吗,我就用氛围编程来做这个,看看会得到什么。”关键是理解权衡,并在正确的情境中使用正确的方法。

把氛围编程想象成一辆高速探索车:它可以快速带你离开既定路径,非常适合探索发现。AI 辅助工程更像是轨道上的可靠列车:你必须先铺设轨道(计划),但这是一个更安全的选择,更有可能到达既定目的地而不脱轨。中级和高级开发者应该能够驾驭这两种工具,但他们会根据手头的任务进行选择。如果目标是快速创新或构思(比如在黑客马拉松中或验证想法的可行性时),氛围编程提供了动力。只需记住,如果你计划重用该代码,要加以完善。如果目标是在专业环境中构建可维护的产品功能,倾向于 AI 辅助工程可确保你不会在代码库中留下一个没人真正理解的黑盒代码块。

我观察到的一个有趣现象是,随着开发者使用 AI 工具的经验增加,他们的使用往往自然地从氛围端转向工程端。最初,让 AI 从单个提示生成整个代码块的新奇感很诱人——谁不想尝试本质上”谈话”出一个应用程序呢?

但在蜜月期之后,实用主义开始发挥作用。开发者开始看到 AI 的优势所在以及它的不足之处。他们学会分解问题,并将它们分块提供给 AI,而不是在一次性要求整个解决方案。实际上,他们从”提示艺术家”转变为 AI “管弦乐团指挥”——仍然利用 AI 的创造力,但用熟练的手引导它,并遵循清晰的乐谱。在我自己的实践中,我在提示方面变得更加deliberate(深思熟虑),经常编写小段伪代码或注释,并要求 AI 完成它们,而不是只是提出开放式问题。这样,我在自己控制的结构内获得了类似氛围的流畅性的好处。

值得注意的是,工具正在演进以支持整个谱系。一方面,我们有基于聊天的界面和自然语言编码环境,专门为氛围式编码设计,你甚至可能在询问之前都看不到代码。另一方面,IDE 正在添加 AI 功能,无缝融入传统编码:例如,建议改进的 AI 代码检查工具(linter)、解释代码的文档生成器,以及可以自动创建拉取请求并建议审查更改的版本控制机器人。这些工具通过融入常规开发工作流程(编辑、审查、测试等)来鼓励工程思维,同时仍然利用 AI。

随着最佳实践的出现,氛围式编码和 AI 辅助工程之间的区别甚至可能会随着时间的推移而模糊。我们可能会发现,今天感觉像”氛围式”的方式将获得更多护栏,而感觉像”结构化工程”的方式将变得更加流畅。事实上,我认为理想的未来是我们可以毫不费力地在这个谱系上下移动:当我们想要时与 AI 一起探索创造性解决方案,但在需要强化和交付软件时始终用扎实的工程实践加以约束。

这种方法谱系代表了我们今天使用 AI 工具方式的重大演变。然而,即使我们改进了与 AI 协作的技术——无论是通过快速的氛围式编码还是结构化的工程工作流程——一个更根本的转变正在形成。编程本身的本质正在发生变化。我们正在从传统的范式转变,在传统范式中,开发人员必须将他们的想法转化为明确的指令,而转向未来,我们可以直接表达我们的意图,让 AI 处理到代码的转换。

这种转变挑战了我们关于成为程序员意味着什么的最基本假设。几代人以来,我们的价值一直与我们像机器一样思考的能力相关——将问题分解为计算机可以执行的离散逻辑步骤。但是,当机器能够理解我们想要什么,而不仅仅是我们告诉它们做什么时,会发生什么?这就是意图编程进入画面的地方,它不仅代表了一个新工具或技术,而是对开发人员角色的根本重新构想。

超越代码行数:意图编程

几十年来,编程意味着编写指令:一行又一行的代码告诉计算机如何做某事。每个函数、循环和条件语句都必须由人类精心制作。意图编程翻转了这个脚本。开发人员不再关注底层实现,而是关注结果或目标:你希望程序完成什么。你以高层次的方式(通常用自然语言)表达这种意图,AI 系统会找出实现它的代码。

这样想:传统编码就像给某人一步一步的指示,而基于意图的编码就像告诉他们你的目的地,让他们找出最佳路线。通过关注什么而不是如何,开发人员可以在更高的抽象级别上工作。这种方法并不完全是新的——可视化编程、低代码平台和代码生成器等工具长期以来一直承诺提高抽象级别。但今天的 AI 进步终于使用简单语言描述复杂行为并获得可工作的代码变得切实可行。

提示词的崛起:从指令到描述

这种转变的核心是简单的提示词。提示词是你提供给 AI 编码系统的输入或问题。本质上,它是对你希望程序做什么的描述,而不是如何做的指令。这与编写代码的感觉可能非常不同。例如,与其编写一个循环来解析文件,你可能会提示:

读取这个 CSV 文件并提取所有年龄大于 18 岁的用户的电子邮件地址。

AI 将尝试生成完成该描述的代码。

为什么现在会发生这种情况?LLM 在理解和生成文本(包括编程语言)方面的快速进步一直是一个改变游戏规则的因素。这些 AI 模型已经在大量代码和自然语言文本上进行了训练。它们可以解释看起来像软件行为描述的提示词,并将其转换为实现该行为的实际代码。换句话说,它们已经学会了人类如何描述任务以及这些任务如何转化为代码的模式。

基于提示词的开发的兴起意味着,作为开发者,你越来越多地用自然语言或伪代码来描述功能和逻辑,让 AI 来处理编写语法正确代码的繁重工作。提示词成为你的新思维单元。它是意图的简洁表达。我们已经从告诉计算机”先做 X,然后做 Y,再做 Z”转变为说”我需要完成 X、Y 和 Z”,并相信 AI 会填补空白。

重要的是要注意,编写好的提示词本身就是一项技能(我们将在[第3章]中深入探讨)。模糊的提示词可能导致错误或低效的代码,就像模糊的需求会让人类程序员感到困惑一样。你越能清楚地表达你的意图,AI 的输出就越能满足你的需求。这就是为什么许多人称提示词编写为新的编程素养(programming literacy)。

工作原理:迭代循环和 AI 在代码生成中的角色

那么 AI 是如何从你的自由形式描述转化为实际的、可运行的代码的呢?魔力在于大语言模型(LLM)解释上下文和生成文本的能力。“大语言模型”中的”大”指的是它拥有的参数数量(内部配置),通常是数十亿或更多,这使它能够捕捉自然语言和编程语言的复杂性。这些模型已经在公共代码仓库、论坛、文档和问答网站上进行了训练,学习了编程语言的语法以及如何使用代码解决问题的语义。当你与 AI 编码器交互时,你正在利用这种广泛的学习知识。让我们用简单的术语分解一下:

理解提示词

当你提供提示词时(例如,“生成一个检查数字是否为质数的函数”),AI 模型会分析该提示词的文本。Google、OpenAI 和 Anthropic 的现代模型已经在无数语言和代码示例上进行了训练,因此它们使用统计模式来推断你在问什么。本质上,AI 试图预测最有可能用有意义的代码完成提示词。

利用上下文

这些 AI 系统通常会考虑除单行提示词之外的额外上下文。例如,如果你在带有 AI 助手的 IDE 中工作,模型可能还会考虑当前文件内容、你的编码风格、注释,甚至相关文件。所有这些上下文都有助于 AI 生成适合你项目的代码。这类似于人类开发者阅读周围的代码和文档来理解下一步该做什么。

生成代码

一旦模型理解了(或至少对你的意图做出了最佳猜测),它就会开始生成代码。在底层,它使用训练期间学到的概率一次生成一个标记(token)(标记是单词或代码符号的一部分)。该模型不会以传统意义上”思考”;它没有编译器或运行时来检查代码。它只是非常擅长以一种很有可能是正确代码的方式继续文本,因为它之前见过很多例子。如果提示词和上下文清晰,它生成的代码可能非常准确,甚至遵循它在训练数据中看到的最佳实践。

通过人工监督验证

重要的是,AI 不会自行运行并为你部署应用程序。你仍然在循环中。你审查生成的代码,测试它,可以接受或修改它。在许多情况下,如果被问到,AI 还可能提供代码的解释,帮助你理解结果。AI 的角色就像一个为你起草代码的助手——但你,开发者,仍然是决策者,确保代码正确并符合项目的需求。

真正令人印象深刻的是,这个过程在几秒钟或更短的时间内就能完成。高层概述是,你的描述(提示词)进入预测引擎(大语言模型),它产生可能的代码作为输出。虽然模型的内部工作涉及复杂的数学和神经网络层,但在用户层面,它感觉几乎像是在与一位能够立即回忆起如何实现几乎任何东西的专家合作。

关于氛围编码(vibe coding)(基于意图的编程)要理解的关键之一是,它是人类和 AI 之间的迭代协作过程。你不只是写一个完美的提示词,然后坐等 AI 完美无瑕地编写整个程序。在实践中,你进行来回交流,一个反馈循环,逐渐将模糊的想法转化为完善的代码。

以下是一个典型的循环:

步骤1:你描述你想要什么

这是你的初始提示词或请求。例如:

生成一个函数,根据本金、利率和期限计算月度贷款还款额。

步骤2:AI 提供初始解决方案

AI 为该函数生成代码,包括参数和贷款还款公式。它甚至可能包含解释公式的注释。

步骤3:你审查和测试

你查看代码。它合理吗?它处理边缘情况(edge case)了吗?你快速测试:如果利率为0会怎样?它能正确运行吗?你注意到它可能无法很好地处理这种情况。

## 步骤4:你优化你的请求或代码

如果代码不完美(通常第一次尝试都不会完美),就优化它。也许你再次提示AI(“修改函数以优雅地处理0%利率”),或者自己编辑代码并告诉AI,“解释这部分”,如果有什么不清楚的话。这种指导有助于纠正任何误解。

## 步骤5:AI优化解决方案

AI接受你的反馈或新提示并调整代码。现在函数检查零利率并适当地处理它。

## 步骤6:根据需要重复

你继续这个循环直到满意。也许接下来你要求AI为这个函数生成单元测试(unit test)以确保它正常工作。它这样做了,然后你运行它们来验证一切正常。

这种协作非常像结对编程(pair-programming)场景,其中一个伙伴是人类,另一个是AI助手。人类设定方向并了解高层需求,而AI提供建议,编写样板代码(boilerplate),并加快繁琐的部分。对于复杂任务,两者单独都不够有效:AI依赖人类提供方向和验证,而人类将一些工作卸载给AI以更快地推进。

至关重要的是,迭代不仅仅是修复错误;它也是关于演化解决方案。你可能从一个非常粗略的提示开始,然后随着你看到AI产生的内容,逐步优化你的意图。

这鼓励了一种实验心态。如果第一次尝试不对,你没有浪费太多时间——只需优化提示或调整代码并再次尝试。在传统编码中,编写一个模块却只能丢弃它可能令人沮丧,但使用AI生成的代码,错误开始的成本很低,这鼓励探索不同的方法。

生产力、可访问性和编程的变化本质

为什么带有意图的编程(programming with intent)如此重要?这种转变有几个深远的影响:

提高开发者生产力

: 也许最直接的好处是速度。当AI处理日常工作时,开发者可以更快地完成任务。手工编写可能需要数小时的常规代码(如设置数据库模型、API端点或数据清理脚本)通常可以在几分钟内生成。关于AI编码助手的早期研究支持这一点:使用GitHub Copilot等工具的开发者被证明可以显著更快地完成任务(一项研究发现,在Copilot协助下,给定任务的时间减少了55%)。当你将这些收益乘以整个项目时,它暗示了一个软件开发周期大幅缩短、团队可以更快迭代的未来。

保持开发者处于”心流状态”

: 除了原始速度之外,还有心理上的好处。编写样板代码或查找语法可能会打断程序员的心流和思路。有了AI处理许多这些中断,开发者可以专注于他们正在解决的问题。许多用户报告说,在AI的帮助下,他们对繁琐任务感到不那么沮丧,可以专注于编码的创意和设计方面。换句话说,它可以通过卸载无聊的部分使编码更有趣,这反过来可以提高工作质量(更快乐的编码者通常会产生更好的代码)。

降低入门门槛

: 传统上,编程需要学习严格的代码语法以及各种库和框架(framework)的怪癖。通过基于意图的编程,其中一些负担转移到AI身上。新手可能不记得打开文件的确切语法或绘图函数的参数,但如果他们能描述他们想要什么,AI可以填充这些细节。这并不意味着任何人都可以在零知识的情况下编写复杂系统(你仍然需要理解程序应该做什么),但这确实意味着产生有用结果的学习曲线更短。可以想象,领域专家(如生物学家或经济学家)可以通过描述他们的需求在他们的领域编写原型(prototype),即使他们不是专业开发者。从这个意义上说,编程对那些有想法和意图但没有深厚编码技能的人来说变得更容易获得。

改变开发者角色和技能

随着 AI 承担更多代码生成工作,人类开发者的角色正在演变

随着 AI 承担更多代码生成工作,人类开发者的角色正在演变。架构设计、问题分解和验证等技能变得更加重要。你可能会发现自己花更多时间决定要构建什么,以及审查代码为什么有效(或无效),而不是敲出语法。“懂得如何编码”的本质可能会转向”懂得如何让 AI 编码”。这可能会使软件开发的某些方面民主化,同时也会提升专业人士的操作层次。我们可能会看到围绕如何有效引导 AI 的新最佳实践(我将在[第3章]中介绍这个主题,并在整本书中重新审视)。

生产力与创造力

有趣的是,随着 AI 处理更多常规编码工作,人类开发者可以专注于更高层次的创造性任务,比如优化用户体验、头脑风暴新功能,或解决 AI 可能无法很好独立解决的棘手算法问题。在这种理想情况下,AI 提高了 80% 重复性编码工作的生产力,释放你的精力用于那 20% 的创造性工作。这是我们分配精力方式的转变。

然而,这并不全是好消息。这种新的开发方式也带来了挑战:

信任与正确性

你能信任 AI 编写的代码吗?如果你没有看到每一行代码,就有可能会忽略错误。开发者需要彻底测试和审查 AI 生成的代码。确保输出正确、安全和高效的责任在人类身上。盲目信任 AI 输出是有风险的,我们将讨论这一点。

失去一些底层技能

如果你依赖 AI 进行常规编码,你是否会逐渐失去从头编写代码或深入调试问题的能力?这种担忧类似于过度依赖计算器会削弱算术能力。开发者需要有意识地在便利性和保持对基础知识的扎实理解之间取得平衡。

工作格局的转变

随着意图编程(programming with intent)变得普遍,行业可能会重视不同的技能。对那些只擅长编写样板逻辑的人的需求可能会减少,而对那些能够设计系统、集成组件和验证正确性的人的需求会更多。软件工作的性质可能会转变,AI 处理更多实现工作,而人类专注于设计和监督。

此外,“vibe coding”中最关键的因素之一是上下文窗口(context window)大小。Gemini 提供了所有 AI 模型中最长的上下文窗口,这在处理大型项目时可能改变游戏规则。一些模型现在支持超过一百万个 token 的上下文窗口,使它们能够保持对整个应用程序的感知。开发者可以将整个代码库提供给 AI 以获得全面的理解。

我们将在本章末尾更深入地探讨这些权衡。但首先,让我们熟悉一下支持这种新编码方式的新兴工具。

工具一瞥:新兴生态系统

Vibe coding 可能是一种哲学,但它是由新一代 AI 驱动的工具实现的。想要采用这种工作流程的经验丰富的开发者需要熟悉一些使 AI 辅助编码有效的关键平台和模型。

本节快速介绍 vibe coder 工具包中的基本工具。这些工具包括 Visual Studio Code (VSCode) 及其不断增长的 AI 功能和扩展生态系统、像 Cursor 和 Windsurf 这样的下一代 AI 集成 IDE、像 Claude(各种版本)这样的 LLM,以及 ChatGPT。本节不涵盖后台编码代理(background coding agents),但我会在[第10章]中详细讨论它们。

当你阅读本节时,不要担心记住特定的工具名称或功能;格局正在快速发展。目标是了解可用解决方案的类型。

VSCode + Copilot:微软的集成 AI 开发平台

VSCode 已经从世界上最受欢迎的代码编辑器转变为一个全面的 AI 辅助开发平台,通过与 GitHub Copilot 的深度集成。这种演变代表了微软的愿景,即在数百万开发者每天已经使用的熟悉的 VSCode 环境中保持 AI 能力。

GitHub Copilot 是一个集成到 VSCode 中的 AI 驱动编码助手。它基于自然语言提示和现有代码上下文提供代码建议、解释和自动化实现。这种集成的独特之处在于其无缝性——Copilot 不仅仅是一个附加组件,而且感觉像是编辑器本身的自然延伸。

VSCode的AI能力核心围绕三种主要的交互模式。首先是内联代码自动补全,Copilot在您输入时提供内联代码建议,从单行补全到整个函数实现。当您编写代码时,会出现带有建议的幽灵文本,您可以用Tab键接受或逐字部分接受。

其次是聊天界面,通过侧边栏面板访问,您可以在其中就代码进行对话、提问或请求特定实现。第三个,也许是最强大的,是agent模式,它使用工具调用(tool calling)来访问Visual Studio内不断增长的能力集。当给定一个目标时,它会逐步选择并执行正确的工具。这个agent模式可以分析您的代码库,跨多个文件提出编辑,运行终端命令,响应构建错误,并在循环中自我纠正直到任务完成。

VSCode的Copilot实现特别引人注目的是它对模型上下文协议(Model Context Protocol, MCP)的支持。MCP为AI模型提供了一种标准化的方式来发现和与外部工具、应用程序和数据源交互。这意味着VSCode中的Copilot可以连接到数据库、调用API、访问文档,并与您的整个开发生态系统集成。例如,启用GitHub MCP服务器后,您可以要求Copilot”为我们讨论的每个bug创建一个issue”,它将直接与GitHub的API交互来创建这些issue。通过MCP的可扩展性(extensibility)将Copilot从代码生成器转变为一个全面的开发助手,它不仅理解您的代码,还理解您的整个工作流。

要在专业开发中有效利用VSCode和Copilot,首先根据任务复杂性探索不同的交互模式。对于简单的代码补全和重构,依赖内联建议和出现在错误附近的闪光图标—点击它获取AI驱动的修复。

对于更复杂的任务,通过打开聊天面板并从下拉菜单中选择”Agent”来切换到agent模式。Agent模式针对在项目中跨多个文件进行自主编辑进行了优化。它特别适用于不仅需要代码编辑还需要调用工具和终端命令的复杂任务。VSCode熟悉的界面与Copilot不断发展的AI能力的结合,为希望在不离开其既有开发环境的情况下获得企业级AI辅助的团队提供了一个引人注目的选择。

VSCode + Cline: 开源自主编码Agent

在探索专用AI IDE之前,值得研究Cline(以前称为Claude Dev)如何将VSCode转变为强大的AI辅助开发环境。Cline代表了与Microsoft的Copilot不同的理念。它不是一个紧密集成的助手,而是作为一个自主编码agent运行,可以从头到尾承担复杂的多步骤开发任务。这个开源扩展为VSCode带来的能力通常超过专有AI编辑器中的能力,同时保持了VSCode用户期望的灵活性和可扩展性。

Cline的独特之处在于其真正的代理式(agentic)软件开发方法。当您给Cline一个高级请求,如”创建一个带身份验证的用户管理REST API”时,它不会简单地生成样板代码。相反,它会分析您的项目结构,规划跨多个文件的实现,创建适当的文件夹层次结构,安装必要的依赖项,甚至可以运行测试来验证实现。在整个过程中,Cline通过向您展示每个计划的操作—文件创建、修改和终端命令—并让您有机会批准或修改每个步骤来保持透明度。这种人在回路中(human-in-the-loop)的设计在自动化和控制之间提供了完美的平衡,允许开发人员利用AI的能力,同时保持对代码库的监督。

Cline的技术能力远远超出了代码生成。它可以使用浏览器自动化来研究API文档,通过分析跨多个文件的错误跟踪来调试复杂问题,甚至可以通过其MCP支持与外部服务交互。对于调试,您可以粘贴错误消息,Cline将跟踪您的代码库以识别根本原因,提出修复方案,实现它,并添加适当的错误处理以防止类似问题。它的MCP集成意味着Cline可以连接到您的数据库以在生成查询之前理解模式(schema),访问您的项目管理工具以使实现与需求保持一致,或与任何其他兼容MCP的服务交互。这种可扩展性将Cline从代码生成器转变为一个全面的开发伙伴,它理解您的整个技术生态系统。

对于团队而言,Cline 提供了几个引人注目的优势。作为开源项目,团队可以检查其代码、贡献改进或为定制需求进行分支——这对于有特定安全性或合规性要求的组织至关重要。它支持多个 AI 提供商,包括 Anthropic 的 Claude、OpenAI 的模型、Google 的 Gemini,甚至可以通过 Ollama 支持本地模型,让团队能够根据性能、成本或数据驻留要求灵活选择模型。

要有效使用 Cline,需要编写包含项目上下文和约束条件的详细提示词(prompt),利用其在进行更改前分析整个代码库的能力,并充分利用其迭代开发能力。在 Cline 实现某个功能后,你可以立即测试并在同一对话上下文中请求改进。VSCode 成熟的生态系统与 Cline 的自主能力相结合,为团队提供了一条强大、灵活且成本效益高的 AI 辅助开发路径,而无需放弃现有的工具和工作流程。

Cursor:AI 驱动的代码编辑器

氛围编程(vibe-coding)运动的旗舰工具之一是 Cursor,这是一个 AI 增强的 IDE,在寻求更流畅编程体验的开发者中迅速流行起来。Cursor 本质上是一个 AI 优先的代码编辑器(实际上是 VSCode 的一个分支),它将最先进的代码生成和理解功能直接内置到你的开发环境中。

它的标语是”AI 代码编辑器”,旨在让你使用纯语言指令来编写和修改代码。例如,你可以高亮显示一个函数并要求 Cursor”优化这个函数”或”在这里添加错误处理”,它会立即建议代码更改。Cursor 的 AI 具有项目感知能力——它会索引你的代码库并理解文件的上下文,因此可以提供更相关的建议(远超简单的自动完成)。Cursor IDE 将 LLM 能力集成到其核心界面中。它就像是了解你代码库的 ChatGPT。

在底层,Cursor 利用先进的语言模型(通常是 Anthropic 的 Claude 或 OpenAI 的模型,取决于你的设置)来支持其功能。它有一个聊天侧边栏,你可以在其中与代码进行对话,甚至还有一个用于多步骤代码生成的”Composer”模式。Andrej Karpathy 本人在他的氛围编程实验中使用了 Cursor 的 Composer 配合一个名为”Sonnet”的模型。这种设置允许他真正地编辑器对话(通过”SuperWhisper”使用语音转文本),然后代码就会出现,他随后可以接受或改进。

Cursor 不仅可以生成代码,还可以在收到指令时编辑现有代码。例如,你可以询问:

你能让传输监听器中切换证书变得更容易吗?

Cursor 会理解你指的是你的代码,并在相关文件中提出直接编辑建议,或从相关文件(如规范 markdown 文件)中读取(见图 1-3)。在免费版本中,它通常会在聊天中提供差异(diff)供你批准;在专业版中,它可以自动将更改应用到你的工作区。

图 1-3. Cursor 的界面体现了集成 AI 的新一代 IDE。通过索引你的项目并迭代提示词,像 Cursor 这样的工具能够实现”让编辑器保持运行,去喝杯咖啡,回来时功能已完全实现”,带来指数级的生产力提升。

在专业工作流中高效使用 Cursor

要在专业工作流中高效使用 Cursor,你应该系统地利用其功能。首先在 Cursor 中打开聊天窗口,描述你想要的功能或修复。例如:添加一个用户登录表单,包含电子邮件和密码,以及验证和错误信息。Cursor 会生成所需的代码(创建新文件或修改现有文件),并以草稿状态呈现。你可以审查这些更改(它会显示差异或预览),然后点击”应用”将它们合并到你的代码库中。许多开发者遵循这个循环:提示 → 审查 → 接受。如果建议不够完美,你可以优化提示(例如,“使用 Tailwind CSS 来设置表单样式”)或直接要求 Cursor 修复你发现的任何问题(“现在处理电子邮件已被注册的情况”)。本质上,你与代码进行对话,直到它看起来满意为止。

Cursor 在理解错误和日志方面也表现出色。如果你运行代码并遇到错误追踪或错误信息,你可以将其粘贴到 Cursor 聊天中,AI 通常会分析它并建议修复方案。这将调试转变为一种协作体验:你不再需要手动搜索 Google 或 Stack Overflow,Cursor 的 AI 通常能够精准定位问题,甚至编写补丁。也就是说,明智的做法是验证修复方案,因为 AI 可能不会总是第一次就做对。

另一个专业提示:利用 Cursor 考虑多个文件的能力。你可以选择一组文件(或在提示中告知项目上下文),这样它在生成代码时会考虑整个代码库。例如:在后端添加一个新的 API 端点以支持登录表单,并将其连接到我们刚刚创建的前端表单。Cursor 会回忆起刚刚编写的前端代码,并帮助制作相应的后端逻辑。这种项目级的上下文理解能力,相比早期只能逐个文件工作的编码助手来说,是一个游戏规则改变者(game changer)。

总之,Cursor 就像在你的 IDE 内部拥有一个全天候的 AI 结对编程员。它直观(你用简单的语言与它对话),可以直接更新你的代码。你越是练习分解任务并用清晰的指令提示 Cursor,就会发现在短时间内能完成更多工作。它特别适合迭代开发:你构建一点,运行并查看输出,然后立即要求 Cursor 调整或扩展代码,然后重复这个过程。

Windsurf:具有完整代码库索引的 AI 驱动 IDE

在 vibe-coding 工具箱中另一个冉冉升起的新星是 Windsurf,这是一个 AI 驱动的开发环境,将代码理解提升到了新的水平。Windsurf 由 Codeium 团队构建,它通过索引整个代码库并使用检索技术在你工作时将相关部分提供给 AI 模型来实现差异化。实际上,这意味着 Windsurf 在处理大型项目时表现极佳,即使问题的答案可能分散在多个文件中。其核心使用了所谓的检索增强生成(RAG, retrieval-augmented generation),这是一种巧妙的方式,即它查找与你的提示相关的代码部分,并将该上下文提供给 AI,使其建议与你现有的代码保持一致。

对开发者来说这意味着什么?假设你刚接触一个大型代码库并需要添加功能。使用 Windsurf,你可以用自然语言询问:

代码库中用户身份验证逻辑在哪里处理?

它会搜索索引并指向正确的文件甚至函数。然后,你可以打开聊天(Windsurf 称之为”Cascade”视图,通过 Cmd+L 触发)并说:

在登录流程中添加基于手机的双因素身份验证。

因为 Windsurf 拥有你的身份验证逻辑的上下文,它可以生成跨多个文件(数据库、API、前端)的更改来实现这个功能,做出与你的系统结构一致的明智选择。

Windsurf 的写入模式(Write mode)可以大胆地为你应用更改:它会自动创建新文件或编辑现有文件,而不仅仅是在侧边栏中建议差异。这可以极大地节省时间:你不必从建议中复制粘贴,而是看到项目在原地演变。Windsurf 本质上试图在有信心时代表你采取行动,表现得像一个自主的初级开发人员在代码库中实现功能。(Cursor 的理念更加保守,会要求确认,尽管其 Pro 版本也有”自动应用”功能。)

要有效利用 Windsurf,理解其优势会很有帮助:

代码库问答

代码库查询

您可以用简单的英语查询您的代码库,几乎就像一个为您的项目定制的 Stack Overflow。这对于大型遗留项目非常有用,在这些项目中查找某个定义可能需要数小时。Windsurf 将通过从索引代码中提取信息,在几秒钟内给出答案。

全局上下文建议

因为它会将相关文件提供给模型,Windsurf 可以很好地处理诸如”将支付模块重构为使用我们编写的新日志工具”之类的任务,因为它同时了解支付模块和日志工具。

操作模式

Windsurf 有多种模式(如前所述的自动完成、聊天、命令和级联)。级联模式类似于超级聊天,它可以考虑更广泛的上下文。写入模式(在聊天中)实际执行更改。作为工程师,您可以决定给予它多少自主权。

对于团队而言,Windsurf 可以像 Cursor 一样集成到日常开发中。在两者之间选择时,一些开发人员更喜欢 Windsurf,因为它的速度和大胆性(注意到它生成和应用更改的速度感觉更快),以及由于其索引功能而适合处理非常大的项目。另一方面,Cursor 的界面对 VSCode 用户来说可能感觉更熟悉。这不一定是非此即彼的选择——一些工程师会同时使用两者,或者团队可能会标准化使用其中一个。

总之,如果您想要一个在编写代码之前真正”阅读文档/代码”的 AI 编程助手,Windsurf 是一个出色的工具。它最大限度地减少了函数幻觉或变量名错误的机会,因为它可以查找信息。要充分利用它,请向它提供清晰的指令,并在写入模式下让它处理大任务,但对于细微的更改,也可以以更受控的方式使用它。始终检查它所做的更改(它会向您显示),特别是对于关键代码。Windsurf 很智能,但并非万无一失。明智地使用,它就像一个了解您整个项目的超智能 IDE,可以跨项目实现想法,大幅提升您的产出。

AI 模型:代码生成的格局

AI 编码格局已经发生了巨大变化,现在有多个强大的模型在竞争开发人员的注意力,包括来自 Claude、Gemini 和 OpenAI 系列的模型。 曾经可能只有一个模型占据主导地位,而如今的生态系统提供了丰富的选择,每个选择都有独特的优势,使它们适合不同的编码场景。

理解模型类别

当今的编码模型通常分为几个类别,基于它们的方法和优势:

速度优化型

这些模型优先考虑快速响应,非常适合实时代码补全和快速迭代。它们通常提供较低的延迟,代价是在复杂任务上的准确性略有降低。

深度推理型

这些模型花更多时间”思考”问题,但在复杂调试、架构决策和多步骤问题解决方面表现出色。具有高级推理能力的模型可以逐步分解复杂的错误。

多模态强力型

一些模型不仅可以处理代码和文本,还可以处理图像、图表,甚至视频内容。这使它们在理解可视化文档或处理 UI/UX 元素时特别有价值。

开源替代品

DeepSeek 的突出之处在于提供了与闭源模型相当的 AI 能力水平,无需付费或注册,尽管它可能缺少一些功能,如图像生成或网页浏览能力。

为您的任务选择合适的模型

成功的开发人员现在不再寻求单一的”最佳”模型,而是将模型与特定任务相匹配:

许多工具现在支持多种AI模型,包括OpenAI、Claude和Gemini变体,以及专有模型,允许开发者根据手头的任务在它们之间切换。

适用于任何模型的实用技巧

无论您选择哪种AI模型,某些实践始终能改善结果。首先,提供丰富的上下文。不要只是要求”一个支付处理函数”。相反,分享您的数据模型、现有代码模式、错误处理方法以及任何具体要求。您提供的上下文越多,输出就越能与您的代码库保持一致。

大多数现代编码模型都擅长审查自己的输出。在收到生成的代码后,要求模型检查潜在问题、提出改进建议或解释其推理过程。这种自我批评通常能发现细微的错误或建议优化方案。

利用模型维护对话上下文的能力。从基本实现开始,然后通过后续请求逐步完善它。这种迭代方法通常比试图预先指定所有内容产生更好的结果。

每个模型在处理问题的方式上都有细微差别。有些在解释时更冗长,而另一些则更简洁。有些默认使用较新的语法,而另一些则更保守。了解这些倾向有助于您制定更好的提示。

主要模型

AI编码领域每月都在演变,新模型定期挑战既有领导者。竞争变得如此激烈,以至于开发者从前所未有的选择和能力改进中受益。最重要的不是选择”完美”的模型,而是理解如何利用可用工具的优势。

许多开发团队现在采用组合方法——利用快速模型处理日常任务,利用强大模型应对复杂挑战,并利用专门模型处理特定领域,如数据库优化或前端开发。一些IDE甚至允许在任务中途无缝切换模型。

成功来自于理解这些选项并策略性地应用它们来加速您的开发工作流程。

Google Gemini:多模态编码强者

Google的Gemini系列通过其原生多模态能力代表了AI辅助开发的根本性转变。与主要在文本和代码上训练的模型不同,Gemini从底层架构上就被设计为能够无缝理解和处理文本、代码、图像、视频和其他数据格式。这使其在视觉上下文与文本信息同等重要的现代开发工作流程中异常强大。

Gemini的多模态特性在Web开发场景中特别有价值。开发者可以分享设计原型的截图,Gemini能够生成与视觉风格完美匹配的像素级实现。它擅长理解图表、图示和UI元素,使其成为将视觉设计转化为功能代码时的理想合作伙伴。这种能力不仅限于简单的图像识别:Gemini可以对视觉元素进行推理,理解设计模式(design patterns),并在整个项目中保持美学一致性。

Gemini 通过流行的编辑器(VSCode、Cursor、Windsurf)以及 Cline 和 Code Assist 等插件与开发工作流程集成,为开发者提供了强大的自定义选项,可以从个人偏好扩展到团队标准。开发者可以为重复性任务创建自定义命令,建立适用于每次代码生成的规则,并在大型代码库中维护一致的编码模式。其慷慨的免费套餐使学生、爱好者和初创公司都能使用,而企业功能则支持复杂的组织需求。

Gemini 在编码领域的独特之处在于其能够深入思考问题的同时保持实用的速度。该模型可以在简单任务的快速响应和复杂挑战的深入推理之间切换,根据手头的问题调整其方法。这种灵活性与其视觉理解能力相结合,使其在全栈开发中特别有效,因为后端逻辑和前端美学同等重要。

Claude:推理大师

Anthropic Claude 的编码辅助方法以透明度和深度推理能力为中心。Claude 系列,特别是 Sonnet 模型,已确立自己在需要仔细分析和逐步解决问题的复杂软件工程任务方面的卓越能力。Claude 的独特之处在于其能够展示思考过程,让开发者能够跟随其推理并在实施解决方案之前验证其逻辑。

Artifacts 功能代表了开发者与 AI 编码助手交互方式的范式转变(paradigm shift)。Claude 不是简单地在聊天界面中提供代码,而是创建一个专用工作空间,可以实时查看、编辑和预览代码。这种交互式环境对于前端开发、数据可视化以及即时视觉反馈可以加速开发过程的任何场景都特别强大。开发者可以在同一对话中迭代设计、测试功能并改进实现。

Claude 在实际软件工程基准测试中表现出色,在错误修复、功能实现和代码重构等任务方面始终位居顶级模型之列。其优势不仅在于生成代码,还在于理解软件项目的更广泛上下文。Claude 可以分析现有代码库、识别模式和反模式(antipattern)、建议架构改进,并保持与既定编码风格的一致性。这使其对于绿地项目(greenfield project)和遗留系统维护都非常有价值。

该模型的内存和上下文管理方法使其能够在扩展的编码会话中建立理解。在处理大型项目时,Claude 可以提取并保留有关代码库结构、设计决策和项目特定模式的关键信息。这种累积的知识使其能够随着开发进展提供越来越相关和符合上下文的建议,让人感觉更像是一个随着时间推移熟悉项目的团队成员,而不是一个无状态的助手。

ChatGPT:多功能编码伙伴

ChatGPT 已确立自己作为 AI 编码助手中的瑞士军刀地位,其价值不在于专业化功能,而在于其卓越的多功能性和广泛的知识库。它在开发者工具包中的地位是独特的。虽然其他模型可能直接集成到 IDE 中或提供专门的编码环境,但 ChatGPT 作为一个始终可用的编程顾问,开发者在整个工作日都会在浏览器中保持其打开状态。

ChatGPT 的对话界面使其在探索性问题解决和学习方面表现出色。开发者经常使用它进行橡皮鸭调试法(rubber-duck debugging),粘贴有问题的代码并通过自然对话思考问题。其广泛的训练使其能够识别几乎所有常用编程语言、框架和工具的模式。无论是调试正则表达式、理解晦涩的错误消息,还是探索不熟悉的库文档,ChatGPT 都能从其全面的知识库中提供相关见解。

ChatGPT 的优势在于其能够弥合人类意图与代码实现之间的鸿沟。它擅长双向翻译(bidirectional translation)——将自然语言描述转换为可运行的代码,并用简单的英语解释复杂的代码。这使得它在团队内的文档编写、代码审查和知识传递方面非常有价值。开发者可以粘贴不熟悉的代码并获得其功能的清晰解释,或者描述期望的行为并获得跨多种编程范式的适当实现。

该模型的多功能性超越了传统编程语言,延伸到配置文件、脚本、数据格式和领域特定语言(domain-specific languages)。虽然专业编码工具在其专注领域表现出色,但 ChatGPT 在整个软件开发任务范围内提供有价值的帮助。这种广度使其在跨不同技术的边界工作或遇到跨多个领域的问题时特别有用。它在扩展对话中保持上下文的能力允许开发者迭代地探索复杂问题,通过协作对话完善解决方案。

根据需求选择合适的模型

这些强大的 AI 编码助手的可用性代表了软件开发实践的根本性转变。成功的开发者不会将它们视为竞争选项,而是认识到每个模型家族在开发过程的不同方面都带来了独特的优势。当视觉上下文和多模态理解(multimodal understanding)至关重要时,Google 的 Gemini 表现出色,特别是在 UI/UX 开发和处理设计规范时。在需要深度推理、复杂重构和透明问题解决方法的场景中,Anthropic 的 Claude 表现突出。OpenAI 系列模型提供无与伦比的多功能性和广泛知识,使其成为学习、调试和跨领域挑战的理想选择。

现在许多开发团队采用组合策略(portfolio approach),在同一项目中针对不同任务利用不同模型。典型的工作流程可能包括使用 Gemini 将设计原型转换为初始实现,使用 Claude 进行复杂的架构决策和代码审查,使用 ChatGPT 进行一般问题解决和文档编写。这种多模型方法通过将每个工具的优势与特定开发挑战相匹配来最大化生产力。

随着这些模型的持续发展,有效进行 AI 辅助开发的关键不在于选择单一的”最佳”选项,而在于理解如何协调多个 AI 助手来加速和增强软件开发生命周期的每个方面。

这个生态系统还很年轻且快速变化。每隔几个月就会出现新的参与者和能力。关键要点是,你不必从头构建自己的 AI 来利用意图编程(programming with intent)——有许多工具将这种能力带到你的指尖。在本书中,我将讨论各种平台以及它们如何融入氛围编码(vibe coding)工作流程。

氛围编码的优势与局限:细致的观点

重要的是要认识到 AI 辅助开发真正发光的场景——以及它可能仍然不足的地方。让我们探讨一些氛围编码表现出色的理想用例,以及当今 AI 仍然存在困难或需要大量人工干预的情况。

氛围编码的理想用例

正如某些架构适合某些问题一样,氛围编码在软件开发领域也有其”最佳场景”。

从零到一的产品开发

Vibe编程对于从零开始启动一个全新项目来说是一个游戏规则改变者。“零到一”一词(由Peter Thiel推广)指的是从零开始创造全新的东西。借助AI,你可以以闪电般的速度从一张白纸变成一个功能原型。需要建立一个从未存在过的Web应用程序?你可以在一次疯狂的提示会话中生成前端、后端、数据库架构甚至部署脚本的样板代码。这对于目标是快速验证想法的初创公司或黑客马拉松项目来说非常完美。你可以让AI在几分钟内完成这些工作,而不是花费数周时间来设置项目的”脚手架”(所有重复的设置代码)。

许多开发者讲述了他们如何在AI配对程序员的帮助下在一个周末构建了一个MVP(最小可行产品)——这在以前独自工作可能需要一个月的时间。通过快速将想法具体化为工作产品,你可以更快地开始与用户或利益相关者进行测试。AI擅长处理通用的东西(设置路由、基本UI组件、标准CRUD操作),这让你可以专注于产品的新颖方面。

然而,一旦你的MVP获得关注并走向生产环境,你的方法就必须改变。这就是AI辅助工程变得至关重要的地方。虽然vibe编程帮助你快速探索和验证,但现在扩展需要更加深思熟虑的实践。你需要用适当的错误处理重构快速生成的代码,添加全面的测试覆盖率,并建立清晰的架构边界。从原型到产品的过渡标志着从vibe编程的探索性自由到工程的结构化规范的自然演变。聪明的团队会认识到这个拐点并相应地调整他们的AI使用方式——在保持速度的同时引入可持续增长所必需的护栏。

功能原型和CRUD应用

许多软件工程,特别是在业务应用程序中,涉及围绕数据的CRUD——创建、读取、更新、删除——功能。这是AI特别擅长的公式化工作,因为它见过无数的例子。如果你需要向系统添加一个新的”库存”模块,包含CRUD界面和API,vibe编程将处理得非常好。它可以生成数据库迁移、ORM模型、API端点和带验证的UI表单——基本上是全栈——基本上没有错误,因为这些模式在其训练数据中非常常见。即使你的应用程序有自定义规则,你也可以在提示中指定这些规则并获得不错的初稿。结果是:曾经需要一周时间的枯燥连接工作变成了一个下午的提示和测试。对于内部工具或管理面板(本质上是大型CRUD应用程序),考虑到它们通常如此简单却又耗时,你几乎可以完全依赖AI来生成它们。

当这些CRUD操作涉及复杂的业务逻辑、数据验证规则或与现有系统的集成时,工程方法变得至关重要。虽然vibe编程可以快速生成基本结构,但AI辅助工程确保你的库存模块能够正确处理边缘情况,如并发更新,维护引用完整性,并遵循组织既定的模式。例如,你可以使用vibe编程生成初始CRUD脚手架,然后切换到工程模式来实现特定领域的规则,如库存阈值警报、多仓库分配逻辑或与现有身份验证和授权系统的集成。关键是识别何时从快速生成过渡到仔细完善。

粘合代码和集成

需要将两个服务或API集成在一起?这通常涉及阅读文档并编写代码以将数据从一种格式转换为另一种格式。AI模型通常在API文档和代码示例上进行过训练,这意味着它们可以加速集成工作。要求ChatGPT展示如何从语言B调用服务A的API——很可能它会生成带有正确端点甚至可能包含身份验证示例的示例代码。当AI可以建议样板和要处理的边缘情况时,组合多个系统(如将支付网关与订单系统连接或连接第三方分析SDK)变得更容易。它擅长这些标准集成模式。

现代框架利用

AI编程助手已经有效地阅读了所有流行框架(frameworks)的手册:React、Angular、Django、Rails、Node/Express、Flutter等等。这意味着如果你使用知名框架,AI可以为这些框架生成符合惯用法的代码。例如,它可以生成一个带有hooks和状态管理的新React组件,或者一个带有适当admin类和serializer的新Django模型。好处是你不必记住每个细节,AI会填补这些空白。Vibe编程在现代Web开发任务中表现尤其出色,比如生成带有正确类的HTML/JSX或连接控制器端点,因为这些是AI模型反复见过的任务。这就像有一个框架专家总是在你身边编写样板代码,而你只需决定功能的具体实现。

重复性代码生成

有时你需要创建大量相似的代码(比如为某个模式(schema)中的每种类型创建许多相似的端点或类)。这对人类来说可能既繁琐又容易出错。另一方面,AI喜欢重复性结构——一旦你展示一两个示例,它就能一致地生成其余部分。这种批量代码生成可以节省大量时间。例如,如果你要为50种类型的记录编写数据模型类,你可以提供一个示例并要求AI按照该模式为所有50种类型生成类。它很可能会在几秒钟内完美完成。结果是:你避免了一整天的单调编码工作。

AI辅助工程应该优先的情况

虽然vibe编程在某些场景中表现出色,但AI辅助工程(AI-assisted engineering)在其他情况下变得不可或缺。理解这些情况有助于开发者从一开始就选择正确的方法,避免代价高昂的重写或技术债务(technical debt)。复杂的算法实现需要工程方法。当你构建复杂的数据结构、实现性能关键的算法或解决新颖的计算问题时,你需要对实现的每个方面进行精确控制。

在这里,AI充当知识丰富的助手而非代码生成器。你可能会要求它解释算法方法或审查你的实现的正确性,但你保持对架构和优化决策的直接控制。AI帮助你思考问题,而不是完全解决它们。

关键任务系统(mission-critical systems)从一开始就需要工程严谨性。金融交易、医疗应用、安全基础设施和其他高风险领域承受不起vibe编程的探索性特质。在这些环境中,每一行代码都需要仔细考虑、全面测试,并且通常需要符合监管要求。AI通过建议最佳实践、识别潜在漏洞和帮助确保符合标准来提供协助,但开发者保持对实现的严格控制。

这些系统中失败的成本远远超过快速生成带来的任何速度优势。遗留系统集成(legacy system integration)带来了独特的挑战,在这些挑战中工程纪律被证明是必不可少的。当处理几十年前的代码库、专有协议或具有大量技术债务的系统时,vibe编程的模式匹配往往会失败。这些场景需要深入理解现有约束、仔细规划集成点以及有条不紊的重构。AI可以通过解释遗留代码模式或建议现代化策略来提供帮助,但实际实现需要只有结构化工程才能提供的精确性。

性能优化(performance optimization)代表了工程胜过vibing的另一个领域。虽然AI可以快速生成功能性代码,但它很少为性能关键路径产生最优解决方案。内存管理、缓存优化、并行处理和延迟降低等任务需要对硬件、操作系统和算法复杂度有深入理解。在这里,AI最好充当研究助手,帮助你探索优化技术或对不同方法进行基准测试,而你做出关于实现的明智决策。

在这些场景中,AI的模式识别和速度与任务完美契合。本质上,vibe编程在编程中的常见任务(如CRUD或典型的Web应用结构)和受益于快速试错的任务(原型、新想法)上表现出色。这就像有一个初级开发者,他读过每个GitHub仓库,可以立即回忆起通常是如何完成的,并为你编写供审查的代码。这对于快速推进事情来说非常强大。

识别转换点

现代 AI 增强开发的艺术不在于选择其中一种方法,而在于识别何时在它们之间转换。成功的开发者会培养出对这些拐点的直觉。开始一个新功能?从氛围编码(vibe coding)开始快速探索可能性。注意到代码变得复杂或涉及关键系统?切换到工程模式。为客户演示构建概念验证?氛围编码能让你快速完成。将概念验证转换为生产系统?是时候采用工程规范了。

这种流动性——在快速探索和仔细构建之间无缝切换的能力——区分了真正高效的 AI 增强开发者。他们明白氛围编码和 AI 辅助工程是工具箱中的互补工具,各自适用于开发生命周期的不同阶段。目标不是选边站,而是策略性地利用这两种方法,在整个软件开发过程中最大化速度和质量。

AI 仍然困难的领域

尽管当前的 AI 编码工具令人印象深刻,但它们并非魔法。有些类别的问题对于 AI 来说仍然难以可靠地处理,通常需要人类洞察力或传统编码技术。了解这些局限性有助于设定正确的期望,并让你规划何时依赖 AI,何时重新掌控。

这些局限性包括以下几点:

深度复杂系统

如果你正在处理非常复杂的算法或 AI 可能没有见过的新颖问题,它可能会陷入困境。例如,从研究论文编写全新算法,或者做一些像编写编译器或高度并发系统的事情——这些涉及需要真正理解和通常需要创造性飞跃的复杂逻辑。AI 可以尝试,但它可能会在细节上出错。

在这些复杂领域中,AI 倾向于生成大致正确但不完全正确的代码,这可能导致大量的来回修改。正如第 3 章和第 4 章将讨论的,最后 30% 左右的正确性对 AI 来说很难钉住。这与我所说的 70% 问题有关——AI 能快速让你完成大部分工作,但最后部分很困难。有经验的开发者可能会使用 AI 为这些复杂任务生成骨架或辅助函数,但核心逻辑自己完成。

底层优化和系统编程

当前的 AI 模型主要在高级语言和抽象上训练。如果你需要进行底层位操作,为特定微控制器编写高度优化的 C 代码,或生成矢量化 SIMD 指令,AI 可能不可靠。它可能会生成看起来合理但在硬件层面上并不真正优化甚至不正确的代码。

同样,对于内存管理或实时约束之类的事情,AI 没有真正的概念(它不会在脑海中模拟 CPU 缓存)。因此,对于性能关键的代码,你需要彻底测试 AI 的建议或手动编写这些部分。话虽如此,AI 仍然可能通过提供起始模板或解释汇编来提供帮助,但在这些场景中你不能盲目信任它。

独特或小众框架

如果你使用的是在 AI 训练期间不存在的非常新或晦涩的框架,它就不会知道。在这种情况下,AI 可能会尝试泛化,或者可能生成看起来合适但实际上调用不存在的函数(幻觉)或使用过时版本 API 的代码。例如,如果一个新的 Web 框架版本上个月发布并带有破坏性更改,AI 就不会知道这些更改。它可能会给你旧版本的代码。在这些情况下,你必须依靠文档,甚至可能通过在提示中提供文档中的上下文来帮助训练 AI(基本上是即时教学)。

创意 UI/UX 设计

如果你要求 AI 设计一个完全新颖的用户界面或体验,它在这种创造性飞跃上并不擅长。它可以为已知模式生成 UI 代码(如标准表单或仪表板),但如果你想要一个没有明确先例的创新 UI,AI 可能不会给你带来灵感的东西。它可能只是将熟悉的组件拼接在一起。人类设计师和前端开发者仍然非常需要去构想新的用户体验。从编码角度来说,AI 可以快速为你制作一个标准外观的界面,但对于那种特殊的定制感觉,你需要引导它或手动调整。

解释意图和需求

有时当需求是隐含的或矛盾的时候,AI 会遇到困难。除了你明确告诉它的内容之外,它对最终目标没有真正的理解。如果需求含糊不清(“让它高效”——这到底意味着什么?),AI 可能会错误地猜测你关心的是什么(例如内存与速度)。人类更擅长澄清意图,特别是与非技术利益相关者沟通时。AI 也可能误解指令,特别是如果存在它不知道的特定领域上下文(如业务规则)。它可能生成一个逻辑上正确的解决方案,但实际上并不能解决真正的问题,因为细微差别在翻译中丢失了。

一个结合这些的好例子场景:想象一下在 Rust(系统级、性能关键)中开发一个新的 3D 图形引擎(复杂系统)。你有用于渲染的新颖算法(独特问题)。AI 可能能帮助编写一些样板代码,但核心部分你主要依赖人类的创造力。AI 可能会帮你开始设置窗口和基本的渲染循环(常见任务),但对于定制部分,你需要采用传统的仔细编码方式,也许可以从 AI 那里以伪代码的形式获得一些算法帮助。如果你让它优化汇编语言中的热循环,你必须验证每一条指令。

AI 也缺乏真正的问题解决洞察力。归根结底,它是模式匹配。所以如果你的问题需要一个恍然大悟的洞察,AI 可能只会四处摸索,呈现看起来像代码但并不能解决问题的东西。这时人类退一步、抽象思考或借鉴真实经验就能挽救局面。一旦你有了洞察,你就可以使用 AI 快速实现它。

理解这些优势和劣势可以确保你在正确的情况下部署氛围编码(vibe-coding)技术。为了最大化成功,利用 AI 擅长的方面(已知模式),并将你的创造力应用于应用程序的独特部分。准备好在 AI 已知会遇到困难的领域进行干预。例如,仔细审查它编写的任何安全敏感代码,因为它可能会遗漏一两个边缘情况。

使用 AI 来补充人类优势:让它处理广度(大量代码、样板代码),而你处理深度(复杂逻辑、架构)。在它擅长的地方将其作为助推器使用,不要害怕在那些更艰难的路段接管方向盘。这既发挥了双方的优势,又产生了最佳结果。知道何时使用 AI 以及何时依靠人类技能,将使你在这个新时代成为一名高效的开发人员。

每一项新技术都有其优势和注意事项。当我们拥抱 AI 辅助开发带来的生产力和创造力提升时,重要的是以细微差别的理解来对待它的局限性和权衡。主要优势包括:

更快的开发周期

: 项目可以更快地从概念到原型到成品。AI 可以快速生成脚手架代码(如为新项目设置样板代码),因此你可以将更多时间花在应用程序的独特部分上。

增强的原型设计和实验

: 因为尝试某件事的成本更低(只需向 AI 描述你想要什么并获得快速草稿),开发人员可能会更自由地进行实验。你可以通过以不同方式提示 AI 来原型化问题的多种方法,然后选择最好的一个。这种迭代构思可以带来更具创造性的解决方案。

知识触手可及

: LLMs 是在大量编程知识语料库上训练的。它通常”知道”晦涩的 API 或错误消息解决方案。实际上,它可以呈现你可能没有想到的解决方案或想法,使你成为更有效的问题解决者。

一致性和标准化

: 在团队环境中,AI 助手可以通过生成一致风格的代码来帮助执行编码标准和最佳实践。如果配置了你项目的风格指南,它可以确保每个人的代码遵循类似的模式。即使没有明确的训练,AI 模型通常也会产生惯用代码(因为它们从数百万个示例中学习)。这可以减少代码审查所涉及的工作量,因为它的函数可能看起来很熟悉并且默认遵守常见约定。

需要考虑的一些局限性和权衡包括:

可变的输出质量

: 这些模型并非万无一失。它们可能会生成看起来正确但有细微错误或低效的代码。它们可能会选择过时的方法,因为它们的训练数据包含了大量较旧的代码。作为开发人员,你必须保持警惕。就像你不会在不理解的情况下从互联网复制粘贴代码一样,你也不应该不假思索地接受 AI 代码。本书的[第二部分]将讨论彻底验证和测试 AI 生成代码的技术。

提示的歧义导致代码的歧义

提示不够明确

如果你的提示不够明确,AI 必须猜测你的意图——而它可能猜错。例如,如果你告诉它”对名字列表进行排序”,它可能默认按字母顺序排序,但也许你想要的是其他方式(比如按名字长度排序)。除非你明确说明,否则 AI 无法知道这种差异。这就是为什么提示的明确性([第2章]的主题)至关重要——你需要学会预见哪些细节需要明确说明。

过度依赖和技能退化

如果新开发人员总是依赖 AI 来编写代码,他们是否还能形成对算法和调试的深入理解?这存在技能退化的风险,类似于依赖 GPS 导航可能会削弱你自己的方向感。为缓解这一问题,重要的是将 AI 作为学习工具使用(关注它提供的代码并询问原因),有时还要在不使用 AI 的情况下练习编码,以确保保留基本技能。

隐私和安全问题

使用基于云的 AI 编码工具通常意味着将你的代码(可能是专有或敏感的)发送到第三方服务进行分析。公司需要考虑这一点。许多工具正在通过允许本地部署模型或保证不存储代码来解决这个问题,但这仍然是一个需要考虑的因素。此外,AI 可能会无意中生成与其训练数据中某些内容非常相似的代码,而这些代码可能受开源许可证(如 GPL)约束。虽然这种情况不太可能(并且已有措施防止逐字输出长内容),但这强调了在集成之前需要审查和理解 AI 产出的必要性。[第8章]深入探讨安全性和可靠性问题。

AI 输出中的偏见

AI 模型可能反映其训练数据中存在的偏见。在编码环境中,这可能像偏好某些变量名这样无害,也可能像使用假设特定用户属性的示例这样重要。例如,它可能在每个示例变量中都使用 foo/bar(因为许多示例都这样做),或者它可能对用户区域设置做出假设。与其他 AI 应用相比,这在代码生成中通常不是一个大问题,但值得注意这种可能性。更微妙的是,AI 可能偏向于它更常见到的解决方案,即使这些方案不是最适合你的情况。[第9章]讨论偏见和其他道德考量。

人为因素和信任

并非所有开发人员都能立即适应这种工作方式。编码有其独特的乐趣和艺术性,有些人可能觉得 AI 的介入削弱了这一点。还可能存在最初的不信任——“它真的做对了吗?”——只有良好的实践和时间才能克服。采用 AI 的团队应该允许一段适应期,并鼓励分享经验和技巧。随着时间推移,就像对待任何工具一样,大多数人会找到一个平衡点,在这个平衡点上 AI 的贡献得到重视,人类专业知识则专注于人类最擅长的领域。

总结与下一步

转向意图编程的氛围转变为加快软件开发、提高可访问性以及在许多方面使开发更愉快提供了巨大潜力。但要实现这一潜力,需要理解新的动态:如何有效地与 AI 沟通、如何验证其输出,以及如何负责任地将其整合到开发流程中。

我的观点基于使用这些工具的经验和观察众多项目得出,即 AI 的最佳用途在于将创造性的”氛围”与扎实的工程规范相结合。鼓励 AI 能够提供的大胆想法和快速草稿——这些是我们掌握的新超能力。但要用软件开发数十年积累的智慧来引导它们:规划、测试和理解你所构建内容的重要性。

当我们取得这种平衡时,我们就能获得两全其美的效果。我们可以更快、可能更富想象力地构建软件,同时也是我们信任、维护并充满信心发展的软件。这最终就是我们如何在 AI 时代提升我们的技艺:不是在氛围与工程之间二选一,而是掌握两者之间的整个光谱。

接下来,[第2章]探讨制作提示和与 AI 协作的艺术。有了本章的基础概念,你已经准备好探索这个新编程时代的实践方面。这将为后续章节中的实践示例和更深入的提示技术奠定基础。

第2章.提示的艺术:与 AI 有效沟通

在vibe coding中,提示词(prompt)就是新的源代码。

你向AI传达意图的方式直接影响它生成代码的质量。编写好的提示词既是艺术也是科学,通常被称为提示词工程(prompt engineering)。本章将为你提供一些技巧,帮助你充分利用AI编程助手。我们将从提示词为何重要的基本原理开始,然后深入探讨从简单到高级的提示词技巧工具箱。通过学习如何编写有效的提示词以及如何迭代优化它们(图2-1),你将能够更高效、更准确地与AI协同创作。

提示词工程基础

如果说vibe coding是你与AI模型之间的对话,那么提示词工程(prompt engineering)就是掌握AI语言以获得最佳结果的技能。精心设计的提示词可以决定AI是给出不相关或有bug的代码建议,还是完美的解决方案。掌握提示词工程意味着理解如何有效引导AI、如何提供上下文,以及当第一次回答不够理想时如何与AI迭代。

当你使用AI编程时,本质上是通过AI使用自然语言进行编程。你提供的提示词就像一种高级编程语言,AI解释器随后将其转换为实际代码。就像编译器的输出质量取决于输入的源代码质量一样,AI的输出质量也取决于提示词的质量。

为什么提示词如此重要?尽管LLM(大型语言模型)非常复杂,但它们并不能读心。它们只对给定的输入做出响应。模糊或措辞不当的提示词可能导致不相关或不正确的代码,而清晰且具体的提示词可以在第一次尝试时就产生精准的解决方案。在传统编程中,你花时间思考算法和编写代码;在vibe coding中,你花时间思考如何向AI传达你的需求。这是”编写代码”含义的转变:你可能会写一段话而不是一个函数,但你仍然需要精确和符合逻辑。

可以把编写提示词想象成为一个非常字面化和迂腐的初级开发者编写文档或用户故事,这个开发者会完全(且仅仅)按照文档所说的去做,拥有大量知识但除了他们见过的模式之外没有常识。如果你的指令(提示词)留有解释空间,AI可能会以你意想不到的方式填补空白。因此,学会与AI沟通与学习编程语言的语法一样重要。

提示词至关重要的另一个原因是可重现性和面向未来。如果你发现一个提示词能够可靠地为某个特定模式或任务生成良好的代码,那么这个提示词就成为一项有价值的知识(几乎像代码片段或模板)。你可能会保存它或在类似的上下文中重用它。在团队中,开发者可能会相互分享有效的提示词模式,就像他们分享编程最佳实践一样。

最后,随着模型变得更好、集成度更高,它们可能允许更复杂的交互。擅长提示词编写将使你能够快速利用新功能。例如,一些高级系统允许你附加详细的指令或提供整个参考文档作为模型上下文的一部分。知道如何构建这种输入是充分利用这种能力的关键。

因此,将提示词编写视为一项新的基本技能。在很多方面,提示词编写就是编程。主要区别在于你用AI随后转换为代码的语言(如英语)编写。但你仍然必须清晰、符合逻辑,并在描述中预见边界情况。

特定性和清晰度:编写能够产出结果的提示词

提示词编写的黄金法则之一(我将在第3章更全面地阐述)是对你想要的内容要具体和清晰。与人类协作者不同,AI并不会真正理解你提供的文字之外的目标。一个常见的错误是给AI一个非常高层次的提示词,比如”做一个网站”,然后期待奇迹发生。AI在具体细节下工作得更好。

始终假设它对你的项目一无所知,除非你提供相关信息。包含相关细节,如编程语言、框架和库,以及所涉及的具体函数或代码片段。如果有错误,提供确切的错误消息并描述代码应该做什么。任何模糊或可解释的空间都可能导致意外的输出。

例如,不要说”编写一个排序函数”,而应该说:

编写一个Python函数sort_by_lastname(customers),接收一个客户记录列表(每条记录包含first_name和last_name字段),返回按last_name字母顺序排序的列表。包含简要的文档字符串(docstring),并通过将缺失的last_name视为空字符串来处理这种情况。

这个提示词明确了语言(Python)、函数名称和用途、输入结构、排序键、附加要求(文档字符串)以及边界情况。它很可能产生你所需要的结果,或者非常接近。本质上,要像规格说明书编写者那样思考:你对任务的规格说明越精确,AI需要猜测的就越少,你需要修改的次数也就越少。

提高具体性的策略包括:

提及语言或环境

如果你想要JavaScript的解决方案,明确说明:“编写一个JavaScript函数…”,而不是仅仅说”编写一个函数…“。如果你想要特定框架或版本的代码,包含这些信息(”使用React Hooks…“或”在Python 3中…“)。

定义输出范围

你只想要一个函数吗?一个完整的文件或模块?包含测试吗?例如,“仅提供函数实现”和”提供一个完整的可运行脚本”会产生不同的响应。

包含需求和约束

在登录示例中,我们指定了密码长度和尝试次数限制。考虑边界情况或约束条件并将它们放入提示词中。如果你需要代码针对性能优化或使用特定算法,请说明:“使用O(n)时间和O(1)空间”或”使用二分搜索方法”。

避免模糊的引用

不要在没有明确前置词的情况下使用像这样的词。不要说”处理它并返回结果”,而应该说”处理数组并返回结果数组”。

指定期望的输出格式

如果你希望AI仅输出代码、带注释的代码或包含解释的代码,你可以明确指示:“仅提供代码,不要解释”或”提供代码和每个步骤的简要注释”。

清晰的提示词为AI的成功奠定基础。如果你发现AI的答案经常需要大量修正,检查一下你的提示词是否可能规格说明不足。

以下是不应该做的:

不要写长篇大论

包含无关信息的冗长提示词可能会混淆模型或导致它关注错误的内容。在描述中做到简洁但完整。例如,在编码环境中通常不需要以”你是一位世界级的程序员…“作为开头(有些人在一般的ChatGPT使用中会这样做,但对于编码任务,这通常是不必要的,可能会增加噪音)。

不要假设AI会自己正确填充细节

如果某些内容很重要(如线程安全、特殊字符的处理等),请提及它。如果没有提及,假设AI可能不会处理它。

当需要确定性输出时避免开放式的”创意”提示词

例如,说”编写一些代码来分析数据”可能会导致AI猜测你想要什么分析。相反,应该明确指定:

计算一个数字列表的平均值和标准差。

总之,准确表达你的意思。AI对你真正想要的内容”了解”得越多,它就能提供越好的结果。如果你发现自己必须多次纠正AI,问问自己:我的初始提示词是否可以更清晰?

迭代优化(Iterative Refinement):与AI的反馈循环(Feedback Loop)

即使有清晰的提示词,你也不会总是第一次就得到完美的答案。将与AI的交互视为对话或迭代开发过程。这就是我在第1章中提到的反馈循环。

当AI给你代码时,像审查人类编写的代码一样批判性地审查它。它是否满足要求?如果不满足,找出缺少或错误的地方。然后提供反馈或优化后的提示词。这可以在对话式AI中通过简单地继续对话来完成,或者在编辑器中通过编写另一条注释让AI响应来完成。

通过向AI提供反馈,你可以引导它更接近你期望的结果。从某种意义上说,你正在针对你的具体问题即时训练它。高级提示工程就像图2-2中的循环:提示 → AI输出 → 审查 → 改进提示 → AI输出 →…直到满意为止。保持每次迭代的改动较小是有用的;如果你过度改动提示,可能会丢失上一次输出中的一些好的部分。

例如,你可以提示:

编写一个函数,接收一个整数列表并返回它们的总和。

AI随后返回一个函数,但它的代码假设列表非空,并且没有很好地处理空列表。然后你可以回复:

看起来不错。但是,请修改它以在列表为空时返回0。

AI会相应地更新函数。这样,你不必从头开始提示;你只是告诉AI做一个调整。AI已经有了它之前给出的代码的上下文。

如果你使用的是内联助手(inline assistant),改进可能看起来像编辑代码,也许写一个注释如# TODO: handle empty list,然后看AI是否建议修复。

另一种改进方法是,如果第一次输出不正确,用更多信息重新提示。假设你说”对名字列表进行排序”,它给出了区分大小写排序的代码,但你想要不区分大小写。你可以重新表述:

对名字列表进行不区分大小写的排序。

或者甚至:

之前的代码是区分大小写排序的。修改它为不区分大小写。

在调试中,对于更复杂的逻辑错误(没有明显的错误消息抛出但输出错误),你可以提示AI逐步执行代码。例如:

逐行执行这个函数,跟踪每一步total的值。它没有正确累加—逻辑在哪里出错了?

这是一个”橡皮鸭”调试提示的例子:你实际上是在要求AI模拟人类可能用打印或调试器进行的调试过程。这样的提示通常会揭示微妙的问题,如变量未重置或错误的条件逻辑,因为AI会详细说明每一步的状态。如果你怀疑代码的某个特定部分,你可以聚焦:

解释这里的filter调用在做什么,以及它是否可能排除了比应该排除的更多项目。

让AI扮演解释角色可以在解释过程中暴露错误。

在解释之后,直接要求你需要的内容通常是有效的:

可能是什么导致了这个问题,我该如何修复它?

这邀请AI既诊断又提出解决方案。如果AI的第一个答案不清楚或部分有帮助,不要犹豫提出后续问题:

那个解释说得通。你能展示如何修复代码吗?请提供修正后的代码。

在聊天环境中,AI有对话历史,所以它可以直接输出修改后的代码。如果你使用的是像VSCode中的Copilot或Cursor这样的内联工具而没有聊天,你可以在代码上方写一个注释:

// BUG: 返回NaN,修复这个函数并看它如何自动完成

不过一般来说,交互式聊天能产生更全面的解释。

另一种后续模式:如果AI给出了修复但你不理解为什么,询问:

你能解释为什么那个改动解决了问题吗?

这样,你为下次学习,并且你再次确认AI的推理是合理的。

LLM在示例和修正中蓬勃发展。如果你指出什么是错的或给出一个快速示例,AI可以将其纳入:

如果输入是[],它应该返回0,但现在它报错了。

这个迭代过程是正常的。事实上,试图将每个细节塞进一个提示可能不如几轮来回交流有效。利用这一点来发挥你的优势。

在反馈中要有耐心和具体。不要说”不,那是错的”,而是说什么是错的或需要什么:

这段代码没有正确处理负数。它应该在求和时将它们视为0。

另外,如果AI偏离方向,你可以引导它回来:有时重置或重新表述比试图挽救一个完全错误的尝试更容易。运用你的判断。如果AI输出显示它完全误解了你,从头澄清你的提示。

在改进过程中,你也会了解AI如何解释你的提示。这可以告诉你如何编写未来的提示。你可能会意识到,“哦,它把’登录系统’理解为整个UI。下次我会指定仅后端。”

把它想象成调试代码:如果AI输出错误,“bug”可能在你的提示中,而不在AI的处理中。就像当你的代码产生不正确的结果时你会检查和修复它一样,当AI生成意外或不正确的输出时,你应该改进你的提示。你和AI之间的对话就像一个调试会话,每次交流都帮助你确定和修复问题。

比较两个提示

假设你有一个简单的 Node.js 函数,用于将用户对象列表转换为按用户 ID 索引的查找映射。然而,它抛出了一个错误。以下是有问题的代码:

// 有bug的函数: 将用户数组转换为按ID索引的映射
function mapUsersById(users) {
  const userMap = {};
  for (let i = 0; i <= users.length; i++) {  
    // 注意: 使用 <= 会在最后一次迭代时越界
    const user = users[i];
    userMap[user.id] = user;
  }
  return userMap;
}

// 使用示例:
const result = mapUsersById([{ id: 1, name: "Alice" }]);

这段代码应该遍历用户数组并构建一个对象,其中键是用户 ID。然而,这里有一个 bug:循环使用了 i <= users.length 而不是 i < users.length。这将导致 users[i] 在最后一次迭代时变为 undefined,很可能导致运行时错误(比如尝试访问 undefined 的 ID 属性)。让我们看看 AI 助手对于这个问题的两种不同提示词会如何响应(见图 2-3)。

糟糕的提示词

以下是一个糟糕提示词的示例:

为什么我的 mapUsersById 函数不工作?

AI 对糟糕提示词的响应(模拟):

没有更多信息很难说。你确定函数调用时传入的是正确的用户数组吗?也许问题在于 users 是空的或者不是数组,导致循环无法正确执行。也可能是在 userMap 上设置属性时出现了错误。确保每个用户都有 id 属性。如果 users 是 undefined 或 null,那也会导致它不工作。

这个回答相当模糊。提示词除了函数名之外没有给出任何细节,所以 AI 只能猜测一些通用原因(“也许数组是空的或不是数组”,“确保每个用户都有 ID”)。它没有识别出实际的 bug。

这就是当问题描述不够具体时得到的响应类型——模型只能重复一些常见的调试技巧。如果你是开发者,这并不太有帮助,因为它没有解决真正的错误。提示词中缺乏上下文和具体性导致了一个通用的答案:本质上是 AI 版本的”你试过重启了吗?“这印证了社区的建议:模糊的提示词会导致不相关或通用的答案。

改进的提示词

让我们再试一次:

我有一个 JavaScript 函数 mapUsersById,它应该将用户对象数组转换为按用户 ID 作为键的映射(对象)。然而,当我运行它时会抛出错误。例如,当我传入 [ {id: 1, name: "Alice"} ] 时,我得到 TypeError: Cannot read property 'id' of undefined。以下是函数代码:

function mapUsersById(users) {
  const userMap = {};
  for (let i = 0; i <= users.length; i++) {  
    const user = users[i];
    userMap[user.id] = user;
  }
  return userMap;
}

它应该返回 { "1": {id: 1, name: "Alice"} }。bug 是什么,我该如何修复它?

AI 对改进提示词的响应(模拟):

错误 Cannot read property 'id' of undefined 表明在某个时刻,user 是 undefined,然后你尝试访问 user.id。查看你的循环,问题出在循环边界上。你使用了 i <= users.length。如果 users.length1(数组中有一个用户),循环会在 i = 0i = 1 时运行。当 i1 时,users[1] 是 undefined(因为数组中唯一的索引是 0)。因此 user 在那次迭代中变成 undefined,user.id 抛出 TypeError。修复方法是将循环条件改为 i < users.length,这样 i0users.length-1。例如:

for (let i = 0; i < users.length; i++) {
  const user = users[i];
  userMap[user.id] = user;
}

这样,i 对于第一个(也是唯一的)元素将是 0,然后循环停止。通过这个改变,你的函数将不再遇到 undefined 的 user,应该能按预期工作,对于给定的输入返回 {"1": {id: 1, name: "Alice"}}

这个响应直接指出了 bug(在循环中使用了 <=)并解释了为什么它会导致 user 变为 undefined。然后它提供了正确的代码解决方案(i < users.length)并确认了预期的结果。改进的提示词之所以成功,是因为它遵循了我们的原则:它指定了语言(JavaScript),描述了函数的目的,包含了确切的错误消息和示例输入,甚至提供了有问题的代码片段。

注意AI如何利用错误信息作为线索,将重点放在循环边界上——有针对性的提示使AI能够进行真正的问题解决,有效地模拟人类调试者的思考方式:“undefined可能从哪里来?很可能来自循环索引。”这具体展示了详细提示的好处。

提示技术:有效沟通的工具箱

现在让我们深入了解一些可以增强你提示技能的具体技术。这些就像你在直接指令不够用,或者想以特定方式引导AI时可以使用的模式或配方。

通过掌握这些技术,你可以处理一系列情况:用简单的英语指导AI、给它举例、让它解释或构建输出、或将其设置为不同的思维模式或角色。所有这些都有助于你引导AI准确生成你需要的内容。

提示技术并不相互排斥;你通常会将几种技术结合使用以获得最佳结果,特别是在复杂任务上。

关于风格的说明

当你使用这些技术时,要根据模型调整你的语气。许多模型对礼貌或中性的指令响应良好。你不需要使用古老或过于正式的语言。直接但礼貌通常有效:“请执行X”或”让我们做Y。“例如,在链式思考(CoT)提示中,一个流行的短语是”让我们一步步思考。“像GPT-4这样的模型会将其识别为显示推理的提示。

零样本提示

零样本提示只是在不提供任何示例或额外指导的情况下,要求模型做某事,只提供指令。本质上,模型是从”零”个示例中解决任务。

何时使用:这是最常见的场景:你只是用简单的语言要求你想要的东西。如果任务是标准的并且提示清晰,这通常就足够了。

示例:

编写一个检查数字是否为质数的Python函数。

这是零样本。AI很可能会使用循环或试除法生成一个质数检查函数。

优点:快速且依赖于模型的学习知识。现代模型在许多编程任务的零样本响应方面表现出人意料地好,特别是如果它们很常见(如质数检查、排序或字符串操作)。

缺点:如果任务不寻常或输出格式很具体,零样本可能在第一次尝试时产生不太符合你需要的结果,因为模型可能有多种解释方式。

通常,对于简单的事情,首先尝试零样本是个好主意。如果结果不对,你可以转向改进或其他技术。

单样本和少样本提示

单样本提示意味着你提供恰好一个你想要的示例(输入和期望输出)作为提示的一部分;少样本提示意味着在要求模型对新输入执行任务之前提供几个示例(通常是两到五个)。

这就像向模型展示,“这是我如何解决一个实例的。现在你用类似的方法做下一个。”

何时使用:当模型可能不确切知道你需要的格式或风格,或者当任务有点不寻常时,这种类型的提示很有用。通过给出示例,你减少了歧义。

示例(单样本):假设你正在使用模型可能不太常见的语言或某种特定风格。假设你想要特定格式的伪代码。你的提示可能是:

将以下英文指令转换为类似Python的伪代码。

示例指令:“计算n的阶乘”:

示例伪代码:

function factorial(n):

    if n <= 1:

        return 1

    else:

        return n * factorial(n-1)

指令:"在列表中查找最大的数"

伪代码:

你提供了一个示例(阶乘)和你想要的格式。现在模型更有可能以类似的格式为”最大数”指令生成伪代码(带有函数,带有if/else或根据需要的循环逻辑)。

示例(少样本):假设你想让AI使用特定的算法。你可以给它一个该算法实际运行的较小示例作为提示。或者如果任务有多个正确答案但你更喜欢某一个,示例可以将其推向那个方向。

少样本提示对于格式化非常强大;例如:

将以下英文语句转换为SQL查询。 1.”获取2020年后雇用的所有员工” → SELECT * FROM Employees WHERE Hire_Date > ‘2020-01-01’; 2. “列出上个月购买过商品的客户姓名” → SELECT Name FROM Customers JOIN Purchases ON … WHERE Purchase_Date > …; 3. “缺货产品的数量” →

这里,一旦你给出两个英语到SQL的示例,AI就可能通过遵循这个模式正确回答第三个查询。少样本示例(few-shot examples)也可以应用于编码:向AI展示你想要的风格的小样本,然后要求更多。这就像在你的提示词(prompt)中给它一个迷你训练数据集。

优点: 你可以实现非常特定风格的输出。这种技术还帮助模型处理涉及遵循模式或重复应用概念的任务。

上下文窗口

上下文窗口(context window)这个术语指的是语言模型在单次交互中可以处理的最大文本量(以token计量),包括输入提示词和生成的响应。这代表了当前AI模型的一个限制——一旦你达到这个阈值,模型就无法处理额外的信息。当你在制作提示词时,你包含的所有内容(指令、示例、数据和响应所需的空间)都必须适应这个固定容量。

缺点: 特别是少样本提示会使提示词变长(这会占用上下文窗口)。对于非常大/复杂的示例,它可能会”吃掉”模型的大量容量。但通常一两个小示例是可以的。

提示: 如果你想让模型严格遵守某个输出结构,给出一个示例几乎可以保证它匹配该结构,而不是提供一个你必须解析的自由形式回复。

思维链提示

思维链(Chain-of-thought, CoT)提示涉及要求模型在给出最终答案之前逐步思考或展示其推理过程。换句话说,你鼓励模型分解问题。

何时使用: 这对涉及推理和多步计算的复杂问题很有用,或者当你怀疑模型如果直接跳到答案可能会犯错时。当你想要在输出中获得解释时也很有用。

组合数学

组合数学(Combinatorial math)处理根据特定规则或约束对对象进行计数、排列和选择。常见问题包括计算排列(permutations)(顺序重要的排列)、组合(combinations)(顺序不重要的选择)和其他计数原理。关键符号包括”n选k”(写作C(n,k)或nCk),表示从n个总项目中选择k个项目的方式数量,使用公式n!/(k!(n-k)!)计算。这些计算经常出现在概率、统计和离散数学应用中。

示例: 与其只是问一个组合数学问题,比如”12选4是多少?“并得到答案,你可以说:

逐步求解12选4。

模型可能会列出:

12选4 = 12!/(4!*8!) = ... = 495

在编码中,思维链(CoT)对于棘手的算法任务很有用。你可以尝试以下提示:

逐步解释如何合并两个排序列表,然后提供Python代码。

模型首先会概述如下内容:

我们将使用两个指针从每个列表的头部开始,比较元素,将较小的元素追加到结果列表,并移动该指针,依此类推…

然后它可能会给出代码。这确保它在编码之前已经正确构建了解决方案。

另一个用途是调试或理解输出:

演示判断数字19是否为素数的逻辑,然后给出结果。

模型可能会列出被素数整除的情况,然后得出结论:

19是素数。

优点: 提高需要推理的任务的正确性。有研究证据表明,提示模型”大声思考”可以在数学和逻辑任务上获得更好的结果。它还让你深入了解模型的过程,这可以增强理解或帮助你更信任答案。

缺点: 输出更长(这可能不是你在最终代码中想要的)。此外,一些界面(如典型的代码补全)不适合单独显示推理。这种技术在问答或聊天场景中更常见。然而,你可以指示模型将推理作为注释包含在代码中,这是获得完整注释代码的一种巧妙方式。

角色提示

角色提示(Role prompting)意味着你要求AI扮演某个可能影响其响应方式的特定身份或角色。

何时使用: 当你想影响答案的风格或细节程度,或获得某个特定视角时,这很有用。例如,扮演”专家”角色的AI可能会给出更高级的解决方案或更多解释,而”初学者”角色可能会让它解释更多基本概念。

示例:

这可以显著影响响应结果。给 AI 分配安全分析师角色可能会让它关注那些原本不会提及的方面(如数据验证、安全编码实践或潜在漏洞)。教员角色可能会使其提供更清晰的解释,并且可能不会假设你有先验知识。

在编程中,你可能会在请求代码之前这样说:

你是一位精通优化的 C++ 专家程序员,正在指导一名初级开发者。

结果很可能会使用更高级的 C++ 特性,并解释为什么做出某些选择,在技术复杂性和教育清晰度之间取得平衡。

优点:这种技术可以引导答案的语气和深度。这可以将解决方案定制到特定的复杂程度或彻底性。如果你想要一个非常简单的解决方案(告诉它扮演新手,也许它会避免复杂的技巧),或者一个非常优化的解决方案(告诉它扮演性能大师),这很有用。

缺点:有时模型可能会过度关注角色而非必要(“教员”可能会开始解释你已经知道的事情)。此外,某些 AI 安全系统对某些角色描述更敏感——特别是那些可能暗示欺骗、冒充权威或潜在有害活动的描述——尽管像”数据分析师”或”软件工程师”这样直接的技术和专业角色通常不会出现问题。

上下文提示(Contextual Prompting)

上下文提示是指给 AI 提供超出直接任务描述之外的额外上下文或信息。AI 模型不会持久记忆你的整个项目,除非你在提示中提供(或通过高级 IDE 集成中的某些集成上下文窗口)。因此,如果你希望 AI 编写适合现有代码库的代码,就需要给它提供该上下文。基本上,你将相关数据或背景作为提示的一部分提供。

何时使用:当解决问题需要了解模型可能不知道或可能无法从训练中正确回忆起的某些数据或定义时使用。或者当你想确保与某些外部信息(如 API 规范或对话的先前部分)保持一致时使用。

示例:

如果你有一个数据结构并希望代码能够使用它,你可以粘贴其定义:

给定以下类,实现函数 X。

class Node:

    def __init__(self, value, next=None):

        self.value = value

        self.next = next

# 现在编写一个函数来计算从 head 开始的链表中的节点数。

通过包含类定义,你可以让 AI 更有可能在代码中正确使用 Node.valueNode.next

如果你想使用特定的 API,在提示中包含文档片段:

使用 requests 库从 API 获取数据。(API 返回格式为 {…} 的 JSON)

如果你包含文档中 API 使用的简短示例,AI 可以模仿它。

用于消除歧义:

使用术语 student 来指代高中学生,编写一个函数…

如果 student 在上下文中可能有歧义,你已经澄清了它。

优点:你将 AI 定位在你关心的上下文中。如果你提供事实,它就不太可能做出错误的假设。如果 AI 可能不记得或不知道你特定用例的详细信息,这非常有帮助。

缺点:这种技术会使提示变长。此外,模型可能偶尔会将提供的上下文重新输出到答案中(如果不小心,可能会将文档片段中的行复制到代码中)。但通常它会适当地使用它。

提示:如果你有大量上下文(如大型模式或多行代码),有时最好为模型总结关键元素,而不是逐字包含所有内容。这种方法可以帮助你保持在上下文限制内,同时确保模型接收到最相关的信息。然而,如果内容足够小,直接原样包含即可。

在上下文提示中提及约束(constraints)也很有用:性能约束(“优化到 O(n log n) 或更好”)、兼容性约束(“必须在 Python 3.8 上运行”)或库选择(“仅使用标准库,不使用外部依赖”)。这些就像护栏,确保 AI 不会建议超出可接受范围的内容。

元提示(Metaprompting)

元提示

元提示(Metaprompting) 是对输出本身给出指令,而不仅仅是解决方案应该做什么。这就像是告诉 AI 如何格式化或处理解决方案。

何时使用: 当您需要特定格式或风格的答案时,或者当您想控制 AI 解决问题的方式时很有用。

示例:

首先用两句话解释方法,然后提供代码。

这确保 AI 不会直接开始写代码:

解决方案中不要使用任何库。

这对解决方案施加了约束:

将输出格式化为 JSON。

如果您使用 AI 生成数据而不是代码,这很有用:

仅提供函数体,不包括定义行。

如果您想将函数插入现有代码,这很方便:

如果输入无效,不要返回错误,而是返回 None。

这不完全是输出格式,但它指示 AI 在某些情况下如何行为。

优点: 您可以准确地得到所需的内容,以您需要的方式,无需额外编辑。这对某些场景至关重要。如果您计划在流水线中自动使用 AI 的输出,那么您真的需要一致的格式。

缺点: 如果指令与模型的默认风格冲突,有时它可能只部分遵循,或者您必须强调它们。例如,即使您说”仅代码,无解释”,偶尔模型也可能包含一点注释之类的。通常,将其表述为直接命令会有所帮助:

不要包含任何解释;仅在单个代码块内输出代码。

像 GPT 这样的模型很好地遵循这一点。

自洽性(多个输出和多数投票)

自洽性(Self-Consistency) 更像是一种策略而不是提示风格。其思想是对同一提示获取多个输出,然后决定最佳或最常见的输出。正如 Learn Prompting 的 Sander Schulhoff 所指出的,自洽性利用了这样一个概念:如果您多次询问模型(带有轻微的随机性),并且它的许多答案一致,那么这种共识很可能是正确的。

何时使用: 这对于复杂问题很有用,当您不确定模型的第一个答案是否正确时,特别是如果您自己无法轻易验证它,或者如果您想通过查看它是否重复给出相同答案来从 AI 获得置信度检查。

如何手动使用: 在某些平台上(如 ChatGPT),您可以点击”重新生成答案”。或者您可以将提示复制到新会话中,看看它是否给出相同的结果。如果您得到三个答案,其中两个相同,一个不同,您可能会相信这两个(假设问题有一个正确答案)。

在编程上下文中,如果它为某个确定性任务生成代码,通常每次都会给出非常相似的代码(变量名或风格略有不同)。但如果这是一个算法问题(如”这段代码的输出是什么?“),您可以检查多次运行。

这种技术在非编码任务(如逻辑谜题)中更强大,但值得注意。

另一个角度——集成提示: 您实际上可以在一个提示中要求模型考虑多种可能性:

为这个问题提供两种不同的解决方案。

然后也许您可以看到您喜欢哪一个或测试两者。这就像是一次性的自洽性,因为您得到了多个答案。

优点: 如果多次尝试收敛,这种技术可以增加对解决方案的信心。此外,您可能会获得多样性(如果您想从许多方案中选择最优雅的解决方案,这很好)。

缺点: 进行多次调用并比较输出很耗时。

在实践中,如果我对答案不确定,我通常会以不同的方式重新提问,看看是否得到相同的答案。如果得到了,我会更有信心它是正确的。

ReAct(推理 + 行动)提示

ReAct 是一种更高级的提示技术,它结合了推理行动。它使模型不仅像 CoT 那样思考,而且还采取行动,如进行计算、调用 API 或使用工具。(更多信息请参见 ReAct 提示工程指南)。在当前实践中,这通常与 LangChain 等框架一起使用,其中 AI 可以输出程序解释为操作的特殊格式(如要执行的命令或要运行的查询),然后将结果反馈回来。

对于我们的范围(没有这样的执行环境在循环中),您仍然可以通过指示 AI 首先概述计划,然后输出结果来进行一种形式的 ReAct。它类似于 CoT,但专门面向使用工具或执行子任务。

示例:

使用 Python,确定巴黎的当前天气并打印它。

除非AI具有浏览功能,否则它无法真正获取当前天气。ReAct方法会让AI首先通过陈述来推理问题:

我需要访问巴黎的当前天气数据,这需要调用天气API。

然后AI会尝试使用可用的工具来进行API调用。如果成功,它将收到实际的天气数据;如果没有这样的工具,它可能会承认局限性或使用假设数据。最后,AI会编写Python代码来显示天气信息,整合通过这个推理和行动过程获得的任何数据。

如果没有外部工具访问权限,ReAct对于简单的提示任务可能不太相关。然而,在为您的组织评估AI工具时,确定它们是否可以从互联网访问当前信息是一项关键的能力评估。许多AI模型的知识有截止日期,这意味着它们的训练数据只延伸到特定日期,这可能导致快速变化的主题信息过时。

如果您使用的环境中AI可以执行代码(例如Jupyter集成或类似平台),您可以通过指示系统来实现ReAct:

首先为这个函数编写一个测试,运行它,然后相应地调整代码。

这通过推理步骤(编写测试)、行动(执行测试)和基于结果调整代码来展示ReAct模式。然而,通过纯提示编排这样的工作流需要高级提示技术和适当的技术基础设施。

更简单的用法:您可以模拟一个问答,其中AI有模仿行动的中间步骤:

逐步思考,如果需要的话,进行计算。

这实际上是CoT,但语气更加命令式。

优点:当可用时,它可以解决需要外部信息或迭代试验的问题(例如AI可以通过实际运行代码来纠正自己)。在调试环境中,可以执行代码来测试的AI非常棒。

缺点:没有特定工具,这种技术不太容易获得。如果您只是在普通ChatGPT中这样提示,它要么会想象这些行动,要么只是执行CoT。

对于我们在提示编写中的目的,请记住,一些系统(如OpenAI的工具使用代理或其他系统)是存在的,但在普通提示中,我们主要执行CoT,我们自己处理诸如运行代码或测试之类的行动。

高级提示:组合技术和处理复杂性

提示技术可以组合使用。例如,您可能会做一个少样本提示,同时在示例中演示CoT。或者您可能将角色与CoT结合起来:

作为一名高级工程师,逐步思考问题,然后给出代码。

现在我们已经探索了各种提示技术,让我们通过一两个场景来看看它们的实际应用,然后讨论如何审查和改进AI的输出(这将引入下一章关于理解和掌握生成代码的内容)。

想象一下您有一个无法正常工作的函数。您可以使用角色和CoT提示的组合:

您是一名Python调试器。让我们逐步思考以找到以下代码中的错误。

接下来是代码。AI可能会对每一行进行分析并精确定位错误。

或者假设您想为一个稍微复杂的算法生成代码,确保它有良好的注释,并且还要获得测试用例。组合提示可能如下所示:

您是一名专业的Python开发人员。让我们逐步解决这个问题。我们需要一个函数merge_sorted_lists(list1, list2),它将两个排序列表合并为一个排序列表。首先,解释方法,然后提供带注释的Python代码。之后,给出2-3个代码示例测试来演示它的工作原理。

这个单一的提示相当全面。第一句设定了角色。第二句请求逐步推理。第三句给出主要任务。第四句要求提供带解释性注释的代码,第五句甚至要求测试。

AI随后可能会输出一个解释,然后是带内联注释的代码,最后是一些测试用例。这是一个高级用法,但它显示了您如何通过多方面的响应来指导AI。

了解模型的限制

提示工程(Prompt Engineering)还涉及到知道什么该问以及如何避免陷阱。如果提示变得太大或包含太多指令,模型可能会感到困惑或截断某些输出。如果你发现它开始忽略提示的某些部分,你可能需要简化或分部分进行。如果AI模型有时会产生不正确的事实或代码(它会”产生幻觉(hallucinate)“),你要学会仔细检查,不要将其作为事实的权威来源。如果你发现它倾向于给出过于冗长的代码,你可以预先用”使解决方案尽可能简洁”来防止。如果它有时使用不存在的函数,你可以指示”仅使用下面列出的API函数”并列出它们。你越了解AI的行为,就越能塑造你的提示以规避任何弱点。

如果任务非常复杂,你也可以将其分解为子任务让AI处理。例如,你可以首先提示:

列出为简单算术表达式语言实现基本编译器的步骤。

一旦AI给出步骤,你就用单独的提示来处理每个步骤,甚至可能在单独的文件或会话中:

现在实现步骤1:词法分析(tokenization)。

这就像与AI进行系统设计:你可以先概述然后细化每个部分。它利用了AI在规划方面的能力(不仅仅是编码)。

有状态对话与一次性提示

在聊天环境中,你有对话历史,称为状态(state)。你可以通过与AI讨论来建立上下文。在IDE补全环境中,上下文主要是你的文件内容和注释。两者都以不同的方式允许累积上下文。如果你需要AI记住所说的内容(比如优化答案),使用对话。如果你想确保它只关注现在相关的内容,使用新的提示或文件上下文。有时清除上下文可以防止模型坚持可能错误的早期假设。

通过在各种示例上练习这些技术,你将熟练掌握何时使用哪种方法:

常见的提示反模式及如何避免

并非所有提示都是平等的。到目前为止,我们已经看到许多有效提示的例子,但同样有益的是识别反模式(antipattern)——导致AI回复不佳的常见错误。本节涵盖一些常见的提示失败案例以及如何修复它们。

模糊的提示

这是经典的”它不工作,请修复它”或”写点做X的东西”而没有足够细节。“为什么我的函数不工作?”这样的问题通常会得到无用的答案。模糊的提示迫使AI猜测上下文,通常会导致通用建议或不相关的代码。

修复方法很简单:添加上下文和具体信息。如果你发现自己提出问题后得到的答案感觉像魔术8球的回应(“你试过检查X吗?”),停下来并用更多细节重新构建你的查询(错误消息、代码摘录、期望与实际结果等)。一个好的做法是阅读你的提示并问:“这个问题是否适用于数十种不同的场景?”如果答案是肯定的,那就太模糊了。让它具体到只能适用于你的场景。

过载的提示

这是相反的问题:一次要求AI做太多事情。例如:

生成一个完整的Node.js应用,包含身份验证、React前端和部署脚本。

或者,在较小的规模上:

一次性修复这5个bug并添加这3个功能。

AI 可能会尝试处理,但你很可能得到混乱或不完整的结果,或者它可能会忽略请求的某些部分。即使它处理了所有内容,响应也会很长且更难验证。

解决办法是拆分任务。优先处理:一次做一件事,正如我们之前强调的那样。这样更容易发现错误并确保模型保持专注。如果你发现自己写的指令段落中多次使用”和”,考虑将其分解为单独的提示词或顺序步骤。

遗漏问题

有时用户会提供大量信息但从未明确提出问题或说明他们需要什么,比如只是转储一大段代码片段并说”这是我的代码”。这可能会让 AI 困惑——它不知道你想要什么。

始终包含明确的要求:

提示词应该有明确的目的。如果你只是提供文本而没有问题或指令,AI 可能会做出错误的假设(比如总结代码而不是修复它等)。确保 AI 知道你为什么向它展示某些代码。即使是简单的补充,如”这段代码有什么问题?“或”请继续实现这个函数”,都能给它方向。

模糊的成功标准

这是一个微妙的问题。有时你可能会要求优化或改进,但没有定义成功的标准——例如,“让这个函数更快”。以什么指标衡量更快?如果 AI 不知道你的性能约束,它可能会微观优化一些无关紧要的东西,或者使用理论上更快但实际上可以忽略不计的方法。或者”让这段代码更清晰”:“更清晰”是主观的。我们通过明确说明目标来处理这个问题,比如”减少重复”或”改进变量名”等。

解决办法:量化或限定改进:

基本上,明确说明你要通过重构或功能解决什么问题。如果你让它太开放,AI 可能会解决与你关心的问题不同的问题。

忽略 AI 的澄清或输出

有时 AI 可能会用澄清性问题或假设来回应:

如果你忽略这些并只是重申你的请求,你就错过了改进提示词的机会。AI 在发出信号表明它需要更多信息。始终回答它的问题或优化你的提示词以包含这些细节。

此外,如果 AI 的输出明显偏离(比如它误解了问题),不要只是逐字重试相同的提示词。花点时间调整你的措辞。也许你的提示词有一个模棱两可的短语或省略了一些关键内容。把它当作对话:如果一个人误解了,你会用不同的方式解释;对 AI 也这样做。

不一致

如果你不断改变提问方式或在一次提问中混合不同的格式,模型可能会感到困惑。两个例子包括在指令中在第一人称和第三人称之间切换,或以令人困惑的方式混合伪代码(pseudocode)和实际代码。

尝试在单个提示词中保持一致的风格。如果你提供示例,确保它们被清楚地划分(使用 Markdown 三个反引号标记代码,使用引号标记输入/输出示例等)。一致性有助于模型正确解析你的意图。此外,如果你有首选风格(比如 ES6 与 ES5 语法),请始终如一地提及它;否则,模型可能在一个提示词中建议一种方式,而在稍后建议另一种方式。

模糊引用如”上述代码”

在使用聊天时,如果你说”上述函数”或”之前的输出”,请确保引用是清晰的。如果对话很长并且你说”重构上述代码”,AI 可能会失去跟踪或选择错误的代码片段进行重构。

在对话中再次引用代码或明确指定要重构的函数名会更安全。模型的注意力窗口是有限的,尽管许多大语言模型可以引用对话的早期部分,但再次给出明确的上下文可以帮助避免混淆。如果距离代码展示已经过去了一段时间(或若干条消息),这一点尤其重要。

总结与下一步

提示的艺术是迭代的和创造性的。随着模型的演进,提示最佳实践可能会改变(例如,未来的模型可能在使用较少文字的情况下更好地理解意图)。但底层原则保持不变:有效沟通,AI就会更好地为你服务。

本质上,掌握提示工程就像掌握一门新的编程语言——与AI交互的指令语言。它是技术写作、前瞻性思维和对提示本身的交互式调试的结合。但一旦你擅长它,AI真的会开始感觉像是你自己思维的延伸,因为你可以以最小的摩擦可靠地提取出你设想的解决方案(甚至是那些你还没有完全设想但可以引导AI去发现的解决方案)。这项技能可能会变得和知道如何使用谷歌搜索或如何使用调试器一样基础——它是氛围编程时代现代开发者技能集的一部分。

如果AI可以解决大约70%的问题,你如何将它作为编程合作伙伴来对待?第三章探讨了开发者如何真正使用AI,并为氛围编程设定了一些”黄金规则”。

第二部分 AI编程实践

第三章 70%问题:真正有效的AI辅助工作流

基于AI的编程工具在某些任务上表现惊人地出色。它们擅长生成样板代码、编写常规函数,并将项目完成到大部分程度。事实上,许多开发者发现AI助手可以实现一个涵盖大约70%需求的初始解决方案。

Peter Yang在X平台的一篇帖子中完美地捕捉到了我在实践中观察到的情况:

作为非工程师使用AI编程的真实感受:

它可以让你完成70%的工作,但最后30%令人沮丧。它不断前进一步又后退两步,出现新的bug、问题等等。

如果我知道代码是如何工作的,我可能可以自己修复它。但由于我不知道,我质疑自己是否真的学到了什么。

非工程师使用AI编程时发现自己遇到了令人沮丧的瓶颈。他们可以惊人地快速完成70%的工作,但最后30%变成了一场收益递减的练习。

这个”70%问题”揭示了关于AI辅助开发当前状态的一些关键信息。最初的进展感觉很神奇:你可以描述你想要什么,v0或Bolt等AI工具会生成一个看起来令人印象深刻的工作原型。但随后现实出现了。

70%通常是工作中直接的、模式化的部分——遵循常规路径或通用框架的那类代码。正如一位Hacker News评论者观察到的,AI在处理软件的”偶然复杂性”(accidental complexity)(重复性的、机械性的东西)方面非常出色,而”本质复杂性”(essential complexity)——理解和管理问题的固有复杂性——仍然由人类承担。用Fred Brooks的经典术语来说,AI处理的是附带的而不是内在的开发困难。

这些工具在哪里遇到困难?经验丰富的工程师一致报告存在”最后一公里”的差距。AI可以生成一个看似合理的解决方案,但最后30%——覆盖边缘情况、改进架构和确保可维护性——“需要严肃的人类专业知识”。

例如,AI可能会给你一个在基本场景下技术上可行的函数,但除非明确告知,否则它不会自动考虑异常输入、竞态条件(race conditions)、性能约束或未来需求。AI可以让你完成大部分工作,但最后关键的30%(边缘情况、保持可维护性和稳固的架构)需要严肃的人类专业知识。

此外,AI有一个已知的倾向,即生成令人信服但不正确的输出。它可能引入微妙的bug或”幻觉”出不存在的函数和库。Steve Yegge讽刺地将当今的大语言模型比作”疯狂高产的初级开发者”——速度惊人且充满热情,但”可能受到改变思维的药物影响”,容易想出疯狂或不可行的方法。

Yegge 的话来说,大语言模型(LLM)可以生成乍看之下很精致的代码,但如果经验较少的开发者天真地说”看起来不错!“并直接使用它,接下来的几周就会出现荒谬(或灾难性)的结果。AI 并不真正理解问题;它只是将通常有意义的模式拼接在一起。只有人类才能辨别一个看似不错的解决方案是否隐藏着长期隐患。Simon Willison 也呼应了这一点,他看到 AI 提出了一个极具迷惑性的巧妙设计,但只有对问题有深刻理解的资深工程师才能识别出它的缺陷。教训是:AI 的自信远远超过了它的可靠性。

至关重要的是,当前的 AI 无法创造出超越其训练数据的全新抽象或策略。它们不会为你发明新颖的算法或创新的架构——它们只是重新组合已知的东西。它们也不会为决策承担责任。正如一位工程师指出的:“AI 没有比其训练数据所包含的’更好的想法’。它们不会为自己的工作负责。”

所有这些意味着创造性和分析性思维——决定构建什么如何构建以及为什么构建——仍然牢牢属于人类领域。总之,AI 是开发者的力量倍增器(force multiplier),可以处理重复性的 70% 工作,为我们的生产力提供”涡轮增压”。但它不是可以取代人类判断的银弹(silver bullet)。软件工程剩余的 30%——困难的部分——仍然需要只有训练有素、思考周全的开发者才能带来的技能。这些才是需要重点关注的持久技能,[第 4 章]专门讨论这些内容。正如一个讨论所说:“AI 是一个强大的工具,但它不是魔法子弹……人类判断和良好的软件工程实践仍然至关重要。”

开发者实际如何使用 AI

我观察到团队在利用 AI 进行开发时有两种不同的模式。我们称之为”引导者(bootstrappers)“和”迭代者(iterators)“。两者都在帮助工程师(甚至非技术用户)缩小从想法到执行(或 MVP)的差距。

首先是引导者,他们通常将新项目从零开始做到 MVP(最小可行产品)。像 Bolt、v0 和截图转代码 AI 这样的工具正在革新这些团队引导新项目的方式。这些团队通常:

结果可能令人印象深刻。我最近看到一位独立开发者使用 Bolt 在极短的时间内将 Figma 设计转换为可工作的 Web 应用。它还没有达到生产就绪状态,但已经足够获取最初的用户反馈了。

第二阵营是迭代者,他们在日常开发工作流程中使用 Cursor、Cline、Copilot 和 Windsurf 等工具。这不太引人注目,但可能更具变革性。这些开发者:

但问题在于:虽然这两种方法都可以显著加速开发,但它们都有一些不会立即显现的隐藏成本。

当你观看资深工程师使用 Cursor 或 Copilot 等 AI 工具工作时,看起来像魔术一样。他们可以在几分钟内搭建整个功能,包括测试和文档。但仔细观察,你会注意到一些关键的东西:他们不只是接受 AI 的建议。他们不断将生成的代码重构为更小、更专注的模块。他们添加 AI 遗漏的全面错误处理和边缘情况处理,加强其类型定义和接口,并质疑其架构决策。换句话说,他们正在应用多年艰苦获得的工程智慧来塑造和约束 AI 的输出。AI 正在加速他们的实现,但他们的专业知识才是使代码保持可维护性的关键。

常见失败模式

初级工程师经常错过这些关键步骤。他们更容易接受 AI 的输出,导致我所说的”纸牌屋代码(house of cards code)“——看起来完整,但在现实世界的压力下会崩溃。

退两步

接下来通常发生的事情遵循我称之为”退两步(two steps back)“的可预测反模式(antipattern)(如图 3-1 所示):

对于非工程师来说,这种循环特别痛苦,因为他们缺乏理解实际出了什么问题所需的心智模型(mental models)。当经验丰富的开发者遇到 bug 时,他们可以基于多年的模式识别(pattern recognition)来推理潜在的原因和解决方案。如果没有这种背景知识,你基本上就是在玩打地鼠游戏,对付着你并不完全理解的代码。这就是我在本书前言中提到的”知识悖论(knowledge paradox)“:高级工程师和开发者使用 AI 来加速他们已经知道如何做的事情,而初学者试图用它来学习应该做什么

对于使用 AI 的”自力更生者(bootstrapper)“模式的非工程师来说,这种循环特别痛苦,因为他们缺乏构建 MVP 时解决这些问题所需的心智模型。然而,即使是经验丰富的”迭代者(iterators)“,如果过度依赖 AI 建议而不进行深入验证,也可能陷入这种打地鼠陷阱。

这里有一个更深层次的问题:让 AI 编码工具对非工程师来说易于使用的特性——它们代表你处理复杂性的能力——实际上可能会阻碍学习。当代码”凭空出现”而你不理解底层原理时,你就无法培养调试技能。你会错过学习基本模式的机会。你无法对架构决策(architectural decisions)进行推理,因此你难以维护和演进代码。这会产生一种依赖关系,你需要不断回到 AI 模型来修复问题,而不是培养自己处理这些问题的专业能力。

随着自主 AI 编码代理(autonomous AI coding agents)的出现,这种依赖风险进入了一个新的维度——我将在[第10章]深入探讨这个主题。与当前建议代码片段的工具不同,这些代理代表了软件开发方式的根本转变。在我写这本书的时候,我们正在见证能够以最少的人工监督独立规划、执行和迭代整个开发任务的系统的早期部署。

从辅助型 AI 到自主型 AI 的演变引入了关于开发者专业知识和控制权的深刻问题。当 AI 系统可以处理从初始实现到测试和部署的完整开发工作流时,技能退化(skill atrophy)的风险变得严重。那些严重依赖这些代理而不保持基础知识的开发者,可能会发现自己无法有效地审计、指导或干预 AI 的决策偏离预期结果时的情况。

当我们考虑这些自主系统如何在整个项目中做出级联决策(cascading decisions)时,挑战变得更加复杂。每个单独的选择可能在孤立的情况下看起来都很合理,但累积效应可能会将开发引向意想不到的方向。如果没有及早识别和纠正这些轨迹偏移的专业知识,团队可能会在他们并不完全理解的基础上构建越来越复杂的系统。

正如我们将在后面更深入地探讨的那样,自主编码代理的出现并没有降低软件工程基础知识的重要性——而是放大了它。我们的 AI 工具越强大,我们就越需要保持专业知识,以确保我们仍然是系统的架构师(architects)而不仅仅是操作员(operators)。只有通过对软件原理的深刻理解,我们才能确保这些强大的工具增强我们的能力而不是侵蚀它们。

演示质量陷阱

这正在成为一种模式:团队使用 AI 快速构建令人印象深刻的演示。正常路径(happy path)运行得很好。投资者和社交网络为之惊叹。但当真实用户开始点击操作时呢?那时候问题就出现了。

我亲眼见过这种情况:对普通用户来说毫无意义的错误消息,导致应用程序崩溃的边缘情况(edge cases),从未清理的混乱 UI 状态,完全被忽视的无障碍性(accessibility),以及在较慢设备上的性能问题。这些不仅仅是低优先级的 bug——它们是人们能容忍的软件和人们喜爱的软件之间的区别。

创建真正自助服务的软件

创建真正自助服务的软件——那种用户永远不需要联系支持的软件——需要一种不同的思维方式,这完全关乎打磨(polish)这门失传的艺术。你需要专注于错误消息;在慢速连接和真实的非技术用户身上进行测试;使功能易于发现;并优雅地处理每个边缘情况。这种对细节的关注(也许)无法由AI生成。它来自同理心、经验和对工艺的深切关注。

真正有效的方法:实用的工作流模式

在我们深入本书第二部分的编码之前,我们需要讨论现代开发实践以及AI辅助编码如何融入团队工作流。毕竟,软件开发不仅仅是编写代码——它是一个完整的工作流,包括规划、协作、测试、部署和维护。而vibe编码(vibe coding)不是一个独立的新奇事物——它可以融入敏捷方法论(agile methodologies)和DevOps实践中,在保持质量和可靠性的同时增强团队的生产力。

在本节中,我们将探讨团队成员如何集体使用vibe编码工具而不会相互干扰,如何平衡AI建议与人类洞察,以及持续集成/持续交付(CI/CD)管道如何整合AI或适应AI生成的代码。我还将涉及版本控制策略等重要考虑因素。

在观察了数十个团队后,以下是我发现在单人和团队工作流中持续有效的三种模式:

AI作为初稿撰写者
AI模型生成初始代码,然后开发者对其进行完善、重构和测试
AI作为结对编程伙伴
开发者和AI持续对话,具有紧密的反馈循环、频繁的代码审查和最少的上下文提供
AI作为验证者
开发者仍然编写初始代码,然后使用AI来验证、测试和改进它(参见图3-2)
图3-2. AI验证工作流:开发者编写初始代码;AI系统分析错误和安全问题,然后提出改进建议;开发者审查并应用推荐的更改。

在本节中,我将依次介绍每种模式,讨论工作流和成功的技巧。

AI作为初稿撰写者

在你要求AI模型起草任何代码之前,确保团队中的每个人都在同一页面上是很重要的。沟通是关键,这样开发者就不会让他们的AI助手执行冗余任务或生成冲突的实现。

在每日站会(敏捷工作流的主要组成部分)中,不仅值得讨论你正在做什么,还要讨论你是否计划将AI用于某些任务。例如,两个开发者可能正在开发不同的功能,这两个功能都涉及日期格式化的实用函数。如果两人都要求AI创建一个formatDate辅助函数,你可能最终会得到两个相似的函数。提前协调(“我会生成一个我们都可以使用的日期实用工具”)可以防止重复。

成功整合AI工具的团队通常从就编码标准和提示实践达成一致开始。例如,团队可能决定采用一致的风格(代码检查规则、项目约定),甚至将这些指南反馈给他们的AI工具(一些助手允许提供风格偏好或示例代码来引导输出)。正如Codacy博客中提到的,通过让AI熟悉团队的编码标准,你可以获得更统一的生成代码,每个人都更容易使用。在实践层面,这可能意味着在项目README中添加一个”AI使用技巧”部分,在其中注明诸如”我们只使用函数式组件”或”优先使用Fetch API而不是Axios”之类的内容,开发人员在提示AI时可以记住这些。

另一个实践是使用工具的协作功能(如果可用)。一些AI辅助IDE允许用户共享他们的AI会话或至少是他们使用的提示。如果开发人员A通过一个提示获得了复杂组件的良好结果,与开发人员B共享该提示(可能通过问题跟踪器或团队聊天)可以节省时间并确保一致性。

至于使用版本控制,基本原则保持不变——只是有所变化。在现代开发中使用Git(或其他版本控制系统)是不可协商的,这在氛围编码中不会改变。事实上,当AI快速生成代码时,版本控制变得更加重要。提交充当安全网来捕获AI的失误;如果AI生成的更改破坏了某些内容,你可以恢复到以前的提交。

一个策略是在使用AI辅助时更频繁地提交。每次AI产生重要的代码块(如生成功能或进行一些重大重构)并且你接受时,考虑用清晰的消息进行提交。频繁的提交确保如果你需要二分查找问题或撤销AI引入的部分代码,历史记录足够细粒度。

此外,尝试隔离不同的AI引入的更改。如果你让AI在不同领域进行许多更改并将它们全部一起提交,那么在出现问题时就更难以解开。例如,如果你使用代理来优化性能,它还调整了一些UI文本,请分别提交这些内容。(你的两个提交消息可能是”优化列表渲染性能 [AI辅助]“和”更新锻炼完成消息的UI文案 [AI辅助]“)。描述性提交消息很重要;一些团队甚至标记涉及大量AI的提交,只是为了可追溯性。这不是关于责备,而是关于理解代码的起源——标记为”[AI]“的提交可能向审查者表明,代码可能需要对边缘情况进行额外彻底的审查。

本质上,团队应该将AI使用视为开发对话的正常部分:分享经验、成功技术以及关于不该做什么的警告(比如”Copilot建议对X使用过时的库,所以要小心”)。

审查和改进对这种模式至关重要。开发人员应该手动审查和重构代码以提高模块化,添加全面的错误处理,编写详尽的测试,并在改进代码时记录关键决策。下一章将详细介绍这些流程。

AI作为结对程序员

传统的结对编程涉及两个人在一个工作站上协作。随着AI的出现,出现了一种混合方法:一个人类开发人员与AI助手一起工作。这种设置可以特别有效,提供了人类直觉和机器效率的融合。

在人类-AI配对中,开发人员与AI交互以生成代码建议,同时审查和改进输出。这种动态允许人类利用AI在处理重复任务方面的速度,例如编写样板代码或生成测试用例,同时保持监督以确保代码质量和相关性。

例如,在集成新库时,开发人员可能会提示AI起草初始集成代码。然后开发人员审查AI的建议,与官方文档交叉参考以验证准确性。这个过程不仅加速了开发,还促进了知识获取,因为开发人员深入参与AI的输出和库的复杂性。

让我们将此与传统的人类-人类结对编程进行比较:

两种方法都有其优点,你可以根据项目的复杂性、资源可用性和开发过程的具体目标来选择。

AI配对编程的最佳实践

为了最大化AI辅助开发的好处,请考虑以下实践:

为不同的任务启动新的AI会话

这有助于保持上下文清晰,并确保AI的建议与当前的具体任务相关。

保持提示聚焦且简洁

提供清晰具体的指令可以提高AI输出的质量。

频繁审查和提交更改

定期集成和测试AI生成的代码有助于早期发现问题并保持项目进度。

保持紧密的反馈循环

持续评估AI的贡献,根据需要提供更正或改进,以指导其学习并改善未来的建议。

AI作为验证者

除了代码生成,AI还可以作为有价值的验证者,协助代码审查和质量保证。AI工具可以分析代码中的潜在错误、安全漏洞以及对最佳实践的遵循情况。例如,DeepCode和Snyk的AI驱动代码检查器等平台可以识别缺失输入清理或不安全配置等问题,直接在开发环境中提供可操作的见解。Qodo和TestGPT等平台可以自动生成测试用例,确保更广泛的覆盖范围并减少手动工作。许多AI工具还可以协助监控应用程序性能,检测可能表明潜在问题的异常情况。

通过将AI验证者集成到开发工作流中,团队可以提高代码质量,减少缺陷的可能性,并确保符合安全标准。这种主动的验证方法补充了人工监督,从而产生更强大、更可靠的软件。这些工具通过处理重复和耗时的任务来提高质量保证(QA)流程的效率和有效性,使人工测试人员能够专注于QA中更复杂和更细致的方面。

将AI融入开发过程,无论是作为配对程序员还是验证者,都提供了提高生产力和代码质量的机会。通过深思熟虑地集成这些工具,开发人员可以利用人类和人工智能的优势。

为了最大化AI和人类能力在QA中的好处,我建议以下几个最佳实践:

Vibe Coding的黄金法则

虽然vibe coding在软件开发中提供了前所未有的速度和创造性自由,但其灵活性本身要求采用结构化方法来确保一致的质量和团队凝聚力。如果没有平衡创造性探索与工程规范的明确指导原则,快速、直观的AI辅助开发可能很快导致混乱。

这些黄金法则来自成功将vibe coding集成到工作流程中的团队的集体经验。它们代表了关于AI擅长的领域、AI遇到困难的领域以及人类判断如何在整个过程中保持必要性的来之不易的见解。这些原则不是限制创造力,而是创建一个框架,让团队能够自信地进行实验,同时保持生产就绪软件所需的标准。

这些规则涉及vibe coding的三个关键维度:人类与AI之间的交互、将AI生成的代码集成到现有系统中,以及培养支持可持续AI辅助开发的团队实践。通过遵循这些指导原则,团队可以利用vibe coding的变革力量,同时避免导致技术债务、安全漏洞或无法维护的代码库的常见陷阱:

对你想要什么要具体而清晰

: 在与AI交互时,清楚地阐明你的需求、任务和预期结果。精确的提示词产生精确的结果。

始终根据你的意图验证AI输出

: AI生成的代码必须始终与你的原始目标进行核对。在接受之前验证功能、逻辑和相关性。

将AI视为初级开发者(需要监督)

: 将AI输出视为需要你仔细监督的草稿。提供反馈、完善,并确保质量和正确性。

使用AI扩展你的能力,而不是取代你的思考

: 利用AI自动化常规或复杂任务,但在解决问题和做决策时始终保持积极参与。

在生成代码之前与团队提前协调

: 在开始AI驱动的开发之前,与团队就AI使用标准、代码期望和实践达成一致。

将AI使用视为开发对话的正常部分

: 定期与团队讨论AI经验、技术、成功和陷阱。将AI规范化为集体改进的另一个工具。

通过单独提交在Git中隔离AI变更

: 在版本控制中清楚地识别和分离AI生成的变更,以简化审查、回滚和跟踪。

确保所有代码,无论是人工还是AI编写的,都经过代码审查

: 通过让所有贡献都接受相同的严格审查流程来保持一致的标准,提高代码质量和团队理解。

不要合并你不理解的代码

: 除非你完全理解其功能和影响,否则永远不要集成AI生成的代码。理解对于可维护性和安全性至关重要。

优先考虑文档、注释和ADRs

: 清楚地记录AI生成代码的基本原理、功能和上下文。良好的文档确保长期清晰度并减少未来的技术债务。

共享和重用有效的提示词

: 记录能够产生高质量AI输出的提示词。维护一个经过验证的提示词库,以简化未来的交互并增强一致性。

定期反思和迭代

: 定期审查和完善你的AI开发工作流。利用过去经验的洞察来持续增强团队的方法。

通过遵守这些黄金法则,你的团队可以有效地利用AI,在保持清晰度、质量和控制的同时提高生产力。

总结和下一步

70%问题定义了AI辅助开发的当前状态:这些工具擅长生成样板代码和常规函数,但在最后30%的工作上遇到困难,包括边缘情况、架构决策和生产就绪性。我们确定了两种主要使用模式——快速构建MVP的启动者和将AI集成到日常工作流的迭代者——以及常见的失败模式,如”后退两步”反模式和”演示质量陷阱”,其中令人印象深刻的原型在现实世界压力下失败。

已经出现了三种经过验证的工作流模式:AI作为初稿者(生成然后完善)、AI作为结对程序员(持续协作)和AI作为验证者(人工编写的代码加上AI分析)。Vibe编码的黄金法则提供了重要的防护措施,强调清晰的沟通、彻底的验证、团队协调,以及在合并之前理解所有代码的不可妥协的要求。

个人开发者应该选择一种工作流模式进行系统性实验,同时在日常实践中实施黄金法则。专注于培养第4章中涵盖的持久技能:系统设计、调试和架构——而不是在代码生成上与AI竞争。

团队需要建立AI使用标准,创建有效提示词的共享库,并将AI考虑因素整合到现有的敏捷实践中。定期分享成功和陷阱的知识将帮助团队避免常见陷阱,同时最大化AI的好处。

随着自主AI编码代理(autonomous AI coding agent)的出现,人类的角色将转向架构监督和战略决策。下一章探讨如何最大化这种不可替代的人类贡献,帮助各个级别的工程师作为日益强大的AI系统的合作伙伴而不是竞争对手而蓬勃发展。

1 本章基于最初发表在我的Substack新闻通讯上的一篇文章。参见Addy Osmani,“70%问题:关于AI辅助编码的硬道理”与Addy Osmani一起提升,2024年12月4日。

第4章 超越70%:最大化人类贡献

你已经看到像Cursor、Cline、Copilot和Windsurf这样的AI编码助手如何改变了软件的构建方式,承担了大部分繁重工作和样板代码——大约70%。1 但是将玩具解决方案与生产就绪系统分开的最后”30%“的工作呢?这个差距包括困难的部分:理解复杂需求、设计可维护的系统、处理边缘情况和确保代码正确性。换句话说,虽然AI可以生成代码,但它经常在工程方面遇到困难。

Tim O’Reilly 在回顾几十年的技术变革时提醒我们,每一次自动化的飞跃都改变了我们如何编程,但并未改变我们为什么需要熟练的程序员。我们面临的不是编程的终结,而是”我们今天所知的编程方式的终结”,这意味着开发者的角色正在演变,而不是消失。

当今工程师面临的挑战是拥抱 AI 在其最擅长领域的能力(前 70%),同时加倍投入剩余 30% 所需的持久技能和洞察力。本文深入探讨专家见解,以识别哪些人类技能仍然至关重要。我们将探讨高级和中级开发者应继续利用什么,以及初级开发者必须投资什么才能在 AI 时代蓬勃发展。

因此,本章的目标是为您提供实用指导,以最大化那不可替代的 30% 的价值,并为各个级别的工程师提供可操作的要点。

高级工程师和开发者:利用您的经验与 AI 协作

如果您是高级工程师,您应该将 AI 编码工具的出现视为放大您影响力的机会——前提是以正确的方式利用您的经验。高级开发者通常拥有深厚的领域知识、对可能出错之处的直觉,以及做出高层技术决策的能力。

这些优势是 AI 无法单独处理的 30% 的一部分。本节探讨经验丰富的开发者如何最大化其价值。

成为架构师和主编

让 AI 处理代码的第一稿,而您专注于架构解决方案,然后完善 AI 的输出。在许多组织中,Steve Yegge 写道,我们可能会看到团队只需要”高级员工”的转变,他们”(a) 描述要完成的任务;即创建提示,以及 (b) 审查结果工作的准确性和正确性”。拥抱这种模式。作为高级开发者,您可以将复杂需求转化为对 AI 助手有效的提示或规范,然后用您的批判性眼光审查生成的每一行代码。您实际上是在与 AI 结对编程——它是快速打字员,但您是大脑。

在审查期间保持高标准:确保代码符合您组织的质量、安全性和性能基准。通过充当架构师和编辑,您可以防止”高审查负担”压倒您。(一个警示说明:如果初级员工只是将原始 AI 输出直接扔给您,请予以回击——建立一个流程,要求他们必须首先验证 AI 生成的工作,这样您就不是唯一的安全网。)

将 AI 用作大型项目的力量倍增器

高级工程师经常推动大型项目或处理初级工程师无法单独应对的复杂重构。AI 可以通过处理大量机械性变更或在您的指导下探索替代方案来增强这些工作。Yegge 为这种工作方式引入了术语面向聊天的编程 (CHOP,chat-oriented programming)——“通过迭代提示优化进行编码”,将 AI 作为协作者。利用 CHOP 在您承担的工作上更加雄心勃勃。

拥有 AI 辅助降低了项目值得投入时间的门槛,因为原本可能需要几天的工作现在可以在几小时内完成。因此,高级开发者可以尝试那些总是看似略微遥不可及的”如果能……就好了?“项目。

关键是保持引导性思维:您决定追求哪些工具或方法,并将各个部分整合成一个连贯的整体。您的经验使您能够筛选 AI 的建议——接受那些合适的,拒绝那些不合适的。

指导和设定标准

另一个高级工程师的关键职责是指导经验较少的团队成员有效使用 AI 以及永恒的最佳实践。你可能拥有通过艰难经验获得的知识,了解初级工程师可能看不到的陷阱,例如内存泄漏、差一错误(off-by-one errors)和并发危险。

由于初级工程师现在可能通过 AI 生成代码,因此教他们如何自我审查和测试这些代码非常重要。通过展示如何彻底测试 AI 贡献来树立榜样,并鼓励质疑和验证机器输出的文化。一些组织(甚至包括律师事务所)已经制定了规则:如果有人使用 AI 生成代码或文字,他们必须披露并自己验证结果——而不是假设高级同事会发现错误。

作为高级工程师,在你的团队中倡导这样的规范:欢迎使用 AI,但需要保持严谨。通过这种方式指导初级工程师,你可以分担一些监督负担,并帮助他们更快地成长到那 30% 的技能水平。

继续培养领域精通和远见

你的广泛经验和背景比以往任何时候都更重要。高级开发人员通常拥有关于公司为什么以某种方式构建事物或行业如何运作的历史知识。这种领域精通能力让你发现 AI 的失误,而新手可能察觉不到。

继续投资于深入理解问题领域。这可能意味着及时了解业务需求、用户反馈或影响软件的新法规。除非你告诉 AI,否则它不会自动纳入这些考虑因素。当你将领域洞察力与 AI 的速度相结合时,就能获得最佳结果。

此外,利用你的远见来引导 AI。例如,如果你知道快速修复会在未来造成维护困难,你可以指示 AI 实现更可持续的解决方案。相信你多年来磨练的直觉——如果一段代码看起来”不对劲”或好得令人难以置信,就深入研究。十次中有九次,你的直觉发现了 AI 没有考虑到的问题。能够预见代码的二阶和三阶效应是高级工程师的标志;不要让 AI 的便利性削弱这种习惯。相反,将其应用于 AI 产生的任何内容。

磨练你的软技能和领导力

随着 AI 承担一些编码工作,高级开发人员可以将更多精力投入到工程的人性化方面:与利益相关者沟通、主持设计会议,以及做出将技术与业务战略相结合的判断。Tim O’Reilly 和其他人建议,随着常规编码变得更容易,价值转移到决定构建什么以及如何编排复杂系统上。

高级工程师通常是编排和看到全局的人。承担起这个角色。主动编写架构路线图,评估采用哪些工具(AI 或其他),或定义你组织的 AI 编码指南。这些是 AI 无法完成的任务——它们需要经验、人类判断力,并且通常需要跨团队的共识建设。通过增强你的领导存在感,你确保自己不仅仅是一个代码生成器(可以被另一个工具替代),而是一个指导团队的不可或缺的技术领导者。

简而言之,继续做经验丰富的开发人员最擅长的事情:见树木更见森林。AI 将帮助你砍伐更多树木,但仍然需要有人决定砍哪些树以及如何用木材建造一座稳固的房子。你的判断力、战略思维和指导能力现在比以往任何时候都更重要。有效利用 AI 的高级开发人员可以比不使用的人生产力高得多——但真正出类拔萃的将是那些运用人类优势来放大 AI 输出的人,而不仅仅是让它肆意运行。

正如一位Reddit用户观察到的,“AI是一个编程力量倍增器”,“大大提高了高级程序员的生产力”。倍增效应是真实存在的,但被倍增的是你的专业知识。保持这种专业知识的敏锐性,并将其置于开发过程的中心。

中级工程师:适应与专业化

中级工程师可能面临最大的演进压力。许多传统上占用你时间的任务——实现功能、编写测试、调试简单问题——正变得越来越自动化。

这并不意味着过时;而是意味着提升。重点从编写代码转向构建更专业的知识,以下部分将探讨这一点。

学习管理系统集成和边界

随着系统变得更加复杂,理解和管理组件之间的边界变得至关重要。这包括API设计、事件模式(schema)和数据模型——所有这些都需要仔细考虑业务需求和未来的灵活性。深化你的计算机科学基础知识,包括获得对以下学科的深入理解:

这些知识帮助你理解AI生成代码的影响,并做出更好的架构决策。

同时也要学会处理边缘情况和模糊性。现实世界的软件充满了异常场景和不断变化的需求。AI倾向于默认解决一般情况。由开发者来提出”如果…会怎样?“的问题,并探寻弱点。

这里持久的技能是批判性思维和前瞻性——列举边缘情况、预测失败并在代码或设计中解决它们。这可能意味着考虑空输入、网络中断、异常用户操作或与其他系统的集成。

构建你的领域专业知识

理解业务背景或用户环境将揭示通用AI根本不知道的边缘情况。有经验的工程师习惯性地考虑这些场景。系统地实践测试边界和质疑假设。专注于人类理解仍然至关重要的复杂领域。通用领域包括:

软件工程特定领域包括前端和后端工程、移动开发、DevOps和安全工程等。领域专业知识提供了当前AI工具所缺乏的背景知识,并帮助你更好地决定在何处以及如何应用它们。

精通性能优化和DevOps

虽然LLM可以提供基本的优化建议,但识别和解决系统级性能问题需要对整个技术栈的深入理解,从数据库查询模式到前端渲染策略。随着代码生成变得更加自动化,理解系统如何在生产环境中运行变得更有价值。

关注以下领域:

关注代码审查和质量保证

随着AI编写大量代码,严格审查和测试这些代码的能力变得更加关键。Yegge强调:“每个人都需要对测试和审查代码变得更加认真。”像对待初级开发人员的输出一样对待AI生成的代码:你是代码审查员,负责发现错误、安全漏洞或草率的实现。这意味着要加强你在单元测试、集成测试和调试方面的技能。

编写良好的测试是一项持久的技能,它迫使你理解规范并验证正确性。明智的做法是假设在证明之前什么都不工作。AI通常会产生功能性但未经优化的代码,直到你引导它进行迭代改进。这可能是由于多种原因,包括用于训练编码模型的训练数据并没有尽可能完整地反映所有最佳实践。

培养测试思维:验证每个关键逻辑路径,使用静态分析或代码检查工具,如果AI给出的代码不符合你的质量标准,不要回避重写它。即使你遵循前一章讨论的”AI作为验证器”模式,质量保证也不是一个可以简单外包给AI的领域——这正是人类勤奋的闪光之处。当软件没有按预期工作时,你需要真正的解决问题的能力来诊断和修复它。AI可以协助调试(例如,通过建议可能的原因),但它缺乏对应用程序运行的特定上下文的真正理解。人类测试人员拥有特定领域的知识和对用户期望的理解,而AI目前缺乏这些。这种洞察力在评估潜在问题的相关性和影响时至关重要。诊断复杂的错误通常需要创造性的问题解决和考虑广泛因素的能力——这些都是人类固有的技能。评估软件行为的伦理影响,如公平性和可访问性,需要人类的敏感性和判断力。

能够推理复杂的错误——重现它、隔离原因、理解底层系统(操作系统、数据库、库)——是一项永恒的工程技能。这通常需要对基础知识有深刻的理解(内存和状态如何工作、并发等),初级开发人员必须通过实践来学习。将AI用作帮手(它可能会解释错误消息或建议修复方法),但不要盲目依赖它。在调试时有条不紊地排查问题和应用第一性原理的技能,使优秀的开发人员脱颖而出。这也是一个反馈循环:调试AI编写的代码将教会你下次更好地提示AI或避免某些模式。

学习系统思维

软件项目不仅仅是孤立的编码任务;它们存在于用户需求、时间表、遗留代码和团队流程的更大背景中。AI对大局没有天生的感知,比如项目的历史或某些决策背后的理由(除非你明确将所有这些内容输入到提示中,这通常是不切实际的)。人类需要承载这些上下文。

这里的持久技能是系统思维——理解系统一个部分的变化如何影响另一个部分,软件如何服务于业务目标,以及所有活动部件如何连接。这种整体视角让你能够适当地使用AI输出。例如,如果AI建议一个与监管要求或公司惯例相矛盾的巧妙捷径,你会发现它,因为你了解上下文。努力学习项目的背景并阅读设计文档,这样你就可以培养关于什么合适、什么不合适的判断力。

保持适应性——永不停止学习

最后,一个元技能(metaskill):学习新工具和适应变化的能力。AI 辅助开发领域正在快速发展。保持开放心态并学习如何有效使用新 AI 功能的工程师将保持领先地位——Tim O’Reilly 建议”渴望学习新技能”的开发者将从 AI 中获得最大的生产力提升。投资于深入学习基础知识并对新技术保持好奇心。这种组合使你能够将 AI 作为工具来使用,而不会变得依赖它。

这是一个平衡的过程:使用 AI 来加速你的成长,但也要偶尔不使用它来练习,以确保你不会跳过核心学习(一些开发者会定期进行”AI 排毒(AI detox)“,以保持他们的原始编码技能的敏锐性)。简而言之,成为那种不断学习的工程师——这是任何时代都能证明职业价值的技能。

擅长跨职能沟通

当实现时间减少时,在业务需求和技术解决方案之间进行转换的能力变得更加有价值。能够有效地与产品经理、设计师和其他利益相关者沟通的工程师将变得越来越有价值。这里的重点领域包括:

学习系统设计和架构

中级工程师可能不再花费数天时间实现新功能,而是花时间设计能够优雅处理规模和故障模式的健壮系统。这需要对分布式系统原理、数据库内部机制和云基础设施有深入的理解——这些领域目前 LLM 提供的价值有限。

练习设计解决大规模实际问题的系统。无论代码如何生成,这些技能都保持价值,因为它们需要理解业务需求和工程权衡。

设计一个连贯的系统需要理解权衡、约束以及超越编写几个函数的”大局”。AI 可以生成代码,但不会自动为复杂问题选择最佳架构。

整体设计——组件如何交互、数据如何流动、如何确保可扩展性和安全性——是那 30% 需要人类洞察力的部分;这包括以下内容:

高级开发者长期以来一直在磨练这项技能,中级和初级开发者应该积极培养它。从模式和原则的角度思考(如关注点分离和模块化)——这些指导 AI 生成的解决方案走向可维护性。记住,扎实的架构不会偶然出现;它需要有经验的人来掌控方向。

使用 AI!

记住,AI 应该成为你工作流程中不可或缺的一部分——这不是应该抵制的东西。将 AI 融入日常工作的实用方法包括:

涉足 UI 和 UX 设计

有一种日益增长的说法认为,中级软件工程师应该”直接退出”——因为随着 AI 处理实现细节,纯工程技能将变得过时。虽然这个结论被夸大了,但关于工程之外技能(如设计)重要性的讨论值得关注。在 2024 年 12 月 X 平台上的一次代表性交流中,@fchollet 写道:

我们即将进入一个可以将测试时计算转化为能力的世界——这在软件历史上是第一次,边际成本将变得至关重要。

对此,@garrytan 回应道:

UX、设计、对工艺的实际投入将在下一个时刻成为中心舞台。

真正做出人们想要的东西。软件和编码不会成为限制因素。创造优秀软件的关键是成为通才(polymath)的能力,以及在多个领域同时保持聪明和高效。

成功的软件创作始终需要的不仅仅是编码能力。正在改变的不是工程的消亡,而是纯实现障碍的降低。这种转变实际上使工程判断力和设计思维变得更加关键,而非相反。

想想是什么让 Figma、Notion 或 VSCode 这样的应用成功。不仅仅是技术卓越——而是对用户需求、工作流程和痛点的深刻理解。这种理解来自以下方面:

最优秀的工程师一直以来都不仅仅是编码者。他们是既理解技术约束又理解人类需求的问题解决者。随着 AI 工具降低实现的摩擦,这种整体性理解变得更加宝贵。

然而,这并不意味着每个工程师都需要成为 UX 设计师。相反,这意味着要培养更强的产品思维能力,与设计师和产品经理建立更好的协作技能。这意味着更多地思考用户,理解他们的心理和行为模式,并学会做出支持用户体验目标的技术决策。你正处于实现技术优雅的阶段:现在要通过密切关注实际用户需求来平衡它。

Tan 继续发帖说:

UX、设计、对工艺的实际投入将在下一个时刻成为中心舞台。

真正做出人们想要的东西。软件和编码不会成为限制因素。创造优秀软件的关键是成为通才的能力,以及在多个领域同时保持聪明和高效。

未来属于那些能够在人类需求和技术解决方案之间架起桥梁的工程师——无论是通过自己培养更好的设计敏感性,还是通过与专业设计师更有效的协作。

初级开发者:与 AI 共同成长

如果你是初级或经验较少的开发者,你可能对 AI 感到既兴奋又焦虑。AI 助手可以编写你可能不知道如何自己编写的代码,有可能加速你的学习。然而,有关于“初级开发者之死”的头条新闻,暗示入门级编程工作面临风险。与流行的猜测相反,虽然 AI 正在显著改变早期职业体验,但初级开发者并未过时

你需要主动培养能力,确保自己贡献的价值超越AI能够产出的内容。随着这些任务日益自动化,通过实现基本的CRUD应用和简单功能来学习的传统路径将会演变。

考虑一个典型的初级任务:按照现有模式实现一个新的API端点。以前,这可能需要一天的编码和测试时间。有了AI辅助,实现时间可能会降到一小时,但关键技能变成了:

这些技能无法纯粹通过遵循教程或AI提示来学习——它们需要生产系统的实际经验和资深工程师的指导。

这种演变对早期职业开发者来说既是挑战也是机遇。入门级职位的门槛可能会提高,需要更强的基础知识来有效审查和验证AI生成的代码。然而,这种转变也意味着初级工程师可能在职业生涯早期就能解决更有趣的问题。

以下是如何投资自己以有效应对那30%差距的方法。

学习基础知识——不要跳过”为什么”

依赖AI回答每个问题(“如何在Python中做X?”)而从不真正吸收底层概念,这很诱人。抵制这种冲动。将AI用作导师,而不仅仅是答案售货机。例如,当AI给你一段代码时,询问它为什么选择那种方法,或让它逐行解释代码。

确保你理解数据结构(data structures)、算法(algorithms)、内存管理(memory management)和并发(concurrency)等概念,而不是总是依赖AI。原因很简单:当AI的输出错误或不完整时,你需要自己的心智模型来识别和修复它。如果你没有积极思考AI为什么生成某些代码,你实际上可能学到的更少,阻碍你的成长。所以花时间阅读文档,从头编写小程序,巩固你的核心知识。这些基础知识是持久的;即使你周围的工具发生变化,它们也会为你服务。

在没有AI安全网的情况下练习问题解决和调试

要建立真正的信心,有时你必须独自飞行。许多开发者倡导设立”无AI日”或定期限制AI辅助。这确保你仍然可以仅凭自己的技能解决问题,这对于避免技能退化(skill atrophy)很重要。你会发现这迫使你真正思考问题的逻辑,这反过来使你更擅长使用AI(因为你可以更智能地指导它)。

此外,每当你在AI生成的代码中遇到bug或错误时,在要求AI修复之前,先亲自跳进去调试它。通过使用调试器或添加打印语句来查看出了什么问题,你会学到更多。

将AI建议视为提示,而非最终答案。随着时间推移,解决任务中那些棘手的最后部分将培养你在AI困难领域的技能——正是这使你有价值。

专注于测试和验证

作为初级开发者,你可以养成的最佳习惯之一是为代码编写测试。如果你使用AI生成代码,这一点尤为重要。

当你从 LLM 获得一段代码时,不要假设它是正确的——要质疑它。编写单元测试(或使用手动测试)来验证它是否真正处理了需求和边界情况。这样做有两个目的:它能捕获 AI 输出中的问题,并且训练你在信任实现之前先思考预期行为。

你甚至可以使用 AI 来帮助编写测试,但要定义测试什么。Yegge 的建议关于认真对待测试和代码审查适用于所有级别。如果你培养出仔细验证工作的声誉(无论是否有 AI 辅助),资深同事会更加信任你,你也会避免他们觉得你只是在向他们”倾倒”有问题代码的情况。

实际操作中,开始将测试视为开发的组成部分,而不是事后补充。学习如何使用测试框架,如何进行探索性手动测试,以及如何系统地重现 bug。这些技能不仅让你在 30% 的工作中表现更好,还能加速你对代码实际工作方式的理解。

记住:如果你捕获了 AI 引入的 bug,刚刚做了 AI 做不到的事情——这就是附加价值。

培养对可维护性的敏感度

初级开发者通常专注于”让代码运行起来”。但在 AI 时代,获得一个基本可运行的版本很容易——AI 能做到这一点。更难的部分(也是你应该关注的)是编写可读、可维护和简洁的代码。

开始培养对良好代码结构和风格的敏感度。将 AI 的输出与你知道的最佳实践进行比较;如果 AI 代码混乱或过于复杂,主动重构它。例如,如果 LLM 给你一个做太多事情的 50 行函数,你可以将其拆分为更小的函数。如果变量名不清楚,重命名它们。

本质上,假装你在审查同事的代码,像同事写的一样改进 AI 的代码。这将帮助你内化良好的设计原则。随着时间推移,你会开始以产生更简洁代码的方式提示 AI(因为你会指定你想要的风格)。软件维护者(通常在几个月或几年后工作)会感谢你,你也会证明你的思考超越了”让它运行”——你在像工程师一样思考。保持可维护性正是那 30% 人类驱动工作的核心,所以从职业生涯一开始就把它作为你的关注点。

明智地发展你的提示和工具技能

不可否认,“提示工程”(prompt engineering)——有效地与 AI 工具交互的技能——是有用的。作为初级开发者,你绝对应该学习如何向 AI 提问,如何给它提供适当的上下文,以及如何迭代提示以改进输出(本书的[第 2 章]是一个很好的起点)。这些是能让你脱颖而出的新技能(许多经验丰富的开发者也还在摸索!)。但是,记住善于提示通常是理解问题的代理。如果你发现无法让 AI 做你想要的事,可能是因为需要先澄清自己的理解。将此作为信号。

一个策略是在要求 AI 实现之前,自己先用简单的英语概述解决方案。此外,尝试不同的 AI 工具(Copilot、Claude 等)来了解它们的优势和劣势。你越熟练使用这些助手,就越有生产力——但永远不要将它们的输出视为绝对正确。将 AI 想象成一个超强版的 Stack Overflow:一个辅助工具,而不是权威。

你甚至可以使用 AI 帮助构建小型个人项目来挑战自己的极限(“我能借助 AI 的帮助构建一个简单的 Web 应用吗?”)。这样做会教你如何将 AI 集成到开发工作流程中,这是带入团队的一项很好的技能。只需在如前所述的时间段内平衡无网络工作。

寻求反馈和指导

最后,一个能加速你成长的持久技能是寻求反馈和向他人学习的能力。AI 不会因为你忽略它的建议而生气,但你的人类队友和导师对你的发展是无价的——尤其是在软技能、领导力、沟通和应对办公室政治方面。

不要犹豫向资深开发者询问为什么他们偏好某个解决方案而不是另一个,特别是当它与AI建议的不同时。与更有经验的同事讨论设计决策和权衡——这些对话揭示了经验丰富的工程师如何思考,这对你来说是宝贵的财富。在代码审查中,要特别乐于接受关于你的AI生成代码的评论。如果审查者指出”这个函数不是线程安全的”或”这种方法会有扩展性问题”,花时间去理解根本问题。这些正是AI可能遗漏的东西,而你需要学会发现它们。随着时间推移,你会建立一个心理检查清单。

此外,寻找结对编程(pair programming)的机会(即使是远程)。也许你可以与一位在工作流程中使用AI的资深开发者”结对”——你会观察到他们如何提示AI以及如何纠正它。但更重要的是,你会看到他们如何沟通、引导讨论以及处理微妙的团队动态。对反馈保持开放并主动寻求指导,将帮助你从执行AI能做的任务成长为执行只有人类才能做的高价值任务。从某种意义上说,你正在尝试尽可能高效地获得通常伴随经验而来的智慧。这使你不仅仅是房间里的另一个编码者——而是让你成为团队渴望留住和提升的那种工程师。

沟通与协作

构建软件是一项团队运动。AI不参加会议(谢天谢地)——人类仍然必须与其他人交谈以澄清需求、讨论权衡并协调工作。强大的沟通技能和以往一样有价值。练习提出好问题并清晰地描述问题(对同事和对AI都是如此)。

有趣的是,提示AI本身就是一种沟通形式;它要求你精确表达你想要什么。这与一项核心工程技能重叠:需求分析(requirements analysis)。如果你能制定清晰的提示或规范,这意味着你已经思考了问题。

此外,分享知识、编写文档和审查他人的代码都是AI无法替代的协作技能。在未来,随着开发者”与”AI一起工作,团队中的人与人之间的协作——确保正在解决正确的问题——仍然至关重要。一个新兴趋势是,开发者可能会更多地专注于高层设计讨论(通常AI作为参与者)和协调任务,本质上承担更多的指挥者角色。沟通和领导技能将在那个指挥者的位置上很好地服务于你。

转变思维方式:从消费到创造

值得注意的是,在AI时代,初级开发者需要转变思维方式:你需要从消费解决方案转变为创造理解。在过去,你可能会费力地阅读文档最终编写一个功能;现在AI可以将解决方案直接呈现给你。如果你只是消费它(复制粘贴然后继续),你并没有成长多少。

相反,将每个AI给出的解决方案作为学习案例。剖析它,实验它,并思考你自己可能如何得出它。通过将AI输出不视为终结所有问题的答案,而是作为互动学习材料,你确保你——人类——持续提升。这样,AI不是取代你的成长,而是加速它。

许多专家认为,虽然AI可能会减少对大量初级”代码工”团队的需求,但它也提高了成为初级开发者的门槛。这个角色正在转变为能够有效地与AI合作并快速攀升价值链的人。如果你采纳本节讨论的习惯,你将把自己区分为一个初级开发者,不仅仅带来AI能带来的东西(任何公司都可以通过订阅获得),而是带来洞察力、可靠性和持续改进——未来资深开发者的特质。

总结与下一步

为了在AI增强的开发世界中茁壮成长,各个级别的工程师都应该加倍投入AI尚未(还)能够复制的持久技能和实践。无论我们的工具变得多么先进,这些能力都将保持至关重要。特别要关注以下领域:

这些技能构成了软件工程中的人类优势。它们是持久的,因为它们不会随着下一个框架或工具的变化而过期;实际上,AI的崛起使它们更加突出。Simon Willison认为,AI辅助实际上使强大的编程技能变得更有价值,而不是更少,因为那些具有专业知识的人可以更有效地利用这些工具。

一台强大的机器在不熟练的人手中可能是危险的或被浪费的,但在有能力的人手中它是变革性的。在AI时代,一位经验丰富的工程师就像一位拥有新的先进副驾驶的资深飞行员:旅程可以走得更快更远,但飞行员仍必须驾驭风暴并确保安全着陆。

软件工程一直是一个持续变化的领域——从汇编语言到高级编程,从本地服务器到云,现在从手动编码到AI辅助开发。每一次飞跃都自动化了编程的某些方面,然而每一次,开发人员都适应了并找到了更多要做的事情。在回应Tim O’Reilly的一篇笔记时,一位HN评论者指出,过去的创新”几乎总是为开发人员带来更多工作、更多增长、更多机会”。AI的崛起也不例外。它不是让开发人员变得无关紧要,而是重塑成功所需的技能集。平凡的70%编码工作正在变得更容易;具有挑战性的30%成为我们价值的更大部分。

为了最大化人类的30%,专注于永恒的工程技能:深入理解问题,设计简洁的解决方案,审查代码质量,并考虑用户和上下文。经验丰富的程序员从AI中获得更多,因为他们知道如何引导它以及当它失败时该做什么。那些将这些技能与AI工具结合起来的人将超越那些只有其中一种的人。事实上,专家们达成的共识是,AI是熟练者的工具:“LLMs是为强大用户(power users)设计的强大工具(power tools)。”这意味着我们每个人都有责任成为那个”强大用户”——培养让我们有效使用这些新工具的专业知识。

最终,软件工程的技艺不仅仅是编写可以工作的代码。它是关于编写运行良好的代码——在真实世界环境中,随着时间推移,在不断变化的需求下。今天的AI模型可以帮助编写代码,但还不能确保代码在所有这些维度上都运行良好。这是开发人员的工作。

通过加倍投入刚才概述的技能,资深开发人员可以继续领导和创新,中级开发人员可以加深他们的专业知识,初级开发人员可以加速他们通往精通的旅程。AI将处理越来越多的例行工作,但你的创造力、直觉和深思熟虑的工程将把原始输出转化为真正有价值的东西。AI是一个强大的工具,但关键在于我们如何使用它。良好的工程实践、人类判断和学习意愿将继续是必不可少的。

在实际操作中,无论你是与一个”渴望的初级”AI进行结对编程来编写你的函数,还是审查一个充满AI生成代码的差异,永远不要忘记应用你独特的人类视角。问问自己:这是否解决了正确的问题?其他人能够理解和维护这个吗?风险和边缘情况是什么?这些问题是你的责任。编程的未来确实将涉及更少的手动输入每个分号,更多的指导和策划——但它仍然需要掌舵的开发人员,他们有智慧正确地完成它。

最终,伟大的软件工程始终关乎问题解决,而不仅仅是编写代码。AI 并没有改变这一点:它只是挑战我们将问题解决能力提升到新的层次。拥抱这一挑战,你将在我们行业的新篇章中蓬勃发展。

[1] 本章基于我首次在 Substack 新闻通讯上发表的两篇文章:Addy Osmani,“超越 70%:最大化 AI 辅助编程中人类的 30%”Elevate with Addy Osmani,2025 年 3 月 13 日;以及 Addy Osmani,“让你的软件工程职业生涯面向未来”Elevate with Addy Osmani,2024 年 12 月 23 日。

[2] 要了解更多关于系统思维(systems thinking)的内容,请参阅 Donella H. Meadows,系统思维:入门,第 2 版(Rizzoli,2008);以及 Peter M. Senge,第五项修炼:学习型组织的艺术与实践(Crown,2010)。

[3] 有关此主题的更多信息,请参阅 Mark Richards 和 Neal Ford,软件架构基础,第 2 版(O’Reilly,2025);以及 Mark Richards、Neal Ford 和 Raju Gandhi,深入浅出软件架构(O’Reilly,2024)。

第 5 章 理解生成的代码:审查、优化、掌控

你已经学会了如何提示 AI 生成代码,到目前为止,你可能已经使用这些技术产生了一些代码。现在进入了一个关键阶段:确保代码是正确的、安全的和可维护的。

作为开发者,你不能只是接受 AI 的输出并盲目地交付它。你需要审查它、测试它、可能改进它,并将其与代码库的其余部分集成。本章重点介绍如何理解 AI 提供给你的内容,迭代地编辑和调试它,并完全掌控代码作为项目的一部分。

本章涵盖:

通过掌握这些技能,你将能够自信地将 AI 的贡献集成到你的项目中。

从意图到实现:理解 AI 的解释

当你获得 AI 的代码时,你的第一步应该是将其与你的意图(你给出的提示)进行比较。代码是否满足你设定的要求?有时 AI 可能会轻微误解或只是部分实现你所要求的内容。

仔细阅读代码。在脑海中或纸上逐步执行它:

就像你对待同事的代码一样,如果有什么不清楚的地方,记录下来。如果你为它的存在寻找一个好的理由,你可能会找到一个。如果找不到,就质疑它或考虑删除它。

例如,如果你要求一个素数检查器,而 AI 代码还为每个数字打印类似”正在检查 7…“的内容,这可能是你如何提示它的副产品或来自其训练数据的模式(一些教程代码会打印其进度)。如果你不想要那个,计划删除它或提示 AI 删除它。

还要确保边缘情况(edge cases)按你的预期处理。如果你希望它处理空输入,它做到了吗?如果输入可能是 None 或负数,AI 考虑到了吗?

如果你的提示中有什么是模糊的,AI 必须选择一种解释,识别发生这种情况的地方。也许你没有指定输出格式,它选择打印结果而不是返回它们。现在你必须决定是接受它还是修改代码。

这个理解阶段至关重要;不要跳过它。即使你要测试代码,通过阅读来理解它也很重要,因为测试可能无法覆盖所有内容(而且对于一些明显的事情,阅读更快)。

最后,考虑 AI 的假设。AI 通常倾向于”多数”或最常见的解释(这引出我们下一节的内容)。

“多数”问题:最常见不代表最合适

代码可读性和结构:模式和潜在问题

在大量代码上训练的AI模型通常会生成训练数据中最常见的解决方案(或最符合条件的最简单解决方案)。 我称之为多数解决方案效应(majority solution effect)。它在一般情况下是正确的,但可能不是你特定情况下的最佳选择。

例如,如果你在没有进一步上下文的情况下请求一个搜索算法,AI可能会输出一个基本的线性搜索,因为这很直接且常见。也许你实际上需要二分搜索,但AI不知道效率至关重要,因为你没有说明。线性搜索适用于许多中等情况,但如果性能是关键则不适用。

类似地,AI可能使用全局变量,因为许多简单示例都这样做,但也许在你的项目中,这不是可接受的实践。

要注意AI的解决方案可能针对通用场景进行优化。作为人类开发者,你对AI缺乏的上下文有深入了解。

为了解决这个问题:

如果AI代码适用于”常规”情况但不适用于对你重要的边缘条件,那就需要修复。例如,也许它没有考虑某些数学运算中的整数溢出。在许多训练示例中,这可能没有被处理,但在你的上下文中,这可能很重要。

理解AI倾向于通用解决方案将使你更擅长审查其代码。它不是魔法或量身定制的;它是对解决方案的非常有根据的猜测。定制是你的工作。

代码可读性和结构:模式和潜在问题

AI生成的代码通常有一些明显的模式。 它可能:

检查这些并考虑它们是否与你项目的风格匹配。 代码在功能上可能没问题,但需要可读性检查。 在该检查中,你可能想要:

还要查找任何不寻常的结构。 AI是否定义了多个类或函数,而你期望一个?有时它可能将问题分解为多个函数,因为训练示例就是这样做的。如果这过度了,你可以内联它们(或相反)。代码是太聪明还是太简单?AI有时会产生一个非常直接的解决方案,或者偶尔是一个花哨的单行代码。这是否符合你团队的偏好?如果不符合,请相应调整。

其他需要注意的潜在问题包括:

差一错误(Off-by-one errors)

是的,AI也会犯这种错误。例如,循环边界可能很棘手。如果有时间,在脑海中测试一个简单的情况通过循环。

未处理的异常

代码是否假设文件成功打开或所有输入都采用正确格式?如果需要,添加错误处理。

性能陷阱

也许AI在大型数据集上使用内循环进行成员检查,尽管存在更好的方法,比如使用集合。AI的解决方案可能是正确的,但不是最优的。

库的使用

如果代码使用了库,请确保这是你想要使用的库(并且它是可用的)。有时它可能会使用numpy来做简单的求和(因为它在训练数据的示例中看到过这种用法)。如果引入该依赖不值得,你可以切换到纯Python或你原本打算使用的库。

不一致性

有时,AI代码可能会有一些小的不一致,比如函数文档字符串说的是一回事,但代码做的是另一回事(例如,如果它修改了逻辑但没有修改注释)。请修复这些问题。

小的语法问题

这在经过充分测试的模型中很少见,但在某些语言中可能会混淆某些东西,这并非不可能。

使用过时的API

AI可能会使用库函数的旧版本,例如该函数已经发生了变化。如果你看到一个不认识的函数调用,快速查看库文档以确保它对于你使用的版本是正确的。

占位符

如果AI输出使用了像”Your code here”这样的占位符(很少见,但在通用模板中可能会发生),请填充这些内容。

简而言之,将AI代码视为实习生写的并已经下班离开的代码。你需要审查它的质量并正确集成它。

调试策略:查找和修复错误

假设你运行了代码(或为其编写测试,我们很快会讲到)但某些东西不工作。调试AI生成的代码与调试你自己或其他人的代码没有什么不同——只是你没有编写它,所以你可能不太熟悉。但因为你已经仔细阅读过它,你已经处于良好的状态(见图5-1)。

以下是调试的六步方法:

  1. 复现问题。

    使用会失败的输入运行函数或代码。观察输出或错误。

  2. 定位问题的源头。

    使用典型的调试技术,如打印语句,或使用调试器逐步执行。如果是逻辑错误(错误的输出),手动跟踪逻辑或使用打印语句查看它在哪里偏离了你的预期。

  3. 将提示与代码进行对照检查。

    有时错误只是代码没有完全实现需求,比如如果你要求对某些东西进行排序但它没有正确排序。这可能意味着AI的逻辑有缺陷,或者没有处理边缘情况(如空列表)。

  4. 利用AI来调试!

    你实际上可以将有问题的代码反馈给AI并说:“这段代码对X给出了错误的结果。你能帮我找到bug吗?”通常,它会分析它(就像代码审查)并指出问题。例如,也许它会发现循环应该到len(arr)但却到了len(arr)-1。它可能会更快地发现这一点。(也要注意不要完全信任它——但这就像请同事帮忙调试。)

  5. 修复代码。

    现在你有一个选择:手动修复它或提示AI提供修正版本。如果修复很明显,就直接做。如果不明显,你可以尝试这样说:“上述函数在输入X时失败(预期Y,得到Z)。请纠正它。”然后AI可能会相应地调整代码。

  6. 再次测试。

    确保bug已解决,并且没有引入新问题。

我建议使用测试驱动调试(test-driven debugging)。如果可能,为关键函数编写一些测试(本章后面的测试部分将详细介绍)。任何失败的测试都会直接显示出问题所在。对于除最简单函数之外的任何东西,这可能比手动检查更快。

最后,在调试时,确保你问的是为什么,而不仅仅是什么。试着理解为什么 AI 会犯这个错误。是提示词在这一点上不够清晰吗?这可以帮助你了解下次如何提示,或者是否需要始终仔细检查 AI 输出的这个方面。例如,如果你注意到 AI 经常不处理空输入(除非明确告知),你就会开始在提示词中始终指定这一点,并在输出中对此进行审查。

重构以提高可维护性:让 AI 代码成为你的代码

一旦代码在功能上是正确的,就要考虑重构它,使其符合项目的标准,并使其在未来更易于使用。AI 的工作是快速为你生成代码;你的工作是对其进行打磨。

以下是重构的六步流程:

  1. 符合风格指南。

    通过格式化工具或代码检查工具运行代码。修复任何警告,如”变量名应为小写”或”行太长”。这会立即使代码看起来与代码库的其余部分一致。许多 AI 工具在风格方面做得不错,但可能需要稍作调整。

  2. 改进命名和结构。

    如果 AI 在类中将函数命名为 _helper1_helper2,而你更喜欢有意义的名称,那就重命名它们。如果它创建了一堆只使用一次的小函数,也许可以内联它们,除非它们能增加清晰度。

  3. 删除任何不必要的部分。

    例如,也许 AI 在输出中包含了你没有要求的主程序块或测试代码。如果你不需要这些,就删除它。相反,也许它将所有内容都写在一个函数中,但你想将其拆分成更小的部分以提高清晰度;如果是这样,现在就进行拆分。

  4. 添加文档。

    如果这段代码打算成为其他人将使用的库或模块的一部分,请在适当的地方添加文档字符串或注释。AI 可能已经注释了一些,但要确保它符合你的标准。例如,也许你的项目需要特定的文档字符串格式,其中包含参数和返回值的文档。

  5. 根据需要优化。

    既然代码能工作了,它是否足够高效?如果这段代码可能在紧密循环中或在大数据上调用,请检查其复杂度。AI 可能没有使用最优的方法(同样,“多数解决方案”可能是一个简单的循环,而不是更优化的方法)。如果性能是一个问题,重构为更好的算法。你可以再次让 AI 参与:

    通过使用集合而不是列表进行查找来优化这段代码,使其运行更快。

    但是,作为开发者,你通常知道你想要什么模式,所以你可能只是实现那个更改。

  6. 根据需要简化。

    有时 AI 代码可能过于冗长。例如,它可能使用带有返回语句的 if-else,而使用带条件的单个返回语句就足够了。虽然明确的代码不一定不好,但你可能想将其简化为更少的行,以提高可读性而不失清晰度。

重构的目标是,如果另一个开发者稍后查看这段代码,不应该明显看出”这是 AI 写的”。它应该看起来就像好代码。这通常意味着赋予它使代码简洁的细微人工润色。

当你重构时,需要验证你没有破坏任何东西。那么让我们转到测试。

测试的重要性:单元测试、集成测试和端到端测试

测试始终很重要,但对于 AI 生成的代码尤其重要,原因有二。首先,由于你不是从头开始编写的,你希望确保它在所有情况下都能工作。其次,如果你稍后提示 AI 进行更改或集成更多 AI 代码,测试可以帮助你确保任何新更改不会破坏现有功能。让我们快速看看不同类型的测试:

单元测试(unit tests)

为你从AI获得的每个函数或模块编写测试,特别要覆盖边界情况。对于我们的质数示例,你可能需要测试一个质数、一个非质数、1(边界情况)、0或负数(可能需要定义预期行为)、一个大质数等等。如果代码通过了所有这些测试,它很可能是正确的。

你甚至可以要求AI生成这些测试:

为上述函数编写PyTest单元测试,覆盖边界情况。

它通常做得不错。不过,仍要审查它们以确保它们有效并覆盖你认为必要的内容。

集成测试(Integration tests)

如果AI代码与代码库的其他部分交互,比如使用数据库的函数,编写一个在上下文中调用它的测试。它实际上是否将应该存储的内容存储到数据库了?如果它产生被另一个函数使用的输出,在测试中将它们链接起来。

端到端测试(End-to-end tests)

如果这段代码是更大工作流的一部分,从头到尾运行一个场景。例如,如果AI代码是Web路由的一部分,在测试环境中对该路由进行测试请求,看看格式、错误处理和其他所有内容是否正常。

你需要进行的测试级别取决于代码的关键性和复杂性。但即使是快速的手动测试运行或脚本中的简单断言语句,也比没有验证要好。记住,测试不仅仅是发现错误;它还锁定行为。如果你以后更改某些内容(或AI这样做),测试可以帮助你确保代码的功能不会退化。

测试也是主张所有权(ownership)的好方法。一旦你测试并修复了任何问题,你就可以对代码充满信心。在这一点上,可以说代码是”你的”,就像代码库中的任何其他代码一样。你理解它,信任它,并有测试来保护它。

AI与测试的说明

一些AI编码工具开始集成测试建议。例如,CodeWhisperer有时会在一段代码后建议一个断言。将这些建议作为起点,但不要假设它们100%全面。想想创造性的边界情况——这是人类直觉仍然非常有价值的地方。

总结与后续步骤

我们已经完成了代码的生成、理解、调试和重构。对于一个小函数,这个循环可能在很短的时间内发生(几分钟内);对于复杂的模块,可能需要更长的时间(数小时或数天,需要间歇性的AI协助)。

重要的是要承认你,开发者,对最终代码负责。AI是加速创建的工具,但如果出现故障,它不会承担责任。还存在许可或版权风险:一些AI提供商表示,超过一定长度的输出可能在统计上包含复制的材料。这种情况很少见,提供商在很大程度上缓解了这个问题,但就像你扫描Stack Overflow答案以查找任何明显的许可文本或归属一样,快速检查一下——特别是如果输出很大或过于干净。例如,如果你提示”实现快速排序”,AI给你20行原始代码,这可能没问题且是常识。但如果你询问一些晦涩的东西并获得大量代码,尝试在线搜索其中的唯一字符串,看看它是否是从某处逐字提取的。这个问题最近变得更加明显,有记录在案的案例显示AI系统从期刊文章和其他受版权保护的来源中复制文本。作为负责任的代码所有权的一部分,开发者应该验证任何AI生成内容的来源,如果它似乎超出了通用模式或对特定来源异常具体。

最后,将代码集成到你的项目中:将其添加到版本控制系统中,也许在提交消息中提到AI提供了帮助。这不是必需的,但有些团队喜欢跟踪它。

随着时间的推移,随着需求的变化,你可能会修改这段AI生成的代码。像对待任何其他代码一样对待它:不要想,“哦,那是AI的代码;我会要求AI更改它。”如果你愿意,可以这样做,但你也可以随意手动修改它。做最高效和可维护的事情。

通过仔细审查和测试,AI生成的代码成为你项目中的又一段代码。在那时,AI是否编写了第10行或你编写的已经无关紧要——重要的是它满足项目的需求和标准。

通过遵循这些实践,你在确保质量的同时利用AI编码的速度。你避免了毫无疑问地信任AI输出的陷阱,而是将其集成到专业的开发工作流程中。

接下来,[第6章] 探讨了AI工具如何从根本上改变软件开发的原型设计阶段。我将探索利用AI助手的实用技术,以加速从初始概念到可工作原型的过程,通常将开发时间从数天缩短到数小时。讨论涵盖了具体的AI驱动原型设计工具,包括Vercel v0和截图转代码工具,以及在AI指导下进行迭代改进的策略。

我还将探讨从AI生成的原型过渡到生产就绪代码的关键过程,分析当AI成为开发工作流程的核心部分时所产生的机遇和潜在挑战。通过真实世界的案例研究,我将展示开发人员如何成功使用AI快速测试想法同时保持代码质量——并避免从概念快速实现时可能出现的常见陷阱。

第6章.AI驱动的原型设计:工具和技术

本章探讨AI驱动的氛围编码(vibe coding)如何加速软件开发的原型设计阶段。原型设计的核心是将想法快速转化为可工作的模型。借助AI助手,开发人员可以在几小时内完成通常需要数天的工作,快速迭代概念。我将讨论使用AI从概念到原型的技术,比较流行的AI原型设计工具(包括Vercel v0和截图转代码工具),并探讨如何在AI指导下迭代改进原型。我还将讨论将粗糙的AI生成原型过渡到生产质量代码的关键步骤。在整个章节中,我还将研究AI驱动原型设计带来成功结果的案例,并展示这种方法的潜力和陷阱。

使用AI助手进行快速原型设计

原型设计从AI生成代码的速度中获益匪浅。原型设计的目标不是完善的、生产就绪的代码,而是可以评估和改进的概念验证(proof of concept)。AI编码助手在这方面表现出色,能够从最少的输入快速生成可运行的代码。例如,开发人员无需手动编写UI模型代码,而是可以用自然语言描述所需的界面,让AI生成HTML/CSS或React组件。这使得从想法到实现的周期非常快速。

一位UX工程师描述了使用生成式AI工具如何彻底改变了他的工作流程:“我使用生成式AI生成功能原型的速度令人惊叹。我在几个小时内构建的原型通常需要数天时间。”AI自动处理常规样板代码和重复模式,使他能够专注于更高层次的设计决策。在原型设计中,这意味着你可以在相同的时间内尝试更多想法。另一个好处是AI可以几乎即时填充原型的繁琐部分(基础UI组件、表单处理、示例数据),使开发人员能够专注于正在测试的核心概念或独特功能。

然而,重要的是要记住原型代码通常是一次性代码。AI可能快速生成可工作的解决方案,但该代码可能没有为可维护性或扩展性而构建。这在原型中是可以接受的,因为速度和实验比优雅更重要——只要你计划为生产环境重构或重写关键部分(我将在本章后面讨论这个过程)。正如第[3]章和第[4]章所探讨的,AI可以自信地处理原型约70%的编码工作,而你指导整体架构并纠正任何关键缺陷。

带有意图的编程(programming with intent)是[第1章]中介绍的概念,在这里至关重要。你提供高层次的指令(你希望原型做什么或看起来如何的意图),让AI填充实现细节。为了说明这一点,让我们使用AI助手完成一个非常简单的原型设计示例。假设你有一个为新服务创建注册页面的想法。你想快速原型化前端,因此从以下开发者提示开始:

创建一个简单的 HTML 页面,包含一个注册表单,字段包括姓名、邮箱和密码,以及一个提交按钮。使用基本样式使其看起来美观。

现代代码助手如 Cline 可能会提供一个完整的 HTML/CSS 示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Sign Up</title>
  <style>
    body { font-family: Arial, sans-serif; max-width: 400px; margin: 2em auto; }
    form { display: flex; flex-direction: column; }
    label { margin-top: 1em; }
    input, button { padding: 0.5em; font-size: 1em; }
    button { margin-top: 1em; background: #4CAF50; color: #fff; border: none; }
  </style>
</head>
<body>
  <h2>Sign Up</h2>
  <form>
    <label>Name: <input type="text" name="name" required></label>
    <label>Email: <input type="email" name="email" required></label>
    <label>Password: <input type="password" name="password" required></label>
    <button type="submit">Create Account</button>
  </form>
</body>
</html>

这段 AI 生成的代码是注册表单原型的良好起点。它包含了基本布局和一些内联 CSS 样式。作为开发者,你不需要手写任何 HTML/CSS——只需描述想要的结果,AI 就会提供实现方案。这展示了意图编程(programming by intent):你专注于 UI 应该做什么,AI 会找出如何实现

当然,这只是一个简单的例子。在实践中,原型可能更复杂,涉及多个文件、框架或数据。但原理是相同的:使用 AI 快速创建初稿。然后你可以在浏览器中打开这个原型,查看效果并进一步优化。这引出了下一个主题:使用超越纯语言提示的专业 AI 原型工具。

AI 原型工具

虽然 Gemini、ChatGPT 和 Claude 等通用助手可以从提示生成原型代码,但专业 AI 辅助原型工具的生态系统持续快速发展。在我写作时,可用的工具提供了不同的方法来处理 AI 生成原型中保真度(fidelity)和控制度之间的基本权衡。

这个生态系统已经成熟到可以服务于不同的原型需求。一些工具擅长将视觉设计转换为代码,允许设计师上传截图或草图,并在几秒钟内获得可工作的 HTML、CSS 或 React 组件。这种”截图转代码”(screenshot-to-code)能力极大地加速了设计到代码的过程,特别是当你有手绘草图或 Figma 设计需要快速实现时尤为有价值。Vercel v0 等工具体现了这种方法,提供对原始设计的高保真度,同时在代码结构控制上做出一些权衡。

其他平台专注于通过对话界面生成完整应用程序。这些工具允许用户用自然语言描述功能并获得全栈实现。例如,想要在不编码情况下快速构建应用的设计师可能会使用 Lovable 或 Bolt.new 等工具,它们提供高级提示界面,可以搭建整个应用程序的脚手架。一些设计师报告称,使用这些工具在几小时内构建了传统上需要几天才能完成的功能原型,AI 自动处理繁琐的组件和模式。

第三类工具将AI直接集成到开发环境中,在原型设计阶段充当智能结对编程伙伴。这些AI增强的IDE(集成开发环境),如Cursor、Windsurf和Cline,允许开发者在代码生成过程中保持更多控制权,同时仍能从AI加速中受益。这些工具的区别通常在于工作流理念:有些优先考虑自动应用更改以实现快速实验,而另一些则要求明确接受修改以进行更谨慎的迭代。

所有这些方法的共同点是它们能够缩短从概念到工作原型的过程。然而,它们在两个关键维度上存在显著差异,这些维度决定了它们对不同用户和用例的实用性。

保真度(Fidelity)指的是生成的输出与你的输入或意图的匹配程度。截图转代码工具通常对视觉设计提供高保真度,但可能产生与你的架构偏好不一致的代码。对话式工具可能对你的需求解释得更宽松,生成功能性但通用的实现,需要进一步完善。

控制力涵盖你引导和修改生成过程的能力。有些工具像黑盒一样运作,产生完整的输出,而其他工具则允许通过持续对话或直接代码编辑进行迭代优化。当你需要特定的架构模式、性能优化或与现有代码库集成时,这个维度变得至关重要。

理解这些权衡有助于为你的原型设计需求选择合适的工具。验证新交互模式的设计师可能会优先考虑保真度和速度,接受对实现细节的较少控制。探索技术可行性的开发者可能更看重控制力和透明度,即使这意味着在生成过程中需要更多手动干预。

这些工具都不能在没有人工监督的情况下生成生产级质量的代码。它们通常提供我所说的”80%原型”——功能足以测试概念并向利益相关者演示,但需要额外工作才能用于生产部署。剩余的20%通常涉及安全加固、性能优化、错误处理和架构改进。

即使在快速原型设计期间,快速代码审查仍然是必不可少的。虽然你可能不会打磨原型中的每个细节,但扫描明显问题(如暴露的API密钥或不安全的数据处理)可以防止问题传播到后续开发阶段。大多数现代工具都提供对生成代码的透明度,允许你检查和理解正在创建的内容。

随着AI原型设计领域的持续发展,具体工具无疑会发生变化,但保真度与控制力之间的基本考虑,以及对人工监督的需求,将保持不变。关键是理解你的原型设计目标,并选择符合你特定需求的方法,无论是快速视觉实现、功能演示还是技术探索。

从概念到原型:迭代优化

AI驱动的原型设计的优势之一是迭代循环:你可以生成初始版本,然后通过与AI交互来完善它。无需手动编辑代码,你只需告诉AI你想要改变什么(见图6-1)。虽然我主张采用比纯粹的”凭感觉编码”更负责任的方法,但快速反馈循环绝对是原型设计中值得拥抱的特性。

每个人都应该对道德的AI使用负责;这是集体的努力,而不仅仅是某个时刻使用工具的个人的负担。为了将其正式化,考虑在你的团队或组织中指定一名”道德倡导者”或一个小型道德委员会。这个个人或小组不会是道德的唯一所有者(因为这一责任仍然是共同的),但他们将负责:

由于这个领域发展极快,团队合作以了解AI工具的新版本及其能力、局限性和负责任使用的演进最佳实践至关重要。

由于这个领域发展迅速,团队应共同努力以了解AI工具和最佳实践的新版本。一个需要整合到工作流程中的重要概念是使用模型卡(model cards)。模型卡本质上是提供机器学习模型透明度的标准化文档。可以把它们看作AI模型的营养标签。它们通常包括以下详细信息:

每当你使用预训练模型或评估模型以供使用时,查找其模型卡。如果你在微调或开发模型,创建自己的模型卡是最佳实践。

  1. 创建护栏和安全网。

    实践负责任的设计意味着你的AI生成系统应该有安全网。例如,如果AI建议一个可能掩盖潜在问题的越界索引修复,系统安全失败比导致静默错误要好。如果AI生成的推荐系统可能出错,提供用户纠正或覆盖的方式显示了对其人类自主权的尊重。努力构建在AI组件出现问题时能够优雅降级的系统。

  2. 在团队内部记录AI使用决策。

    保留一个内部日志,记录你为什么使用某些AI建议(或没有使用):“我们尝试将AI用于模块X,但它倾向于产生过多重复代码,所以我们手动编写了那部分。”这可以帮助你改进流程,为新团队成员提供关于AI在代码库历史中角色的背景,并增强团队的集体记忆。在审计期间这也很有用。

  3. 主动避免偏见、歧视和不公平。

    警惕AI使用可能导致歧视的迹象,并在这些情况发生之前努力避免。例如,如果你的应用是全球性的,你的AI是多语言的还是偏向说英语的人?你的所有团队成员是否都能平等地访问AI工具和培训?

负责任的AI检查清单

  1. 提示和代码生成(开发者)

  2. 代码审查检查(开发者和代码审查者)

  1. 治理和流程(组织)

如何使用此检查清单

随着AI领域的持续变化和发展,软件行业可能会引入AI标准或认证。虽然还处于早期阶段,但你的公司甚至可以通过参与标准化工作来帮助制定这些指南,比如IEEE或ISO关于AI软件工程的工作组。从伦理角度来看,由开发社区帮助制定规则比完全交给监管机构或法院更好。

总结与后续步骤

负责任的氛围编码(vibe coding)意味着以尊重所有利益相关者的方式将AI集成到软件开发生命周期中:原创作者(通过尊重他们的知识产权(IP))、同事(通过透明度和公平性)、用户(通过隐私、安全和结果的公平性)以及社会(通过防止滥用造成伤害)。这是关于利用AI的优势,同时勤勉地防范其弱点。

我经常说氛围编码不是低质量工作的借口。它也不是伦理捷径的借口。作为负责的人类,开发人员必须确保速度不会损害价值观。

接下来,第10章将探讨一项正在改变我们与AI模型工作方式的新技术:自主编码代理(autonomous coding agent)。

[1] 案件信息通常可以在法庭文档上找到,如美国加利福尼亚北区地方法院和第九巡回上诉法院的文档,或通过法律新闻媒体和案件跟踪器找到。

[2] 存在一些伦理上合理的例外。渗透测试人员和安全研究人员可以在负责任的披露协议下,合乎道德地使用AI来查找应该修复的漏洞。

第10章 自主后台编码代理

自主后台编码代理正在迅速成为AI编码工具的下一个演进。与你在输入时提供代码建议的熟悉”副驾驶”助手不同,这些代理的运作更像是你可以派遣去异步处理整个任务的后台初级开发人员。代码在为代理启动的隔离环境中生成,可以运行测试,结果通常作为一个完整的拉取请求(pull request)返回供你审查。

在本节中,我将探讨后台编码代理(background coding agents)是什么、它们如何工作、当前的工具格局(OpenAI Codex、Google Jules、Cursor、Devin等),以及它们与传统IDE内助手的比较。我还将研究它们的能力、局限性,以及它们对软件工程未来所预示的实际变化。

从副驾驶到自主代理:什么是后台编码代理?

传统的AI编码助手(如Cursor、GitHub Copilot或VSCode扩展如Cline)是监督式编码代理(supervised coding agents)——它们是交互式助手,响应开发者的提示或内联上下文。它们本质上是增强版的自动补全,在聊天中或在你编写代码时生成建议,但人类开发者仍处于主导地位,指导每一步。

相比之下,自主后台编码代理(autonomous background coding agents)具有更大的独立性。你给它们一个高层次的任务或目标,然后”让它们去工作”,让它们自己解决问题,无需持续监督。这些代理会读取和修改你的代码库,制定计划,执行代码(甚至运行测试或命令),并产生结果(通常是提交或拉取请求)——所有这些都在异步工作流中完成。

可以这样理解副驾驶和自动驾驶之间的区别:你的副驾驶(就像GitHub Copilot)始终在驾驶舱中陪伴你,等待你的输入;而自动驾驶(后台代理)可以独立驾驶飞机一段时间。这种自主性意味着后台代理可以处理多步骤的编码任务,而你可以专注于其他事情。使用像Codex和Jules这样的异步代理(async agents)就像扩展了你的认知带宽:你可以向AI发出任务,然后忘记它,直到完成为止。你不再是与AI进行单线程的来回交流,而是突然拥有了多线程工作流:代理与你并行工作,就像一个能干的初级开发者在后台工作一样。

关键的是,后台代理在隔离的开发环境(通常是云虚拟机或容器)中运行,而不是直接在你的编辑器中。它们通常会将你的代码库克隆到沙箱中,安装依赖项(dependencies),并拥有构建和测试项目所需的工具。为了安全起见,这些沙箱是受限的(比如”除非明确允许,否则不能访问互联网”)且是临时的。代理可以运行编译器、测试、代码检查工具等,而不会对你的本地机器造成任何风险。当任务完成时,代理会输出代码变更(差异)和它所做工作的摘要。通常这会以拉取请求的形式呈现(包含代码差异、提交消息,有时还有解释),你可以审查并合并。

总而言之,后台编码代理是一个由AI驱动的自主编码器,它理解你的意图,在沙箱环境中通过读写代码和测试来完成整个任务,然后交付结果供你审查。它不仅仅是建议一两行代码——它可以处理更大范围的任务:

这是我们将AI融入开发工作流方式的重大转变,从辅助性建议转向委托实际的实现工作

自主编码代理是如何工作的?

在底层,大多数后台代理遵循类似的操作模式:规划(plan)、执行(execute)、验证(verify)报告(report)。让我们逐步了解这些步骤及其能力。

规划

当你给代理一个任务(通常通过描述你想要什么的提示或命令)时,代理首先解析请求并制定攻击计划。一些代理在开始之前会明确向你展示这个计划。例如,Google的Jules会呈现一个执行计划,你可以在它开始编码之前审查和调整,这”可以防止你担心代理是否正确理解了你的请求”。一个好的代理会将任务分解为子步骤:

步骤1:搜索代码库中的相关部分;步骤2:在文件A、B、C中进行更改;步骤3:运行测试;步骤4:提交更改。

这个规划阶段是有效自主性的关键:这是AI在深入研究之前,对如何完成你的目标进行推理的方式。

该代理为任务启动一个专用开发环境。例如,Jules “将您的代码库克隆到安全的 Google Cloud 虚拟机中”,并在那里异步工作。OpenAI 的 Codex 类似地在自己的云沙箱中运行每个任务,预先加载您的存储库。Cursor IDE 的后台代理等工具使用具有互联网访问权限的远程 Ubuntu 机器来安装包,并可以通过 Docker 或快照进行自定义。确保环境具有所有需要的依赖项(如正确的语言运行时和构建工具)既至关重要又非常复杂。正如我在之前的分析中指出的那样,“找出一种流畅的体验来为代理启动恰到好处的环境是关键…而配置它的用户体验和 CI 管道一样令人沮丧,甚至更加令人沮丧。” 尽管如此,代理正在通过允许配置文件指定设置步骤来解决这个问题。目标是在云中创建一个开发环境,镜像人类开发人员成功运行项目代码和测试所需的环境。

值得注意的是,许多代理在设置后会禁用对其代码的互联网访问,因此可以沙箱化运行,而不会出现未经授权的数据泄露或不受限制的互联网调用。有些允许针对特定需求进行受控的互联网使用:例如,OpenAI 最近为 Codex 任务启用了可选的互联网访问,例如获取包更新或文档。

执行

接下来是主要内容:代理根据计划开始编写和修改代码。配备了为编码微调的大型语言模型(或模型组合),它可以读取多个文件、生成新代码,甚至在需要时创建新文件。这是代理本质上像程序员一样行事的地方:定位应该在哪里进行更改、编辑代码以及插入新逻辑。

早期运行中的一个有趣观察是,代理经常使用暴力文本搜索(如 Unix 的 grep 命令)来查找代码库的相关部分。例如,代理可能搜索函数名或关键字以找出在存储库中的何处进行更改。这似乎出奇地简单——它们不应该使用高级语义代码搜索或基于 AST 的分析吗?然而,它是有效且可靠的。正如 Birgitta Böckeler 所指出的,许多编码代理默认使用直接的全文搜索,尽管存在更先进的技术,但可能发现它是最广泛有效的方法。

当代理编辑代码时,一些系统会提供实时日志或状态更新,以便您可以根据需要跟进。OpenAI Codex 在处理任务时公开代理的”思考”和命令(摘要)日志。Cursor 允许您”查看它们的状态并进入代理正在运行的机器”以观察甚至在任务中途进行干预。但实际上,这个想法是您不需要照看——您可以让代理在自动驾驶模式下运行。

验证

这些代理的一个决定性能力是它们不会止步于编写代码——它们通常会编译代码并运行测试来验证它们的更改。例如,OpenAI 的 Codex 被设计为迭代运行测试,直到收到通过结果。如果代理可以运行项目的测试套件(或至少是测试的相关子集),它可以捕获错误并在后续迭代中自动纠正它们。这是巨大的:它将 AI 从仅仅生成代码转变为也调试验证其代码。

理论上,具有强大测试工具的代理可以尝试修复、看到测试失败、调整代码,并循环直到测试通过——无需人工干预。在实践中,环境问题有时会阻碍这一点。在我研究的一个案例中,Codex 由于环境不匹配(缺少某些工具)而无法运行完整的测试套件,导致提交的拉取请求仍有两个失败的测试。如果环境完全对齐,代理本可以在发起 PR 之前修复这些琐碎的问题。

这强调了为什么环境设置对自主代理如此重要:如果它们可以运行开发人员会运行的所有内容(linter、测试、构建),它们可以自动纠正许多错误。像 Devin 这样的代理强调这个循环——Devin “编写代码、在代码中发现错误、纠正代码,并运行自己的端到端测试以验证其工作”,这是其操作的正常部分。事实上,Devin 甚至会启动它构建的前端应用程序的实时预览部署,以便您可以在浏览器中手动验证功能,这是验证步骤的巧妙扩展。

报告

一旦智能体(agent)有了候选解决方案(所有测试都通过了,或者它认为代码已经准备好),它就会为你准备结果。根据平台的不同,这可能是 GitHub 上的 PR、聊天中的差异和解释,或者准备合并的文件。

此时,作为人类的你需要进行审查。这里我们回到”信任但验证”的原则:你信任智能体能产生有用的东西,但你通过代码审查和额外测试来验证这些更改。许多智能体系统明确集成了 PR 审查流程,因为这是开发人员熟悉的工作流。例如,Jules 会接入你的 GitHub,并为其更改创建一个分支和 PR。OpenAI 的 Codex 在 ChatGPT 中呈现差异,供你批准或提出后续问题。如果你发现问题或有变更请求,通常可以将反馈提供给智能体进行下一次迭代。

一些智能体通过聊天处理这个过程(Devin 可以从关联的 Slack 线程接收反馈:如果你指出问题或要求调整,它会”开始着手回复”来解决问题)。其他智能体可能需要使用调整后的提示重新运行,或使用审查评论界面。令人印象深刻的是,Devin 甚至会回应 GitHub PR 评论,询问它为什么做出某些更改——它会用”眼睛”表情符号表示看到了评论,然后发布对其推理的详细解释。(在那个案例中,解释并不完全正确,但它能够讨论 PR 这一事实说明了这些智能体可以变得多么具有交互性。)

如果一切看起来都很好,你就合并智能体的 PR 或集成这些更改。如果不好,你可能会放弃它或让智能体再试一次。团队面临的一个实际问题是,如果智能体的输出几乎不错但不完全正确,该怎么办。你是否要花时间修复智能体生成的补丁的最后 10%-20%,即使这是一个你外包给 AI 的低优先级任务?这就是我所说的 AI 贡献的”沉没成本”困境。Birgitta Böckeler 思考道,如果一个智能体 PR 只是部分成功,团队将不得不决定”在哪些情况下会放弃拉取请求,在哪些情况下会投入时间让它完成最后 20%“,而这个任务最初并不值得花费太多开发时间。没有唯一的答案——这取决于更改的上下文和价值——但这是自主智能体引入的一种新的权衡。

总之,后台编程智能体处理编程任务的端到端循环:理解 → 规划 → 编码 → 测试 → 交付。它们本质上模拟了一个勤奋、有条理的开发人员在分配任务时可能会做的事情,尽管是在当前 AI 的限制范围内(见图 10-1)。

图 10-1. 自主 AI 智能体工作流:自主导向的智能体规划任务、执行解决方案、验证结果并报告成果,只需最少的人工干预。

后台智能体与 IDE 内 AI 助手相比如何?

值得在我们使用了几年的编程 AI 工具(GitHub Copilot、ChatGPT 编程模式等)和这一代新的自主智能体之间划清界限。两者都很有用,但它们扮演不同的角色,有不同的优势和劣势。

最明显的区别是它们的自主程度。IDE 内助手如 Copilot 或 VSCode 的 AI 扩展与你同步工作——它们在被调用时生成建议或回答问题,它们的范围通常限于即时上下文(如你正在编辑的文件或函数,或你给出的特定提示)。决定何时接受建议、请求另一个建议或应用更改。

使用后台代理(background agents)时,一旦你对某个任务点击”开始”,代理将自主执行数百个可能的操作(文件编辑、运行、搜索),而无需进一步确认。它以异步方式运行。这需要更高程度的信任(你让它自行更改内容),但也使你摆脱了微观管理。我经常将其描述为拥有AI结对程序员与AI助理开发人员之间的区别。结对程序员(Copilot)与你一起逐个按键工作;而助理开发人员(Codex/Jules等)则在另一个问题上并行工作。

AI工具的copilot风格意味着它们擅长微任务—编写函数、完成一行代码、生成小代码片段、回答关于如何使用API的问题。它们不会维护长篇叙述或项目级的理解,除非是编辑器中打开的文件或有限的窗口内容。

自主代理在项目级别运行。它们加载你的整个代码仓库(或至少对其进行索引),并可以跨多个模块进行协调更改。它们跟踪多步骤计划。例如,GitHub Copilot可能在你提示时帮助你编写单元测试,但后台代理可以自主决定在一个文件中添加相应的实现,在另一个文件中添加测试,在第三个文件中修改配置—所有这些都作为一个统一任务的一部分。这使得代理更适合处理诸如重构横切关注点(logging、错误处理)、执行升级(通常涉及多个文件)或实现涉及后端和前端的功能等任务。IDE助手无法轻松处理这些,因为它们缺乏长期任务记忆和全仓库可见性。

Copilot风格的助手是被动的—它们响应你的代码或查询。它们不会主动发起操作。后台代理是主动的,一旦激活,它们将主动采取行动以达到目标。Jules或Devin代理可能会决定”我需要在这里创建一个新文件”或”让我现在运行测试”,而无需在每一步都被明确告知。它们还可以主动通知你事情,例如:

我在另一个地方找到了应用此更改的位置,所以我也会包含它。

它们的行为更像一名员工,可能会说:“我在代码中注意到X,所以我也修复了它。”也就是说,自主性也意味着它们可能会做一些你没有预料到或不一定想要的事情。这种工具的监督性质意味着它只会执行你接受的操作(除了可能存在你没注意到的细微错误建议)。因此,强大的能力(主动性)伴随着更大监督的需求。

一个主要区别是后台代理可以执行代码和命令,而传统的IDE助手通常不能(除非你算上ChatGPT的代码解释器模式之类的功能,但那更多用于数据分析,而不是与你的项目构建集成)。

代理会运行你的测试套件、启动开发服务器、编译应用程序,甚至可能部署它。它们在沙箱中运行,但实际上就像拥有一个可以使用终端的自动化开发人员。这改变了游戏规则—它完成了验证/修复的循环。IDE助手可能生成看起来合理的代码,但如果它实际上没有运行它,可能会存在运行时问题或测试失败。

使用运行代码的代理,你有更大的机会获得实际可用的输出。它还卸载了调试步骤;如果出现故障,代理可以立即尝试修复它。反过来说,这要求代理的环境正确(如前所述),并且为潜在的副作用打开了大门。想象一下代理运行数据库迁移或修改数据—通常它们处于沙箱模式,所以这不会影响生产环境,但要小心。

GitHub Copilot 和类似工具运行在编辑器中,这对于流畅的编码体验非常有用。代理(Agent)通常还会与项目管理和 DevOps 工具集成。例如,你可以创建一个 GitHub issue,让代理接手并生成 PR,或者从 CI 流水线触发代理运行来完成特定任务(如自动修复 PR 上的 lint 错误)。事实上,CodeGen 宣传其代理能够连接到问题跟踪器,当问题状态变为”进行中”时,AI 代理就会开始处理它。这种集成超出了 IDE 工具的范围。这暗示 AI 代理可以成为 CI/CD 循环的一部分——例如,自动尝试修复构建失败或自动为小问题创建后续 PR。这是一种不同的协作模式:不仅仅是帮助开发者编写代码,而是作为团队工具链中的机器人用户。

使用 copilot 类型的助手通常仍然像编程,只是更快——你输入,它们建议,你接受,你测试。使用后台代理更像是委托后再审查。人工工作从编写代码转向编写好的任务描述,然后审查生成的代码。我将此称为”生成者与审查者不对称”(generator versus reviewer asymmetry)——从零开始生成解决方案(或代码)很难,但审查和改进它更容易。异步代理利用了这一点:它们处理大量生成工作,留给你(通常更快的)审查和调整工作。这可以大幅提升生产力,但也意味着作为工程师,你需要提升代码审查和验证技能。

代码审查一直很重要,但现在不仅仅是审查其他人类同事的代码——还包括 AI 生成的代码,这些代码可能有不同的错误模式。我的原则是:你应该把代理生成的代码当作一个稍微过于热心的初级开发者写的:假设意图良好且能力尚可,但要验证一切,如果不符合标准,不要犹豫请求修改或拒绝。

在实践中,我发现我会同时使用 copilot 风格的工具和后台代理。例如,当我主动编写复杂逻辑时,我可能会使用 Copilot 或 Cursor 的内联建议,因为我想对该逻辑保持严格控制。同时,我可能会将外围但耗时的任务(如为新端点更新所有 API 客户端库)委托给后台代理并行处理。它们填补不同的需求。一个不一定取代另一个。事实上,我预见 IDE 将提供统一体验:一系列选项,从”完成这一行”到”生成一个函数”到”嘿,AI,请帮我实现整个工单”。你可以根据范围选择工具。

组合多个 AI 模型以最大化优势

到目前为止,我经常把”AI”称为一个单一的助手。实际上,有许多 AI 模型,各自有不同的优势。有些擅长自然语言理解,其他擅长生成代码,还有些可能专注于特定领域(如数学问题求解器或 UI 生成器)。氛围编码(vibe coding)的高级实践者可以协调多个 AI 一起工作,让每个 AI 做它最擅长的事。这就像拥有一个专家团队,而不是单个通才。

考虑一个未来的工作流程,你拥有:

你可以通过这些 AI 来传递你的任务。例如,你让 CodeGen AI 编写实现。然后立即将输出提供给 TestGen AI 来为其生成测试(或进行批评)。然后将代码和测试都提供给 Doc AI 来生成文档或使用指南。如果代码涉及用户界面,也许 Design AI 会更早使用来提出布局结构,然后 CodeGen AI 再实现它。通过链接它们,你利用每个模型的领域专长。这类似于软件流水线或装配线,但不是不同的人类角色,而是不同的 AI 角色。

即使在相似的模型之间,组合它们也能提高可靠性。如果你有两个来自不同提供商或不同架构的代码生成模型,你可以让它们都尝试解决方案,然后比较或测试两个输出。如果一个模型的输出通过了所有测试而另一个没有,你就选择通过的那个。如果两个都通过但采用了不同的方法,你可以手动选择更易读的那个。如果一个失败了,你甚至可以向失败的模型展示成功的代码作为学习提示。这种AI交叉对话可以减少错误,因为两个不同的模型不太可能犯完全相同的错误。这就像获得第二意见。你已经可以找到使用一个AI检查另一个AI推理的研究和工具——例如,一个生成答案,另一个评判它。

按任务类型区分模型

使用正确的工具来完成工作。大型语言模型(LLMs)是很好的通才,但有时较小的专用模型或工具表现更好。例如,对于算术或某些算法,确定性工具(或更受约束的AI)可能更好。一些高级开发设置将符号求解器或旧的基于规则的AI用于特定子任务,而将LLMs用于其他任务。作为高级vibe程序员,你可能会维护一个工具箱:当你需要正则表达式时,你调用一个专门的正则表达式生成器;当你需要提交消息时,可能使用一个针对摘要进行微调的模型。优点在于这些可以通过简单的脚本或提示包装器集成。例如,你可以有一个本地脚本如ai_regex_generator,它在内部提示AI,但带有一些预处理和后处理来确保输出是有效的正则表达式,并可能在提供的示例上测试它。

使用编排系统

如果你发现自己经常组合模型,你可能会使用或构建一个编排系统(orchestration system),这是一个新兴的框架类别,通常被称为AI编排代理(agents)。这些系统允许你定义一个流程;例如:

步骤1:使用模型A解释用户请求。

步骤2:如果请求是关于数据分析的,使用模型B生成SQL;如果是关于文本的,使用模型C…

步骤3:将结果提供给模型D进行解释。

如果你正在构建由多个AI步骤驱动的应用或服务,这会更相关。但即使在个人开发中,你也可以编写多步骤方法的脚本。例如,一个自定义CLI工具ai_dev_assist,接受一个提示,在幕后使用AI将提示分类为codedesigntestoptimize等类别。根据类别,它将提示转发给相应的专业AI。当它收到结果时,可以选择将结果传输到另一个AI进行审查或改进。

这种协调其他AI的元AI听起来很复杂,但高级用户可以使用现有技术设置它。随着我们开始看到IDE或云平台的专门支持,这可能会变得更容易。

人类-AI混合团队

在谈论多种智能的主题时,我们不要忘记人类协作者。高级vibe程序员也知道何时让其他人类开发者参与进来。例如,你可以使用AI为一个功能生成两到三个不同的设计原型,然后将这些原型提交给团队的UX设计师征求反馈。哪一个符合我们的品牌?哪一个感觉直观?如果AI编写了一段复杂的代码,你可能会与同事进行代码审查会议,重点关注那段代码,承认”AI帮助编写了这个,所以我也想要另一双人眼来审查它”。从某种意义上说,“多模型”方法可以将人类也包括在内,作为高度先进的模型——每个实体(人类或AI)都有独特的优势。未来的开发可能经常是人类+AI结对编程,甚至是团队编程,其中一些”团队成员”是AI。

想象一下通过vibe编码构建一个小型Web应用程序。你的工作流程可能如下所示:

  1. 你使用UI布局AI根据描述生成页面的HTML/CSS(专门用于前端)。

  2. 你使用内容AI生成所需的一些占位符文本或图像(如营销文本,可能使用面向文案写作的模型)。

  3. 然后你使用主要的代码AI生成JavaScript中的交互功能,向它提供HTML,以便它知道要连接到哪些元素ID。

  4. 然后你要求测试AI为界面交互生成Selenium或Playwright测试。

  5. 最后,你使用安全 AI 扫描代码以检查常见漏洞。这可以是一个模型,也可以是一个由 AI 增强的静态分析工具。

这种多模型方法在一个集成流程中涵盖了前端、后端(如果有的话)、内容、测试和安全。每个 AI 处理其各自的部分,而你作为协调者,确保它们全部保持一致。

虽然今天你可能需要手动将一个工具的输出复制到另一个工具,或使用一些粘合脚本,但未来的 IDE 可能会让你配置这个流水线,使其感觉无缝衔接。关键要点是:如果你可以访问多个 AI 模型,不要只依赖一个。针对每项工作使用最好的模型,并让它们协同工作。这会带来更好的结果,也减少了单点故障——如果一个模型不擅长某些事情,另一个可能会弥补这个弱点。

组合 AI 模型是一个高级操作,但它是专业化原则的逻辑延伸,这一原则在软件工程中众所周知(想想微服务,每个服务做好一件事)。在这里,每个 AI 服务做好一件事。作为 vibe coder(氛围编码者),你的角色扩展为 AI 指挥家,而不仅仅是 AI 提示者。这需要更多的设置和思考,但回报是一个 AI 协作者的交响乐,每个都为高质量的最终产品做出贡献。

现在你知道它们如何工作了,让我们来看看一些领先的例子,看看它们如何表现。

自主编码代理的主要参与者

在我写这篇文章的 2025 年,自主编码代理领域在过去一年中迅速发展,不同平台上出现了独特的方法。这些工具代表了从被动完成代码到作为能够独立执行复杂任务的主动开发伙伴的转变。

基于云的命令行代理:OpenAI Codex

OpenAI 的 Codex 体现了基于云的代理方法,通过 ChatGPT 的界面或开源 CLI 运行。它启动隔离的沙箱来并行执行编码任务,处理从 React 升级到单元测试创建的所有事情。Codex 的独特之处在于它在真实编码任务上的强化学习训练,使其能够遵循最佳实践,例如迭代运行测试直到通过。虽然结果可能在运行之间有所不同,但 Codex 通常会收敛到对于边界明确的任务的可行解决方案。它的优势在于在类似 CI 的环境中实际执行代码,代表了第一波真正与开发流水线”配对”的代理。

工作流集成代理:Google Jules

Google Jules 采用不同的方法,深度集成 GitHub 工作流。Jules 在 Google Cloud VM 上运行,具有完整的仓库克隆,强调可见的、结构化的规划——展示其推理过程并允许在执行前修改计划。这种”先规划,再执行”的理念,结合实时反馈能力,将 Jules 定位为受监督的助手而不是黑盒自动化。它的 GitHub 原生设计意味着它直接在团队工作的地方运行,创建分支和 PR 而无需切换上下文。该代理甚至尝试了新颖的功能,如音频变更日志,指向更易访问的代码审查流程。

IDE 集成代理:Cursor

Cursor 的后台代理代表了以 IDE 为中心的方法,直接从编辑器启动但在远程机器上执行。这种混合模型让开发者从他们的指挥中心编排多个 AI 工作者,同时保持本地控制。Cursor 提供具有可定制环境的 Ubuntu 实例(通过 environment.json 或 Dockerfiles),为代理提供完整的互联网访问和软件包安装能力。关键创新是无缝的 IDE 集成:开发者可以监控代理进度,在需要时进行干预,并在完成时立即在本地访问更改。这种方法模糊了本地 AI 辅助和云执行能力之间的界限。

团队集成代理:Devin

Devin作为AI队友

Devin 将自己定位为”AI队友”而非仅仅是一个工具,它与Slack、GitHub和Jira等问题跟踪器集成。由Cognition Labs构建,它使用专为长期推理和多步骤执行调优的定制AI模型。Devin擅长并行执行小型维护任务,如错误修复、测试添加和代码检查清理等经常被降低优先级的工作。其协作设计包括状态更新、澄清请求,甚至自动预览部署。虽然它能很好地处理简单任务,但复杂问题仍可能需要大量人工干预,这凸显了当前自主编码的边界。

该领域正在快速扩张,老牌企业和初创公司都在竞相定义这一类别。微软已暗示将推出”Copilot++“,从内联建议转向代理能力。CodeGen等初创公司(使用Anthropic的Claude)向企业承诺提供”永不休息的软件工程师”。与此同时,开源项目和学术研究继续推动边界,探索如何使代码生成更加可靠和符合上下文。

这种激增表明我们正在见证一种新的开发范式的诞生,单个开发者可以编排多个AI代理,每个代理专门负责软件生命周期的不同方面。出现的关键差异点包括:

挑战与局限

虽然自主编码代理继承了AI辅助开发的基础性挑战,正如本书中讨论的那样——特别是第3章探讨的70%问题——但它们的自主特性引入了值得单独研究的独特复杂性:

顺序决策的复合效应

与人类在每一步都进行干预的交互式AI辅助不同,自主代理会做出一连串决策,这些决策可能以独特的方式复合错误。当代理误解初始需求时,它不仅仅生成一个有缺陷的函数:它会基于这种误解构建整个实现架构。每个后续决策都会强化最初的错误,创造出我所说的”连贯的错误性”(coherent incorrectness):代码内部一致但从根本上与实际需求不符。

这种顺序决策特别挑战处理多文件更改的代理。实现新功能的代理可能正确修改了后端API,但随后通过前端、数据库模式和测试套件传播了错误的假设。当你审查完整的拉取请求时,解开这些相互关联的错误往往比传统AI辅助可能实现的交互式、增量式纠正需要更多努力。

规模化的环境脆弱性

虽然第8章讨论了一般的环境配置挑战,但自主代理从其沙箱执行模型中面临独特的复杂性。每次代理运行都需要启动一个精确镜像你开发设置的隔离环境——这是一个扩展性很差的挑战。当你并发运行多个代理时,即使是环境中的轻微变化也可能导致截然不同的结果。

考虑这样一个场景:五个代理同时处理不同的功能。代理A的容器中可能有一个稍旧的Node版本,代理B可能缺少特定的系统库,代理C可能有不同的时区设置。这些在执行期间不可见的变化,在你开始集成它们的工作时会表现为微妙的错误。这种代理沙箱之间的”环境漂移”(environmental drift)代表了单开发者工作流中不存在的新一类集成挑战。

异步协调悖论

自主代理承诺并行开发,但这引入了与人类团队动态截然不同的协调挑战。当多个代理修改重叠的代码部分时,它们缺乏人类使用的隐式沟通渠道——没有快速的Slack消息询问”你在处理认证模块吗?“或对同事正在做什么的非正式感知。

这创造了我所说的异步协调悖论(async coordination paradox):你并行运行的代理越多以提高生产力,集成它们就变得越复杂。与通过站会和非正式沟通自然协调的人类开发者不同,代理是孤立运行的。你可能会发现代理A重构了一个实用函数,而代理B正忙于向旧版本添加新调用,创造了如果代理具有人类开发者对彼此工作的自然感知就不会发生的冲突。

审查瓶颈——放大

为有效使用AI编码代理的最佳实践

虽然代码审查(code review)对所有AI生成的代码仍然至关重要(如前面章节所讨论的),但自主代理(autonomous agent)通过庞大的数量和时机放大了这一挑战。与交互式AI辅助不同——代码在你工作时逐步到来——代理生成的PR以完整的实现形式出现,通常是在通宵运行后同时到达的多个PR。

这创造了一种不同于审查人类PR时的认知过载。对于人类贡献,你通常可以依赖提交消息和PR描述来反映编码者的实际思维过程。然而,代理PR要求你从代码本身反向推导代理的”推理”。当五个代理在周一早上各自提交500行或更多代码的PR时,审查负担从协作质量检查转变为更像是考古探险。

委托给代理需要信任

也许最重要的是,自主代理以交互式AI工具所没有的方式挑战我们的信任模型。当你将任务委托给代理并离开时,你在对可接受的风险做出隐含的赌注。这与有监督的AI辅助根本不同,后者让你保持每时每刻的控制。

考虑代理技术的安全影响。具有仓库写入权限和执行能力的自主代理呈现出独特的攻击面。被攻破或误导的代理不仅仅是建议糟糕的代码,它会主动提交代码,甚至可能部署它。我们对代理的沙箱化和访问控制必须比基于建议的工具更加复杂(在第8章中介绍)。

新兴的组织挑战

随着团队扩大其代理使用规模,正在出现传统AI辅助所不存在的新组织模式。当请求的开发人员生病时,谁”拥有”代理生成的代码?你如何跨团队跟踪代理资源使用?当代理的一个月长的重构项目与紧急功能开发冲突时会发生什么?

这些不是技术限制,而是组织挑战,并且它们是自主系统独有的。它们需要新的角色(代理协调员?)、新的流程(代理影响评估?)以及新的工具(代理集群管理?),这些超出了本书在早期章节中讨论的个体开发者考虑因素。

这些代理的自主性——它们独立工作、做出连续决策和大规模操作的能力——将它们从生产力工具转变为类似团队成员的东西。这种转变不仅需要本书中讨论的技术实践,还需要全新的协调、信任和集成框架,而我们才刚刚开始理解这些。

有效使用AI编码代理的最佳实践

虽然许多通用AI开发实践适用于自主编码代理,但基于代理的开发的某些方面需要特别考虑。基于Codex、Jules、Devin和Cursor的后台代理等工具的集体经验,这些实践解决了将整个开发任务委托给独立运行的AI系统的独特挑战。

战略性地选择自主代理将要实现的任务

AI助手和自主代理之间的根本区别在于它们的范围和独立性。代理擅长具有明确成功标准的、定义明确的、封装良好的任务——特别是那些涉及并行执行许多小任务的任务。理想的代理分配包括全面的测试覆盖率改进、系统化的依赖项更新、批量重构操作以及跨多个组件的标准化功能实现。

考虑要求AI助手帮助编写单个测试与要求代理在整个模块中实现80%测试覆盖率之间的区别。代理可以有条不紊地遍历每个未测试的函数,生成适当的测试用例,运行它们以验证正确性,并迭代直到达到覆盖率目标。这种系统化、可衡量的工作是自主代理的最佳选择。

相反,需要做出重大架构决策、解释复杂利益相关者需求或设计新颖算法的任务仍然更适合由人类主导的开发与AI辅助。关键在于识别较大任务的哪些方面可以有效地委托给代理,哪些需要人类的判断和创造力。

利用特定于智能体的规划和监督功能

现代自主智能体(autonomous agents)通过复杂的规划和执行透明度功能来区分自己,这些功能需要主动参与。当Jules在开始工作之前展示其执行计划,或者当Cursor显示智能体活动的实时日志时,这些代表了基于智能体开发所特有的关键干预点。

规划阶段是你的主要质量关卡。审查提议的计划不仅要看正确性,还要看效率以及与代码库约定的一致性。如果Jules计划更新Next.js应用程序但遗漏了关键的webpack配置更改,在规划期间发现这一点可以防止后期的大量返工。这种主动审查与被动代码审查有本质区别,代表了开发者工具包中的一项新技能。

运行时监控提供了另一层特定于智能体的监督。虽然你不需要观察每一个操作,但定期检查可以防止智能体追求低效的解决方案或进行不必要的广泛更改。Cursor能够在任务执行中途”进入”智能体的环境,这体现了现代工具如何支持干预而不完全放弃自主工作流。为了最大化效率,你需要学会何时介入,何时让智能体自我纠正。

管理并发智能体操作

与传统开发不同,传统开发中单个开发者一次只做一项任务,而智能体实现了真正的并行开发。这种能力需要新的协调策略。当同时运行多个智能体时——也许一个在更新依赖项,而另一个在添加日志基础设施——你必须考虑它们工作之间的潜在冲突和依赖关系。

为每个智能体的范围建立明确的边界,以最小化合并冲突。尽可能将智能体分配到应用程序的不同模块或层。考虑集成顺序:添加新功能的智能体可能需要等待另一个智能体的基础设施改进完成。这种编排更像是管理分布式团队,而不是传统的单人开发。

演进团队实践以集成智能体

自主智能体的引入从根本上改变了团队动态和审查流程。与审查同事精心制作的PR不同,智能体生成的PR可能包含技术上正确但风格不一致的代码。团队必须制定新的审查实践来应对这种差异。

考虑建立特定于智能体的审查清单,不仅强调正确性,还强调与团队约定和架构模式的一致性。记录你在与智能体合作时发现的常见怪癖:也许你选择的智能体始终使用某些反模式(antipatterns)或错过特定的优化机会。这种组织知识帮助审查者快速识别和解决反复出现的问题。

与自主系统建立反馈循环

也许最重要的是,自主智能体实现了一种新形式的迭代开发,其中反馈循环超越了单纯的代码审查。当智能体的拉取请求需要改进时,你通常可以将其发回并要求根据具体指导进行另一次迭代。这与传统开发不同,在传统开发中,将工作退回给人类同事会带来社交和时间成本。

努力开发与你选择的智能体配合良好的提示模式(prompting patterns)。当你发现能够持续产生高质量结果的成功提示公式时,将其记录下来。为常见任务类型创建模板,包括所有必要的上下文和约束。这是一种专门针对智能体的提示工程(prompt engineering),它考虑了智能体的规划、执行和修订周期,代表了一项不同于一般AI交互的独特技能。

目标保持不变:高效地交付高质量软件。自主智能体只是提供了实现这一目标的新工具,你应该深思熟虑地将其集成到现有实践中,而不是全盘替换已建立的方法。通过理解这些智能体并利用它们的独特能力,同时保持严格的质量标准,团队可以在不牺牲代码质量或架构完整性的情况下实现显著的生产力提升。

总结与后续步骤

总结一下,我想呼应[第4章]中的一个观点:AI不会取代开发者,但能够有效使用AI的开发者很可能会取代那些不能的人。自主编码代理(autonomous coding agents)的出现是朝这个方向迈出的一大步——那些学会驾驭这些”无头同事”的人将能够用更少的时间完成更多的工作。对于软件工程师来说,这是一个激动人心的时代,只要我们适应并继续保持高标准。工具可能在变化,但目标依然不变:构建可靠、高效和创新的软件。有了AI代理在我们身边(或在后台),我们有了实现这些目标的新方式——也许还能在机器人们通宵工作时好好睡一觉。

接下来,本书的最后一章将更广泛地展望AI在编程中的未来,包括代理式AI的未来。

第11章 超越代码生成:AI增强开发的未来

Vibe编程可能始于AI根据我们的提示生成代码,但其影响远远超出了编写代码本身。随着AI技术的进步,它们有望改变软件开发生命周期的每一个方面。在本章中,我将以推测但有根据的方式展望AI在软件中的角色如何在未来扩展。我将探讨AI驱动的测试、调试和维护;AI如何影响软件设计和用户体验个性化;AI辅助下项目管理的演进;甚至编程语言本身的未来。目标是想象一个未来,在那里AI不仅仅是代码生成器,而是软件工程的全方位参与者——同时将讨论建立在基本原则之上,使其在特定技术不断变化的情况下仍然保持相关性。

AI在测试、调试和维护中的应用

想象一下未来的开发环境,当你编写一个函数时(无论是手工编写还是通过vibe编程),AI工具会立即为它编写一套单元测试,发现潜在的bug,甚至可能修复它们——所有这些都在几秒钟内完成。这种场景正在迅速变得可行。让我们分解一下AI在质量保证和维护方面的潜力(以及已经出现的)贡献。

自动化测试生成

编写全面的测试既耗时又常常因截止日期而被忽视。正如你在[第7章]中看到的,当前的AI助手可以通过自动生成测试来缓解这个问题。例如,给定一段代码,AI可以建议一组涵盖典型情况、边界情况和错误条件的单元测试。

在未来,这可能会更进一步:AI可以检查你的整个代码库,识别测试覆盖率不足的函数或模块,并生成额外的测试。它甚至可能模拟人类测试人员不会想到的输入(如模糊测试),从而可能捕获边界情况的bug。好处是以最少的手动测试编写获得更健壮的代码库。

需要注意的是,测试的质量取决于AI对规范的理解。因此,人类应该审查AI生成的测试,以确保它们符合软件的预期行为。例如,AI可能会断言某个输出在技术上是代码所做的,但也许需求是不同的——只要有人在循环中,这实际上可以帮助在代码或测试中捕获误解。

智能调试

调试通常涉及繁琐的日志搜索或逐步执行代码以定位错误源。[第5章]向你展示了AI如何充当智能调试伙伴。一些当前的AI工具可以将错误消息和有问题的代码作为输入,返回解释和修复它的代码更改。

要了解AI辅助调试工作流可能如何演进,可以考虑一个监控程序执行的AI系统,当发生崩溃或异常时,它会分析堆栈跟踪和变量状态以确定可能的原因。它可能不只是给你一个错误消息,而是说:

应用程序崩溃是因为在调用getEmail()时userProfiles为null。这表明在加载用户配置文件时缺少空值检查。

此外,AI可以建议修复方案:

一个可能的解决方案是在userProfiles为null时初始化它,或者在调用getEmail()之前添加一个条件。您想让我应用这个修复吗?

未来的调试AI可以直接与运行时环境集成,实时捕获问题。它们甚至可能通过分析代码路径在问题发生之前预测问题:

如果使用y = 0调用此函数,可能会抛出除零异常;请考虑处理该情况。

这类似于静态分析,但由AI从无数代码库和错误模式中学到的知识提供支持,使其可能更有洞察力或更灵活。

预测性维护和重构

随着需求随时间变化,代码会变得过时或次优。维护涉及诸如重构(在不改变行为的情况下改进代码结构)、更新依赖项和优化性能等活动。AI可以在这些领域中提供帮助:

重构

未来的AI可以识别代码异味(如重复代码或过长函数)并自动重构它们。例如,它可能检测到你在三个地方有相似的代码块,并建议将它们抽象为单个辅助函数。或者它可以将深度嵌套的循环转换为更易读的形式。由于AI已经看过许多”好”代码的示例,它可以建议风格改进以保持代码库的整洁和可维护性。我们可能有一天会在编辑器中拥有一种模式,AI在后台持续重构代码,开发人员审查和批准更改。

更新依赖项

未来的AI服务可能会监控你项目的依赖项(如库和框架),并自动生成拉取请求(pull request)以将它们更新到更新版本,包括适应破坏性更改所需的任何代码更改。例如,如果Web框架的新版本更改了API,AI可以将你的代码适配到新API。这将使开发人员免于阅读迁移指南和修复版本问题的重复工作。

性能调优

维护通常包括随着数据规模或使用模式变化而改进性能。AI可以通过分析性能配置文件并指出低效之处来发挥作用。例如,AI可能注意到代码中某个数据库查询耗时很长,并建议添加索引或重写查询。它可能识别出代码中的循环正在进行冗余计算并提议缓存。这类似于拥有一位性能专家始终关注你的应用程序——主动检测低效之处,如冗余循环或次优数据结构。

AI可能在预发布环境中运行,模拟高负载,然后向你提供报告:“在高负载下,模块X由于Y成为瓶颈。考虑使用方法Z进行重构。”本质上,AI不仅发现问题,还教育团队更好的模式。

AI驱动的设计和用户体验个性化

除了代码和逻辑之外,AI还将影响我们设计软件的方式以及用户体验软件的方式。好的软件不仅在底层是正确的;它还应该是直观的、易访问的,并让用户满意。AI将继续开发新方法来创建更好的用户界面并根据个人用户需求定制体验。

生成式设计工具

当今的AI设计工具使用生成对抗网络(generative adversarial networks)或变换器(transformers)的技术,从描述中生成UI模型。产品经理可以用自然语言描述功能:

我们需要一个移动注册界面,带有欢迎消息、有趣的插图,以及姓名、电子邮件和密码的表单。它应该使用我们的品牌颜色并具有友好的外观。

AI设计助手可以接受这个描述,并在几秒钟内生成几个候选UI设计,包括布局、占位符文本,甚至样式化组件。然后设计师或开发人员选择最接近的一个并进行完善。

未来,这些工具可以直接集成到设计软件甚至编码环境中,使”设计”和”编码UI”之间的界限变得模糊。AI可能直接输出它生成的设计的HTML/CSS或Flutter代码,使其可以立即测试。这将极大地加快设计迭代周期。你不再手工或在软件中绘制草图,而是与AI协作,AI基于最佳实践和用户认为有吸引力或可用的大量训练数据来提议设计。

即使在设计的创作过程中,AI也可以成为灵感来源。当设计师为应用程序头脑风暴配色方案或插图风格时,AI工具可以生成颜色情绪板,甚至即时创建自定义图标。例如,他们可能告诉AI:

我需要一个结合代码和音乐理念的标志。

它会生成几个将编程符号(如花括号)与音符混合的示例logo。虽然专业设计师最终可能会手工制作最终资产,但AI的建议可以激发灵感并加速探索阶段。从本质上讲,AI可以扮演快速原型制作者和创意伙伴的角色,拓宽设计师的选择范围。

需要注意的是,在设计和UX领域,人类判断至关重要。审美品味、对人类情感的理解、品牌识别——这些是AI可以近似但无法真正拥有的东西。因此,设计中的AI是增强人类创造力的工具,而不是取代它。它可以处理生成变体和处理用户数据的繁重工作,让设计师专注于同理心和创意决策。

对于开发者来说,AI驱动的设计意味着设计和开发之间的传统交接可能会变得更加流畅。开发者可以与设计师合作使用AI生成UI代码,反之亦然。这也意味着前端开发者可能会花更少的时间逐像素调整布局,而将更多时间用于确保设计与功能保持一致并以可访问的方式实现。他们还可能致力于创建个性化的钩子(hooks)——编写允许AI根据用户数据在布局A或B之间进行选择的代码,并确保两种布局都具有良好的性能和稳定性。

在vibe coding的未来,你也可以进行”vibe design”:只需描述你想要应用程序外观和感觉的氛围(vibe),AI就会帮助将其具体化。结果是一个整体的AI开发流程——不仅仅是在AI辅助下编写后端逻辑或数据库查询,而是与AI合作打造整个产品体验。

AI用于UX研究

设计的另一个方面是理解用户行为。AI可以分析你应用程序的使用数据(考虑到隐私因素),突出显示用户遇到困难的地方。例如,AI可能检测到许多用户将鼠标悬停在某个图标上,期望它可以点击,但实际上不能——这表明存在UX改进的机会。或者它可能注意到来自某个特定人口统计群体的用户始终在工作流程的某个特定步骤流失,这表明该步骤对他们来说可能不够直观。

在未来,AI甚至可以模拟用户交互(使用用户行为模型),在真实用户遇到UX问题之前预测这些问题。这种”虚拟UX测试”可以在开发过程中捕获诸如过于复杂的导航或不清晰的标签等问题,此时修复它们更容易。

个性化用户体验

个性化(Personalization)已经成为一个热门词汇有一段时间了——即根据偏好或历史记录向不同用户提供不同内容的意义上。AI可以将个性化提升到新的水平,通过实时微调每个用户的软件行为和界面。例如,应用程序的AI可以了解到某个特定用户倾向于通过搜索而不是菜单来导航应用程序。然后AI可以通过为该用户使搜索栏更突出来进行调整,甚至可以根据上下文预加载它预期用户可能想要的搜索结果(就像人类助理预测老板的需求一样)。

另一种情况可以改善可访问性:如果AI检测到用户正在使用屏幕阅读器技术(因此可能存在视觉障碍),它可以自动将应用程序切换到高对比度、大字体模式,并优化屏幕阅读器标签,甚至超越静态可访问性设置可能做到的。从本质上讲,软件可以变得具有适应性(adaptive)。

想象一个电子商务网站可以即时重新排列其布局——一些用户可能会看到产品网格,而另一些用户则看到包含更多详细信息的列表,这取决于什么似乎更能吸引他们。这些变化可能是微妙且持续的,因为AI会进行实验和学习——有点像A/B测试的工作方式,但是在个人层面上并且是自主的。

AI推动项目管理的演进

软件开发不仅仅是编写代码和制作设计;它还包括规划、协调和决策——这是项目管理和团队领导的领域。AI的分析和预测能力可以极大地协助项目管理,从任务分配到风险管理和决策支持。以下是AI如何重塑我们规划和执行软件项目的方式:

任务分配

管理一个团队需要了解每位开发者的优势、劣势和当前工作量,然后相应地分配任务。AI项目管理助手可以分析各种数据点——代码提交历史、专业领域(可能从开发者在代码库的哪些部分工作中获得)、甚至个人生产力模式(有些人在早上编码更有效率,其他人则在深夜)——并推荐谁应该处理新任务。

例如,如果一个新功能涉及数据库工作,而AI知道Alice成功完成了大量数据库相关任务且工作量不大,它可能会建议将任务分配给Alice。此外,AI可以通过将任务与过去的类似任务进行比较并考虑个人的工作速度来预测任务可能需要多长时间。这有助于项目经理设定更现实的时间表,避免过度负担任何单个团队成员。随着时间的推移,这样的AI可以学会像一个熟练的管理者那样平衡工作量,确保没有人闲置,也没有人不堪重负。

## 调度和冲刺规划

AI可以协助将高层目标分解为可操作的项目。你可以向AI提供一个功能请求或用户故事,它可以建议实现它所需的子任务列表。本质上,它可以生成一个草案计划或工作分解结构(work breakdown structure)。在冲刺规划(sprint planning)(在敏捷方法中),AI可以分析待办事项列表,并根据团队过去的速度,建议哪组任务适合下一个冲刺。

它甚至可以突出显示任务之间的依赖关系,确保计划在逻辑上是有序的:

任务B应该在任务A之后完成,因为它建立在该功能之上。

对于长期路线图规划,AI工具可能会模拟不同的场景:

如果我们现在优先考虑功能X,模型预测由于资源需求重叠,我们可能会将功能Y延迟2周。

拥有这些模拟和数据驱动的洞察可以帮助人类管理者在优先级方面做出明智的决策。

## 风险分析和管理

风险管理通常涉及预测可能出现的问题——延迟、技术障碍、集成问题——并规划缓解措施。AI非常适合模式识别,因此它可以分析历史项目数据(在公司内部或甚至整个行业,如果可用)来识别风险因素。

例如,AI可能会标记如下内容:

有了这些信息,管理者可以预先为这些阶段分配更多时间或资源。另一个角度是监控当前进度:AI系统可以监视任务完成率、bug发现率等,并在感知到问题时发送警报:

团队在本次冲刺中以预期速度的一半完成任务;可能存在需要关注的阻碍因素。

本质上,AI可以成为一个时刻警觉的项目审计员,在问题升级之前发现它们。

## 决策支持

项目管理涉及许多决策——比如是否削减功能以满足截止日期,或者是否投资重构而不是添加新功能。AI无法做出这些决策,因为它们涉及业务和人为因素,但它可以提供数据来支持它们。例如,如果在讨论重构时,AI可能会报告:

如果我们重构模块Z,基于复杂度指标和团队输入,它可以将相关功能的未来开发时间减少20%。现在可能会增加两周的延迟,但在六个月后会有回报。

虽然这些数字是估计值,但拥有客观的分析有助于利益相关者更具体地权衡取舍。

另一个例子可能是决定是采用一个新库还是自主开发。AI可以扫描该库的文档、社区支持和已知问题,并总结其优缺点,为团队节省数小时的研究时间。

## 自然语言状态查询

利益相关者或管理者有朝一日可以用自然语言向AI查询项目状态:

支付集成功能进展如何?有哪些阻碍因素?

AI在解析了工单更新、提交消息和测试结果后,可能会回答:

支付集成已完成70%。一个阻碍因素是与货币转换相关的失败测试,目前有两位开发者正在调试。如果明天解决,该功能有望在周五前完成。

这种易于访问的状态报告可以改善沟通,特别是在大型团队或有非技术利益相关者的团队中。AI基本上成为了一个无所不知的项目助手,了解所有细节并可以根据需要进行总结。

情绪和团队健康洞察

自主代理如何改变软件工程

我们仍处于这项技术的早期阶段,但它发展迅速。值得思考的是长期影响以及未来几年可能如何演变。以下是对自主编码代理时代软件工程未来的展望,基于当前趋势和一些有依据的推测:

AI 代理将成为开发团队的标准组成部分

就像今天使用源代码控制或 CI/CD 已成为标准一样,让 AI 代理参与开发可能会成为常规操作。每天早上检查”AI 助手看板”,查看代理在夜间完成的任务,这可能会成为正常现象——当你登录时,代码审查已经在等着你了。今天已经有了这方面的迹象,代理在”你睡觉时”运行。工程师可能会习惯在一天结束时委派一批任务,让 AI 在第二天早上之前尝试完成。“开发者工作”的含义将发生转变:减少输入样板代码或进行常规更新,更多地专注于定义问题、集成解决方案和指导 AI。可以说,开发者将更像是 AI 开发者的产品经理——他们指定需要做什么,并确保满足需求。

多代理协作将更加普遍

目前,每个代理基本上都是独立完成你分配给它的任务。但未来可能会出现多个具有不同专长的代理协作的场景。一个代理可能擅长前端任务,另一个擅长后端任务,你给它们分配一个协调任务(或者它们甚至可能自己找出如何分工)。或者,一个代理可以并行探索多个解决方案路径——Kojo 称之为多分支探索

想象一下,你给 AI 一个复杂的问题,它启动三个具有不同方法或架构的子任务,然后选择最好的一个——甚至询问你更喜欢哪个方向。这可能会大大减少评估不同实现所需的时间(目前这可能需要多名工程师花费数天时间进行原型设计)。当然,协调这一切并非易事,但随着代理框架变得更加先进,这并非不可能。

智能检查点将让 AI 在需要时向人类寻求帮助

未来的代理可能足够智能,能够在决策点主动寻求指导。这不仅仅是推测:关于大语言模型的不确定性估计和自我反思的研究正在积极进行,早期迹象表明模型可以被训练或提示来识别何时不确定,并寻求帮助而不是盲目前进。例如,一个代理可能会遇到这样的情况:可以使用两个库来实现某些功能,它不会盲目猜测,而是暂停(就像初级开发者可能会做的那样)并询问你:

我可以使用库 A 或 B 来实现这个功能——你有偏好吗?

行业内越来越多的人相信,添加这种”智能检查点”(intelligent checkpointing)会让智能体(agent)感觉更可信,更像是协作者而不是黑盒子。这也与人类团队的工作方式非常契合——知道何时询问而不是虚张声势。虽然目前还处于早期阶段,但我们开始看到更多模型通过工具使用反思(tool-use reflection)、带有不确定性阈值的规划(planning with uncertainty thresholds)以及为运行中的用户反馈提供明确支持等技术来支持这种行为。智能检查点要求智能体了解自己的不确定性,这是一个挑战,但研究人员正在研究AI自我意识,包括置信度(confidence)。

## 智能体用户体验将得到改善

随着我们将更多工作交给智能体,我们需要更好的方法来跟踪它们正在做什么。Kojo提出了智能体收件箱(agent inbox)的概念——一个统一的视图,显示智能体正在处理哪些任务、已完成什么以及哪些需要你的关注。这可以是一个仪表板,显示所有正在运行的智能体任务及其进度(“已完成3/5步”或”等待审查”)和结果。

取代当前日志和PR的混合方式,将会出现一个清晰的界面来管理智能体。也许IDE会有一个”智能体”侧边栏,列出活跃任务和更新动态。你可能还会收到通知:

这种基础设施对于在不失去总览的情况下扩大使用规模至关重要。毕竟,没有人希望10个沉默的机器人在没有中央控制的情况下做着谁知道是什么的事情。

## 智能体将与问题跟踪器和CI系统集成

我预见到一个更紧密的循环,你的跟踪器(Jira、GitHub Issues、Linear)中的问题可以由智能体从头到尾处理。事实上,CodeGen的Linear集成已经暗示了这一点。

工作流程可能如下:

  1. PM提交一个带有规格说明的工单。

  2. 开发人员(或技术负责人)批准用于AI处理。

  3. AI智能体接手,完成任务,并将PR附加到工单上。

  4. 人类审查并测试修复,然后关闭工单。

这可以使开发过程更加连续。类似地,CI系统可能在某些检查失败时自动调用智能体。例如,如果安全扫描发现漏洞,智能体可以尝试升级易受攻击的库或重构有风险的代码,然后打开一个带有修复的PR。或者如果代码覆盖率在PR之后降到阈值以下,智能体可以生成额外的测试来提高覆盖率。可以把它看作自动化维护(automated maintenance)。

作为一个具体例子,Dependabot目前会打开PR来更新依赖项。AI智能体不仅可以打开PR,还可以调整因更新而破坏的任何代码,运行测试,并确保一切正常——基本上是一个增强版的Dependabot。

## 模型改进将缩小30%的差距

主要的AI模型本身(GPT-4、Gemini、Claude等)将继续改进它们的代码理解和生成能力。随着它们变得更强大,那”最后30%“的差距可能会缩小。我们可能会看到几乎不会错过明显重用或边缘情况的智能体,因为模型已经在更多场景上进行了训练或具有更好的推理能力。

有了更好的模型,智能体将犯更少的错误,需要更少的监督,并可能处理更复杂的任务。话虽如此,软件本质上是复杂的,所以我怀疑总是会有一些需要人类判断的差距。也许它会变成最后5%-10%而不是最后30%。

我还预计模型将变得更高效,使那些担心数据隐私(或成本)的人能够运行本地或自托管的智能体。开源编码模型可能会迎头赶上,以至于你可以拥有一个本地部署的智能体,在许多任务上几乎和大型云智能体一样好。

## 智能体和工具将变得更加专业化

我们可能会看到针对不同领域或角色的专业化编码智能体。想象一个”BugFixer”智能体,你将它指向一个失败的测试或错误日志,它就会锁定bug;一个”PerformanceGuru”智能体,专注于分析和优化热点;或者一个专门从现有代码库编写文档和代码注释的智能体。

通过专业化,智能体可以整合更多特定领域的知识或工具。我们可能会看到一个与游戏引擎集成的智能体来帮助游戏开发任务,或者一个擅长数据工程管道的智能体。一组狭义的AI专家可以与人类团队内部的专业知识分布相呼应,其中一些开发人员以前端工作闻名,另一些则以基础设施闻名。你可以拥有像DocsBot、TestBot、RefactorBot和SecurityBot这样的AI队友,每个都针对这些目的进行了调优。事实上,Cursor已经有了一个叫做BugBot的东西用于自动PR审查,这是朝这个方向迈出的一步。BugBot不编写代码;它在PR上发表评论,重点关注bug风险,就像增强版的静态分析。

## 开发人员将经历文化和技能转变

如果智能体处理更多常规编码工作,开发人员的技能组合将更多地转向设计、架构和监督,如第4章所讨论的。软技能,比如清晰地传达需求(对人类和AI都是如此),变得更加重要。代码阅读和审查技能可能会变得与代码编写技能一样重要。我们可能还会更加强调测试:由于测试是验证AI输出的关键方式,擅长编写测试用例(或指导AI编写它们)仍然很有价值。

本质上,“人类的30%”将专注于软件开发中更高层次的批判性思维和质量控制方面。我怀疑我们还会看到初级开发者成长方式的变化。也许他们会从管理AI代理完成简单任务开始,而不是自己编写大量代码,这可能既有好处(他们可以快速交付价值),也有挑战(他们需要学习基础知识,而不是把AI当作拐杖)。对于那些愿意适应的人来说,这是一个令人兴奋的时代,但对于那些喜欢旧方式的人来说,可能会感到不适。正如我在[第4章]中指出的,在这个AI时代”让职业面向未来”的一个重要部分是拥抱这些工具并强调你独特的人类优势。

新角色和流程将会出现

我们可能会看到工程团队中出现”AI管理员”或”自动化负责人”等角色——这些人特别擅长利用AI代理,围绕它们设计工作流程,并维护它们的配置。这类似于当构建系统变得复杂时出现的”构建/发布工程师”,或随着基础设施自动化发展而出现的”DevOps工程师”。同样,检查AI是否引入任何不安全模式的审计可能会成为代码审查的标准环节。

可能会更加强调测试文化以提供额外的信心:也许每个代理PR都必须包含测试(由代理或人类编写)才能被考虑合并。如果AI代理正在编写大量代码,也许人类工程师应该编写更多测试(或反之亦然)以确保独立验证。

从本质上讲,有后台编码代理的未来看起来像是开发者进行编排和验证,而AI代理执行和实现(见[图11-1])。软件工程可能会更多地变成监督一队自动化编码者,而不是手动完成每一步。这可以释放巨大的生产力,减少无聊的苦差事,甚至允许团队处理以前从未有时间处理的技术债务和维护任务。(想象一下清除所有那些小错误和不一致,因为现在你可以直接让AI处理它们!)它还可能降低新想法原型制作的门槛:你可以让AI起草整个原型应用,然后自己进行微调。我们还可能在做出决策之前探索更多解决方案,因为AI可以快速生成替代方案。

然而,我们的行业必须谨慎地整合这些变化。人类元素——凭借其创造力、直觉和道德判断——仍然是不可替代的。AI可以放大我们的能力,但如果不加以控制,它也可以放大错误。

我的愿景是乐观的:如果明智地使用,自主编码代理将使开发者更有生产力,并让我们专注于构建软件中真正具有挑战性和有趣的部分,最终带领我们更快地构建更好的软件。实现这一目标意味着培养良好的实践,并意识到我们作为开发者和工程师的角色正在演变。

图11-1. 多代理AI协作架构:开发者编排专门的AI代理进行测试、设计、编码和安全工作,以协作开发全面的软件解决方案。

编程语言的未来:自然语言驱动开发?

关于vibe编码(vibe coding)未来最有趣的问题之一是它将如何塑造编程语言。如果我们可以”只是告诉AI我们想要什么”,我们还需要传统的语法和语言吗?英语(或任何人类语言)会成为新的编程语言吗?本节探讨这些可能性。

我们已经看到自然语言作为代码的迹象,在这些工具中,你用普通语言描述一个任务,AI就会编写代码。如果这一趋势继续下去,我们可能会将更多的编程工作转移到指定意图(intent)和需求(requirements)上,而不是实现上。未来的开发环境可能允许开发者(甚至非开发者)编写这样的内容:

每小时检查我们的数据库中的不活跃用户,并向任何90天未登录的用户发送电子邮件提醒,使用模板X。如果电子邮件退回,在数据库中将该用户标记为”无效电子邮件”。

AI 可以接收这个规范并将其转换为相应的代码(比如设置 cron 作业或定时函数、编写 SQL 查询或使用 ORM,或者调用邮件 API)。本质上,程序员的角色更多地变成了策略和行为描述。

这并不意味着编程语言会在一夜之间消失。相反,可能会出现一种分层:自然语言用于高层编排,现有的编程语言在底层用于细粒度控制。

编程语言存在的一个原因是自然语言可能存在歧义。如果我们完全移除形式化语言,我们就有可能与机器产生误解。AI 可能通过基于上下文的消歧和提出澄清性问题来弥合这一差距,但这可能存在极限;某些复杂的算法或优化可能仍然需要非常具体的指令,而这些指令用代码表达比用散文更容易。因此,可以想象未来的程序员在某种意义上需要是双语的:流利使用人类语言与 AI 交流,同时精通底层技术概念以验证和调整 AI 产出的内容。

我们还可能看到领域特定自然语言的兴起——经过约束的英语(或其他语言)形式,AI 可以可靠地理解,并针对软件领域进行定制:例如,一种”需求语言”,用于编写用例,AI 可以将其转换为测试或代码。

即使没有完全发展到纯自然语言,AI 的影响也可能将编程语言带到更高的抽象层次。过去,我们从汇编语言发展到高级语言,从手动内存管理发展到垃圾回收环境,每次都提高了抽象级别。AI 可以让我们即时定义抽象。可以从本书中讨论的”意图编程”的角度来思考这个问题:你指定一个目标,AI 找出如何实现它,可能会根据需要编写底层代码。

另一种可能是融合自然语言和代码的混合语言。例如,未来的语言可能允许这样的代码:

// 从订单中创建客户名称列表,排除重复项
// 并按字母顺序排序,然后打印它。

list<Customer> customers = orders -> map(order -> order.customerName)
                                   -> unique()
                                   -> sort()
                                   -> print();

在这个伪示例中,英语注释几乎可以由 AI 执行。也许在实际环境中,你甚至不需要 lambda 语法;AI 可以从注释中推断出你的意图并将其填充。或者该语言可能具有看起来像英语但足够形式化以供 AI 解析的构造。可以把它看作是注释和伪代码演变为实际代码,AI 解释其背后的意图。

编码已经变得更加对话化。你不是编写完整的程序,而是与 AI 开始对话:

提示: “我需要一个函数,根据客户的购买历史来计算忠诚度积分。”

AI: “好的。所有产品的计分都一样吗,还是有些产品给更多积分?时间应该如何影响(例如,最近的购买与较早的购买)?”

提示: “电子产品的积分是其他类别的 2 倍。最近一个月的购买额外获得 10% 的奖励。”

AI: “明白了。这是实现该功能的函数… [AI 展示代码]。我还需要为不同场景生成测试吗?”

提示: “是的,还要确保它能妥善处理没有购买历史的情况(应该返回 0 积分)。”

在这个场景中,编程是用自然语言与 AI 进行来回交流,AI 编写代码并提出澄清问题。这类似于结对编程(pair programming),只不过搭档是 AI。我们已经在 ChatGPT 插件和 Copilot Chat 等工具中看到了早期版本。未来,这可能成为创建软件的主导模式:一种逐步完善软件的对话,比从头开始编写严格的静态文本文件要流畅得多。

即使大部分编码都由自然语言驱动,理解代码和计算机的工作原理仍然很重要。计算器和电子表格并没有消除数学家或会计师理解算术的需求。你需要知道 AI 的输出在某种程度上何时不对。如果 AI 误解了英语指令,熟练的开发人员可能会切换到伪代码或实际代码来明确表达。因此,虽然语法细节可能变得不那么重要(如果 AI 可以填充,就不需要记住某个 API 参数的确切顺序),但算法思维(algorithmic thinking)和调试仍然至关重要。语言可能会改变,但底层逻辑和问题解决技能会持续存在。

然而,编程的入门门槛已经降低。非开发人员和领域专家可以通过氛围编程(vibe coding)与 AI 对话,直接创建简单的应用程序。这种民主化令人兴奋:更多人可以在没有深厚编程知识的情况下创建软件解决方案。专业开发人员将处理更困难的问题,安全地集成那些公民开发的脚本,或构建允许此类交互的平台。

即使 AI 帮助我们用自然语言编码,AI 本身也可能演化出介于两者之间的新”语言”。也许会出现新的编程范式,这些范式本质上对 AI 友好——这意味着它们为 AI 留出了填充空白的空间,例如,一种允许部分程序带有 AI 可以解决的占位符的语言(“[此处为速度优化]”),或者带有模糊逻辑(fuzzy logic)的语言,AI 可以将其细化为确定性逻辑。

最终,可能的结果不是用英语完全取代编程语言,而是两者的融合:为开发者提供更强的表达能力和一种更直观的方式来告诉计算机该做什么。正如 Andrej Karpathy 恰当地指出,“也许编程的未来不再是编写完美的代码。也许是完美地解释你想要什么。”编程的本质——清晰地思考问题并指定解决方案——仍然存在。然而,规范的形式将演变得更加自然,AI 作为翻译器将我们的高层意图转化为低层执行。

这个未来充满希望:更快的开发速度、更高的可及性,以及通过专注于我们想要实现什么而非如何输入的细节来创建日益复杂系统的能力。一如既往,每一次抽象层次的飞跃都带来了创造力的爆发(高级语言使得汇编语言永远无法扩展的软件成为可能)。自然语言驱动的开发可能释放另一波创新浪潮,氛围编码者处于最前沿,通过软件字面意义上地谈论出新世界的存在。

氛围编码如何重塑行业

在本书中,出现了几个基本原则和思想:

意图优于实现

氛围编码将重点从编写逐步代码转移到表达意图或期望的结果,并让 AI 处理实现细节。这改变了我们处理问题的方式:我们更多地思考想要实现什么,而更少地思考如何输入。这是一种更高层次的软件开发思维方式。

AI 作为协作伙伴

在氛围编码中,AI 不是孤立使用的工具,而是像结对程序员或助手一样。它是交互式和迭代的。我们看到引导 AI(通过提示词工程(prompt engineering))、审查其输出以及结合我们的优势与 AI 的优势是多么重要。未来不是”AI 取代程序员”,而是程序员与 AI 并肩工作以提高生产力

伦理和责任

我们强调,AI 的强大力量伴随着巨大的责任。减轻偏见、确保公平、保持流程透明和维护问责制都至关重要。行业正在认识到,在没有防护措施的情况下依赖 AI 可能会导致问题,因此围绕测试 AI 输出、记录 AI 参与以及解决法律问题(如 AI 生成代码的知识产权(IP))的最佳实践正在成为标准程序的一部分。

AI 超越代码生成

AI 的作用延伸到测试、调试、设计、项目管理等方面。这种整体集成意味着整个软件生命周期都被 AI 加速和增强。工具将越来越多地支持这些阶段——有些已经支持,比如 IDE 中的 AI 测试生成或基于 AI 的项目调度工具。

技能在演变,但基础知识是常青的

采用前面提到的实践的程序员会发现他们的技能组合正在演变——转向包括提示词工程、AI 监督、数据分析和高层设计,以及传统的编码和算法技能。核心的解决问题思维方式仍然至关重要,但日常任务看起来不同了。

然而某些基础知识仍然成立:深入理解你的问题领域、编写清晰的规范(提示词基本上就是规范)、维护严格的测试和验证,以及关注用户需求。AI 不会改变这些;如果有什么不同的话,它会放大它们的重要性,因为任何歧义或缺乏清晰度都可能被 AI 的超快执行放大。

这种vibe编码的新范式正在以实际的方式重塑整个行业。采用AI工具的团队报告称生产力显著提升:开发者可以在更短的时间内完成功能,或者用相同的资源处理更复杂的项目。它也在降低进入门槛:经验较少的开发者可以在AI指导下实现更多,可能会更快地提升水平。另一方面,它也在推动经验丰富的开发者拓展视野,避免对旧工作流程产生自满情绪。

公司开始招聘时不仅看重编程知识,还看重”AI素养(AI literacy)“——有效利用AI工具的能力。职位描述可能很快就会包含对AI编码助手的熟悉程度,就像今天它们包含对版本控制或云平台的熟悉程度一样。因此,成为vibe编码的先驱者能够提供职业优势。

重要的是,vibe编码在一定程度上让编程更加民主化。更多人——包括那些不是传统软件工程师的人——可以通过描述他们想要什么来参与软件创建。这可能会导致专为小众需求定制的软件蓬勃发展,由领域专家在AI的帮助下创建(专业开发者则专注于为他们提供防护栏、平台和精良的核心组件)。

这是一个令人振奋的时代。我们站在一场变革的边缘,而我们作为开发者有机会塑造它。回想计算机的早期:那些拥抱个人计算机革命的人最终创造了我们现在拥有的世界。今天,编程中的AI是一个类似的拐点。拥抱它意味着参与定义未来几十年软件的构建方式。

总结与后续步骤

编程的未来不是会发生在我们身上的事情——它是我们将要创造的东西。开发者社区中的每一个人都在vibe编码和AI工具如何被采用、监管和推进方面扮演着重要角色。这是对你作为读者和实践者的行动号召:

实验

不要等待所有答案都给你。走出去,在不同的场景中尝试vibe编码。使用AI构建一些新奇有趣的东西。突破这些工具能做什么的界限。也许你会发现一个新颖的用例或一个尚未被记录的局限性。每个实验,无论成功还是失败,都为社区贡献了知识。

分享你的发现

写下你的经验,或至少与同行讨论它们。如果你发现一种非常有效的技术,就发布它。如果你遇到一个陷阱,就警告其他人。在这个快速演进的过程中,社区知识共享是我们所有人保持同步的方式。通过发布你找到的AI怪癖(quirk)的解决方案,你可能会为某人节省数天的调试时间,或者通过分享一个很酷的AI辅助项目来激发某人的创造力。

为工具做贡献

如果你有这个意愿,可以为AI工具本身的开发做出贡献。这可能意味着为开源AI框架贡献代码,或者只是向工具制作者提供详细的反馈(他们中的许多人非常渴望听取用户关于改进建议的意见)。通过帮助塑造工具,你可以直接影响未来的样子。今天的许多AI编码助手已经取得了长足的进步,因为像你这样的开发者测试了测试版本并提供了见解。

倡导积极的变化

在你的组织或社区中,倡导使用AI来提高生产力,同时倡导培训人们正确使用它。鼓励管理者为学习AI工具留出时间,或更新可能因误解而禁止使用AI的政策。展示如何安全且有益地使用它。AI积极增强团队的成功案例越多,行业就会越倾向于拥抱它。

保持终身学习的心态

在这个新时代,采用我们都是学生的心态。保持谦逊和开放的心态。未来的新手可能会原生地了解AI工具(就像今天的应届毕业生可能比一些年长的人在成长过程中有更多的编码接触)。准备好向任何人学习,无论经验水平如何,因为这在某种程度上对每个人来说都是新的。如果你保持学生心态,你将始终找到成长,避免陷入认为自己已经弄清楚一切的陷阱。

平衡热情与谨慎

对可能性充满热情——你的兴奋会激励他人。但在需要时也要成为谨慎的声音,确保热情不会导致粗心使用。例如,倡导AI驱动的开发,但也推动对AI输出进行单元测试和代码审查。这种平衡的方法将使vibe编码可持续且受到尊重。

指导下一代

当你获得精通时,帮助新手。Vibe编码降低了进入门槛,这意味着更多的初学者可能会投入编程。他们需要指导来学习AI可能抽象掉的扎实基础知识。通过指导他们,你可以确保下一代开发者不会过度依赖AI而不理解。你将传承良好软件工程实践的火炬,现在由AI增强。

我们看到的指数级变化是一个难得的机会。想想之前的技术飞跃,从工业革命到互联网繁荣——那些参与其中的人塑造了整个行业。我们正处于AI在软件开发中的这样一个关键时刻。这不仅仅是关于保住你的工作或让工作变得更容易;这是关于在技术如何演进以及如何影响社会方面拥有发言权。

通过阅读本书,你已经展现出自己是一个具有前瞻思维的人。现在,我鼓励你将这种前瞻思维付诸行动。你用AI编写的每一行代码,你设计的每一个提示词(prompt),你教导的每一位同事,你影响的每一项政策——这一切都在为vibe coding的未来做出贡献。

最后,请记住,编程的核心始终是关于创造和解决问题。由AI驱动的vibe coding是一种极其强大的新型创造媒介。以乐观和好奇的心态拥抱它。用它来构建有意义的东西。在这样做的同时,始终将人的因素放在中心——我们的创造力、我们的判断力、我们的价值观。

编程的未来正在此刻被书写,不仅体现在代码中,还体现在我们如何选择将这些AI伙伴融入我们的工作中。这是一条令人兴奋的、未经探索的道路,我们每个人都有机会成为先驱。所以勇敢向前,大胆实验,慷慨分享,以人类智慧和精神的精华引领前行。这样做,你不仅仅是在适应未来——你是在积极地塑造未来。

祝你vibe coding愉快,我们将在你帮助创造的未来中相见!

索引

A

B

C

D

E

F

G

H

I

J

K

L

M

N

O

P

Q

R

S

T

U

V

W

X

Z

关于作者

Addy Osmani是Google的高级工程领导者,致力于开发者体验、性能和AI驱动的软件开发工具。他拥有25年的行业经验,构建Web技术,并撰写了多本关于软件工程最佳实践的书籍。

Addy在AI驱动的开发者工具方面拥有丰富的经验,测试和评估新兴平台,如Cursor、Cline、Copilot、Bolt、v0、Lovable和Claude Code。他关于AI辅助软件开发的著作影响了成千上万的开发者,他在Google Chrome的领导地位帮助塑造了Web性能和AI增强开发者工作流的未来。

本书提炼了他在软件工程方面的深厚专业知识以及在AI驱动编码助手方面的实践经验,为开发者提供了将AI集成到日常工作流程中的实用策略,并帮助他们适应快速变化的软件开发环境。

版权页

《Beyond Vibe Coding》封面上的鸟类是红翅旋壁雀(wallcreeper)(Tichodroma muraria),这是一种原产于欧洲、中东和亚洲内陆悬崖和山峰的物种。据说红翅旋壁雀在飞行时看起来像大型蝴蝶,但它们在岩壁上休息时很难被发现。翅膀具有丰富的红色,羽毛尖端为黑白色,而身体大部分为蓝灰色。繁殖期的雄性有黑色的颈部。

成年红翅旋壁雀长约6英寸,重约0.6盎司。它们每年养育一窝雏鸟,在楔入岩石缝隙的苔藓和草制成的杯状巢中产下三到五枚卵。它们是食虫动物。

IUCN濒危物种红色名录将红翅旋壁雀的保护状态列为”无危”。O’Reilly封面上的许多动物都濒临灭绝;它们都对世界至关重要。

封面插图由José Marzan Jr.创作,基于《Lydekker’s Royal Natural History》中的古董线条版画。系列设计由Edie Freedman、Ellie Volckhausen和Karen Montgomery完成。封面字体为Gilroy Semibold和Guardian Sans。正文字体为Adobe Minion Pro;标题字体为Adobe Myriad Condensed;代码字体为Dalton Maag的Ubuntu Mono。