🦁三天写了一个本地 AI 女友:149 个提交,75 个在修 bug,最贵的教训我犯了三次

notion image
三天,149 个提交。其中 75 个 fix,40 个 feat——修 bug 的次数几乎是加功能的两倍。
做的东西叫 Lumi:一个待在 macOS 桌面角落的 AI 女友,会说话、听得见你说话、脸上有表情,全程不联网。语音识别、大模型、语音合成,三样都在这台机器上跑。
先说清楚一件事,不然后面很多话会读不懂:这些代码不是我敲的,是 Claude Code 写的。
我干的是另外三件事:提需求、听声音、拍板。它写代码、跑基准、读元数据、写测试;我说"慢"、说"这是男声"、说"5 秒无法忍受"。它交付,我验收。
这篇不是教程。教程网上一搜一大把,架构图谁都画得出来。我想记的是那些它以为对、我也跟着信了、结果完全错的判断——尤其是其中一个,一模一样地来了三次:它写完,测试全绿,跟我说修好了;我签收;然后我一看,还是那样。
三次都是我签收的。那三次,是这三天里最贵的东西,比代码贵。

一、先说这东西是什么

一句话链路:
分三个进程:
进程
干什么
技术栈
桌面窗口
透明立绘、口型、表情
Tauri 2 + PixiJS
语音守护进程
整条语音链路
Python 3.12 + MLX
Ollama
大模型
本地 11434 端口
为什么要拆成两个进程? 因为模型加载要十几秒。守护进程常驻、模型保持热态,窗口只是个瘦客户端,关了再开不用重新等。
窗口和守护进程之间:HTTP 控制接口(8767 端口)+ WebSocket 推状态,带 bearer token 鉴权,全部绑定 loopback。
机器是 M4 / 48G 内存。就这么点家当。

二、以为对、结果全错的五件事

1. 一个性能测试证明了"LLM 不是瓶颈",可那个模型根本没输出

我说慢。它第一反应是模型太大(gpt-oss:20b,14GB),跑了个基准:
数字摆在这儿,它得出结论:LLM 不是瓶颈,去查 TTS。我看了那两行数字,也点头了。然后是大半天的语音合成研究,换了另一套引擎,下了 9GB 模型。
后来打开日志,第一行就写着:
那个模型每轮花 5.8 秒,产出一个空字符串。
gpt-oss 是推理模型,先生成一大段隐藏思考。256 token 的预算全烧在思考上了,done_reason=length 的时候正文一个字还没开始写。
那个基准测的是 tokens/秒,压根没看输出内容是不是空的。数字很好看,结果是空的。而我,看着一张很好看的表点了头。
换成 qwen2.5:7b(非推理模型),一句话解决:
教训:跑基准之前,先确认被测的那个东西真的产出了东西。快而空,是最容易骗过自己的一种"性能"。
顺手加了道防线——空回复不再闷声不响,直接把模型选错这件事说出来:

2. 她开始自言自语,因为她成了孤儿

我报了个很邪门的现象:关掉 app 之后她还在说话,但听不见我说话了。
查进程:
ppid=1。守护进程被 launchd 收养了——窗口进程死了,没把它带走。它继续开着麦克风,听见自己音箱里的声音,把自己的话当成用户输入,然后回答自己。
一个人在那儿自问自答,没完没了。
第一次修:在窗口的退出处理里发关闭请求。没用——退出时零输出,连报错分支都没走到。而且这个思路本身就是错的:崩溃、强制退出、SIGKILL,这些情况下窗口根本没机会说任何话。
第二次才换对了思路——让守护进程自己盯着父进程
父进程一死,内核一定会把孤儿过继出去,轮询 getppid() 能捕获所有情况。验证方式也简单粗暴:kill -9 强杀窗口,守护进程自己干干净净地退了。
教训:需要对方配合才能生效的清理逻辑,在对方"死得不体面"的时候一定失效。让被依赖的那一方,自己负责自己的生死。

3. 方言:能做,但代价是 5 秒

