一、自动化编程的线性幻觉
使用大模型1进行编程时,我们常会设想这样一个流程:人先写出清楚的需求或规约,智能编程代理2理解后将其实现为代码。这个流程看似高效,也符合我们对自动化的期待。但实际开发很少沿着这样一条直线推进。编程代理并不是在一个抽象、干净、没有历史的空间里写代码。它总是在某种环境中工作:一个已有的代码库、一个技术栈、一套命名习惯、一组测试、一种团队审美,以及许多没有被明说却实际支配开发的规则。
因此,使用代理写代码并不是把自然语言直接翻译成程序。需求进入代码库之后,会受到已有结构、命名、抽象、测试和工具链的约束。代理面对的不是一个脱离历史的问题,而是一个已经形成许多默认做法的工程现场。它会从现有实现中寻找范例,也容易把长期存在的做法当成合理默认。
二、代码库文化会被代理复制
代码库3当然首先是技术对象,但也可以把它理解为一种工程文化4。长期积累的命名、目录结构、错误处理、测试写法和审查习惯,会共同形成一套局部默认:什么样的代码看起来“属于这里”,什么样的改动显得突兀。人类工程师会受这些默认影响,智能编程代理在读取和模仿现有代码时也会受到影响。
编程代理也不是天然的改革者。它越依赖现有代码作为范例,就越可能延续其中的风格、判断标准、捷径和盲点。如果代码库结构清晰、边界合理、命名准确、测试可靠,这些模式会给代理提供较好的局部参照;如果代码库充满历史妥协、错误抽象和模糊概念,代理也可能高效地产生更多“看起来属于这里”的坏代码。
因此,代码库的质量不仅影响当前维护成本,也会影响后续生成代码时可见的范例。技术债5不只是过去留下的问题:一个糟糕的模式如果反复出现,代理就更容易把它当作局部规范继续沿用。反过来,一个边界清楚的模块、一组范围恰当的测试、一个合理的领域模型6,既解决当下问题,也为后续修改提供更好的参照。好的设计在代理时代不只是局部改进,也可以成为一种生成性基础设施7。
三、上下文与语言都不是透明介质
这也改变了我们对“上下文”8的理解。更多上下文不一定带来更好的结果。把整个代码库不加区分地交给代理,会让好的设计、历史遗留和已经过时的模式同时进入当前任务的参考范围。关键不在于上下文越多,而在于哪些信息与当前任务相关,哪些代码值得作为范例,哪些做法需要明确标记为遗留或禁止继续扩散。软件工程因此多了一项工作:不仅维护代码,还要管理哪些代码会成为后续生成和修改时的参考。
语言本身也不是透明的9。需求文档或提示词里的“用户”“项目”“会话”“权限”“简单”“优雅”,在不同代码库里可能对应完全不同的对象和约束。代理未必是不理解这些词的字面意思,更常见的问题是它选错了当前代码库里的对应概念。于是,一个看似明确的需求,也可能得到功能正确、结构却不合适的实现。
提示词并不是悬浮在代码之上的控制层。它更像一次翻译请求:用代码库已经形成的内部语言表达人的意图。翻译是否成功,不只取决于模型能力,也取决于这套内部语言是否清楚、稳定、值得学习。
四、规约不能成为理解实际情况的唯一依据
这也解释了为什么规约驱动10在探索性强、语境复杂的任务里会显出局限。规约可以描述目标和约束,却未必能完整说明某个代码库里最合适的实现方式。代理即使满足了规约,也可能复用已经准备淘汰的旧模式,引入与现有边界冲突的抽象,或者继续强化本应迁移的历史结构。换句话说,文字中的目标会与代码库里已经存在的局部约束相互作用,不能假设前者能够自动覆盖后者。
规约仍然重要,尤其适合边界稳定、验证条件明确的问题。只是到了探索性强、语境复杂或既有结构影响很大的场景,规约需要和代码阅读、原型及反馈一起工作。否则,尚未验证的设想很容易先被写成确定需求,再由代理迅速固化成代码。
即使面对一个空代码库,规约驱动也未必是理想选择。空代码库没有旧代码文化,但不等于问题已经消失。相反,由于缺少实际约束,未经验证的设想更容易直接变成代码。过早写出的规约,可能会让尚未验证的概念迅速变成具体结构。代理可以在短时间内生成完整的目录、模型、接口、测试和抽象,但这些结构可能只来自早期那些听起来合理、实际尚未成立的概念。空代码库里,危险不是代理继承错误的过去,而是它太快实现了错误的未来。
早期开发往往要先弄清问题是什么,再决定完整实现。很多产品概念、数据模型和交互边界中的问题,只有做出一个小型实现并让它运行起来才会显现。规约容易沿着已有想象继续展开,原型11则能更早暴露这些想象与现实之间的差距。因此,在空代码库中,与其一开始就写出完整规约,不如先做一个足够小、足够便宜、允许被推翻的纵向切片12,再根据实际结果修正规约。
五、人的角色是设计环境与验证机制
从这个角度看,使用编程代理不只是“写提示词”的问题,它还要求我们改变开发方法。我们不应把代理当作简单执行命令的工具,而应把它看作会进入某个代码文化、学习它、复制它、放大它的参与者。人的角色也不只是提出需求,而是设计工作环境:明确边界,挑选范例,标记遗留区域,设置验证机制,让好的模式更容易被复制,让坏的模式更容易被暴露。
这也解释了为什么“非设计”13有时可以成为一种设计策略。使用代理时,人不必预先规定每一行代码,更重要的是创造条件,让合适的实现更容易出现:先观察,再介入;先理解场域14,再修改结构;必要时先让代理或原型暴露规约中的含糊和错误假设,再进入完整实现。有效的工作流不一定从“实现”开始,也可以从理解代码库及其局部规则开始。
测试、持续集成15和代码审查也不是完全中立的裁判。它们体现了团队选择把什么写成可执行检查,什么仍然留给人工判断。验证机制因此会影响哪些工程知识被形式化16,也会影响谁有权定义“正确”以及哪些风险更容易被看见17。
通过测试并不等于符合长期架构,也不等于符合好的代码文化。代理尤其容易优化那些已经写进流程的检查,而忽略尚未形式化的工程判断。因此,验证机制不应只是最后的盖章,还需要持续把实际结果反馈给开发过程,让输出能够被检验,也允许既有判断在证据面前被推翻。
六、工程责任:让代码库值得被学习
常规重构18同样值得重新审视。重构可以让结构更清楚,却未必会改变旧的领域模型、边界和判断标准。如果真正的问题出在这些默认假设上,仅仅整理代码还不够,更困难的是完成一次迁移19:建立新的概念、新的边界、新的范例和新的验证方式。编程代理可以帮助执行这种变化,但前提是目标不能只从现有代码库里推导,否则它很容易继续沿用原有做法。
因此,智能编程代理不会自动让代码库变好。它会沿用代码库已有的模式,并在生成新代码时放大这些模式的影响。如果代码库体现出清楚的工程判断,代理会延续这种判断;如果代码库积累了债务,代理也会放大这种债务。关键问题不再只是代理能不能写代码,而是它会从哪里学习什么叫好代码。
代理时代的工程质量不只取决于模型能力,也取决于代码库是否提供了值得延续的范例。软件工程师因此不只是代码的作者,也越来越像代码文化的策展者20:维护的不只是功能和文件,还包括哪些实现会成为未来修改时的参照。代码库不是一台没有历史的机器,而更像一个已经形成规则的地方。每一个进入其中的编程代理都会受到这些规则影响;我们要负责的,是这个地方究竟在鼓励什么。
脚注
Footnotes
-
大模型:本文主要指大语言模型(large language model),即通过大量文本和代码训练的生成式模型。它能根据上下文生成语言和代码,并完成一定程度的多步任务,但这不等于它掌握了整个系统的历史、目标和组织约束。 ↩
-
智能编程代理:指能够读取文件、调用工具、修改代码、运行测试,并在授权环境中围绕编程任务持续推进的人工智能系统。它不同于普通代码补全工具,因为它可以跨越多个步骤规划、执行和修正。 ↩
-
代码库:一个软件项目的整体代码、配置、测试、文档和工程结构。本文强调,代码库不只是文件集合,也包含长期形成的习惯、判断标准和隐性规则。 ↩
-
文化:本文不是指艺术或民族传统,而是指一套被群体反复实践、默认接受并传递给后来者的行为方式和判断标准。放在代码库中,文化体现为命名、架构、测试、审查和维护习惯。 ↩
-
技术债:软件开发中为了短期速度、历史原因或认知限制而留下的结构性问题。它未必马上导致故障,但会增加未来修改、理解和扩展系统的成本。 ↩
-
领域模型:软件中对业务对象、关系和规则的抽象表达。例如“用户”“订单”“权限”“项目”等概念如何被定义、关联和操作,都会影响系统结构。 ↩
-
生成性基础设施:本文中的说法,指那些不仅解决当前问题,还会影响未来代码如何被生成、模仿和扩展的设计。好的模块、测试和命名都会成为后续开发的隐性模板。 ↩
-
上下文:在大模型使用中,指模型当前能看到并用来生成回答的信息,包括提示词、文件、代码片段、错误日志、文档和历史对话。上下文并不等于真实理解,它只是模型生成时可参考的材料。 ↩
-
语言不是透明的:这一观点与现代语言哲学和符号学有关。词语并不是天然、直接地对应现实对象;它们的意义依赖使用场景、社会约定和具体实践。维特根斯坦关于“语言游戏”的思想可作为这一点的代表性参考。 ↩
-
规约驱动:指先写出详细的需求说明、功能规则或技术规格,再让开发过程围绕这些规约展开。它适合边界清楚、验证明确的问题,但在探索性强或语境复杂的问题中容易过早固化假设。 ↩
-
原型:用于快速验证想法的初步实现。它的价值不在于完整或优雅,而在于尽快暴露问题,让团队看到需求、交互和系统结构是否真的成立。 ↩
-
纵向切片:指从用户界面到后端逻辑、数据存储和验证机制都贯通的一小段完整功能。它比单独搭建某一层框架更能暴露真实系统问题。 ↩
-
非设计:不是完全不设计,而是避免过早、过度地把设计者意志强加给系统。它强调观察已有秩序、设置条件、减少不必要干预,让结构从实际使用和反馈中逐渐显现。 ↩
-
场域:社会学概念,可理解为一个由规则、位置、资源和权力关系构成的具体实践空间。放在软件开发中,代码库、团队、工具链和审查制度共同构成了一个工程场域。 ↩
-
持续集成:一种软件工程实践,指频繁把代码合并到主分支,并通过自动化构建、测试和检查来发现问题。它能提高可靠性,但只能验证它被设计来验证的内容。 ↩
-
知识生产:指知识并不是凭空出现的,而是在具体制度、工具、语言、方法和权威结构中被制造、确认和传播。放在软件开发中,“什么算正确代码”也依赖测试、审查、文档和组织规范。 ↩
-
权力结构:这里指团队中谁有权定义标准、批准修改、决定风险优先级,以及解释什么是“好代码”。这种权力不一定表现为直接命令,也可能体现在测试门禁、流程、评审习惯和工具规则中。 ↩
-
重构:在不改变外部行为的前提下改善代码内部结构。它通常用于提高可读性、可维护性和扩展性,但不一定会改变系统背后的概念模型和文化惯性。 ↩
-
迁移:本文中指从一种旧的系统结构、概念模型或工程文化转向新的结构和标准。它不只是移动代码或更换框架,而是改变系统如何组织、命名、验证和演化。 ↩
-
策展者:原指负责选择、组织和解释展品的人。本文借用这个词,指对代码范例进行选择、组织和解释的人。 ↩