AI 写了 10 万行 K8s 代码,真正难的不是生成

webernetes 把 Kubernetes 的一部分核心行为搬进浏览器,但它最值得看的不是 140KiB 的技术炫技,而是 Sam Rose 如何用逐行审查、对照 k3s 的测试和人的判断,把 LLM 生成的大量代码压到值得信任。

你可能已经用了几年 K8s。

Deployment 会写,Service 会配,Pod 挂了也知道先看 events。可真要问 kubelet、scheduler、controller、CNI 在里面怎么配合,很多人心里还是一团黑箱。

你也可能已经开始用 AI 写代码。

让它补测试、改函数、迁移一段逻辑,确实省时间。但到了 code review,你又会忍不住多看两眼:这个 helper 哪来的?这个边界条件是不是少了?它看起来很顺,真的和原来的行为一样吗?

webernetes 这个项目有意思,就卡在这两个不信任中间。

Sam Rose 在 ngrok 博客里写,他把 Kubernetes 的一部分核心行为搬进了浏览器:kubelet、调度器、deployment controller、kube-proxy、CNI 网络模拟、容器运行时。博客开头还给了几个很刺眼的数字:接近 10 万行代码,552 个 commit,629 个文件,两个月。

更反常识的是,它的 gzip 后体积大约 140KiB。

作为对比,一个 Go 写的 hello world 编译成 WebAssembly,gzip 后大约 540KiB。也就是说,你直觉里那个“把 K8s 编译成 WASM 塞进浏览器”的方案,连一个 hello world 的体积都先把你劝退了。

浏览器里的 webernetes 与可信度回路

所以 webernetes 最值得看的地方,不是“AI 写了 10 万行代码”。

真正值得看的是:这些 AI 写出来的代码,最后是怎么被人审查、被测试、被对照到可以相信的。

它不是把完整 K8s 编译进浏览器

很多人第一反应会问:这是不是把 Kubernetes 编译成 WebAssembly?

答案很干脆:不是。

官方博客里 Sam Rose 直接写了这句话:Did you compile Kubernetes to WebAssembly? The answer is no.

原因也不神秘。完整 Kubernetes 会调用很多浏览器里不存在的系统级 API,硬编会遇到编译期错误。就算绕过去,体积也很难接受。一个 Go hello world WASM 都比 webernetes 大,更别说整个 Kubernetes。

webernetes 走的是另一条路:用 TypeScript 重新实现 Kubernetes 的一部分行为。

注意,是一部分。

它不是生产级 Kubernetes 发行版,不是 minikube、k3s 的浏览器替代品,也不能跑 Docker Hub 上的真实镜像。README 说得很清楚,它是为了做长期可维护的交互式 Kubernetes 内容。你可以把它理解成一个浏览器里的 Kubernetes 模拟器:保留教学演示需要的关键因果链,把不需要的真实世界复杂度切掉。

这反而是它聪明的地方。

一个好 demo 不一定要还原全部现实。它只需要保留你要解释的那条因果链:Pod 怎么被调度,Service 怎么把请求分到后端,Deployment 怎么追踪 ReplicaSet,容器运行时怎么和 kubelet 对话。

这条链跑起来,读者才会第一次感觉到:K8s 不是一坨神秘 YAML,而是一组持续对账、调度、修正状态的控制回路。

这也是浏览器版本的价值。

很多后端学习 K8s 的困难,不是资料少,而是反馈太重。你想看一个 Pod 从 Pending 到 Running,要准备集群;想看 Service 怎么转发,要配网络;想解释 Deployment 和 ReplicaSet 的关系,最好还得有一个能动的环境。真实集群当然更准确,但它太沉,沉到很多人只剩下复制 YAML。

webernetes 把这件事变轻了。

它不追求完整复刻,而是让“状态如何流动”这件事第一次可以嵌进文章、demo 和浏览器页面里。对教学工具来说,这比假装自己能替代生产集群重要得多。