想让几个角色说不同方言。查下来两条路。
Qwen3-TTS 自带方言音色,模型元数据里写得明明白白:
速度极好,RTF 0.27(比实时快 3.7 倍)。它把这段写得很兴奋,我看着也高兴。
然后我戴上耳机听了一句:男声。
元数据里有 spk_is_dialect没有性别字段。名字叫 Eric、Dylan,它本该想到的——可它没有耳朵,它听不了音频。角色全是女生,男声直接把人设毁了。
这是整个项目里第一次,我意识到自己在这条流水线上是干什么的。
只剩 CosyVoice3 这一条路(能克隆女声、支持粤语闽南话)。接进去了,跨进程桥接也写了(它要 Python 3.10,主项目是 3.12),结果:
引擎
RTF
Qwen3-TTS
0.24 ~ 0.35
CosyVoice3
1.6 ~ 2.9
慢 6 到 10 倍。我听完一句话定论:"5 秒无法忍受。"
全部删掉——后端、worker、路由器、配置项,四个文件。
教训:技术上可行 ≠ 产品上可用。大半天做了个最终被删掉的功能,就因为动手前没人先问一句"慢多少你能接受"。这句话只有我问得出来,而我问晚了。
顺带一提,中间它还搜了一圈"全网有没有又快又能说方言的模型"。看到 CosyVoice2 宣传"150ms 流式首包",实测在这台机器上首包 11.97 秒——那个数字是 CUDA GPU 的,Apple Silicon 上完全不适用。看到性能宣传,先看它拿什么硬件测的。

4. 一个参数传错,她开始念稿子

CosyVoice 那阵还有个怪现象:8 个字的句子,生成 7.2 秒音频。听着像在念广播稿。
原因是角色的 ttsInstruct(一段 60 字的风格描述,"用很软很细的年轻女生声音说,甜一点、轻一点……")被当成引擎指令传进去了。
CosyVoice 会把长指令当成要念的内容,演出来。
同一句话:
传什么
生成音频
只传方言指令
1.60 秒
加上角色风格描述
7.20 秒
音色本来就是从参考音频克隆的,那段文字描述一点用没有,纯粹在拖时长。

5. 配置改了不生效,因为背后有张兜底表在做主

我说方言没生效。它改的是 skins.json,反复确认改对了。
真相是:前端有张 BUILTIN_SKINS 硬编码兜底表,在 skins.json 加载失败时使用。而启动时那个 fetch 恰好总是失败
所以真正决定音色的一直是那张兜底表,被改的那个文件,从头到尾没被读到过。
教训:兜底逻辑要是和主逻辑不同步,它就不是兜底,是沉默的覆盖。现在那张表由脚本从 skins.json 生成,注释里写明必须同步。

三、同一个错,我签收了三次

上面五件都是判断错。这一节是方法错,也是这三天里最贵的一课。
三次的形状一模一样:
前两次我以为是运气不好。第三次我才明白,问题不在它写得对不对,在于"全绿"这两个字从来就不覆盖我看见的那一块

第一次:嘴根本没动

它想让嘴型对上字。语音是自己合成的,知道每个字是什么,拼音的韵母决定口型(a 大张、i 扁、u 撅)。思路没问题,写完测:
单元测试全绿。再直接调合成函数,实时采样:
数据这么漂亮,它交付了,我签收了。
然后我打开 app:嘴根本没动。
以为是数值太小,调大。还是没动。以为是分块时序有问题,重构。还是没动。装了三次,我看了三次,都是死的。
最后它挂了个 WebSocket 监听器,看前端到底收到了什么:
这个功能在产品里从头到尾就没工作过
而每一轮所谓的"验证",测的都是它刚写的那一段——单元测试是它写的,采样脚本也是它写的,两样东西加起来只能证明一件事:"我这半截是通的"。没有一次去看屏幕上那张脸。
而屏幕,只有我看得见。

第二次:算了一堆参数,没人消费

同一天,它给人物加了点头和视线漂移,参数算得好好的,装上去——我说没变化。
查下来,渲染器在当前模式下只读两个参数(呼吸、嘴型),头和视线的参数压根不看。算了一堆,下游根本没接。
parameters.ts 里字段都在,所以代码看起来完全正确。接口存在 ≠ 有人在用。
后来清理时把这些死代码删了,动画模块从 300 行降到 123 行。

