用 AI 写代码久了,最烦的一直是最后一步
说真的,AI 编程助手用了这么长时间,我发现自己陷入了一种很微妙的循环。前面写代码的过程有多爽,到最后收尾的阶段就有多烦躁。相信不少朋友都有同感:AI 把功能模块"刷刷刷"地生成出来,主体逻辑跑通的那一刻特别有成就感,但紧接着就是漫长的“最后一步”——让交付的代码真正经得起推敲。
这个“最后一步”,在我看来往往不是指按一下运行键那么简单,而是指那些为了让代码能真正落地、能交付、能维护而不得不做的一系列扫尾工作。比如:清理无用引入、统一错误处理、补齐边界条件、整理项目结构、修复潜在的类型隐患,还有最关键的——验证 AI 生成的代码逻辑是否真的符合业务预期。
我前阵子接手一个内部的数据清洗脚本项目,AI 生成了将近八百行代码,核心逻辑跑得飞起,我当时一度觉得这波稳了。结果到了收尾阶段,我一跑完整测试用例,挂了二十多个。那一刻的挫败感让我突然意识到,AI 写代码这件事,真正的分水岭不在生成,而在收尾。
1. 为什么偏偏是“最后一步”让人抓狂
1.1 AI 写代码的“高开低走”现象
你有没有发现,AI 写代码的时候特别容易“高开低走”?一开始它给你的框架非常漂亮,函数划分清晰,注释写得比很多人手工敲的还规范。但随着代码量增加,它开始暴露出一些耐人寻味的问题。
我观察下来,最典型的就是“局部合理、整体失衡”。AI 在生成单个函数或者模块的时候,逻辑往往很自洽。可一旦这些模块拼在一起,就会出现接口对不上、参数命名混乱、异常处理各管各的情况。
举个例子。我之前让 AI 生成一个文件批处理工具,它单独看每个功能点都没问题:读文件的部分用open()配合with语句,处理逻辑封装得也挺干净,输出部分还做了日志记录。结果三个模块拼接起来,读取模块返回的是List[str],处理模块却期望接收Iterator[str],类型兼容上虽然没有直接报错,但内存占用直接翻了三倍。
这种问题是最难受的。因为它在语法层面完全合法,测试小数据量的时候也看不出来,非要等到收尾阶段的集成测试才暴露。你让 AI 修,它修完一个又冒出另一个,好像永远在打地鼠。
1.2 最后一步真正考验的是什么
我后来想明白了,为什么大家普遍觉得 AI 写代码的收尾阶段特别费神。因为最后一步考验的根本不是写代码的能力,而是对系统的整体把控力。
这里面包含了几个层面:代码审查能力、测试覆盖率判断、性能瓶颈定位、依赖关系梳理,还有最容易被忽略的——文档与代码的一致性维护。这些能力恰恰是 AI 在生成代码时最薄弱的环节,因为它们需要的是全局视角,而非局部生成能力。
AI 更像一个执行力很强的下属,给它的指令越明确,它做得越好。但到了收尾阶段,面对的是“这个项目的整体质量是否达标”这种模糊问题,它很难给出让人放心的答案。它和人的协作关系很像:你负责判断方向,它负责执行路径。收尾恰恰是方向判断最密集的阶段。
1.3 从 bug 类型看待收尾的本质
我统计过自己项目中 AI 生成代码在收尾阶段的 bug 分布,大致是这样的:
| Bug 类型 | 占比 | 典型特征 |
|---|---|---|
| 边界条件遗漏 | 28% | 空值、超长输入、特殊字符场景未处理 |
| 异常处理缺失 | 24% | 只处理了理想路径,异常路径靠裸奔 |
| 类型与接口不匹配 | 18% | 模块间参数类型不一致,运行时才暴露 |
| 状态管理混乱 | 14% | 全局变量被隐式修改,排查非常困难 |
| 资源未释放 | 9% | 连接、文件句柄、临时文件等未妥善处理 |
| 其他 | 7% | 命名不规范、死代码、逻辑冗余等 |
这个统计给了我一个很重要的启发:AI 写的代码并不是“能不能跑”的问题,而是“极端条件下还正不正常”的问题。收尾阶段的核心任务,恰恰就是把这些极端情况一个个堵上。
2. 收尾阶段的核心工作:从“能用”到“扛得住”
2.1 建立验收驱动的收尾思维
我后来摸索出一套比较有效的收尾方法,核心思想是“验收驱动”。也就是在开始收尾之前,先明确这件事的“完成”到底长什么样。没有明确的验收标准,收尾就很容易变成无底洞。
对于 AI 辅助开发的场景,我建议至少从这几个维度来定义验收标准:
- 功能验收:核心业务流程是否全部走通,关键分支是否覆盖
- 健壮性验收:异常输入、极端数据、资源瓶颈下是否还能正常工作
- 一致性验收:代码风格、命名规范、架构模式是否统一
- 可维护性验收:下一开发者接手时,能否在合理时间内理解并修改代码
有了这层定义,收尾工作就从“感觉差不多”变成了“逐项检查”。我每次做完这个流程都会感慨,AI 帮我把“写了”这部分完成得很快,但“写好了”这个判断,始终得我来下。
2.2 收缩范围:先扫描,再深挖
收尾阶段最忌讳的就是一头扎进细枝末节。我见过很多人拿到 AI 生成的代码,第一反应是“这个变量名不太优雅,改一下”,然后就开始一行一行抠注释。这是标准的时间黑洞。
正确的打开方式是先扫描全局,筛选出值得深挖的点。我都会先回答这三个问题:
- 哪些模块的复杂度最高?
- 哪些模块的测试覆盖率最低?
- 哪些模块承担了最关键的业务逻辑?
回答完这三个问题,收尾的优先级就一目了然了。我一般遵循“核心路径优先、高频路径次之、边缘路径最后”的顺序。核心路径出了问题,整个项目就崩了;边缘路径出问题,顶多影响部分用户。
2.3 追踪数据流,而不只是读代码
读 AI 生成的代码时,我有个特别深的体会:光读代码是看不出问题的,要追数据流。因为 AI 生成代码的时候,它的上下文窗口决定了它更容易“看到”局部数据,而不是全链路的数据流动。
我收尾时都会在项目里画一张简单的数据流草图,标注出关键数据从输入到输出经历了哪些转换、哪些地方有分支、哪些地方可能产生异常值。然后逐个节点验证 AI 生成的代码是否真的覆盖了这些转换。
之前那个清洗脚本项目,我就是这么发现的问题。AI 生成的代码里,日期字符串的解析只处理了YYYY-MM-DD格式,但实际数据里有YYYY/MM/DD和YYYY.MM.DD。这种问题读代码根本发现不了,只有追踪数据流才能看到。
3. 实操案例:一个数据清洗脚本的收尾全记录
3.1 项目背景与痛点
几个月前,我参与了一个市场数据分析项目。原始数据是从几个渠道汇总来的 Excel 文件,每个渠道的字段命名还不一致,有的叫“日期”,有的叫“时间”,有的直接叫“date”。整个清洗过程涉及去重、格式统一、异常值剔除、字段映射、聚合计算等多个步骤。
这类任务的共同特点是:逻辑不复杂,但细节特别多。特别适合让 AI 先写一版,但收尾阶段就需要人工把那些渠道差异、边界情况、数值判定规则逐一验证。
AI 生成初版代码大概花了不到十分钟。我拿一份脱敏后的样例数据跑了一遍,主流程基本能通,但问题是,样例数据太规整了,跟真实数据的脏乱程度完全不是一个量级。
3.2 收尾第一步:跑真实数据,建立基线
我做的第一步,就是用一份未经任何处理的原始数据去跑 AI 生成的代码。这一步的目的不是看功能对不对,而是先建立性能与准确性的基线。
结果很快就炸了。问题主要出在三个方面:
第一,内存占用异常。AI 用了一个pd.concat循环拼接的方式处理分片数据,数据量一大直接吃掉了几个 G 内存。第二,类型推断不稳定。某个渠道的金额字段在部分行里是字符串格式,AI 生成的代码没有做预处理,导致后续数值计算直接报错。第三,缺失值处理策略太激进。AI 默认对所有缺失值都做了删除处理,但实际场景里缺失率超过 30% 的字段根本不适合删除,需要单独判断。
这些问题的共同点是:不是 AI 写的逻辑“错”了,而是它“不够稳”。这恰恰是收尾要解决的核心矛盾。
3.3 针对性修复:边界值、异常与性能
确定了问题清单后,我开始逐项修复。这里记录几个比较典型的处理过程。
问题一:内存占用过高
AI 生成代码用的是循环内逐批处理、最后统一合并的方式。我对数据量和耗时做了个简单的对比:
| 数据量(行) | AI 原版耗时 | 优化后耗时 |
|---|---|---|
| 10,000 | 1.2 秒 | 0.8 秒 |
| 100,000 | 8.7 秒 | 3.2 秒 |
| 1,000,000 | 崩溃 | 21 秒 |
问题根源在于concat在循环里的反复复制。优化方式也很直接,改用列表收集片段后一次性合并。这个改动看起来简单,但对大数据量的影响是质变的。
问题二:字段格式不一致
金额字段有三种格式:纯数字、带千分位逗号、带货币符号。AI 只处理了纯数字的情况。修复方案是定义了一个归一化函数,先去除货币符号和千分位逗号,再做类型转换。这里需要注意正则表达式的坑:货币符号在不同渠道里可能是$,也可能是¥,甚至可能是空白。我最后做了一组规则优先级,先替换,再清洗,最后兜底转换。
问题三:缺失值策略过于激进
流失率在 30% 到 70% 之间的字段,直接删除会丢掉太多有效信息。修复时按字段做了分级处理:缺失率低于 5% 的直接删除对应行;5% 到 30% 的用中位数或众数填充;超过 30% 的单独保留缺失标记,不参与部分聚合计算。
这个判断逻辑本身不复杂,但需要结合业务场景来定,AI 很难自己做出这种决策。这就是我在收尾阶段存在的意义——把数据领域的经验规则注入到 AI 生成的骨架里。
3.4 测试才是收尾的试金石
修完这些问题后,我没有急着交付,而是加强了测试环节。这里分享一个我常用的实战做法:为每个关键函数准备三组测试数据,一组是常规数据,一组是边界数据,一组是异常数据。
边界数据专门用来测试“恰好能跑”和“恰好跑不了”之间的临界区域。比如:空字符串、单元素列表、超大数值、负数、零值、None 值、混合类型列表等。异常数据则用来测试函数面对不合理输入时的表现——是抛出有意义的错误,还是静默返回错误结果。
我之前踩过很深的坑是:AI 生成代码里有些函数在异常输入下不报错,而是返回了某个奇怪的值。这种错误比抛异常更可怕,因为你根本察觉不到它出错了。比如有一个去重函数,传入None时竟然返回了空列表,看起来挺合理,实际上掩盖了调用方传参的问题。
所以我在收尾时会专门加一层“守卫代码”,在函数入口对关键参数做显式校验。这类代码看起来有点啰嗦,但能极大地提高排错效率。说到底,好的报错机制等于给未来的维护者留了一张清晰的线索图。
4. 收尾阶段的高频问题与排查工具箱
4.1 我经常遇到的五个问题与排查思路
结合自己这段时间的实战经验,我总结了五个收尾阶段最常遇到问题的排查思路:
问题一:AI 生成的代码“上一步能用,下一步就打回原形”。这种情况往往是全局状态被隐式修改了。排查手法:重点检查是否有模块级的可变对象被多处修改,比如
list、dict默认参数、全局变量缓存等,可以顺手用copy.deepcopy隔离。问题二:小数据跑得很好,一上大数据就卡死。多为算法复杂度问题。排查手法:看是否有循环内重复计算、无意识的嵌套循环、频繁在循环里做
DataFrame筛选等操作。该换set就换set,该换查找表就换查找表。问题三:报错信息指向的位置,和我觉得该出错的位置不一样。这意味着异常被层层吞掉后又重新抛出。排查手法:搜代码里的
except关键词,检查是否有“裸捕获”(except:不带异常类型)的情况,还有raise是否丢失了原始异常链。问题四:同一个函数,多调用几次的结果不一致。大概率是有隐藏的随机因素或外部状态依赖。排查手法:检查
random、time、环境变量、文件路径等不稳定因素,必要时显式注入随机种子。问题五:AI 反复修改同一段代码,但始终不解决根本问题。说明它在“表面症状”上打转。排查手法:这时候别继续对话了,干脆手动重写那一小段逻辑,或者换一个更明确的重写指令。
4.2 收尾阶段的实用工具链
工欲善其事,必先利其器。这个环节我平时会用到下面这些工具,各有各的不可替代性。
代码检查:静态分析工具能帮我把变量名错误、未定义引用、类型标注问题这类低级错误提前筛掉。重点要配置好规则集,否则默认规则太多、噪音过大,反而干扰判断。
运行时追踪:逻辑复杂的时候,我会在关键节点加临时日志输出,或者直接用调试器逐步跟踪。从数据流追踪的效率远远高于盲读代码。
测试覆盖率工具:检查测试到底覆盖了哪些行、哪些分支。我一般关注分支覆盖率,而不只是行覆盖率。行覆盖率高不代表分支都跑到了,很多隐蔽 bug 恰恰藏在未被覆盖的分支里。
依赖梳理工具:分析项目里模块间的依赖关系,帮助我快速识别“这个模块到底影响了谁”。这在收尾阶段做影响面评估时特别有用。
4.3 收尾的节奏感:制定一个“完成清单”
收尾阶段如果没有节奏感,特别容易陷入“一直在收尾”的死循环。我现在给自己定了个简单的三段式清单,每次按顺序走完就可以安心交付:
第一段:结构体检。检查项目结构是否清晰、模块划分是否合理、函数是否太长、命名是否统一。这一段主要是“看得顺不顺眼”。
第二段:数据验证。用多组真实数据跑通功能,重点观察边界行为和异常行为。这一段主要是“跑得稳不稳”。
第三段:边界打磨。补齐文档、完善注释、清理死代码、统一错误处理。这一段主要是“接得上手”。
走完这三段,质量就基本有保障了。我身边不少朋友用 AI 写代码觉得“不靠谱”,后来我发现大部分情况不是 AI 不靠谱,而是收尾阶段跳过了某一段,导致问题提前“埋雷”。
5. 调整心态:用“审稿人”的眼光看待 AI 的输出
5.1 把 AI 当协作对象,定好边界
和 AI 合作写代码,最忌讳的是两种心态:一种是完全放手不管,另一种是处处不放心、每个函数都重写。
正确的姿态是把自己当成代码审稿人。AI 是初稿作者,它负责快、负责全,而你负责准、负责稳。我现在的协作流程基本是:先让 AI 出全局框架,我再做结构调整;然后让它填具体函数,我再做逻辑验证;最后让它补充测试用例,我再做覆盖率检查。
这个模式跑了一段时间,整体效率确实比我一个人硬肝要高出不少。以前写一个完整的数据处理模块要小半天,现在基本能在两小时内完成,其中收尾占了一半多的时间。但反过来说,这个时间分配恰恰说明了收尾的分量——它才是决定 AI 协作质量的上限。
5.2 训练自己的“快速走查”直觉
收尾经验积累久了,自然会有一种“快速走查”的直觉。几乎扫一眼代码,就能大概判断哪些地方会出问题。
我的经验是:AI 生成的代码有几个可疑特征,值得多看两眼。一个是函数参数特别多、超过六七个的,往往职责不够单一,容易出状态耦合问题;另一个是注释比代码还多的地方,往往说明生成者自己也不太确定逻辑走向,写得心虚;还有一个是一个函数里出现三层以上缩进嵌套,可读性与可维护性通常都比较堪忧。
这种直觉说到底是从一次次踩坑中训练出来的。刚开始收尾的时候,我每个模块都要一行一行读,慢且累。现在基本靠“特征扫描”就能定位高风险区域,再集中精力深挖。这种转变,大概是和 AI 协作久了最大的收获之一。
5.3 对“收尾时长”的心理预期管理
最后想说一点心理建设层面的东西。很多朋友刚开始用 AI 辅助编程时,对收尾时长的预期是完全错误的。总以为 AI 都写完大部分了,剩下应该是走个过场,结果一收尾就是一晚上,特别容易产生很强的心理落差。
我的建议是,在做任务拆解的时候,就把“收尾”单独列出来,给出充足的时间预算。比如一个任务预计四小时,那我会按“AI 生成一小时、主流程验证一小时、收尾两小时”来分配。这样整个过程不会因为收尾超出预期而变得焦躁,心态稳了,排查问题反而更快了。
现在每次接手新任务,我甚至会在最开始就跟自己说:AI 负责冲刺,我负责兜底。这一句话基本概括了我对用 AI 写代码这件事全部的心态。它与技术无关,却能决定这个协作模式到底能走多远。
说到底,AI 写代码只是一个放大器,放大的是我们每个人的工程能力与判断力。而真正拉开人与人差距的,从来不是谁写得快,而是谁能在最后一步守住质量这道关。