ziqian

换了 4 次技术栈之后,我开始重新思考怎么用 AI 写软件

#长文

TL; DR:

一、技术栈到底该怎么选?
1. Rust Native:漂亮,但开发反馈很慢  
2. TUI:Agent 的反馈链路不够好  
3. Tauri 还是 Electron?  
4. 先做 Web,再谈最终形态  
5. 一个 WSL 文件扫描问题  
  
二、模型到底该怎么选?
1. 我天天用 Node.js,但其实不懂 Node.js  
2. 要结果,就用强模型  
3. 要学习,我反而会用弱模型  
4. Benchmark 为什么解释不了真实体验  
5. Scaling 和 The Bitter Lesson  
  
三、最后,其实是在问同一个问题:你到底想优化什么?

文: plum

最近我自己在做一个东西,然后这个东西其实本身没有多复杂,就是我想做一个 Skill Manager。

因为我的电脑是 Windows 嘛,然后我平时开发其实有两个环境,一个是 Windows,一个是 WSL。那我就有一个需求,就是我希望有一个中央仓库,或者你可以理解成一个 Skill Vault,它是我唯一的真相源。然后不同的软件、不同的 Agent,它们自己的 Skill 目录,都从这个地方链接过去。

Windows 这边可以用 Junction,WSL 里面就是 symbolic link,然后 Windows 跟 WSL 之间也要能够处理。大概就是这么一个东西。

结果我真正开始做之后,我发现这个项目最好玩的地方,反而不是最后这个 Skill Manager 做成什么样,而是我中间技术栈换了好多次。


一、技术栈到底该怎么选?

1. 从 Rust Native 开始:看起来很漂亮,做起来不是一回事

我一开始想的是,既然都做桌面软件了,那我干脆就做得 Native 一点嘛。所以当时是 Rust 后端,然后配了一个 GUI 框架。具体那个框架名字我现在一下想不起来了,反正不是 GPUI,也是一个相对没那么热门的框架。

它有一个优点确实很爽,就是最后那个 binary 很小,就几兆。

但是做着做着我就发现,首先 Rust 编译真的慢,尤其你在这么一个不断让 Agent 改、不断测试、不断反馈的开发过程中,它会把整个 feedback loop 拉得很长。

然后我还碰到一个特别离谱的问题,就是中文输入法。只要我在那个软件里面切到中文输入法,它就会卡死,然后直接退。

我后面搞得受不了了,我说算了,换。

2. 第二次换到 TUI,我又发现 Agent 根本没那么好开发

然后第二次我就想,那我不要 GUI 了,我做 TUI 行不行?最近不是 OpenTUI 这些也挺火的嘛,我就去做 OpenTUI。

结果做出来之后我又发现,这东西有另外一个问题。

就是今天 Agent 为什么做 Web 特别舒服?因为 Web 的整个反馈链路已经太成熟了。它写完一个东西以后可以直接开浏览器,可以用 Playwright,可以点,可以截图,可以看 DOM,它很容易知道自己刚才做出来的东西到底是什么样。

但是 TUI 就没有这么舒服。

你当然也可以测试,但是整个视觉反馈,还有 Agent 自己操作它的能力,都没有浏览器那么自然。

而且我这个东西本身又是一个管理工具,要看很多 Skill、路径、状态、链接关系之类的。你放在 TUI 里面,我后来自己用着也觉得不太符合人的视觉习惯。

所以我又换。

然后这个时候我就在纠结,到底 Tauri,还是 Electron,还是干脆做别的 Native GUI。

3. Tauri 看起来更优雅,为什么还有人换回 Electron?

因为网上你一搜 Electron,很多人第一反应就是,哎呀,Electron 内存大,安装包大,一个计算器恨不得带一个 Chromium,对吧?然后 Tauri 就显得特别漂亮,Rust、小、快、Native WebView。

我一开始其实也很吃这一套。

但是后来我专门去查了一圈,我发现事情没有网上讲得那么简单。

比如说 OpenCode,它之前桌面端就是有 Tauri 版本的,但现在已经是 Electron 了,而且现在仓库里面的 Desktop README 直接就是 built with Electron,Electron 42。它的前端用的是 SolidJS。之前甚至还有人专门提 issue,说你这个 README 怎么还写着 Tauri,实际上现在构建出来已经是 Electron-only 了。

然后 Codex Desktop 也是 Electron。