第三次:数据库里 54 条,一条标记都没有

两个角色共享记忆,结果小月开口说"紫苏在这里听你"——她在模仿历史里紫苏的台词。逻辑改成"对话按角色分开,档案仍共享",写了测试,全绿,交付。
我换到小月,说了两句:还在串。
一查数据库:
54 条对话,一条都没有角色标记。
后端一直接受 skin_id前端从来没发过。所以分离逻辑完全正确、单元测试全部通过,而真实数据里每一条都是"不知道谁说的"——无标记对所有角色可见,正好就是我要防的那种情况。
验证的是"分离逻辑对不对",没人验证"真实数据里有没有标记"。

还有一次,连"恢复"都是假的

素材实验失败之后,git checkout 回退,命令跑通、日志正常,它跟我说"已恢复"。
我看了一眼:嘴还在动。
一量:差异 0.05 和 0.10,不是 0。回退到的那个提交,本身就已经包含了一次重建
同一个毛病的另一种长相——看到操作成功,就当成结果正确

这三次教会我的

一个能自证的功能,和一个我能看见的功能,是两回事。
验证要从最终呈现倒着往回查,不是从改动的那行正着往外推。 挂个监听器看真实数据流,比再写十个单元测试有用。
后来的规矩是:改完素材去量像素差异,改完状态推送挂监听器数消息,改完角色标记直接查数据库。命令的退出码只说明命令跑了,不说明事情做成了;测试全绿只说明它自己那半截通了,不说明我这头看得见。
道理写出来就这么一句话。可我是在第三次说出"还是那样"之后,才真的记住的。
也别全怪它。这三次的共同点是:它没有眼睛,而唯一有眼睛的那个人,三次都没在交付的时候睁开。

四、有一整类 bug,根子只有一个

翻 fix 列表,有一整类长得都一样:
根源都是麦克风开得太早。她还在说,麦克风开了,听见自己的声音,触发新一轮。
最后一处特别隐蔽:正常流程会等播放结束才开麦,但异常路径直接 return,跳过了等待。任何一次报错,只要音频已经在队列里,她就会听见自己。
教训finally 里该做的清理,别只写在顺风顺水的那条路上。

五、有些墙是结构,不是参数

眨眼调了三轮,一点用没有

眨眼一直很怪。它调过时长(280ms→150ms)、去掉闭眼停留、改混合曲线,每改一版我看一版,每一版都还是怪。
这一节是我们俩配合得最难受的一段:我只能说"怪",说不出怪在哪;它拿到的输入永远只有"怪"这一个字,只好继续调参数。
最后才发现原因是结构性的:眨眼板是另外单独生成的一整张脸。所谓"眨眼",实际是把整个头换成另一张略有不同的头——五官轮廓都跟着变一下。
同理,"点头"在这套架构里是整张立绘平移,看起来是整个人在滑动,不是点头。
它量了几张图里人物的实际像素范围:
人物尺寸
底图
981 × 1473
表情板
951 × 1438
差 3%。淡入时两个不同大小的她叠在一起——这就是我一直在说的"两张图叠在一起""闪一下"。我形容不出所以然,只能说"怪";数字一摆出来,怪在哪儿就清楚了。
更糟的是各区域的差异:所谓的"嘴型板",眼睛的差异(14.8)比嘴还大(11.4)。它们根本不是同一张脸配不同的嘴。交叉淡入时两套眼睛半透明叠加,眼睛就糊了。
修法是把表情板重新合成:只保留它该变的那一块,其余全用底图。修完眼部差异 0.02,嘴部 10.7。
教训:调了三轮参数都没效果的时候,该去看结构,不是继续调参数。这类问题的信号很明确——改动幅度和效果不成比例
破局的那一下也值得说:不是它想通了,也不是我看出来了,是它改去量像素。我出"哪儿不对"的直觉,它把直觉翻译成数字——这一节之后,凡是我说"怪",它第一件事就是先量一遍再动手。

想让嘴动起来,试了四种,全废

