我最近使用了一个AI编程工具,本以为只是做一个微小的改动:更新一段逻辑并修复相关的测试。但当我查看差异时才发现,虽然它修改了预期的文件——这很好——但它也触碰了我没有要求改动的其他文件。比如添加了一个已经存在的辅助函数,或者为一个仓库已有工具库的功能导入了新的依赖包。我当时心想:“技术上没错,但这真的合适吗?”这正是当前许多AI编程工具面临的真正问题。

它们变得非常擅长快速生成更改。你要求写一个函数,它就写出一个;你把错误信息粘贴进去,几秒钟后你就会得到一个看起来很有说服力的补丁。但速度并不等同于理解力。如果你曾在生产环境的代码库中工作过,你会立刻明白这一点:代码库不仅仅是文件夹里的一堆文件。它有历史、模式、共享工具、测试,以及所有那些通常都有原因的奇怪决策。

因此,当AI工具在尚未理解整个系统的情况下就开始编辑时,它可能会制造出非常快速的混乱。让我举个例子:假设你的应用有一个服务层,所有的数据库调用都应该通过这一层进行,因为权限控制、日志记录、重试机制和错误处理都发生在这里。现在,你要求AI工具添加一个新的端点。

如果它只查看你正在编辑的文件,它可能会直接在端点中编写数据库查询语句。起初这听起来没问题:它能返回正确的数据,甚至测试也能通过。但从架构角度看这是错误的,因为它绕过了服务层,跳过了执行权限检查的地方,并创造了一种其他人可能会在后续复制的模式。所以代码虽然能运行,但系统整体质量却下降了。

因此,问题不能仅仅是“AI能否编写代码?”答案显然是肯定的,但更好的问题是:“它能否写出尊重现有代码库的代码?”因为在生产环境中,好的代码不仅仅是能运行的代码,更是与系统契合的代码。首先我们需要具备仓库感知能力(Repo Awareness)。AI需要理解的不仅仅是眼前的文件,因为真正的编码任务很少局限于单个文件。

一个微小的改动可能会影响类型定义、API契约、测试或文档,而这些往往容易被忽视。所以在AI问“我应该写什么代码”之前,它应该先问:“我需要理解哪些内容?”注意,这并不意味着把整个仓库都塞进提示词中。更多的上下文并不总是意味着更好的上下文;如果你给模型成千上万无关的文件,你只是在用噪音掩盖有用的信号。

良好的仓库感知意味着在正确的时间找到正确的上下文:相关的文件、现有的示例、重要的测试,以及已经解决了类似问题的代码。其次,我们需要架构上下文(Architectural Context)。架构不仅仅是文件的位置,它是保持系统可维护性的规则集合。业务逻辑应该放在哪里?验证在哪里发生?哪个服务拥有这些数据?或者我们是否被允许在此处添加依赖项?

当AI工具忽略这些规则时,你会得到能运行的代码,但它会感觉与仓库格格不入。也许它导入一个新库,而项目已有标准工具;或者编写一个重复现有功能的辅助函数。这些在当下看起来并不致命,但久而久之,代码库就会变得杂乱无章。第三点是在打补丁前先规划(Planning Before Patching)。

AI编程工具的第一次输出不应该是代码,而有时应该是理解。在更改任何内容之前,它应该让推理过程可视化:它会说,“我检查了这些文件”,“我发现的模式是这样的”,“我认为更改应该发生在这里”,以及“我建议下一步做什么”。然后它再编写代码。这种停顿让开发者能尽早发现错误,你可以说:“不,不要动那个包”,或者“改用这个现有的服务”。这才是真正的协作方式。

优秀的工程师会先对齐思路,AI工具也应该这样做。由AI生成的代码往往看起来很棒:命名整洁、结构熟悉、注释自信满满,但自信并不是测试结果。尊重代码库的AI工具应该运行开发者会运行的相同检查:单元测试、类型检查、linting和构建命令。但验证不应止步于“测试是否通过”,还应追问:“这个更改是否符合系统规范?”

它遵循现有模式吗?尊重了仓库的架构标准吗?还是引入了一个可能导致未来问题的捷径?因为在生产环境中,某项更改可能能运行,但对系统而言却是错误的。如果出现问题,工具应该理解失败原因,而不是随机编辑直到错误消失。这就是调试与猜测的区别。最后是关于边界(Boundaries)。

优秀的编码代理需要知道它可以触碰什么、不应该触碰什么,以及在何时请求批准。它应该编辑部署文件吗?修改认证逻辑或安装依赖项吗?对于大多数团队来说,如果没有审查,答案可能是否定的。它应该在分支上工作,安全地运行测试,避免接触密钥,并在执行任何高风险操作前征求同意。基本上,它应该懂礼貌:先敲门。

因此工作流程应该是简单的:首先阅读,其次规划,再次打补丁,然后验证,最后审查;而不是先打补丁再事后道歉。作为开发者,我们也应保持同样的意图性:指引工具到正确的文件,展示现有模式,告知约束条件,要求在写代码前先提供计划。因为如果指令模糊不清,模型就会自行填补空白;而在软件工程中,填补空白往往会导致bug。

AI辅助开发的未来不仅仅是更快的代码生成,而是更具上下文感知能力的代码。是那些在编写前先阅读的工具;是在修改前就理解系统的工具;是保留架构而非随意重新发明的工具。