这个更有意思,因为 Codex Desktop 本身其实也被很多人吐槽卡,尤其 Windows 上确实有人报 renderer 内存涨到几个 G、CPU 占用很高这些问题。但是 OpenAI 最后还是选了 Electron。它这个 App 没开源,所以我不能跟你说它官方源码里面百分之百是什么,但是安装包是可以确认 Electron 的,前端 bundle 也基本可以确认是 React 加 Vite 这一套。

然后我继续看,还发现不只是这两个。

像 Paseo,一开始作者也是觉得 Electron 太 bloated 了,所以选 Tauri,结果后来他自己又迁回 Electron,还写了一篇文章就叫《I was wrong about Electron》。还有 UCM Desktop、BSV Desktop、Astron RPA,这几年都出现了 Tauri 转 Electron 的案例。

那当然,我不是说现在大家都在抛弃 Tauri,这肯定不是,因为反过来 Electron 转 Tauri 的也很多。

但是这件事情至少让我意识到一点,就是你不能只看“这个框架理论上优不优雅”。

Electron 最大的问题大家都知道,它自己带 Chromium 和 Node,所以安装包大一点,内存基线高一点。

但是它另外一面是什么?就是它这个环境非常稳定,非常统一。

你 Windows、macOS、Linux,基本都是我自己带着同一个 Chromium 跑。前端生态又是现在最成熟的一套 Web 生态。Agent 对这套东西也最熟。

Tauri 的优势是小,然后它用系统 WebView,但是这个优势反过来也是一个 trade-off,因为不同系统、不同版本的 WebView,它真的可能给你搞出一些差异。UCM Desktop 当时从 Tauri 换 Electron,公开讲的一个原因就是这个:他们觉得跨平台 WebView 的差异太烦了,所以宁愿接受 Electron 大一点,换一个更加可预测的开发环境。

4. 最后我还是回到了最普通的 Web App

然后我当时就想明白了,我现在到底是在干嘛?

我这个 Skill Manager 都还没做出来,我甚至都还不知道这个东西最后到底有没有用,我为什么现在就在纠结它最终 binary 是 8MB 还是 200MB?

这个时候你优化这个东西其实没有什么意义。

所以我最后的想法就变成,我先直接做 Web App。

最普通的 React,后端起一个 server,localhost 打开。

先把整个东西跑通。

因为 Web App 对 Agent 来说开发效率最高,反馈也最快。我让它改一个页面,它马上就能打开看;有问题就 Playwright;数据有问题就直接看请求。

等整个产品逻辑都跑通了,我真的天天在用了,我确定这个东西有价值了,那我要桌面端怎么办?

那再套 Electron 就完了。

因为你前面本身就是 Web 技术,迁过去成本也没那么高。

再往后,如果有一天我这个东西真的有十万、几十万用户了,或者我真的发现某一个地方有非常明确的性能瓶颈,那你到时候再去 Rust,再去 GPUI,再去 Native,都可以。

但是那个应该是后面的事。

就是我现在越来越觉得,做这种东西,尤其是你用 Agent 做东西的时候,不要一开始就追求所谓的最终架构。

因为 AI 会给你一个很大的诱惑,就是你会觉得:反正代码又不是我写,那我为什么不一开始就上最牛逼的技术栈?

Rust 性能高,那上 Rust。

Native 好,那就 Native。

Tauri 小,那就 Tauri。

但是 Agent 帮你消掉的只是“代码谁来敲”这个问题。框架本身的复杂度没有消失,生态的问题没有消失,跨平台的问题没有消失,debug 的问题也没有消失。

所以你首先应该把东西搞出来。

先证明这个东西是有用的,然后再去优化它。

5. 然后一个 WSL 文件扫描问题,又差点让我把整个项目迁走

结果我走到这里以后又碰到一个特别典型的问题。

就是我的 Skill Vault 到底放哪?

因为我 Windows 和 WSL 两边都要用。

假设我把 Vault 放 Windows,然后我的后端现在是跑在 WSL 里面的,那 WSL 去扫 Windows 文件系统,你会发现特别慢。

这个是 WSL 很典型的一个问题,就是你跨 /mnt/c 这种路径做大量文件操作,它性能跟直接扫 Linux 自己的 ext4 完全不是一回事。

我当时看到这个以后又差点急了。

我说完了,那是不是整个项目又得搬到 Windows?

我前面是不是又选错了?

然后后面我才突然发现,其实根本不用。

WSL 扫自己不就行了吗?

Windows 的文件,你让 Windows 自己扫啊。