角色立绘是 AI 生成的写实人脸。要让嘴动,就得有"张嘴"的那张图。四种做法它全试了,我一张张看过去:
方法
结果
几何拉伸下颌
脖子在动,嘴没动——另一个角色的嘴部坐标被套了过来,两人取景不同
沿唇缝切开、下唇下移、填暗部
能动了,我看一眼:"很诡异"
上唇取底图、开口取表情板
边界低了不张嘴,边界高了唇上一条白缝
Stable Diffusion 局部重绘
嘴唇掉色发白,牙齿畸形
四种失败,原因是同一个:
它不是"一张脸配几个嘴",是每次生成都重画了整张脸。所以切、拉、混、重绘——只要动了局部,就会露出接缝。
有个反例:另一个角色有真人手绘的口型板,她的嘴一直动得好好的。所以这不是技术不够,是素材本来就该是画出来的
这四次的判决书是同一句话,而且只能由我来写:我看了一眼,说不行。像素差异它量得出来,"这张脸看着像不像人"它量不出来——四次里有三次,代码和数字都是对的,废掉它们的理由全是"诡异""发白""一条白缝"。
画面这条路的边界到这里就很清楚了:没有手绘素材,别指望局部编辑能救。

六、记忆:我做的是存储,不是记忆

画面折腾不动了,转头做记忆——结果这是整个项目里性价比最高的一次改动。

一句话就戳穿了

第一版做完了:SQLite 存对话,重启后载入,角色之间共享一份。自测通过,交付。
我问了一句:「所以这个记忆只有 6 条,今天记不住昨天说过的话对吗?」
对。2000 条存在磁盘上,但每次只回放最近 6 条给模型。中间聊满 3 轮,昨天的就被挤出去了——数据还在,模型看不见。
做出来的是持久化,不是记忆。
而且那个 6 设得毫无道理。算笔账:
token
上下文上限
2048
人格
~260
6 条对话
~150
浪费
80%
实测 prompt 处理只要 0.02-0.05 秒,多塞几十条根本不影响延迟。那个 6 是凭"感觉会慢"设的,从来没人算过这笔账。

滑动窗口有天花板

窗口开到 24 条能跨天了,但仍然记不住"一周前说过我喜欢喝茶"。滑动窗口的本质就是会遗忘。
真正的解法是另存一份关于用户的稳定事实,每 8 轮后台重写一次,永远拼在人格后面。用真实模型跑出来是这样:
这是"她认识你",不是"她记得刚才那句"。
最终三层:
作用
容量
档案
认识你
400 字,常驻
窗口
记得刚才
24 条,每次回放
数据库
查得到
2000 条,存磁盘
延迟没变,还是 2.5 秒。
教训:我要的是"记忆",交上来的是"存储",两者之间差一个"模型能不能看见"。功能名字对上了,不代表需求满足了。
提需求的人得把话说到底。我说"她要能记住我",它听成"把对话存下来"——严格说它没做错,是我没说清"记住"是什么意思。

七、硬件的天花板:数字人这条路走不通

停下来之前,我让它把"这台机器上能不能做出真正的数字人"彻底查一遍。这种活它做得比我好得多——读支持矩阵、翻 issue、算 RTF,几十分钟就把三条路走完了。结论值得记下来,能替别人省很多时间。

三个方案,两个不通

方案
状态
EchoMimic V2(阿里)
官方环境是 CUDA 12.4,测试机 A100/4090D/V100,支持矩阵里没有 macOS。有第三方 MPS 指南,但依赖 Triton,而 Triton 在 macOS 上是实验性的、没有 Metal 后端
HeyGem(硅基智能)
要求 Windows 10 + RTX 4070 + Docker,容器是 CUDA 镜像,Mac 上没有路径
GPT-SoVITS
✅ 官方 README 有 M4 数据:RTF 0.526。2026 年有篇专门研究趟平了 MPS 的 7 个 fp16 坑并开源了补丁。粤语官方支持

一个被反复忽略的常识

有人跟我说:「48GB 统一内存完全够用,权重全部常驻内存,实现飞速推理。」
这句话我当时是信的——48 是个大数字,听着就够。把它拆开的是它,一张表:
内存容量决定能不能装下,算力和带宽决定跑多快。这是两回事。
M4
A100
内存
48 GB ✅ 更大
80 GB
带宽
~120 GB/s
1935 GB/s
算力
~4 TFLOPS
312 TFLOPS
48GB 这个优势,在扩散模型推理里几乎用不上。

