logo

AI编程越改越错的根源与破局之道

作者:很菜不狗2026.11.06 20:55浏览量:0

简介:AI改代码越改越错,根源不在模型能力,而在协作时喂给它的信息层级太低——只给报错症状,不给架构诊断。本文通过一个并发请求从905ms优化到302ms的真实案例,剖析"实现与测试共享同一盲区"的闭环陷阱,并提出以设计意图驱动修改的高阶协作方法,帮助开发者跳出"贴报错—等修复"的低效循环。

一、问题的提出:同一个模型,为何三轮改不对、一句话改对

一个颇具代表性的现象:让智能编程工具从零编写一个中等规模的系统模块,两千行代码一次成型,能编译、能运行、基础测试全部通过。随后在性能验证中发现,原本应当并行发出的三个耗时约300ms的请求,理论总耗时300ms,实测却达到905ms——请求被串行执行了。

把现象和报错反馈给模型,它开始修改。第一版改完仍然串行,第二版换了一种写法依旧串行,第三版直接引入编译错误。典型的”越改越错”。

换一种协作方式后:不再提供任何报错信息,而是给出了一句架构层面的约束——“I/O 调度不要由业务代码自行管理事件循环,创建连接后注册到全局事件循环并返回一个 pending 状态的 Promise,由全局事件循环统一驱动 I/O”。模型一次改对,涉及9个文件,耗时从905ms降至302ms。

同一个模型、同一份代码库,差异只在于输入信息的层级。这个对比揭示了一个被普遍忽视的事实:报错信息是症状,不是诊断。 告诉模型”这个函数返回值不对”,它就会去改那个函数;但真正的问题往往不在函数内部,而在于这些函数被组织在一起的方式。在错误的架构上做局部修补,每一针都挑不出毛病,缝合出来的整体依然是错的。

二、能力边界的再认识:强在实现,弱在组织

需要澄清一个常见误解:这类现象并不意味着模型”不会写代码”。在上述案例中,域名解析逻辑是对的,套接字创建是对的,HTTP 报文序列化是对的,Promise 封装也是对的。逐行审阅几乎挑不出实现层面的缺陷。问题在于,这些各自正确的代码片段,被安放在了一个错误的组织方式里——每个零件都合格,整机却运转不畅。

由此可以给出一个更精确的能力画像:

  • 实现层能力强:单个函数、单段算法、单个接口的编写质量已经相当可靠,语法正确、边界处理基本到位。
  • 组织层能力弱:判断”这些代码应当以什么粒度拆分、以什么方式组合、由谁负责调度、状态归属何处”这类架构决策,模型缺乏稳定的判断力。它倾向于在既有结构内做最小改动,而不是质疑结构本身。

这也解释了为什么”改来改去还是错”:模型的修改策略是局部最优的,而问题恰恰是全局性的。局部最优的累积不等于全局最优,在错误的结构上尤其如此。

三、更深一层的陷阱:实现与测试共享同一盲区

比”改不对”更值得警惕的,是”看不出错”。

在上述并发问题修复之后,继续做代码审查时发现:性能测试模式下每一次 HTTP 请求实际上都失败了,累计一万六千余次请求,无一成功。但测试报告显示的是——一万六千余次请求,零错误,全部通过。

原因并不复杂:实现代码把每次调用无条件计入”成功”计数,而测试代码只读取这个计数做断言。实现不检查错误,测试不验证错误,二者由同一个模型生成,因而共享同一套认知盲区,完美地互相配合,共同制造出”一切正常”的假象。

这构成一个闭环:

  1. 模型生成实现 → 模型生成测试 → 测试通过 → 结果回喂给模型 → 模型认为无需修改

在这个闭环里,任何一方都无法发现问题,因为问题的判定标准本身就来自同一来源。只有引入外部的人工审查,才能打破闭环。 这也是为什么在智能编程工具高度普及的今天,”人做最终 review”依然不是形式主义,而是质量保障体系中不可替代的一环。

推而广之,这个陷阱有几种常见变体,值得逐一警惕:

  • 断言空转:测试用例存在,但断言条件恒为真,或断言对象与实际返回值不是同一路径。
  • 错误吞没:实现层用宽泛的异常捕获把错误转成默认值返回,上层无法感知失败。
  • 路径覆盖假象:测试覆盖率数字很高,但覆盖的是无分支的直线代码,真正的异常分支从未被执行。
  • 指标自证:监控指标由被测代码自己上报,指标正常只证明上报逻辑跑通了,不证明业务逻辑正确。

