踩坑无数换来的教训:指挥AI开发App,这几点你必须知道

3 阅读16分钟

背景:一个人,加上一堆 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 秒」的假象——那其实是另一段动画,不是它。所以判据必须限定上下文(该段只截取真正处于待机状态的样本),否则你量到的是自己的噪声。


二、全绿 ≠ 能用:验收判据要问「动作」,别只问「几何」

我总觉得运动姿势不对劲:画面上像只有一条腿在动。

用三种独立方法交叉验证之后,结论比我的感觉还糟:

角色四帧里脚的离地高度
角色 A0 / 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。

于是这条纪律后来固化成了流程里的固定顺序:

  1. 功能改动全部完成 →
  2. 随包文案 / 版本号 / 分发文档同步 →
  3. 清理历史产物 →
  4. 构建 → 打包 → 哈希 → 逐项验收

中间任何一步插到第 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」这件事的理解,收敛成了三句话:

  1. 产能不是瓶颈,判断力是。 AI 一天能写的功能,你可能要三天才能验完——那就把三天花在刀刃上。
  2. 你交付的不是代码,是标准。 什么算对、什么算好、什么不许改回去——这些只能你来定。
  3. AI 不会承认自己不知道,所以你要替它承认。 所有「看起来对」的地方,都值得先量一遍。

最后是我始终坚持的一点:人身上有三件事 AI 替不了——拍板(改成蹦跳,是我一句话的事)、体感(「有点怪」才是最有价值的需求)、划红线(统计只记次数、绝不记录内容——这条从第一天就写进了设计说明书,从未讨论过)。

代码可以让它写。这三件事,得你自己来。