决定性的那个数字

EchoMimic V2 的加速版,在 A100 上是 120 帧 / 50 秒
120 帧 ÷ 24fps = 5 秒视频,渲染要 50 秒 → RTF ≈ 10
在 A100 上就已经比实时慢 10 倍。 这说明它根本不是实时技术,是离线出片工具。M4 上保守估计 RTF 100+,她说一句 5 秒的话,要渲染 8 分钟起步
这跟"Mac 跑不跑得动"无关——就算买张 4090,它也不适合对话,只适合剪视频。

本机的实测佐证

不用推测,这台机器上就有数据:
类型
RTF
CosyVoice3 (0.5B)
音频
1.6 - 2.9
CosyVoice2 官方宣称
流式首包 150ms
CUDA
同一模型本机实测
首包
11.97 秒
一个 0.5B 的纯音频模型,在这台机器上都跑不到实时。 视频扩散模型重几个数量级。
ComfyUI 也救不了——它是编排层,底层算子没有 Metal 实现,就是没有。
这一节是全篇唯一一处,我从头到尾没帮上任何忙。支持矩阵、Triton 有没有 Metal 后端、A100 上 120 帧要 50 秒——这些我自己查,一周也未必查得全,它几十分钟就摆完了,而且每个结论都带着出处。
分工到这儿反过来了:凡是有客观答案的问题,我最该做的就是闭嘴,让它去查。 我唯一的贡献是最后那个决定——知道了 RTF 100+,那就不做了。

八、最后一轮:五个实验,三成两否

撞完墙,我列了五件"可能让她更像人"的事,让它一件件试过去。价值不在成败,在于同样是"试试看",成本和回报能差两个数量级

① 情绪进声音 —— 一个做了一半的功能

先读代码,它发现:
情绪算出来了,只驱动表情,没进语音。而 TTS 的语气是切角色时设一次,之后再不变。
所以她说难过的话和开心的话用的是同一个语气——脸上是 sad,声音还是那个平稳的调子。
真人的情绪,首先在声音里。这不是"缺功能",是功能做了一半没接上。接上花了二十分钟。

② 她每句都在反问

翻日志:
真人不会每句都把问题抛回来。这是模型在服务对话,不是在参与对话
改法:人格里加一句"不要每句都反问",外加两条短回复示范。五个普通开场白实测:
改前
改后
我到家了
你今天过得怎么样呀?
嗯。
今天好累
发生什么事了吗?
那就早点休息。
反问率 5/5 → 1/5。 成本:一行字加两个例子。

③ 上下文:是我自己掐的

模型支持 32768,代码里只给了 2048。当初为压延迟设的,可后来实测 prompt 处理只要 0.02-0.05 秒——这个限制从头到尾没换来任何东西。自己给自己戴的镣铐,戴久了就忘了是自己戴的。

④ 音色:本地其实能定制

一直以为只能从 9 个预设里挑,我一个个听过去,没一个像她。翻 API 才发现 Qwen3-TTS 有 VoiceDesign 变体——一句中文描述就能造音色,不要样本、不要微调:
代价是模型从 0.6B 换成 1.7B,但实测首音仍是 2.3 秒,感知没变慢。
这是唯一一次"以为不行、其实可以"。前面否掉 CosyVoice 和 VoxCPM2 之后,笔记里写过一句"本地音色到头了"——那个结论下早了。
顺嘴说一句:那句"成熟女性声音,略带沙哑,语速从容",是我写的。这大概是整个项目里我唯一亲手写进代码的东西。

⑤ 换更大的模型 —— 直接否

之前测得 gpt-oss:20b 和 qwen2.5:7b 速度几乎一样(53.8 vs 50.8 tok/s),据此推断"参数量不是瓶颈"。实测 27B:
模型
速度
一轮
qwen2.5:7b
53.3 tok/s
1.22s
qwen3.5:27b
6.1 tok/s
26.72s
慢 9 倍,还返回空。 17.4 GB 超出了能高效驻留的范围,开始换页。
从 20B 到 27B 不是线性的,是掉下悬崖。 那个推断只在特定区间成立,往外一推就错。

