背景:一个人,加上一堆 AI,九天
先交代一下这是个什么东西,不然下面那串数字看着像是在吹牛。
我做的是一个 Windows 桌面宠物:一只小动物常驻桌面底部,会呼吸、会眨眼、会自己溜达到屏幕另一头,闲着的时候甩甩尾巴,累了趴下睡觉,饿了弹出气泡问你要东西吃。你可以在桌面上喂它、给它换装扮。说白了,是给当年 QQ 宠物还魂------只是这次换成自己动手写。
阵容非常简单:
- 我:一个人。负责产品判断、取舍拍板,以及每一轮的验收。
- AI:负责写代码、写自动化脚本、按需求生成和修改美术素材。
分工听着很清爽,实际跑起来是这个节奏------我提需求或报问题,AI 定位到具体是哪段逻辑、哪张图,改完我复测,通过就进下一轮。 一天能跑四五轮,九天下来攒出了 42 轮日志。
那 47 个测试脚本也是这么来的:每遇到一次说不清的「怪」,就先写一个能量化它的脚本,量不出数字不许动代码。
出发时的计划比现实保守得多。九天前我没想过这东西能跑到可分发。发出这篇之前我回头翻了一遍日志,发现它真正的价值不在「AI 替我写了多少行代码」,而在「我在哪些地方差点被它糊弄过去」。
于是有了下面这篇。
序:先看这九个数字
| 数字 | 含义 |
|---|---|
| 9 天 | 从空目录到可分发版本 |
| 42 轮 | 开发日志里记录的迭代轮次,每轮一次「反馈---定位---修复---验收」 |
| 47 个 | 项目里测试与诊断脚本的数量 |
| 15 万字 | 那份按轮次追加的开发日志体量,它是我跨会话的「存档点」 |
| 100 多 MB | 最终分发包 |
| 0.3.3 | 最终版本号(0.1 → 0.3.3,中间重打了十几次包) |
| 3 次 | 同一句错误结论在文档和注释里被当成事实传递的轮数 |
| 1 句 | 引发一轮「最大技术债」重构动议的错误注释 |
| 0 次 | 靠 AI 报错发现严重 bug 的次数(几乎全是我自己量出来的) |
只看前六个数字,这是个 AI 提效的成功故事。
真正让我后来后背发凉的是后三个:AI 最大的风险不是写错,是写得看起来对。
下面九条,每一条背后都是一次真实的翻车。
一、先造测量仪,再谈修复
开局我在自测里记下三个问题:「开机自启不好使」「站着呼吸丢帧严重」「走路丢帧严重影响观感」。
三个都既没有堆栈,也没有报错。这种情况下直接让 AI 去读代码猜,它会给我三个听起来非常合理的答案------然后大概率全猜错。
那轮我做的第一件事,是让 AI 先写一个测量脚本。理由很简单:「丢帧」至少有三种完全不同的成因,在截图上长得一模一样:
| 成因 | 现象 | 修法 |
|---|---|---|
| 主线程被饿死 | 帧率掉到一半以下,长帧变多 | 减负 |
| 换帧节拍被量化 | 帧率跑满,但间隔成簇(31ms×40 / 63ms×60) | 加密心跳 + 帧间插值 |
| 根本没在换 | 换帧次数远低于期望 | 查素材/逻辑 |
量出来的是第二种:界面稳稳跑满帧率,换帧间隔却被心跳量化成了双峰。这条修法和「减负」完全是两条路。
第二个问题同理。运动「卡帧」的真实原因,是截错了对象:本该截断距离,代码却截断了时间。距离不变、时间被砍,等效速度直接被顶到设计值的 1.6 倍,超过了美术固定的单圈步长,8 帧的节奏被挤成一团。
这个数字不量出来,代码读一百遍也看不见。
可复制的做法:凡是「感觉卡」「有点怪」「不好使」这类主观反馈,我的第一句话永远是------ 「先写一个能把这件事量成数字的脚本,别改代码。」
顺带一个反直觉的发现:测量仪自己也会骗人。同一个采样窗里,主体尾巴撞上一次随机漫游,就混进来 27 次换帧,还冒出「某一图层消失 1.4 秒」的假象------那其实是另一段动画,不是它。所以判据必须限定上下文(该段只截取真正处于待机状态的样本),否则你量到的是自己的噪声。
二、全绿 ≠ 能用:验收判据要问「动作」,别只问「几何」
我总觉得运动姿势不对劲:画面上像只有一条腿在动。
用三种独立方法交叉验证之后,结论比我的感觉还糟:
| 角色 | 四帧里脚的离地高度 |
|---|---|
| 角色 A | 0 / 0 / 31 / 0 px(只有一帧、且只有一条腿) |
| 角色 B | ≤ 4 px |
| 角色 C | ≤ 1 px |
| 角色 D | ≤ 3 px |
四个全都没有步态,唯一的帧间差异是尾巴在甩。
而当时我的切片验收脚本四项判据全绿。为什么?因为那四项全是几何 判据:底边落基线、帧间水平跨度、缩放一致。它只能证明「四帧对齐得很整齐」------四帧一模一样也能全绿。
那轮文档里我写下的那句自我批评,我觉得还算准:
这是流程漏洞,不是脚本写错。
AI 写的验收脚本,验证的是它自己能验证的东西,不是你需要的东西。 这是最隐蔽的一层:脚本没写错,逻辑没报错,判据全过,产品是坏的。
可复制的做法:每加一条自动化判据,追问一句------「如果这个功能完全没生效,这条会红吗?」 答不上来,就是一条装饰性判据。
同类翻车还有一次:判断「某个 UI 元素在不在」时我用了像素亮度做守卫。结果两个元素的纵向位置只差 2 像素,落在同一条扫描带上,脚本把气泡认成了功能栏,20 多帧证据全丢,反手假报「气泡从没出现过」。后来改成按形状 + 配色判才对。
启发很朴素:判「某个 UI 在不在」,要问结构或形状,别靠像素亮度。
三、别用提示词硬撞能力边界------改需求更便宜
发现四个角色都画不出步态之后,我让 AI 重试出图,第二次把提示词几乎写到了指令级------「第 4 帧是第 2 帧的水平镜像」。
结果抬起来的仍然是同一条腿。
结论我写进了文档:
正面视角下,AI 画不出左右腿交替------这是能力边界,不是提示词问题。
程序化补救试了三种,全部否决:整帧水平镜像(附属物件从右边跳到左边)、局部镜像带羽化(接缝肉眼可见)、分部件拼接(矩形错位块)。
最后是我拍板:改成蹦跳式移动。 依据是一句很清醒的判断------正面视角下 AI 能画对「整只腾空」,画不对「左右腿交替」。
一次需求上的让步,换来了问题彻底消失。要是继续死磕提示词,代价是无限的天数。
可复制的做法 :同一个东西让 AI 连撞两次墙,就该怀疑是能力边界,而不是措辞问题。 改需求比改提示词便宜。
四、把「唯一真源」钉死,否则它每轮给你重新发明一遍
AI 没有跨会话记忆,它的默认行为是「重新推导一遍」。项目里几个反复出问题的地方,最后都是靠钉死唯一真源才稳住:
| 东西 | 唯一真源 | 不钉死会怎样 |
|---|---|---|
| 边界坐标 | 一个统一的计算函数 | 主流程内联一份、测试脚本抄一份,改一处漏两处 |
| 挂件锚点 | 一份 JSON 配置 | 四个角色各漂移一次 |
| 版本号 | 构建配置文件 | 分发文档十几处对不上 |
| UI 缩放系数 | 一个共享模块 | 进程间直连,边界被绕穿 |
第十九轮的记录里有一句很典型的自述:位置计算里内联着一份偏移量,测试脚本的断言又自己抄了一遍同样的值------两份事实,两份都会过时。
还有一条不变量被我写成硬约束:边界留缝必须大于贴边容差。哪天有人把这两个值调反,角色走到墙边就会被误判成「已贴边」,切换姿态后半个身子探出屏幕。
这种「两个常量之间的不等式」,AI 根本不可能自己推导出来,只能由人写进记忆。
五、AI 的失败是静默的:不报错才是常态
这是整个项目里最贵的一条教训。把踩到的静默失败列出来,你会发现没有一个会抛异常:
| 场景 | 静默的表现 | 代价 |
|---|---|---|
| 给 exe 写图标 | 失败只 warning,不中断打包 | 打出一个没有图标的安装包 |
| 创建开机自启快捷方式 | 不校验目标路径是否存在,照样返回成功 | 建死链,用户看到「开关自己弹回去」 |
| 同一个文件并行改多处 | 编辑返回成功但没落盘 | 界面「改了一半」,搜构建产物才发现 |
| 依赖安装收尾 | 进程僵死,没输出也没退出码 | 干等,不知道该杀还是该等 |
| 打包时旧产物没清 | 二十几个历史构建被一起打进去 | 分发包白白多了十几 MB |
| 锁屏状态下跑测试 | 合成的鼠标事件全落进锁屏界面 | 整套断言全红,装得极像功能回归 |
| 打包缓存被占用 | 删除失败被网关拦下 | 打包静默挂死 |
「开机自启」那条最典型:便携版的真实文件名带了版本号后缀,代码里却写死了一个不带后缀的名字。系统接口高高兴兴建了一条指向不存在文件的快捷方式,返回值 true。
修法是补一道闸门:建链之前先确认目标真的存在,不存在就直接拒绝并报错,而不是把「调用成功」当成「事情办成了」。
可复制的做法 :凡是 AI 调用的「带外部副作用」的接口(写文件、建链接、改二进制、发通知), 默认它不会告诉你失败了,自己补一道后置校验。 我的做法是给每个打包产物都配一个校验脚本(比如比对图标二进制、验证素材能否正常加载)。
六、「改完复测」不够,要能证明改的是这一处
修一处动画残影时撞上一个诡异现象:改完复测,重合度指标精确回到改动前的同一个数值。
我的第一反应是「改动没生效」。查下去才发现:安装脚本覆盖的是前一帧 ,而不是需要替换的那一帧。
文档里那句总结我到现在还挺喜欢:
这种「精确复现」,本身就是改错对象的强信号。
一次真正的改动,指标不该精确回到原值。能精确回到原值,说明你动的地方和被测的地方不是同一个。
可复制的做法 :复测别只看「通过/不通过」,要看数值有没有往预期方向动。 精确等于原值 = 没改到;变化方向相反 = 改反了。
七、顺序是不能反的:越贵的动作越要放到最后
打包一次十几分钟、产物一百多 MB。项目里有一条被反复强调的纪律:
新增任何「程序主动行为」,必须先把随包文案补齐,否则要白重打一次,哈希还会全变。
第一次违反是这么发生的:我按写文档的习惯在纯文本 README 里写了加粗语法,落到 .txt 里就是字面的星号,用记事本打开看到的是一串星号。改完重打,顺便加了道护栏:打完搜一遍星号,命中数应为 0。
于是这条纪律后来固化成了流程里的固定顺序:
- 功能改动全部完成 →
- 随包文案 / 版本号 / 分发文档同步 →
- 清理历史产物 →
- 构建 → 打包 → 哈希 → 逐项验收
中间任何一步插到第 4 步之后,代价都是「再来一遍一百多 MB」。
可复制的做法 :把最贵、最难回滚的动作(打包、发布、迁移、真机长测)排到流程最后,并在它之前设一道检查清单闸门。AI 很愿意帮你「顺便改一下」,而「顺便」在发布之后就意味着从头再来。
八、把记忆写进仓库,而不是写进聊天框
这条最容易被低估。AI 的上下文会丢,但仓库不会。
这个项目里有两份东西,是我每次开新会话必读的:
- 一份按「第 N 轮」追加的开发日志,记录每轮的起因、结论、改动、验收、还没做的事
- 一份只存跨会话必须记住的不变量和坑的记忆文件
记忆文件里最有效的一种句式,是带「勿回退」的硬约束:
移动只能截距离,不能截时间 某个图层绝不能用条件渲染卸载 绝不退回无条件的最近距离吸附 窗口默认尺寸不能再改回去,原尺寸会裁掉主体
为什么必须这么写?因为下一个会话的 AI 不知道你当初为什么这么定,它会「好心地优化」回错误方案。一条没写理由的约束,在 AI 眼里就是技术债。
所以每条约束后面我都附上理由和实测数字。比如「某个状态切换只能用 visibility,不能用透明度」------因为动画的优先级高于普通样式声明,透明度会被动画覆盖回去,实测单次步进值和正常值差了几十倍。
可复制的做法 :让 AI 在每轮结束时往仓库里写三样东西------改了什么、为什么、下次别改回去。 这不是文档工作,这是给未来的自己买保险。
九、逻辑没错,也可能是 bug
最后一轮修的是「睡觉不回精力」。
先跑纯逻辑仿真:每 tick 确实在加值、数值单调回升、迟滞阈值正常、小数类型不丢精度、降级存储正确、定时器也确实调用到了它。
整条链路都是对的。
问题出在量级:恢复速率换算到分钟只有零点几点,再叠加渲染层半分钟才刷新一次------盯着看几分钟,能量条几乎不动。
于是它就被当成 bug 了。而最危险的处理方式是去改定时器或存储。正确的动作是把速率提上去(几分钟内肉眼可见),并且仍刻意低于「一觉回满」,让付费道具依旧有意义。
可复制的做法 :当你觉得「这个功能没生效」,先分清是逻辑 bug 还是观感 bug 。 两者修法完全不同,而且------逻辑改对了、量级改错了,一样是 bug。
附:一份「AI 翻车模式」速查表
| 翻车模式 | 典型症状 | 防线 |
|---|---|---|
| 幻影事实 | 文档和注释里「因为 A 所以 B」传了三轮,从没人量过 | 写因果之前,A 和 B 各自要有可复现实测 |
| 装饰性判据 | 四帧一模一样,验收全绿 | 每条判据反问:「完全没生效会红吗?」 |
| 静默降级 | 只 warn 不中断,产物是坏的 | 每个外部副作用接口补后置校验脚本 |
| 假红 / 假失败 | 锁屏、时序抖动、旧证据图残留 | 结论要肉眼复核;能复跑的先复跑 |
| 通道名错位 | 类型检查 + 构建全绿,某个 UI 状态恒不生效 | 跨进程契约靠真机验收,不靠类型检查 |
| 同文件多处改丢失 | 界面「改了一半」,还不报错 | 逐条改、逐条检索核验 |
| 污染打包 | 二十几个历史构建被一起打进去 | 判据看「产物理是否只有一套」,不看体积 |
| 改错对象 | 复测指标精确回到原值 | 看数值变化方向,不只是通过与否 |
| 能力边界 | 提示词写到指令级仍撞墙 | 撞两次就改需求 |
| 顺序倒置 | 白重打一次一百多 MB | 贵的动作排最后,前置检查清单 |
尾声:那句被传了三轮的错注释
第十八轮,路线图和选型评估都把「双缩放方案」列为最大技术债,理由是「某个屏幕坐标字段的单位错了」,给出的解法是去掉底层缩放能力、改用样式层的缩放并实现三套并存。
这条链路看着非常完整。于是我先量:
| 量 | 结果 |
|---|---|
| Δ 屏幕坐标 ÷ Δ 逻辑像素 | 1.0000 |
| Δ 客户区坐标 ÷ Δ 逻辑像素 | 1.2500 |
结论:不做。屏幕坐标本来就是屏幕逻辑像素。原注释里那组「鼠标走 100px、窗口只挪 80px」的 100:80,其实是客户区坐标的数字,被误记成了屏幕坐标。
文档里留下的那句教训,是这 42 轮里我最想转述给你的一句:
这条「技术债」是从一句错注释推出来的 :原始事实只有两条,中间那步纯属推断,没人量过, 却在两份文档加五处代码注释里被当成事实传了三轮。 写「因为 A 所以 B」之前,A 和 B 各自都要有可复现的实测或引用。
九天、42 轮、47 个脚本之后,我对「指挥 AI」这件事的理解,收敛成了三句话:
- 产能不是瓶颈,判断力是。 AI 一天能写的功能,你可能要三天才能验完------那就把三天花在刀刃上。
- 你交付的不是代码,是标准。 什么算对、什么算好、什么不许改回去------这些只能你来定。
- AI 不会承认自己不知道,所以你要替它承认。 所有「看起来对」的地方,都值得先量一遍。
最后是我始终坚持的一点:人身上有三件事 AI 替不了------拍板 (改成蹦跳,是我一句话的事)、体感 (「有点怪」才是最有价值的需求)、划红线(统计只记次数、绝不记录内容------这条从第一天就写进了设计说明书,从未讨论过)。
代码可以让它写。这三件事,得你自己来。