6. 我天天用 Node.js,但其实我根本不知道 Node.js 是干什么的

那 Windows 上谁扫?

Node.js 就可以扫。

然后这个地方对我其实刺激还挺大的,因为我天天用 Node.js。

npm 我也天天跑。

装一堆东西的时候我也知道要装 Node。

但是你让我当时回答一句“Node.js 到底是干什么的”,我其实是答不出来的。

后来我才真正把这个概念补上:哦,它不就是一个 JavaScript runtime 嘛。JavaScript 原来主要是在浏览器里面跑,Node.js 让它可以脱离浏览器直接在操作系统里面跑。

那它当然可以读 Windows 文件。

可以扫目录。

可以起进程。

可以开端口。

也可以和 WSL 那边的后端通信。

那这个问题一下就解决了。


二、模型到底应该怎么选?

但是然后我又开始想一个事情:为什么这个这么简单的东西,我前面没想到?

一方面当然就是因为我不知道。

但是另外一方面也跟我当时用的模型有关系。

当时 GPT-5.6 这一代有 Sol、Terra、Luna。Sol 是旗舰,Terra 中间,Luna 就是最快最便宜的那个。

我当时为了省量,很多时候是在用 Luna。

那 Luna 其实并不是不能写代码。你如果把任务说得很清楚,它做很多东西完全没问题。

甚至你去看一些 benchmark 会觉得很有意思,比如第三方的一些 coding benchmark 里面,Luna 把 reasoning effort 拉到 max 以后,有些指标甚至可以做到跟 Sol medium 很接近。

那你看 benchmark 的时候就会觉得,哎,那我为什么还要用 Sol?Luna max 不就行了吗?还便宜。

但是你真正用一段时间以后,你会发现体验完全不是一回事。

因为 benchmark 里面的任务通常有一个特点,就是这个问题已经被定义好了。

它告诉你 repository 在哪。

告诉你 issue 是什么。

告诉你最后怎么样算成功。

然后有测试。

模型在这个框里面把题做出来就行。

但是现实里面不是这样的。

现实里面很多时候,真正的问题就是你根本不知道问题是什么。

像我刚才那个 WSL 扫 Windows 的事情。

我当时给模型的框架可能就是:“WSL 扫 Windows 太慢了,我现在是不是应该把项目迁到 Windows?”

那一个弱一点的模型很可能就顺着你这个框架开始分析,迁到 Windows 有什么好处、要改哪些路径、怎么迁。

但是更强的模型更有可能在前面就跟你说:等一下,你为什么一定要让 WSL 扫 Windows?

Windows 侧起一个进程扫不就行了吗?

这两个体验其实差别特别大。

一个是在你给定的问题里面解题。

另外一个是它可能会发现你这个问题本身就问歪了。

然后我觉得这就引出了另外一个我最近挺强烈的感受,就是你用模型之前,最好先想一下:我这次到底想干嘛?

7. 如果我的目标只是把东西做出来,那我肯定直接用强模型

如果我今天就是为了尽快把这个东西做出来,我根本不想学中间这些东西,我就想要结果,那很简单,我直接上 Sol。

让它把架构想清楚,让它提前帮我找坑,让它给我拆计划。

如果我要省成本,也可以让 Sol 先 plan,把任务拆得特别清楚,然后丢给 Luna 或者 sub-agent 去执行,最后 Sol 再回来 review。

这其实是一个很高效的组合。

8. 但如果我的目标是学习,我反而会故意用弱一点的模型

但是另外一种情况是,我做这个东西本身就想学。

比如说我就是想借这个 Skill Manager,把 Windows、WSL、文件系统、Node、进程通信、桌面端这些东西真正摸一遍。

那这个时候我现在反而觉得,你可以有意识地多用一点弱模型。

9. 弱模型最有价值的地方,是它会暴露你没想清楚的东西

因为弱模型有一个特点,就是它不会那么轻易替你把所有坑都填掉。

你说清楚了,它就能做。

你没说清楚,它很可能就给你做歪。

然后它一做歪,你就得想:它为什么做歪?

是它太笨,还是我这个需求本身就没想清楚?

然后很多时候你最后会发现,真的是自己没想清楚。

你甚至没有办法准确地告诉它应该怎么改。

那这个时候问题就不是模型的问题了,是你自己对这件事情的理解就有洞。

所以我现在觉得,如果你是想边做边学,一个挺好的方式就是,一开始先找一个强模型,比如 Sol,把大的方向聊清楚。

