定制需要一个内核
有了 Agent 之后,改软件这件事的门槛低了很多。过去想让一个工具多一个按钮、换一种流程,得等开发者排期;现在描述清楚,Agent 半小时就能改出来。
这会带来一个直接的结果:定制会变得到处都是。哪怕是一小群人在用的东西,每个人的习惯和要求也不一样,而现在每个人都有能力按自己的意思去改。
问题是,这些定制该落在哪里?
为什么不直接 fork
最直接的做法,是把源码复制一份,让 Agent 直接改。想要什么改什么,没有任何限制。
这条路短期很顺,长期会出问题。原作者还在继续更新,你改过的那一份很快就会和上游分道扬镳,每次想跟上新版本,都要把自己的改动重新合一遍。
但我觉得更根本的原因是:软件最核心的那一层,Agent 改不动。
每个成熟的软件里都有一层很深的抽象。比如数据库里的事务和一致性,编辑器里的文本缓冲和撤销模型,操作系统里的进程与文件。这一层的正确性是全局的:一个不变量牵动所有依赖它的地方;改错了往往不会立刻报错,而是在某个罕见的时序里悄悄坏掉。
这样的东西,很难在一次对话、一个局部上下文里改对。它是被长时间的使用、无数次出错和修正慢慢磨出来的。Agent 擅长在给定范围里做局部正确的事,而内核的正确性恰恰无法在局部验证。
更何况,它的价值就在于稳定。如果每个人都去改,它就不再稳定了。
大部分人也不需要理解它
还有一个同样重要的事实:绝大多数人根本不需要理解这一层。
这本来就是抽象存在的意义。开车的人不需要懂变速箱,写网页的人不需要懂 TCP 的重传。一个好的内核,应该让上面的人可以放心地不去理解它。
想加一个按钮、换一种显示方式、接入一个新的数据源的人,需要的是一个小而清楚的接口:能拿到什么,能做什么,不能碰什么。至于底下的东西如何保证正确,最好一眼都不用看。
按深度分工
于是自然会形成一种分层。
深而稳定的内核,由少数人长期打磨,变化很慢;浅而多变的定制,由每个人带着自己的 Agent 在插件层完成,变化很快。
这是一种新的分工。过去软件团队按功能分工,有人做前端,有人做后端;以后更像是按抽象的深度分工,有人守内核,所有人在外面定制。
VS Code 是这种形态的一个典型。它的核心很小,只管文本、窗口和扩展的运行环境;语言支持、主题、版本控制、调试器,几乎都是扩展。扩展运行在独立的进程里,一个扩展崩了,编辑器还在。正因为核心足够稳定,几万个扩展才能在上面共存。
时间与空间上的约束
我更愿意把这种内核看作一个 harness,用来约束所有人的定制。
在空间上,它让很多人的定制可以同时存在。每个插件只通过接口和内核打交道,彼此隔离,不会因为你改了这里,就把别人的那一块弄坏。
在时间上,它让定制能活下去。内核可以在接口之下不断演进,只要接口不变,昨天写的插件今天还能用,不需要每次升级都重新对一遍。
它还约束了 Agent 本身。插件的边界就是 Agent 的围栏:在一个小而清楚的接口里写代码,出了错影响也有限;而让 Agent 去动内核,出错的代价是整个系统。
内核该放什么
这种架构最难的地方,是决定内核里放什么。
放得太多,内核就退化成一个什么都管的单体,又回到了改不动、也不敢改的状态;放得太少,插件之间就要自己互相协调,最后乱成一团。
我的判断标准是:内核只放大家都要依赖、而且不能各说各话的东西,比如共享的事实、必须始终成立的不变量、最基本的动作。至于“遇到这种情况该怎么做”的策略和偏好,全部交给插件。
插件会变成什么
再往前走一步,插件本身的形态也可能变化。
过去的插件是有人写好、放到市场里、大家下载来用。以后的插件,可能更多是每个人的 Agent 现场写给自己的:只服务一个人,用到不用了就扔掉。
稳定的部分会越来越少、越来越深;易变的部分会越来越多、越来越浅,也越来越私人。
代价
这条路当然也有代价。
Emacs 很早就做到了几乎一切皆可定制,它的问题也很早就暴露了:每个人的配置都不一样,很难分享,时间一长还会慢慢腐烂。插件生态还会带来冲突、质量参差和安全问题,谁也不能保证你装的每一个插件都可信。
另外需要说明,这里说的“微内核”是应用层面的。操作系统领域也有过微内核之争,当年以性能见长的单体内核占了上风,那是另一个问题。
最难的还是设计接口本身。接口一旦被大量插件依赖,就很难再改,第一版画错的边界,会长期留在那里。
结尾
我想,以后软件的典型形状大概是这样:中间一个小而深的内核,由少数人慢慢打磨;外面一圈浅而多变的插件,属于每一个使用它的人。
内核负责不变,插件负责变化。人和 Agent 都在外圈自由地改,内核在里面让这一切不至于散架。