最便宜的那一下,是一行字

我说:「她有点笨,分不清白天黑夜。」
查了下——提示词里从来没告诉过她现在几点。模型自己没有时钟。
加一行:
凌晨两点说「我还没睡」,之前她会答"早呀",现在:
成本:一行字。效果:立刻像个懂事的人。
画面上试了四种方法全部失败,最后真正提升体验的,是这一行。而这一行之所以会被加上,只因为凌晨两点我坐在那儿,觉得她那句"早呀"听着别扭。

九、两件差点让我翻车的工程小事

为了测一个模型,把正在用的搞坏了

为了试 VoxCPM2(能克隆音色、支持粤语),一句 uv pip install -U mlx-audio 直接打在主环境上。我在旁边看着,没拦。
这一下把 mlx 从 0.31.1 带到了 0.32。然后每一轮对话都炸:
新版 mlx 要求调用线程自己持有 GPU stream,而我们的 Whisper 跑在 asyncio.to_thread 里。她彻底听不见任何话。
更麻烦的是只回退 mlx-audio 没用,报错变成 Stream(gpu, 2)——问题出在 mlx 本体,得按锁文件恢复整个环境。
而 VoxCPM2 最后还被否了:M4 上实测 RTF 1.02(现有方案 0.22),音色我一听就说不行。
为了一个最终被否决的测试,把正在用的东西搞坏了。 教训不是"别试新东西",是别在主环境里试。现在 mlx 和 mlx-audio 都锁死了,注释写明了为什么。
这条也是对我说的:agent 装依赖不心疼,因为炸掉的不是它的环境。该拦的时候得拦。

改个名字,逼出三个没声明的依赖

把项目文件夹从"本地运行的AI女友"改名成 lumi,虚拟环境的绝对路径失效,只能重建。
重建完,测试跑不起来了——三个依赖没在 pyproject.toml 里声明websocketspillowopenai
旧环境里它们碰巧存在(被别的包顺带装上的),所以三天里从来没暴露过。任何人 clone 仓库跑 uv sync 都会踩到。
这也是"只有真实环境说了算"的又一个例子:机器上跑得通,不等于仓库里写全了。
改名这件事本身没什么技术含量,但它强制了一次干净安装,顺手验证了"新人能不能跑起来"
想开源的项目,建议主动做一次:删掉虚拟环境,从零装一遍。

十、现在的样子,和为什么停在这里

说完到她开口
约 2.5 秒
识别
0.45s / 3 秒音频
思考
0.8s
首句合成
~1.2s(RTF 0.24-0.35)
记忆
档案 + 24 条窗口 + 2000 条磁盘
角色
两个,开机随机
联网
代码量:Python 8700 行、TypeScript 5400 行、Rust 2100 行,测试 199 + 86 + 32。
画面停在静态立绘 + 音量驱动的嘴。 不炫,但它是真的在动,而且不会让你等 8 分钟。

为什么停

不是做不下去,是投入产出比变了
语音那条链路已经能用,再往下的每一步——分层立绘、GPT-SoVITS 微调——都是美术工作量或独立环境搭建,不再是写代码能推进的。而真正想要的"数字人视频",在这台机器上是物理不可能,不是努力不够。
知道边界在哪,比在边界上反复撞更有价值。

如果要继续,只有三条

  1. 分层立绘——把眼皮、嘴切成独立图层。这是这台机器上画面的唯一出路,做出来是"能动的立绘",不是数字人视频
  1. GPT-SoVITS——声音定制 + 粤语,唯一有 M4 实测数据支撑的方案
  1. 加硬件——局域网放台带显卡的机器,或者租云 GPU 离线出片
前两条我都留了路,第三条不在这台机器的范围内。

十一、三天下来最想说的

