复盘AI 协作2026-10-02

阳春白雪与下里巴人
—— 论肌肉与思维

48 小时,两个模型,六个版本,一台 Windows 虚拟机,一台 macOS,一台香港 VPS,一条跑不通的隧道。 这篇文章讲的不是 AI 有多强,而是这 48 小时教我认清的一件事:能干活的,和会思考的,是两种器官。

一、两次"看起来成了"

凌晨两点,我盯着一行日志:[INFO] mrrc: Server ready!。端口在听,进程都在, 构建脚本退出码 0,日志里明明白白一行 Successful compile。 唯一的问题是——用户打开浏览器看到的是一片黑。

后来我们从包里挖出来一个默认值:

cert=C:\Program Files\MRRC Modern\_internal\certs\fullchain.pem
key =C:\Program Files\MRRC Modern\_internal\certs\radio.vlsc.net.key

这是编译那台机器上的路径。它被写进了一个要发给客户的自签证书默认值里, 而在任何一台别人的机器上,这两个文件都不存在。找不到证书,服务就悄悄退回纯 HTTP; 启动器打开的却是 https:// 地址——浏览器报协议错误,界面一片黑。

同一夜还有另外三个同类:日志目录默认写进 C:\Program Files\(于是 [WinError 5] 拒绝访问,一条日志都没有);串口默认是 macOS 的 /dev/cu.SLAB_USBtoUART(而电台老老实实待在 COM5); 登录口令默认用源码里那个"公开的默认口令"。

四个 bug,同一个病:默认值只在构建机上成立。 而四个中的每一个,都要一次完整的"发版—安装—真机复现"才能被发现。

二、下里巴人:肌肉干的事

这 48 小时里,真正把问题钉死的动作,没有一个是"聪明"的:

动作 它换来了什么
把 exe 从 VM 拉回来,本地算一遍 sha256 发现"构建成功"的那个包,其实是上一版(时间戳 22:10,尺寸一模一样,哈希一模一样)
看时间戳时带上年份 差点把一个 9-25 的旧产物当当晚构建;此后成了硬规矩
逐字节读那行 TOML log.to = "C:\Users\…"——双引号里的反斜杠是转义,\U 被当成 Unicode 转义,frpc 报 non-hex character 拒绝启动。三个小时里所有"配置看起来没错"的推理都输给这一行字节
在 Windows 控制台里跑一遍裸启动,看它到底打印什么 拿到截图里的四行警告,四个 bug 一次性现形
ssh 到 VPS 上 ufw status "云面板没挡 8989"是错的——挡它的是机器自己的防火墙;一条 ufw allow 通了
把中文从 .ps1 里删干净 PowerShell 5.1 按 GBK 读无 BOM 文件,中文字符会把字符串终止符搅乱——我为此连栽三次

这些动作有个共同点:它们都要碰到真实世界——真实的内核、真实的编码、真实的防火墙、 真实的杀毒软件、真实的用户桌面。它们不产生洞见,只产生事实。


而真实世界最喜欢伪造的东西,恰恰是"成功":

肌肉的价值,就是不接受这些证据:它会去数字节、比哈希、看时间戳、 拿真实的浏览器去打那个地址,然后回来说:502。

三、阳春白雪:思维干的事

48 小时里同样有一批工作,看起来"什么都没修",却把整件事的性质改了。

第一个动作是命名:把四个散落的 bug 叫成一类—— "只在构建机上成立的默认值"。命名之后,问题的形状变了:不再是"再修一个", 而是"这类还能从哪儿冒出来"。于是有了那次全仓扫描: LOG_DIR、MEM_FILE、RECORDINGS_DIR、 CERT_DIR、SSL_CERTFILE……一个个对着"这路径在客户机上是可写的吗"过一遍。

第二个动作是造闸门。修完之后,写了一条测试:

def test_runtime_paths_are_outside_the_program_directory(self):
    """任何一个本程序要写入的默认路径,都不许落在程序目录里。"""

它当场咬到了 MEM_FILE——一个我们还没注意到的同类。更重要的是, 从此这一类 bug 再也进不了发布:它不再是"下次注意",而是"下次一定红"。 一条测试抵得上一打复盘。