比如说这个东西大概是什么架构,三步走还是四步走,确保你不要从上海一路走到新疆去了。

大方向确认以后,你真正执行的时候可以换 Luna。

然后一段一段做。

它搞砸了,你就自己看为什么。

你实在搞不明白,再回去问 Sol。

这样你既不会完全瞎走,又不会让强模型直接把整个过程替你吃掉。

因为如果 Sol 从第一步开始就把整个架构、所有 edge case、所有坑全给你想好了,然后最后代码也给你写好了,你当然很爽,两个小时产品出来了。

但是有一个问题,就是两天以后别人问你这个东西为什么这么设计,你可能不知道。

这个就是我觉得现在讲“AI 会不会让人学习能力下降”的时候,一个比较容易被忽略的东西。

不是说用了 AI 就学不到东西。

而是要看你把哪一部分东西交给 AI 了。

如果你连“我为什么这么做”“这个东西为什么工作”“出问题以后应该从哪里查”这些东西也全部外包出去,那你确实就没有建立自己的理解。

反过来,如果你一直在跟一个没那么聪明的模型合作,它反而经常会逼着你把这些东西说清楚。

而且还有一个挺有意思的现象。

就是有时候 Luna 给你一个回答,你一看就觉得,这什么玩意儿,明显不对。

其实你能产生这个感觉,本身就已经说明你在这个问题上的理解比它高了。

那你下一步要做的,就是别停在“感觉不对”。

你要能把它讲清楚:到底哪不对?为什么不对?正确的应该是什么?

你如果能把这件事情说清楚,那其实你就真的把这个知识吃进去了。

10. Benchmark 很接近,为什么实际用起来差这么多?

所以我现在看 benchmark,也会稍微换一个角度。

benchmark 当然有用,我肯定不是说 benchmark 没用。

GPT-5.6 官方的数据里面,Sol 整体肯定还是旗舰,Coding Agent Index、DeepSWE 这些也总体高于 Luna。

Pasted image 20260822180148.png

ps: 也可以参考我做的这个网站, runminton.github.io/gpt-decision-lab/

但是你不能看到 Luna max 在某些 benchmark 上超过 Sol medium,就觉得现实使用里面两个模型也差不多。

因为现实里面最值钱的能力,有时候恰恰没有那么容易 evaluation。

就是你的需求说得不清楚的时候,它能不能知道你真正想干嘛?

你给它一个错误前提的时候,它会不会跟着你一路错下去?

一个开放问题有五六条路的时候,它能不能自己意识到还有另外一条你根本没想到的路?

这些东西在真实的知识工作里面其实特别重要。

11. 再往上看,其实又回到了 Scaling

然后再往后我就会联想到 scaling 这件事。

就是为什么大模型叫“大”模型嘛。

虽然模型能力肯定不能简单粗暴地等于参数量,因为现在还有 MoE、训练数据、后训练、推理计算这些东西,都会影响最后的能力。

但是更大的通用模型、更大的计算量,长期来看确实一直在吃掉很多以前我们觉得需要人工设计的 heuristic。

这个跟 Sutton 那篇《The Bitter Lesson》其实有一点像。

人特别喜欢自己设计一些很聪明的规则,很聪明的策略,觉得我把这个 domain knowledge 塞进去,就能让系统特别厉害。

但是历史上很多时候,最后赢的反而就是更 general 的方法,加上更多 compute。


三、最后,其实技术栈和模型问的是同一个问题

所以回到我自己这个项目,我现在大概就是这么一个想法。

技术栈也是一样,模型也是一样。

你先问自己,我现在到底想优化什么?

我要的是尽快把产品做出来,那我就选开发反馈最快的东西。Web 能解决,我就先 Web;最后要桌面端,那就 Electron。真的到了性能成为问题的时候,再去 Rust、Native。

模型也是一样。

我要最快拿结果,我就 Sol。

我要边做边学,那我反而可能先让 Sol 给我把大方向兜住,然后大量执行过程用 Luna,让自己去碰那些 friction。

因为有些 friction 是完全没必要的。

比如说一个中文输入法 bug 把你卡两天,这种 friction 对你的产品没有任何价值,该绕就绕。

但是还有一些 friction,是因为你自己真的没想清楚。

比如我连 Node.js 到底是什么都说不出来。

这种 friction 如果一个强模型直接替我绕过去了,我其实就错过了一次把这个东西真正搞懂的机会。

我最近做这个 Skill Manager,最大的感受大概就是这个。

--完--