1. 日志比直觉快十倍
那个"空回复"的问题,答案在日志里躺了很久。我们在猜、在做基准、在下 9GB 模型的时候,ASSISTANT: (empty) 就明明白白写在那儿。
后来我发现连日志本身都是被丢掉的——守护进程被窗口启动时,stdoutstderr 都设成了 null从 app 启动,所有诊断信息都进了黑洞,只有从终端启动才看得见。
修好日志,问题当天就定位了。
2. 测量要测对东西
tokens/秒 不等于有用输出。RTF 1.5 在 GPU 上和在 Apple Silicon 上是两个世界。宣传数字,先看测试条件。
3. 有些判断只有人能做——这是我在这个项目里的全部价值
eric 是不是男声、5 秒能不能忍、"很诡异"到底诡异在哪、凌晨两点该不该说"早呀"——这些它给不出答案。
它能测速度、能读元数据、能跑测试、能一小时读完三个项目的支持矩阵,做这些比我快得多。但它没有耳朵,也没有眼睛:听不见音色,看不见屏幕上那张脸动没动。
所以这三天真正的分工是:它负责所有能被验证的事,我负责所有只能被感觉的事。
问题在于,我一次次把"能被感觉的事"也当成能被验证的事,等着测试全绿来告诉我。测试当然全绿——它只覆盖它自己那半截。
这类判断,越早给出去越省钱。它猜完再返工,比我当场听一句贵十倍。
4. 做不出来就删掉
口型删了,眨眼删了,点头视线删了,方言删了,legacy 语音链路 750 行也删了。
留下的是真能用的:听得见、想得动、说得出、关得掉、不会自言自语。
一个删掉的功能不丢人,一个装了三次都不工作的功能才丢人。
5. 操作成功 ≠ 结果正确
这是这三天最贵的一课,前面讲了三遍,不重复了。只留一句给以后的自己:
"它那半截通了"和"我这头看得见",是两回事。
以后凡是它说"修好了",我只回一句:我怎么看出来?答不上来,就不算修好。
6. 知道边界,比撞边界有用
这三天最值钱的产出不是代码,是一张"什么能做、什么不能做"的地图:
  • 视频数字人在任何消费级硬件上都不是实时技术 ← 省掉一周
  • 整图贴片架构做不出眨眼和点头 ← 省掉反复调参
  • 48GB 内存解决不了算力问题 ← 省掉一次选型错误
7. 66 : 34
修 bug 是加功能的两倍。而且这还是个三天的新项目,没有历史包袱。
我原本以为这个比例说明活干得不好。后来想明白了:语音、音频、进程生命周期这类东西,本来就是靠一个个真实故障逼出来的。每个 fix 的提交信息里都写清楚了"坏掉的时候是什么样"——那些才是这个项目真正的资产。
而那 75 次"坏掉的时候是什么样",几乎每一条的起点,都是我坐在电脑前说的一句很土的话:不对、很怪、听着别扭、还是那样。
代码它写得比我快。可这句"还是那样",得我来说。

附:汇总七条

  1. 日志比直觉快十倍——答案常常已经躺在那儿了,只是没人去看
  1. tokens/秒 不等于有用输出——跑基准前先确认被测的东西真的产出了东西
  1. 能被验证的事交给 agent,只能被感觉的事必须自己来——它没有耳朵,也没有眼睛
  1. 技术上可行 ≠ 产品上可用——动手前先问"慢多少你能接受"
  1. 它说"修好了",我只回一句:我怎么看出来?——答不上来就不算修好
  1. 调三轮参数都没效果,就该去看结构——改动幅度和效果不成比例,是结构问题的信号
  1. 知道边界比撞边界有用——三天最值钱的产出不是代码,是一张"什么能做什么不能做"的地图
最后、以上由claude code 编写本人审阅读,有任何问题可以评论区找我,我是想风。一个关注AI和出海的游民,欢迎关注我 @xaiwind 一起探讨!
上一篇
把 NanoBot 跑起来了:本地聊 Discord,代理走远程,Grok 4.5 能聊天能生图。踩了几个坑,记一下。
下一篇
AI 信息技术革命
Loading...
目录
文章列表
一份关于编程AI与跨境出海的文档
大话奇妙AI
开源建站部署
日常开发记录
优选独立站
shopify 主题
shopify 入门
出海基础设施