这类项目如果边界说清楚,反而比很多“本地一键起集群”的教程更适合入门。它不要求你先理解全部术语,只让你先看见几个关键对象怎么互相影响,哪里变了,系统为什么跟着变。这就够了。

好玩的外壳下面,是一个更严肃的问题

如果故事停在这里,它就是一个很酷的技术玩具。

但 webernetes 的第二层故事更现实:几乎所有代码都是 LLM 写的。

这句话很容易把讨论带偏。有人会立刻兴奋:看,AI 已经能写 10 万行基础设施代码了。也有人会马上关门:AI 写的,不就是 slop 吗?

这两种反应都太快。

真正做过迁移、重构、补测试的人都知道,大项目最怕的不是“跑不起来”。跑不起来反而好办,错误会跳到你脸上。最麻烦的是它看起来能跑,局部也说得通,但某个行为和原版差了一点。

基础设施代码尤其怕这种“一点”。

一个 cache 的过期语义错了,不一定立刻炸;一个 controller 少处理一种边界状态,demo 可能照样漂亮;一个测试用例被漏掉,CI 仍然绿。你以为是移植,实际上已经悄悄换了行为。

Sam Rose 在博客里列了 LLM porting 的几个毛病,很像我们平时 review AI 代码时看到的东西。

第一个是偷懒。

Kubernetes 里有 LRU cache、expiring cache、FIFO cache、transforming cache 等不同语义的缓存。LLM 会把它们简化成一个 Map。代码短了,也能存东西,但行为已经不对了。

第二个是过度热心。

它会发明一些原版 Go 代码里不存在的 helper function,把代码“整理”得更干净。问题是,迁移代码时你要的是 side-by-side review,要能一行一行对照原实现。它擅自抽一个 helper,审查成本反而上去了。

第三个更麻烦:漏东西。

移植 Go 的 table tests 时,LLM 会随机漏掉一些测试用例。你问它为什么漏,它有时还会解释这条不适用;继续追问,通常又承认是自己漏了。

这就是 AI 代码最烦人的地方。

它不是一直错。它经常对,而且对得很顺。正因为顺,你才更容易漏看它偷偷省掉的东西。

让 AI 代码可信,不靠信任 AI

webernetes 没有靠“我觉得模型挺强”来压住这个问题。

Sam Rose 做了两件很笨、很慢、也很工程的事。

第一,逐行审查所有代码。

这句话听起来不性感,但它可能是整篇博客最重要的一句。AI 生成 10 万行代码很有传播性;人逐行审查 10 万行代码,才是项目从玩具变成可信 demo 的分界线。

第二,写了大量测试,而且不是只测 webernetes 自己。

他的做法是:同一份测试代码,同时跑在 webernetes 和真实的 k3s 集群上。pnpm test:node 对着 k3s 跑,pnpm test:browser 对着浏览器里的 webernetes 跑。

这就把问题从“我觉得实现对了”,改成了“同一个 Kubernetes client 调用,在真实集群和浏览器模拟器里表现是否一致”。

这个思路很值得抄。

如果你让 AI 改一段业务逻辑,最危险的不是它语法写错,而是它把行为写偏了。你要做的不是祈祷模型更聪明,而是想办法给它设一个外部标尺:旧实现、真实系统、黄金样本、线上录制请求、兼容性测试,都可以。

没有标尺,review 会变成读作文。

有标尺,review 才开始像工程。

官方博客里还提到一个细节:每次发现 bug,作者会先写一个 k3s 通过、webernetes 失败的测试,再让 LLM 帮忙理解和修复。

这个顺序很关键。

不是“先让 AI 修,再看看有没有问题”,而是先把问题钉住,让真实系统当裁判,再让 AI 进入反馈回路。AI 的价值在这里不是替你判断正确性,而是帮你更快穿过搜索空间。

最后一周,agent 军团确实上场了

故事后半段有一段很有 2026 年味道。

Sam Rose 想给 demo app 加 Deployment 支持,一开始觉得不会太久,后来发现自己错了。为了赶进度,他把很多 token 扔了进去,启动了一队 agents 去分析依赖链、port 每个组件,再用更多 sub-agents review。

