
和脆弱架构,并强调了“信任但要核实”作为教学与审查原则的重要
性。
除了这些技术和战略考量,报告还探讨了AI辅助编程中人的一面。
这包括帮助各级经验开发者建立信心、避免常见陷阱的习惯、挫折感
以及教学策略。真实的案例研究、实用检查清单和指导提示,可帮助
讲师、团队领导和专业开发者引导其团队审慎地采用人工智能,将其
速度与构建高质量软件所需的判断力和设计思维相结合。
引言:AI编程助手的承诺与陷阱
在越来越多的公司中,AI编程助手已不再是可选项。诸如GitHub
Copilot、ChatGPT和Claude等工具,能够根据自然语言描述或现有
代码上下文,在生成、补全和重构代码方面表现出色。但它们正日益
被推崇为加速开发和实现更高生产力的必备工具,这给所有经验水平的开发者带来了实实在在的压力。
对于许多开发者,包括我自己在内,那些被承诺的生产力提升是真
实存在的。这些AI工具可以帮助加速日常工作,鼓励探索新方法,
并产生原本可能不会出现的想法(Laster 2025)。但我也看到了
大量的挫败感,尤其是在那些未能获得一致结果并感到落后的早期
职业开发者中。然而,越来越多的证据表明,AI工具并未兑现其承诺(Vizard2025)。开发者报告称,他们花在调试AI生成代码上的时间比自己编写代码还要多。团队发现,看似快速的进展最终变成了需要数周时间才能理清的技术债务。
当开发者试图从演示、研究和探索性项目转向实际的生产工作时,这种系统性问题就会显现出来,而在生产工作中,可维护性和设计才是真正重要的。向AI辅助编程的转变给所有经验水平的开发者带来了真正的压力。
组织要求从AI采用中获得可衡量的生产力提升,但如何可靠地实现
这些提升并不总是明确的,尤其是在项目变得更加复杂时。在精良演
示中有效的方法与实际项目工作中所需方法之间的差距,可能令人沮
丧且具有职业风险。
AI编程工具由自然语言提示驱动,这为开发者增加了一套必须学习才
能完成工作的全新技能。提示工程是指撰写清晰、结构化的输入,以
引导AI工具生成你想要的输出(Phoenix and Taylor 2024),它已
成为使用AI工具的一项关键技能。在代码中清晰沟通与在书面写作中
清晰沟通并非一回事,许多开发者正在寻找掌握这些技能的新颖有效
方法。
AI辅助编码工具确实有效,你可以用它们获得很好的成果。在我的O’Reilly培训课程中,我会给学生布置一些练习,比如用Copilot构建一个数学问答游戏、重构一个类,或者编写一个单元测试,而我也看到他们完成得很好。当我演示这些相同任务时,在Copilot、ChatGPT、Claude或其他AI工具的培训环节中,通常也运行得非常顺利,即使实时AI演示偶尔会出现一些小问题。但一旦你从这些受控的示例转向实际项目工作,就会突然感觉困难得多,而且并不总是很清楚为何如此。大多数开发者正是在这个缺口处陷入了“氛围编码”。
氛围编码是一种探索性的、提示优先的软件开发方法,开发者在此过
程中快速给出提示、获取代码并迭代。当代码看起来接近但不太对时,
开发者会描述问题所在,并让人工智能再试一次。当代码无法编译或
测试失败时,他们则将错误信息复制回给人工智能。这个循环不断继
续:提示、运行、出错、粘贴、再次提示,通常无需阅读或理解生成
的代码。这感觉很有成效——而且通常确实如此——因为你看到了可
见的进展:错误消失、测试开始通过、功能似乎可以工作。你本质上
是在将人工智能当作一个处理实现细节的编程伙伴,而你自己则在高
层面上进行引导(Osmani 2025)。
开发者使用氛围编码来探索和完善想法,并能快速生成大量代码。对
于大多数使用AI工具的开发者来说,这通常是自然而然的第一步,
因为它感觉如此直观且富有成效。氛围编码将细节工作卸载给人工智
能,使得探索和构思变得快速有效,这正是它如此受欢迎的原因。
但由于氛围编码依赖的是人工智能的“理解”而非我们自己的,开发
者很容易抽身而出,让人工智能完成工作,而自己并未真正思考设
计。知道何时该放慢速度、进行审查并保持专注,即使对经验丰富
的开发者而言,也可能是一项挑战。
在实践中,我还观察到一些额外的挑战。当人工智能快速生成大量代码
时,进行全面审查变得不切实际。氛围编码循环可以是一种高效利用人
工智能的方式,但它也容易让开发者迷失对代码真实功能的把握。对于
新手和早期职业开发者而言,这可能会造成一个关键的技能培养差距:
他们可能错过学习一些基本实践,例如可读性、关注点分离、设计
模式、架构,以及更广义上的编写和阅读代码的感觉。这个差距对开
发者来说日益成问题,因为这些恰恰是他们有效评估AI输出所需的批
判性思维技能。即使是经验丰富的开发者,也可能陷入一些看似高效
但会带来长期问题的习惯,比如不加质疑地接受AI建议、跳过设计讨
论,或者过快地推送未经审查的代码。
在我自己的开发工作以及培训和辅导课程中,我反复看到使用人工智
能所面临的挑战。这些经验促使我设计了Sens-AI框架。它包含五种
结构化习惯,帮助开发者知道何时从快速生成切换到仔细审查,在人
工智能协作过程中保持批判性思维活跃,并保持高效工程师日常所依
赖的设计判断力。该框架还为较新的开发者提供了一条清晰的学习路
径,帮助他们将这些基本习惯与核心编码技能一同建立起来。
当氛围编码失效时
氛围编码具有真正的吸引力,因为它使探索想法变得快速而简单。你
无需手动编写每一行代码,只需描述你想要什么,就能快速获得可运
行代码进行优化。它将实现细节从你的大脑卸载到人工智能上,从而
更容易尝试变体、测试设计或克服空白页面的瘫痪感。当它奏效时,
这种即兴风格感觉流畅而自然,这就是为什么它在寻求提升开发速度
和创造力的团队中如此受欢迎。
氛围编码的优势,也可能让人容易忽视人工智能可能失败的几种具体方式:
幻觉发生在人工智能生成看似合理但存在缺陷的代码时。当
它生成的代码看起来能工作,但隐藏着容易被忽视的问题时,
幻觉尤其成问题,例如那些能编译但隐藏着微妙逻辑错误或
忽略了边界情况的方法。
过度自信体现在开发者未经通常的验证、测试或设计评审,
就将AI建议视为正确。这些风险众所周知,但它们仍然可能
让经验丰富的开发者栽跟头,尤其是在交付压力下。它们经
常出现在真实的AI辅助编码会话中,并且可能出奇地一致。
重复循环发生在开发者不断调整提示,而人工智能持续返回
同一有缺陷解决方案的细微变体时。流程并未向前推进,而
是停滞不前,人工智能在同样的几个想法或解决方案上打转。
我在教学和自己的开发工作中都广泛依赖氛围编码。它确实帮助我快
速生成高质量代码,并加速了许多项目。但要成功使用它,就意味着
需要定期审查生成的代码,留意技术债务的迹象,或是那些使代码更
难以维护的、不断累积的捷径和妥协。技术债务的常见例子包括无法
独立更改的紧耦合模块、分散在多个文件中的重复逻辑,或是掩盖了
简单操作的过度复杂的抽象。开发者通常会应用坚实、以人为本的实
践,如单元测试、仔细审查和设计规范,以防止技术债务累积,并保
持代码的整洁和可维护性。
氛围编码是一种正常且有用的、利用人工智能进行探索的方式,但尽
管它颇具吸引力且可能有效,却带来了重大风险。大语言模型所使用
的模型可能会产生幻觉,并编造出虚假答案,例如生成调用不存在的
API或方法的代码。要防止这些AI生成的错误损害你的代码库,首先
要理解这些工具的能力和局限性,并采取一种将这些局限性考虑在内
的AI辅助开发方法。
这里有一个简单的例子,说明这些问题是如何叠加的。当我要求人工智能生成一个处理用户交互的类时,它通常会创建一些直接读写控制台的方法。然后,当我要求它让代码更具可测试性时,如果我没有非常具体地提示一个简单的修复方案,比如让方法将输入作为参数并返回输出值,人工智能经常会建议将整个输入/输出机制封装在一个抽象层中。现在我有了一个接口、一个实现、用于测试的模拟对象,以及贯穿始终的依赖注入。一个原本简单的类变成了一个微型框架。人工智能并非完全错误。这种抽象方法是一种有效的模式,但对于手头的问题来说,它过度设计了。每次
迭代都会增加更多复杂性,如果你不注意,最终会堆积起一层又一层
不必要的代码。这是一个很好的例子,说明了如果你不停下来验证正
在发生的事情,氛围编码如何会膨胀成不必要的复杂性。
AI加速的技术债务信号会迅速显现:模块间依赖彼此内部细节的高度
耦合的代码;承担过多职责的“上帝对象”;简单问题被额外层级掩盖
的过度结构化的解决方案。这些问题与人类编写代码中通常反映技术
债务的问题相同;它们在AI生成代码中如此快速出现,是因为代码可
以更快地被生成,且缺乏监督、有意识的设计或架构决策。人工智能
可以令人信服地生成这些模式,使其看起来像是刻意为之,即使它们
是偶然产生的。因为输出能编译、通过测试并按预期工作,所以很容
易被当作“已完成”而接受,而不会去思考当需求变更时它如何能保持
稳定。
如果任其默认发展,AI辅助开发会偏向于添加新代码,而不是重新
审视旧决策。这可能是因为语言模型被训练成生成看起来新颖且完
整的响应;它们不一定被优化来询问现有代码是否应该被重构。
当开发者添加功能时,他们通常基于对现有架构模式、辅助函数和设
计哲学的理解来工作。然而,人工智能不具备这种整体视角。它是在
一个庞大的代码数据集上训练的,但在生成解决方案时,它主要专注
于眼前的任务。这种狭隘的专注常常导致常见的代码生成失败:
重复
人工智能生成了一个重复现有函数逻辑的函数。这会使代码库变得更大、
更难以维护,并且如果在一个版本中发现了缺陷,就必须在所有出现的
地方进行修复。
缺乏集成
人工智能会创建新的方法、函数、类或模块,而不是扩展现有的。
这错失了应用设计模式和原则的机会,导致设计内聚性降低,变
得僵化且难以扩展。
过度抽象
人工智能生成了额外的类、接口或辅助函数层,这些并未增加实
际价值。这增加了复杂性,使代码更难理解,并且随着时间的推
移,会像重复或集成不良一样,造成同样的僵化性和维护难题。
避免技术债务的纪律性,源于将设计检查融入你的工作流,使人工智
能的速度服务于可维护性,而非与之相悖。防止技术债务始终依赖于
开发者在反模式固化为长期问题之前发现并修复它们。未来迭代的
AI模型或许会更擅长建议重构或复用,但其倾向于生成全新输出的偏
见仍将存在。这就是为什么开发者需要设置审慎的检查点,以确保代
码库是负责任地而非随意地增长。
理解重复循环
尽管幻觉和过度自信吸引了大部分关注,但还有一种同样常见却较少
被理解的故障模式。重复循环是AI辅助开发中的一种故障模式,其特
点是重复的提示-响应循环产生了各种变体,却未能实质性地解决根
本问题。开发者可以识别出自己陷入了重复循环,当人工智能持续以略微不同的形式回应相同的核心想法或有限的解决方案集,并且提示的调整似乎并未朝着可行的解决方案取得任何实质性进展时。典型的开发者反应是试图通过增量变更来逃脱:添加细节、重新措辞指令,或引导人工智能进行修复。但这些调整,在通常的氛围编码会话中本应有效,却仍然会回到同样受限的答案集合中。重复循环是一个令人沮丧的问题,因为进展停滞不前,没有明确的解决路径,甚至没有可能通向解决方案的新思路。更具挑战性的是不确定性:开发者无法判断是确实没有真正的解决方案、工作已陷入真正的死胡同,还是提问方式有误,亦或是人工智能正在幻觉式地给出部分答案并过度自信地认为其可行。重复循环造成的模糊性会让开发者感到束手无策,不知下一步该尝试什么,甚至怀疑问题是否可解。
当你陷入重复循环时,人工智能并没有出故障或产生幻觉。它只是
在严格按其设计行事:基于你提示中的标记以及它对对话的有限视
角,生成统计上最可能的回应。问题的一个根源是上下文窗口:这
是一个固定大小的缓冲区,决定了模型一次能“看到”多少文本。这
包括你的提示、任何共享的代码以及对话的其余部分,通常总计几
千个标记。一旦模型采样了在其中发现的模式,它就开始原地打转。
你得到的那些变体,比如语句重排、变量重命名、这里或那里的小调
整,并非新思路。它们只是模型在同一个狭窄的概率空间内对内容进
行微调。它仍然指向其训练数据中的同一块内容。因此,如果你持续得到相同的错误答案,问题很可能不在于模型不知道如何提供帮助,而在于你尚未为它提供足够的信息来开展工作。要理解为何会发生重复循环,以及为何人工智能会卡在重复部分答案上,我们需要更仔细地审视大语言模型的工作原理:
LLMs它们并不像人类那样真正理解代码。它们通过预测文本
序列中接下来可能出现的内容来生成建议,这基于它们在庞
大的训练数据集(Taulli 2024)中观察到的模式。当你给出
提示时,它们会分析你的输入并预测可能的后续内容,但它
们并不真正理解你的设计或需求,除非你明确提供这些上下
文。
上下文是人工智能用来决定接下来生成什么内容的信息。它
包括你在提示中告诉它的一切、最近的对话,甚至是你项目
中的周边代码。你提供的上下文越好,人工智能的答案就越
有用、越准确。
LLMs它们不理解设计意图或架构;它们只是试图基于上下文
窗口预测下一个最可能的文本,上下文窗口是一个有限的文
本块,包含了人工智能在任何给定时间可以“看到”的提示、
对话历史和周边代码。这就是为什么它们能生成有用的补全、
单元测试,甚至错误修复,但也会幻觉出不存在的API,或
者生成带有微妙设计缺陷的代码(Phoenix and Taylor
2024)。当上下文不完整或框架不佳时,人工智能的建议可
能会偏离主题、重复变体,或者完全错过真正的问题。
虽然重复循环看似一个令人沮丧的问题,但开发者也可以通过认识到
重复循环是人工智能用尽上下文的信号来积极地利用它们。当你陷入
重复循环时,请将其视为一个信号而非问题。要跳出循环并恢复对人
工智能的有效使用,你只需找出缺失的上下文并提供它即可。
人工智能研究员已在模型层面研究了诸如“重复生成”(Doan 2023)或“提示饱和”(Milios 2023)等相关现象,但这些术语并未捕捉到开发者遇到此障碍时的体验。通过明确命名重复循环模式,我们能更好地识别其发生,并将其视为一个重要的信号,从而退后一步,重新思考我们的方法。
认知捷径悖论
生成式人工智能可以成为各个经验水平开发者的强大学习工具,但对于
早期职业开发者却潜藏着危险。对于经验丰富的开发者而言,这可能意
味着能更快地获得可行的解决方案。然而,对于学习路径初期的开发者,
他们面临着我称之为认知捷径悖论的困境:他们需要编程经验才能用好
AI工具,因为经验能培养评估、调试和改进AI生成代码所需的判断力,
但在最初阶段过度依赖AI,可能会让他们永远无法获得这些经验。
我在改编我的书Head First C#以纳入AI练习时(Stellman and
Greene 2024)亲眼目睹了这一点。书中的练习旨在教授特定的开
发概念,如面向对象编程、关注点分离和重构。如果新学习者在自
己掌握基础知识之前就让AI生成代码,他们就会错过那些通向“顿悟”
时刻、让理解真正融会贯通的问题解决工作。
借助人工智能,新学习者很容易完全绕过学习过程:将练习说明粘贴
到编程助手中,几秒钟内获得完整程序,然后直接运行,而无需经历
设计或调试。当AI产生正确的输出时,学习者会感觉取得了进展。但
目标从来不仅仅是拥有一个能运行的程序;而是要理解需求,并构建
一个能巩固书中先前所教的特定概念或技术的解决方案。问题在于,
他们的工作看起来仍然是正确的。代码能编译并产生预期结果,因此
缺失的技能一直被隐藏,直到差距大到无法弥合。
有证据表明,人工智能聊天机器人可以提升经验丰富员工的生产力,但
对于初学者技能增长的影响却微乎其微(Humlum and Vestergaard 2025)。
在实践中,AI编程助手可能导致早期职业开发者的学习差距扩大,因为它们在开发者有机会建立有效运用答案所需的技能之前,就提供了一个现成的、打磨好的答案。
认知捷径悖论不仅仅是一个课堂问题。在实际项目中,最有价值的工
程工作通常涉及理解模糊需求、在一切都不确定时做出架构决策,以
及追踪那些没有明显修复方案的缺陷(Stellman and Greene 2005)。
这些能力来源于与那些没有快速“完成”路径的问题的搏斗。如果开发
者在遇到困难的第一时间就求助于人工智能,他们就跳过了那些能培
养资深工程师所依赖的模式识别和系统性思维的工作。
随着时间的推移,这种影响会加剧。一位新开发者可能通过氛围编
码完成早期的工单,感受到交付可运行代码的满足感,并增强对自
己能力的信心。几个月后,当他们被要求调试一个复杂系统或重构
他们未编写的代码时,差距就显现出来了。到那时,他们整个开发
方法可能都依赖于人工智能来填补每一个缺失的部分,这使得培养
独立解决问题能力变得困难得多。
认知捷径悖论为我们如何在AI时代教授和学习编程提出了一个根本
性挑战。通过挣扎和迭代来构建技能的传统路径并未过时;它变得
比以往任何时候都更加关键,因为正是这些相同的技能使得开发者
能够有效地使用AI辅助开发采取一种更为审慎的方法,一种在利用人工智能能力的同时,保留基本学习经验的方法。
未完待续。。。。。
回复“进群”,进入和虎sir一起学AI交流群:
