这事儿搁在任何一家科技公司,都够写进年度OKR里当战绩。
但NanoClaw的作者做了一件更狠的事——他不是删了40万行代码,而是直接重写。500,000行的一个AI助手框架,砍到只剩8,000行TypeScript,外加6个生产依赖。
6个。
说实话,我第一反应是这人是不是在吹牛。但看完他的架构分析文章,我发现事情没那么简单。
这哥们儿不是删代码上瘾,他是重新定义了"怎么做减法"。
凭证代理:让AI永远拿不到真正的密钥
先说最打动我的一个设计。
AI agents跑在Linux容器里,要调用Anthropic的API,密钥怎么处理?
大多数人的做法:环境变量。塞进去,启动时从密钥管理器拉取,走人。
NanoClaw不这么干。
它给每个容器塞一个假密钥,然后让所有API请求先经过本地的一个代理。代理在宿主机上,监听3001端口。容器里的Agent以为自己在调Anthropic,其实先被代理拦截——代理把假密钥抠出来,换成真的,再转发出去。
Agent永远拿不到真密钥。
哪怕有人搞prompt injection攻击,骗Agent把环境变量全抖落出来,出来的也只是一串占位符。没什么好偷的。
这个模式现在有名字了,叫"Phantom Token Pattern"。Kubernetes那边正在把它当sidecar proxy推广。
NanoClaw是自己琢磨出来的。
有时候,最好的方案不是你想出来的,是问题本身逼你想到的。
容器隔离当授权:文件系统就是权限系统
作者之前在Vend和Xero干过,写过大量的权限系统。Role-based access,permission checks,中间件判断用户能干什么。
他原话是:这玩意儿永远是bug的源头。漏写一个检查,就有一个提权漏洞。
NanoClaw的解法非常野蛮——不判断你能干什么,只控制你能看见什么。
每个容器挂载的目录是定死的。非主组的容器只能看到自己的文件夹,项目根目录?看不见。其他组的数据?看不见。宿主机文件?物理上访问不了。
主组稍微宽松点,能读项目代码,但**.env文件被挂载到/dev/null**。文件就在那儿,但容器里就是读不到。
容器里的Agent用bypassPermissions运行,Bash随便敲,文件随便写。但它能写的东西,操作系统已经替它圈好了。
不用写一行权限检查代码。
安全模型就是目录结构本身。
这让我想起一句话:最好的安全是让错误根本不可能发生,而不是指望人别犯错误。
两个光标:消息系统的"不说第二遍"原则
NanoClaw处理消息用了两个独立的光标(cursor),这是整篇文章里我觉得最精巧的设计。
第一个光标是全局水位线。主循环每2秒扫一次SQLite,看到新消息就推进水位线并持久化。防止同一批消息被重复处理——就算循环提前触发,也不会多读。
第二个光标是每组一个。处理某组消息前,光标先乐观地往前挪。如果Agent失败了怎么办?
- 如果还没给用户回消息——滚回去,等下重试
- 如果已经回复了——保持现状,滚回去会重复
核心逻辑很简单:跟用户说过的话,不能收回去。
作者拿自己做过支付系统的经历类比。这事儿要是搞错了,在支付里就是重复扣款。在消息系统里就是用户看见两条一样的回复。
两个光标,一条规则:一旦开口,不能反悔。
文件系统当消息队列:没有Redis,没有RabbitMQ
IPC(进程间通信)怎么做?
NanoClaw的选择是:JSON文件放磁盘上。
容器往/workspace/ipc/messages/写,宿主机从/workspace/ipc/input/读。两边都一个套路——先写.tmp文件,再原子rename到目标位置。
POSIX系统里rename是原子的。文件要么完整存在,要么根本不存在。
没有WebSocket,没有连接管理,没有事件顺序要维护。
每1秒扫一次IPC目录,每2秒扫一次数据库,每60秒扫一次任务调度。
作者在Xero见过太多团队过早地用上事件驱动架构。他说内部工具里的一半,要是换成简单的轮询,反而更简单。
知道你的scale天花板在哪,轮询就不是妥协,是特性。
重新编译当插件:不要抽象层,不要依赖注入
每个容器启动时重新编译TypeScript。Agent源码从各组的目录挂载,所以每组可以有不同的行为逻辑。编译输出放到/tmp/dist,然后设为只读——Agent改不了自己的运行时代码。
没有插件注册表,没有抽象层,没有依赖注入。
想要不同行为?改源码文件。下次启动容器就生效。
当然比插件系统慢。容器启动得多付一次编译的代价。
但作者说,这笔账划算。
抽象层通常是bug藏身的地方。多一层就多一层出问题的可能。
删掉的每一行,都是没机会炸的炸弹
写到这里,我开始想一个问题:为什么大多数代码库会变成屎山?
因为加功能永远比删功能容易。堆依赖永远比做约束爽。写新的 abstraction 永远比理解现有的业务逻辑有成就感。
NanoClaw的8,000行不是穷,不是资源受限,是刻意选择。
它知道自己是个单用户系统。所以它用轮询不用推送,用文件系统不用消息队列,用容器隔离不用授权中间件。
作者最后问了一个问题:你的代码库里,哪些地方也存在同样的约束?只是你从来没意识到?
这个问题的答案,可能比任何代码技巧都值钱。
【锐评】:500,000 vs 8,000 不是魔法,是知道什么该做之后,大胆地决定什么不做。大多数人缺的不是能力,是砍掉自己作品的勇气。
参考链接:
https://jonno.nz/posts/nanoclaw-architecture-masterclass-in-doing-less/