四、协作模式的根本性错误

把上述分析归结为一句话:问题不在于模型笨,而在于人机协作的信息层级错了。

低效的协作模式是这样的:

  1. 模型写 → 运行报错 → 把报错原文贴给模型 → 模型改 → 又报错 → 再贴 → 循环

这个模式的结构性缺陷在于:开发者始终在向模型提供症状级信息,而缺陷位于架构级。症状级信息只能引导出症状级修补。更糟的是,每轮修补都可能引入新的不一致,使系统熵增,最终从”性能不达标”退化为”无法编译”。

与之相对,高效的协作模式要求开发者先完成一次信息升维:从”哪里报错了”上升到”这段代码应当以什么方式组织”。具体可以拆解为四个动作:

  1. 现象归因,而非现象转述。不要只贴报错,先判断这是实现缺陷、接口契约缺陷,还是调度模型缺陷。若同一类现象在多轮修改后反复出现,基本可以断定是组织方式问题。
  2. 给出约束,而非给出补丁。用一段话描述目标架构的关键约束——谁负责调度、状态归属何处、模块间通过什么契约交互。约束一旦明确,模型在实现层的强大能力才能被正确释放。
  3. 划定修改半径。明确告知可以改动哪些文件、哪些接口不可变更,避免模型在局部做最小改动的同时破坏全局一致性。
  4. 要求模型先复述设计再动手。让模型用自己的话复述目标架构与关键约束,确认理解一致后再生成代码,可以显著降低”改错方向”的概率。

五、可操作的实践建议

将上述方法论沉淀为可复用的工程习惯:

(一)先定架构,再让模型填实现

把工作拆成两阶段。第一阶段只讨论架构:模块划分、职责边界、并发模型、错误传播路径、数据流向。这一阶段由人主导,模型仅作为讨论对象。第二阶段才让模型生成具体实现。架构阶段的投入,会在后续每一轮修改中以复利形式返还。

(二)用不变量(invariant)描述需求

比起描述”要做什么”,更有效的是描述”什么必须始终成立”。例如:”任意时刻最多只有一个协程持有该连接””错误必须沿调用链向上传播,不得在中间层被吞没””该函数的返回值必须反映真实执行结果,不得使用默认值兜底”。不变量是架构级信息的最小载体,模型对不变量的遵循度远高于对描述性需求的遵循度。

(三)实现与测试分离生成

不要让同一个模型在同一轮对话中同时产出实现与测试。可行的做法是:先由模型生成实现,再由人(或另一轮独立会话,仅提供接口契约而不提供实现细节)编写测试。测试的灵魂在于独立视角,一旦测试由实现反推而来,它就失去了发现问题的能力。

(四)为错误处理设立强制契约

在项目层面约定:底层函数不得吞没错误,必须通过明确的返回约定或异常机制向上传递;顶层统一做错误分类与上报。这条契约应当在架构阶段就写入约束,而不是事后靠 review 逐个揪出。

(五)把性能与正确性验证前置

并发模型、调度方式这类问题,越晚发现修复成本越高。在架构阶段就应当明确:I/O 是否并行、由谁驱动、超时与重试策略如何。可以用一个最小可运行样例先验证调度模型是否符合预期,再铺开到全量实现。

(六)保留人工审查作为最后一道闸门

无论模型表现多么可靠,都应当保留人工对关键路径的审查。审查的重点不是逐行挑语法错误,而是检查三件事:架构约束是否被遵守、错误路径是否真实可达、测试断言是否具备独立判别力。

六、小结

智能编程工具在实现层的能力已经足够强,逐行代码的质量不再是主要瓶颈。真正的瓶颈转移到了两个地方:一是开发者能否把架构级意图清晰地表达出来,二是质量保障体系能否提供独立于模型输出的判别信号。

“改来改去还是错”,本质上是把架构问题当成实现问题在修。跳出这个循环的方法不是换一个更强的模型,而是提升输入信息的层级——从症状升级到诊断,从补丁升级到约束,从”这里错了”升级到”这里应当这样组织”。当协作模式对齐了模型真实的能力分布,那些看似”改不对”的问题,往往一句话就能解开。

发表评论

活动