AI 没有减少工作,只是把工作挪到了别的地方。
AI 用 10 分钟写完了我一个功能的前 80%。
代码很干净,逻辑也讲得通,正常流程第一次运行就成功了。我看着功能跑起来,心里甚至冒出了一点开发者特有的小骄傲,忍不住往椅背上一靠。
确实让人惊喜。我感觉效率高得离谱,心想再来 10 分钟,最多 15 分钟,这个功能肯定就能收工。
那是周二。
到了周四晚上,我还在处理同一个功能。
不是因为 AI 失败了。恰恰相反,它非常成功地完成了不该被当成重点的那部分——简单的部分。真正困难的工作,它几乎原封不动地留给了我。
边界情况、错误处理、空值检查,以及真实用户做出正常流程没有预料到的操作时,系统应该怎么办。
这些 AI 都没有写。它甚至不知道这些问题存在。它自信而完整地为“一切正常”的世界做了优化,可惜用户生活的并不是那个世界。
这就是 AI 写代码的 80/20 法则:前 80% 很快、很亮眼,甚至有点像魔法;最后 20% 才是真正的工作,而且往往会吃掉整个任务 80% 的时间。
今天和大家聊一下这道落差,以及为什么和周二省下来的那 10 分钟相比,这件事更值得关注。
前 80%:快、干净,而且确实很厉害
在谈那些让人头疼的部分之前,我得先替 AI 说句公道话。
AI 完成前 80% 的能力确实很强。只要需求描述清楚,它通常能理解正常流程应该是什么样,并生成真正可以运行的代码。不是“勉强能跑”,而是变量命名合理、逻辑顺畅,实际运行也确实能工作。
第一次看到这种效果时,我甚至觉得自己像是在作弊。工单一个接一个关闭,研发速度曲线不断上涨,我交付功能的速度比过去几年都快。
这种感觉是真的,我没有在讽刺 AI。它之所以快,是因为它处理的是熟悉的区域。正常流程是一条被走过无数次的路,同类问题早已在训练数据里以各种形式出现过,也被解决过成千上万次。模型只要识别出模式,就能很有把握地给出结果。
所以,前 80% 是真的,速度也是真的。
问题在于,我们渐渐把这 80% 当成了整个任务。可它不是。
最后 20%:周二的功能,为什么拖到了周四
AI 写完了正常流程。下面是它没有写的东西,一点都不夸张。
空列表
如果用户还没有任何数据,会发生什么?
新注册的账号,数据库里什么都没有。AI 默认列表里一定存在数据,可真实情况偏偏是空的。它没有做检查。上线三天后,你从用户反馈里才知道这个问题,花一个小时顺着调用链排查,最后补上一个本该周二就写好的判断。
错误处理
AI 默认网络会响应,默认 API 会返回你想要的数据,也默认第三方服务一直在线。
每一个 try-catch、每一套降级方案,以及“失败时页面应该给用户展示什么”的决定,最后都要由你来完成。AI 把它们留空了,因为你的提示词里只描述了正确流程,没有描述事情出错时怎么办。
业务特有的边界情况
这个问题每次都让我意外。
AI 不知道你的业务逻辑。它不知道在应用的三个不同位置里,“空”分别代表三种不同含义;不知道历史数据采用过另一种格式;也不知道某个企业客户一直在用一种产品团队从未预料过的方式操作系统。
但你知道。AI 从来没有接触过这些信息。
性能断崖
AI 写出的代码可以处理你提供的示例,却不会主动按照真实规模进行压力测试。
等功能上线后,大数据量用户打开页面需要 4 秒,你才会发现瓶颈。代码本身没有错,它只是从来没有按照真实负载设计过。
可维护性成本
这个问题出现得最慢。
AI 会为今天的问题写一套解决方案。三个月后,需求稍微发生变化,你想在原有代码上扩展功能,才发现当初的抽象和新需求怎么都对不上。最后,重构花掉的时间甚至比从头写一遍还多。
上面每一项都需要时间。合在一起,它们几乎总会占到我使用 AI 开发一个功能时的大部分工作量,大约就是总投入的 80%。
AI 为什么看不到真正的边界情况
一开始,我以为解决办法只是把提示词写得更详细,比如在最后补一句:“请再想想还有哪些边界情况。”后来发现,这句话能帮上一点忙,但解决不了根本问题。
原因很简单:生成正常流程的模型,和负责检查这段流程的模型,看到的仍然是同一批上下文,也受同一套知识边界限制。
它当然可以列出一些“看起来很像边界情况”的东西,但这些通常还是训练数据里常见的失败模式。真正棘手的问题往往来自分布之外:只有你们公司才有的业务规则、迁移了一半的历史数据、藏在三层函数调用下面的空值分支,以及某个客户多年形成的特殊操作方式。
换句话说,AI 可以模拟它见过的边界情况,却无法凭空知道它从未见过的现实。
所以,反复追问同一个模型“还有什么可能出错”,最后得到的很可能只是更像答案的猜测,而不是真正缺失的情况。要抓住最后 20%,不能只靠更用力地问,还得引入来自系统外部的证据:真实数据、失败日志、历史事故、业务专家和能够独立验证结果的测试。
30 秒生成的代码,让我改了 3 个小时
前段时间,我在看一个 Pull Request,大约 200 行 AI 生成的代码,而我写提示词只用了 30 秒。
接下来,我和这 200 行代码待了整整 3 个小时。
不是因为它们坏了。代码没有问题。
这 3 个小时,我都在补 AI 默默划出职责范围的那些事情:错误分支、空值检查、解释关键决策的注释,以及只有真正思考用户会怎么操作时,才会发现的边界情况。
写提示词的那 30 秒,我觉得自己很快。处理代码的那 3 个小时,我又觉得自己很慢。
但后来我反复想到一件事:那 3 个小时才是真正的工作,30 秒生成的只是脚手架。
AI 并没有减少工作,只是重新安排了工作的位置。时间从“写出基本结构”转移到了“让它真正可用”。而让它真正可用更慢,因为这一步依赖 AI 确实没有的东西:你的具体场景、真实用户,以及这套代码一路演变过来的历史背景。
从那以后,我不再关心生成代码用了多长时间,而是开始记录一个更诚实的指标:从开始到真正可以发布,一共花了多久。
如果一定要给这种现象起个名字,我更愿意叫它“AI 债务”:草稿来得很快,集成却很慢。前面的速度让人误以为工作已经接近完成,于是我们放松检查;那些没有被处理的假设、边界和架构问题则在后台悄悄累积,最后由测试环境或生产事故寄来账单。
这笔债务不会出现在代码生成速度里,却会实实在在地出现在日历上。
这不是在抱怨 AI
先说清楚,80/20 的分布不是 AI 的失败。某种程度上,它本来就是这么设计的。
AI 针对常见情况进行了优化,而常见情况通常就是正常流程。快速生成常见流程当然有价值,我并不是在否定它。
真正的问题不在 AI,而在于我们开始用什么方式衡量 AI 带来的生产力。
我们看研发速度、关闭的工单数量、生成的代码行数和提交记录。这些指标非常擅长展示前 80%,因为它们出现得快、看得见,也很容易变成图表上的绿色方块。
最后 20% 在这些指标里几乎是隐形的。
没有哪个看板会专门展示“补充错误处理花了多少时间”,站会里也很少有人说:“我昨天一整天都在处理 AI 没想到的边界情况。”这些工作不会明显出现在任何地方,却吃掉了大部分时间。
前 80% 能把产品带到演示阶段,最后 20% 才能把它带进生产环境。
如果你没有记录最后 20% 用了多久,那你衡量的就不是真实生产力,而是自己能多快写完一段提示词,并因此获得一种“今天效率真高”的满足感。
我现在会怎么做
我没有放弃 AI,也完全没考虑过不用它。不过,我调整了几件事。
一开始就给最后 20% 留出时间
只要任务涉及 AI 生成代码,我就会把预估时间按照生成时间的大约 4 倍来计算。
AI 让一个功能看起来只需要 10 分钟,我会告诉自己这是一个 40 分钟的任务,并按照这个时间安排。不是悲观,只是这个规律一次又一次出现。
当然,4 倍只是我自己的起点,不是固定公式。如果你经常处理历史系统、格式混乱的数据或者特殊业务规则,这个倍数很可能更高。领域越陌生、数据越奇怪,AI 看不到的部分通常就越大。
先写规格,再让 AI 写代码
现在我会尽量把“帮我实现这个功能”改成一份更明确的规格:输入和输出是什么、允许哪些状态、哪些状态绝不能出现、失败后如何恢复、性能边界在哪里、验收条件是什么。
这就是规格驱动开发真正有价值的地方。它不会让 AI 突然变聪明,但会让问题的边界更清楚。很多原本要到周四才发现的事情,会被提前搬到周二写代码之前讨论。
规格不能消灭最后 20%,但能把它从不可预期的返工,变成可以提前安排的工程任务。
在提示词里明确要求处理异常流程
甚至在生成主要代码之前,我就会先加上这些问题:
输入为空时应该怎么办? API 请求失败时应该怎么办? 这里可能有哪些边界情况?
AI 不会自动想到所有这些问题。如果我明确写出来,它至少会尝试处理一遍。
先写错误信息
如果一时不知道有哪些失败模式,我会先问自己:出错时,系统应该对用户说什么?
先写错误信息,会逼着我们提前命名失败状态。比如“请求失败,请稍后重试”“当前账号没有权限”“数据格式不受支持”,每一句话背后都对应一条需要实现、测试和监控的异常路径。
正常流程告诉系统成功时做什么,错误信息则提醒我们失败时不能装作什么都没发生。
在代码出现之前,先写会失败的测试
什么情况能把这个功能弄坏?一个故意捣乱的用户会怎么操作?
我会先写这些测试,再让 AI 写代码,让它面对一个明确的目标。这仍然抓不住所有问题,但至少比完全依赖 AI 自己寻找问题要可靠。
不过,测试只是存在还不够。它必须先在修改前的代码上失败,然后在修改后的代码上通过。如果一个测试在新旧两份代码上都能通过,它就没有真正守住任何东西,只是 CI 里一块亮着绿色的装饰。
我现在会把这一步叫作“咬合检查”:测试必须真的咬住这次改动,证明没有改动时问题确实存在,完成改动后问题才被解决。
给结果安排一个独立的第二视角
最后 20% 之所以容易漏掉,还有一个结构性原因:写代码的人、判断“已经能跑”的人和决定“可以上线”的人,经常是同一个人,甚至是同一个 AI 会话。
更稳妥的做法,是在三个层面安排第二视角:
门禁层:测试必须在修改前失败,不能让没有验证能力的测试混进来。 团队层:“功能能运行”和“功能可上线”采用不同的检查清单,重要改动尽量由另一个人复核。 工作流层:使用真实日志、生产样本、压力测试和独立评测,而不是继续让生成代码的模型评价自己。
这里真正重要的不是层数,而是独立性。如果三层都依赖同一份上下文、同一种假设和同一个模型,那只是同一个检查者换了三件外套。
记住那 3 个小时
每当我因为演示跑通了,就想赶紧把功能推上去时,我都会提醒自己那 3 个小时。
30 秒生成代码的感觉确实很好,但后面的 3 个小时才是工作本身。
这些做法无法让最后 20% 消失,但可以让它从“突然袭击”变成“可以预期”。能提前管理,总比上线后被它打个措手不及要好。
- END -
夜雨聆风