第三个动作是换判据。"是否需要重启才能启用新证书"这个问题, 先前用"导入时的文件快照"来判——它漏掉了真正要命的那种顺序(应用先重启、之后才完成登记)。 改成按事实判:证书的写入时间晚于本进程的启动时间。 不是更聪明,而是更接近那句提问真正想说的事。

第四个动作更安静:把"升级通道比的是版本串"这件事写成结论—— 同一个版本号重建,装上那一版的人永远拿不到新包,点升级只会反复重放同一版本。 这条不是代码,是机制的理解。它决定了那晚的修复必须以 1.24.6 发,而不是"只补文档"。

四、两个模型:一个在写设计,一个在爬控制台

这 48 小时里有两个不同模型在同一套仓库上并行干活,分工几乎是自然形成的:

更像"阳春白雪"的那一侧 更像"下里巴人"的那一侧
产出 设计记录(SDD 决策条目)、干净的提交说明、成体系的测试闸门、启动器改成"问服务器要哪个地址" 装机、杀进程、读 GBK、改防火墙、数哈希、把控制台截图里的四行警告翻译成四个 bug
失败方式 默认值/机制层面的错——不碰到真机不会暴露 手滑层面的错——中文写进 .ps1、pkill -f 杀掉自己的 ssh 会话、用 & 同步启动一个永不退出的进程
贡献 让问题不再复发 让问题第一次被看见

两边都不可或缺,而两边都单独都不够。只有肌肉:48 小时六个版本,bug 一个接一个, 每次都能"修好"然后下次再犯——这就是一台永动发版机。只有思维:文档漂亮、决策完备、 测试齐全,但默认值仍然指向 C:\Program Files,客户仍然看到黑屏。

真正的闭环只有一个方向:肌肉产生事实,思维把事实固化成结构。 每一个下里巴人的、脏兮兮的发现,都要在当天变成一条测试、一条不变量、一句写进技能文档的判据—— 否则它就只是一次运气好。

顺带一个纯社会性的教训:两个写者在一套仓库上并行 = 一份 latest.json 会被另一份覆盖 ("1.24.7 的标签 + 1.24.6 的数字",升级的人会拿到对不上号的包)。 智能解决不了这个,纪律才行——发版列车只能有一个司机。

五、所以,"阳春白雪"和"下里巴人"是什么关系

宋玉说"其曲弥高,其和弥寡"。这个故事常被读成等级:高的雅,低的俗。 但工程里不是这样——它们是同一只手的两段行程。

白雪是那行注释、那条决策、那个 guard test,它让后来的人不必再踩一次。 巴人是那台凌晨还在重装的虚拟机、那行被 GBK 吃掉的引号、那次 ping 全丢包的等待, 它让"应该没问题"这句话第一次有了反面证据。

这 48 小时我最大的收获,是把两句话从口号变成了判据:

① 别用退出码证明成功,用事实证明成功:时间戳(带年份)、哈希(与上一版不同)、真实请求返回的状态码。

② 每一次真机上的失败,都必须当天变成一条测试或一条不变量——不然它一定会以另一个名字再来一次。

至于 AI 的角色:这 48 小时里,它既是那双脏手,也是那个写下闸门的人——偶尔还是那只把东西碰坏的笨手 (我今晚红着测试提交过一次,用 pkill -f 杀掉过自己的会话三次,把半成品的哈希当成过最终产物)。 这恰恰说明老话仍然成立:工具能放大的是方法,不是品格。 方法对了,肌肉与思维就互相成就;方法错了,它们会合谋造出一台永动发版机。

写于 2026-10-02,MRRC Cloud Hub 上线首日。文中的每个数字都来自当天的日志、提交或产物校验: 1.24.2 → 1.24.7,六个版本,一台 Windows VM,一台 macOS,一台香港 VPS。
英文版:Muscle and Mind

另见:两个模型、48 小时、七个版本 —— 能力复盘 · 云端的第一公里 · 全部文章

技术正篇:云端的第一公里 · 全部文章