先说事故本身。
那天在改一个站的内容文件,PHP 数组,几百行。改完直接传上服务器。文件里有一处括号数量不对——一个数组块该用四个方括号收尾,只写了三个。PHP 是解释型语言,语法错误在加载那一刻才暴露,于是整站白屏,五百错误,全站,不是某一页。
两分钟后恢复。补上那个括号,重新传,站回来了。
两分钟不长,但那两分钟里任何一个访客看到的都是彻底崩坏的页面。如果那时候有人正准备联系我们,他不会再回来。
这个错是 AI 犯的,但责任不在它
括号是 AI 改的,这一点没什么好回避。但把这件事归结成「AI 不可靠」是错的判断,会让你得出错误的结论。
人写代码同样会漏括号,而且漏得更频繁。真正的区别在别处:AI 的产出速度快得多,所以单位时间里流向生产环境的改动量大得多。同样的出错率,绝对错误数会上升。
所以问题不是「怎么让 AI 不犯错」——这个目标达不到,人也达不到。问题是:错误从产生到造成损失之间,隔着几道东西。
那天的答案是:零道。文件从编辑器直接到了生产环境,中间没有任何检查。这才是事故的真正原因。
第一道:落地之前先验证语法
当天就写了一个部署脚本,逻辑很简单:
所有文件先同步到服务器上的一个临时目录,对每一个 PHP 文件跑一遍语法检查,全部通过才覆盖到真正的插件目录。有任何一个不通过,临时目录直接删掉,生产环境一个字节都没动过。
这件事的关键不在于用了什么工具——语法检查是每种语言都自带的东西。关键在于顺序:先验证,后落地。原来的顺序是先落地,出了事再回滚,而回滚的前提是你已经知道出事了。
成本是每次部署多几秒。收益是那一类事故从此不可能再发生。这不是「概率降低」,是「结构上排除」——语法错误的文件根本到不了生产目录。
第二道:改完之后自己去看一眼
语法正确的代码,逻辑可以完全是错的。
同一周还遇到一次:一段生成代码的脚本里,有个字符串处理写成了「把结尾的 u 和引号一起替换掉」,本意是去掉多余的引号。结果是所有以字母 u 结尾的名字都被截断了一个字符。
这个错误语法完全正确,跑起来没有任何报错,生成的文件看着也正常——除非你恰好检查了那几个以 u 结尾的条目。
所以部署脚本的第二部分是:装完之后自动请求十几个关键页面,检查返回码。不是「能不能打开」这么简单,而是逐个确认。任何一个不是 200,脚本报错并给出回滚命令。
后来又加了一条:静态页面生成之后,检查关键页面的文件是不是都存在。因为缺页面不会报错,只会安静地变慢或者变空——这类问题能潜伏几个月不被发现。
第三道:让错误可以一步撤回
前两道是拦截,第三道是承认「总有拦不住的」。
所有改动都在版本控制里,包括模板、样式、脚本、内容数据。任何一次改动都能查到改了什么、为什么改、什么时候改的。撤回是一条命令。
服务器上的关键配置文件在动之前先复制一份带时间戳的备份。这条规矩看起来老土,但在你改的是一个五十个网站共用的配置文件时,它是唯一让你敢动手的东西。
有经验的人在这里做什么
说「让 AI 写代码,人来 review」是句正确的废话。逐行看 AI 写的代码,速度优势就没了,而且人看代码的注意力衰减得很快,看到第三百行时和没看差不多。
实际有用的做法是把注意力放在特定几个位置:
凡是「批量」的地方都要抽查。循环、批量替换、正则表达式——AI 在这些地方最容易写出「大部分正确」的代码。上面那个截断名字的错误就是这一类。检查方法不是读代码,是拿三五个真实数据跑一遍看输出。
凡是不会报错的地方都要主动验证。SEO 标签写错了不报错,缓存没清不报错,图片没上传不报错,页面少了一个不报错。这些地方必须主动去查,因为它们不会来找你。
凡是「共用」的东西都要先备份。一个站自己的文件改坏了,影响一个站;共用的配置改坏了,影响所有站。这两件事的谨慎程度应该差一个数量级。
凡是不可逆的操作都要停下来确认。删除、迁移、改域名、动数据库。这些操作 AI 执行起来和改个颜色一样顺手,但后果完全不同。
这套东西为什么值钱
客户买的不是「我们会用 AI」。会用 AI 现在不构成门槛,你自己下午就能开始用。
客户买的是这个:改动会经过验证才上线,上线之后有东西在确认它真的正常,出了问题能在你发现之前就被发现,以及万一真出事,撤回是一条命令而不是一场灾难。
这些东西平时完全看不见。只有在出事的那一天,你才会知道当初有没有人替你把它们建起来。
我们自己的站就是这么跑的,所有防护都是被真实事故逼出来的,包括上面那两分钟。我们交付的每个项目用的是同一套流程。