这听起来像我们对 AI agent 最想听到的故事:任务拆开,agent 并行,最后赶上 deadline。

但作者的反思不是“太爽了,以后都这么干”。

他的说法更克制:这确实比他自己做更快完成,但 token efficiency 非常差;最后的人工 review 仍然要做。博客里那句最值得记住的话是:My time was still the most expensive line item in the project, even at the end.

最贵的不是 token。

最贵的是那个能判断代码有没有偏、测试有没有漏、行为是不是还像 Kubernetes 的人。

这句话放到我们自己的项目里也成立。

很多团队现在讨论 AI 编程,注意力还在“能省多少人天”。这个问题当然现实,但它不够完整。AI 真正改变的,可能不是把人的判断成本归零,而是让以前不值得做的探索变得值得试一试。

以前你不会为了一个教学 demo 手写 10 万行移植代码。太贵。

现在 LLM 能把打字、翻译、重复迁移的成本压低,于是这个项目突然有了可能性。但可能性不等于可信度。可信度仍然要靠审查、测试、边界和责任来买。

买不到,也绕不过去。

这件事对普通后端有什么用

大多数人不会去浏览器里重写 Kubernetes。

但 webernetes 给后端工程师的提醒很直接:以后判断 AI 代码,不要再只问“是不是 AI 写的”。这个问题太粗了。

更好的问题是四个:

  • 它有没有可对照的原始行为?
  • 它有没有覆盖关键边界的测试?
  • 它有没有被人按行为语义审过,而不是只看能不能跑?
  • 它出错以后,责任链是不是清楚?

如果这四个答案都没有,哪怕代码很漂亮,也只是漂亮的风险。

如果这四个答案足够扎实,AI 写的代码也不是天然不能用。它只是不能免审,不能免测,不能免责任。

把这个判断放回团队协作里,会更具体。

以后 code review 里看到一大段 AI 改动,不要只盯着“有没有明显 bug”。那只是最低线。更应该看它有没有改掉原来的语义。

比如迁移一段缓存逻辑,不能只问它有没有通过类型检查。你要问:过期策略还一样吗?淘汰顺序还一样吗?并发下读写行为还一样吗?以前依赖这个细节的调用方,会不会被影响?

比如让 AI 补测试,不能只看它生成了多少 case。你要看它有没有漏掉最脏的那几个边界:空值、重复、乱序、超时、取消、权限失败、旧数据兼容。AI 很擅长把正常路径写得很完整,也很擅长漏掉那些让线上事故发生的路径。

再比如让它重构旧代码,最漂亮的 helper 反而要多看一眼。旧代码丑,不代表它没语义。很多“历史包袱”其实是线上踩过坑留下的疤。AI 不知道这道疤从哪来,它只会觉得这里可以抽象一下。

所以 AI 代码的评审标准,不该比人工代码更低。

恰恰相反,当你不知道它是不是理解了上下文时,标准要更硬:改动越大,越需要对照;行为越隐蔽,越需要测试;看起来越顺,越要怀疑它是不是把复杂性藏掉了。

这不是对 AI 苛刻。

这是对工程负责。

这和 K8s 本身其实有点像。

Kubernetes 从来不是因为 YAML 神奇才可靠。它可靠,是因为背后有一堆控制器不断观察现状、对照期望状态、修正偏差。webernetes 这个项目最有意思的地方,是它自己也用了类似的思路来约束 AI 代码:生成只是当前状态,review 和测试才是控制回路。

这也是我觉得它值得写的原因。

表面上看,这是一个把 K8s 搬进浏览器的酷项目。

往深一点看,它其实在回答另一个更贴近我们的问题:当 AI 开始写越来越多代码,我们到底靠什么继续相信软件?

答案不新鲜。

靠人读。靠测试跑。靠真实系统做标尺。靠有人愿意为最后的判断负责。

AI 能让一个荒唐项目变得可做,但它没有取消工程里最贵的东西。

最贵的,仍然是那个看得懂的人。