网易首页 > 网易号 > 正文 申请入驻

“氛围编程让一切看起来很廉价,我要回归手写编码了!”

0
分享至


如果说这几年 AI 编程令人沉迷的地方,是“几乎不费力就能把东西做出来”,那么真正让人开始警觉的瞬间,往往发生在系统第一次“看起来还在工作,但已经开始悄悄失控”的时候。

这篇来自 k10s 作者的长文,就是从那个临界点开始往回看的。他记录了一次几乎完全依赖 vibe-coding 的开发实验:从一个 GPU 感知的 Kubernetes TUI,到一个功能不断膨胀、最终被自身复杂度吞噬的系统。过程中有过极高的开发速度,也有过 AI 一次性生成完整功能的“爽感时刻”,但同样也埋下了架构失控、状态混乱和隐性 bug 的伏笔。

更重要的是,这不是一篇单纯的“翻车复盘”,而是一份带着具体代码细节、设计选择和反思路径的拆解记录。它试图回答的并不是“AI 能不能写代码”,而是另一个更现实的问题:当 AI 真的参与到软件构建的每一层时,人类到底还需要在哪些地方重新夺回控制权。

原文:https://blog.k10s.dev/im-going-back-to-writing-code-by-hand/

作者 | shvbsle 责编 | 苏宓

出品 | CSDN(ID:CSDNnews)

这件事最开始其实更像一次实验,或者说一个问题——“如果我尽可能不亲自参与开发流程,只靠 AI 来写软件,我到底能走多远?”

话不多说,这篇开发日志最终得出的核心结论是:如果真想做出点有意义的东西,人类依然必须参与其中。

几点感受:

  • 就像 “em-dash(长破折号)” 已经快成 AI 写作的标志一样,“god-object(上帝对象)” 也快成 AI 写代码的典型特征了。

  • “氛围编程” 会让一切看起来都很廉价,你最后很可能会失去重点,做出越来越臃肿的东西。

  • 架构一定要由人(也就是你)来设计,而不是不停地让 AI 往里加功能。

  • 另外,我还整理了一些 AGENTS.md / CLAUDE.md 的指令配置,它们确实能让我稍微少亲自下场一点。

截至 2026 年 5 月 10 日,人类干预依然是必需的。

这项实验到底验证了哪些东西,以下是完整的过程。


234 次提交、30 个周末,用氛围编码开始一个项目

这是 k10s GitHub 仓库:https://github.com/shvbsle/k10s/tree/archive/go-v0.4.0

234 次提交,差不多花了 30 个周末。整个项目几乎完全是在“氛围编程”状态下完成的——只要 Anthropic 的 Claude token 额度还没耗尽,我就继续往前做、继续发功能。

现在,我决定把这个 TUI 工具归档,然后从头开始重写。

k10s 最初的定位,是一个“支持 GPU 感知”的 Kubernetes Dashboard,也是我第一次认真尝试用 AI 去开发一个真正复杂的软件。

你可以把它理解成一个面向 NVIDIA GPU 集群的 k9s,服务的是那些真正关心 GPU 利用率、DCGM 指标,以及哪些节点正在空转烧钱(每小时 32 美元)的人。

我用 Go 和 Bubble Tea 写了它,而且它一开始确实能跑。

至少……有一段时间是这样。

过去 7 个月里我学到的东西,比我现在准备删掉的那 1690 行 model.go 更有价值。我觉得,任何认真尝试“vibe-coding”的人,可能都会从这些经验里得到点东西,因为这部分内容其实很少有人讨论——它通常都会被那些炫酷 Demo 和“开发速度暴涨”的故事掩盖掉。

一句话总结:AI 会帮你写功能,但不会帮你设计架构。如果你长时间不加约束地让它“自己运行”,最后只会留下越来越严重的事故现场。开发速度会让你误以为自己一路领先,直到某个瞬间,整个系统开始同时崩塌。

加入 AMD AI 开发者计划,免费领 50 小时云算力券

进群月月抽显卡、AIPC,好运不停!


“氛围编程”上头的时候

我是在 2025 年 9 月底开始做 k10s 的。

最开始那几周,简直像魔法一样。

我对 Claude 说一句:“加一个支持实时更新的 Pods 视图”,然后“砰”的一下,功能就出来了。

资源列表视图、命名空间筛选、日志流、描述面板、键盘导航……一个个功能都顺利落地。原因也很简单:那时候项目还足够小,AI 还能把整个工程都“装进上下文”里。

最基础的那个 “k9s 克隆版”,我大概只花了 3 个周末。它包含了:

  • Pods、Nodes、Deployments、Services 的资源视图;

  • 命令面板;

  • 基于 Watch 的实时更新;

  • Vim 风格快捷键……

全部都能跑,而且几乎全是在单次 session 里“vibe-coded”出来的。我当时的开发速度,可能是平时的 10 倍。那种感觉真的很爽。

然后,我开始做这个项目真正的核心卖点。

k10s 存在的真正原因,其实是 GPU 集群视图(GPU Fleet View)。

我想做一个专门的界面,让你能一眼看到每个节点的 GPU 分配情况、DCGM 利用率、温度、功耗、显存占用。

不是把信息埋在 kubectl describe node 那种输出里,而是做成一个专门设计的表格界面,并且带颜色状态提示:空闲节点显示黄色、繁忙节点显示绿色、GPU 打满显示红色。


结果 Claude 一次就生成成功了。

我只写了个 prompt,它就直接生成了 FleetView 结构体、GPU / CPU / All 的标签过滤、自定义渲染逻辑、GPU 分配进度条,而且界面看起来还特别漂亮。

那时候我整个人都沉浸在“AI 开发效率爆炸”的快感里。

直到后来,我输入了一句:

:rs pods

想切回 Pods 视图。

结果什么都没出来。表格是空的。实时更新停了。

我切换到 Nodes 视图时,它显示的还是 Fleet View 的旧过滤数据。

再切回 Fleet View,标签统计数字又全错了。

那个“上帝对象(god object)”,终于把自己吞噬掉了。

这也是这篇博客标题的来源。也是我第一次真正“人工介入”的时刻。

整整 7 个月里,我一直都在“prompt → 生成 → 发布”,却从来没有真正坐下来认真读过 Claude 写的代码。

我通常只是看一下 diff、确认能编译、再测一下 happy path、然后继续往前做。

但这次不一样了。

这已经不是再写个 prompt 就能解决的问题。系统的基础结构已经坏掉了。

于是,我第一次真正坐下来,开始读 model.go。整整 1690 行代码。我当场头皮发麻。

代码大概是这样的:一个结构体统治一切。

}

UI 组件、K8s Client、日志状态、Describe 状态、Fleet 状态、导航历史、缓存、鼠标事件处理……全部塞进了同一个 struct。

而 Update() 方法更夸张:一个 500 行的大函数,里面根据 msg.(type) 分发逻辑,堆了 110 个 switch/case 分支。

也就是从这一刻开始——我不再只是凭氛围进行编码,而是开始真正思考软件工程了。



从“事故现场”里总结出的五条原则

这是我花了 7 个月时间,看着 AI 一点点生成、并最终“反噬自身”的代码库后,总结出来的东西。

下面每一条,都是我亲自踩过的坑:

  • 我哪里做错了?

  • 为什么 AI 辅助编程特别容易掉进这个坑?

  • 以及,你到底应该在 CLAUDE.md 或 agents.md 里写些什么,才能提前避免它?

原则一:AI 会写功能,但不会设计架构

每次我让 Claude 加一个功能,它都能做出来,而且完成得相当漂亮。

Fleet View 一次成功,日志流能跑,鼠标支持功能也能运行。

问题在于:每个功能,都是站在“先把当前需求做出来”的角度实现的。它根本不会意识到,系统里还有另外 49 个共享同一份状态的功能。

举个例子,下面这个 resourcesLoadedMsg handler,是每次切换视图时都会执行的代码。

    }

你看到这个「if msg.gvr.Resource == k8s.ResourceNodes && m.fleetView != nil」条件语句了吗?

这代表 Fleet View 被硬编码进了通用资源加载流程。之后,每新增一个需要“特殊行为”的视图,这里就会再多一个 if branch。

而且每个 branch 还得手动清理对应字段,否则前一个视图的数据就会“泄漏”到下一个视图里。

我后来专门数了一下:这个文件里到底有多少个 = nil 的手动清理逻辑?

m.logLines = nil

答案是:9 个。9 个散落在 1690 行文件里的“手动状态回收”。漏掉任何一个,你就会看到前一个视图留下的“幽灵数据”。

这就是没有“视图隔离”时必然发生的事情。而 AI 根本看不到这个架构正在慢慢腐烂。

因为每一次 prompt,它只会关注当前那一条代码路径。

正确做法的是,在写任何代码之前,先自己把架构设计好。

不是那种空泛的设计文档。而是要编写一套有明确的接口、消息类型、状态所有权规则。然后把这些规则写进 CLAUDE.md:

- The App struct is a thin router. It owns navigation and message dispatch. Nothing else.

这样 AI 每次收到 prompt 时,都会先看到这些约束。

原则二:“上帝对象”是 AI 默认生成的产物

AI 天生喜欢“一个 struct 管一切”。因为这是满足 prompt 最省事的方法。

但问题会越来越严重。由于没有视图隔离,键盘事件处理最终会变成灾难。

比如下面这个 s 键的实际逻辑:

    return m, nil

同一个快捷键,在不同视图里有三种完全不同的含义:

  • 在 Logs 里表示“自动滚动”

  • 在 Pods 里表示“进入 Shell”

  • 在 Containers 里表示“进入容器 Shell”

所有逻辑,全塞在同一个巨型 switch 里。

为什么会变成这样?因为我对 AI 说:“给 Pods 加 shell 支持。”

于是它就找到最近的键盘处理逻辑,直接把代码塞进去。

再看 Enter 键。整个 drill-down handler 也是同样的问题。

    // ... 25 more lines of generic drill-down ...

所有视图都被塞进一个“平铺式 dispatch”。整个文件里,有 20 多处:m.currentGVR.Resource == ...这样的字符串判断。

这里说的不是类型系统、不是抽象接口,只是字符串比较。

这意味着每新增一个视图,你都得改所有 handler。

正确的做法是,你应该在 CLAUDE.md 里明确写下规则:

- Adding a view means adding a file. If your change requires modifying existing views, stop and ask.

AI 永远会走“最短路径”——也就是“再加一个 if 分支”。你的工作,是让“最短路径”同时也是“正确路径”。而方法,就是把约束提前写进 AI 每次都会读取的规则文件里。

原则三:开发速度的幻觉,会不断扩大你的项目范围

这一条不是技术问题,是心理问题,也是我觉得最危险的一条。

我一开始做 k10s 时,目标其实很简单,就是设计一个面向 GPU 集群的小众工具,给那些跑训练集群的人用,也就是我自己这种人。

但 “vibe-coding” 会让一切看起来都太便宜了。“哦?Pods 视图一晚上就做完了?”

那顺手再加 Deployments、Services、完整命令面板、鼠标支持、Context 管理、Namespace 管理..


最后我突然发现:我已经在重新造一个 k9s 了。

一个面向所有人的通用 Kubernetes TUI,因为 AI 让每个功能都显得“像不要钱一样”。

但它其实不是免费的。每个新功能,都是那个“上帝对象”里新增的一条分支。

比如这个 keybinding struct:

}

所有视图共用一个扁平化的 keymap。

注释里甚至还得写:“这个快捷键属于哪个视图”;s 同时代表 Autoscroll、Shell;之所以“还能工作”,只是因为 dispatch 里会先检查 m.currentGVR.Resource。

但代价是你已经无法局部理解任何一个快捷键了。

你必须一路追踪整个 500 行的 Update(),才能知道一个按键最终会干什么。

复杂度正在悄悄累积,而 AI 给你的“速度反馈”却一直在告诉你:“你开发得真快。”

正确的做法是:提前写一份 Vision Doc。明确写清楚“哪些用户不是你的目标用户”,然后把项目边界写进 CLAUDE.md。

If a feature request doesn't serve someone running GPU training jobs, reject it.

“Vibe-coding” 会让你误以为自己拥有无限开发预算。其实你拥有的,只是“无限代码行预算”。AI 可以无限生成代码,但你的“复杂度预算”仍然是有限的。无论代码写得多快,架构能承受的功能数量始终有限。超过之后,它一定会塌。

CLAUDE.md 里的 scope section,本质上就是:在“速度快感”让你什么都想加之前,提前替自己说“不”。

原则四:位置型数据结构,就是定时炸弹

在 k10s 里,所有资源数据从 Kubernetes API 拉下来之后,都会立刻被“拍平”:

type OrderedResourceFields []string

列信息完全依赖“位置”。比如 Fleet View 的排序逻辑:

}

ra[3] 表示 Alloc。ra[2] 表示 Compute。ra[0] 表示 Name。全是“魔法数字”。

index 3 为什么代表 Alloc?

唯一的依据,只是一条注释和 resource.views.json 里的列顺序。

}

在 Instance 和 Compute 之间加一列?那所有排序逻辑、所有条件渲染、所有写着 ra[2] 或 ra[3] 的地方,都会在不知不觉中失效。编译器根本帮不上忙,因为这些数据全都是 []string。

更糟的是,JSON 配置根本没法表达排序行为、条件渲染或自定义 drill-down 跳转目标,所以这些逻辑最后只能写进 Go 代码里,而代码又硬编码地依赖 JSON 中字段的位置。

AI 会生成这种模式,因为这是从“获取数据”到“渲染表格”的最短路径。一个 []string 可以立刻塞进任何表格组件里,而强类型结构体(typed struct)前期需要更多样板代码(ceremony)。于是 AI 总会选择那条最快的路。结果六个月后,你开始排查为什么排序后,“Name” 列的数据会出现在 “Alloc” 列里。

正确做法是什么?把这条规则写进你的 CLAUDE.md:

- The ONLY place strings are created for display is inside render()/view() functions.

这样一来,你定义的强类型结构体(typed struct)就能让“不可能出现的状态”真正变得不可能出现 [2]:

}

当列对应的是具名字段时,你就不可能排错列。你也不可能误把 Alloc 字段的字符串当成名字去比较。编译器会替你强制保证这些约束。

而 AI 永远会倾向于选择 Vec ,因为它能更快满足提示词要求。你在 CLAUDE.md 里写下的规则,本质上就是在把“强类型”这条路,变成阻力最小、最容易被 AI 采用的默认路径。

原则五:AI 不应该掌控状态变更。

Bubble Tea 的架构里有一个很漂亮的理念:Update() 是唯一允许状态发生变化的地方,而且所有状态变更都由消息驱动。但 k10s 违背了这一点。

updateTableMsg 处理器启动了一个闭包,在 goroutine 内部修改 Model 字段:

    }

这个返回函数(tea.Cmd)会被 Bubble Tea 放到独立 goroutine 执行。它里面调用了 m.updateColumns(m.viewWidth) 和 m.updateTableData() 函数。这些函数会同时读写 m.resources、m.table、m.viewWidth。

与此同时,主线程里的 View() 也在读取同一批字段。没有锁。没有 mutex。

<-m.updateTableChan 虽然会阻塞 goroutine,直到收到更新信号,但它根本无法阻止 View() 在“状态只更新到一半”的时候进行读取。

这是教科书级别的数据竞争(data race)。99% 的时间它看起来都正常。剩下 1% 的时间,它会以一种极其诡异的方式损坏 UI。严重到让我一度怀疑自己精神出了问题。

AI 为什么会生成这种代码?是因为“直接在 closure 里修改状态”是最快能跑起来的方案。

而正确的消息传递架构是 worker 发消息、Update() 收消息、主循环统一修改状态,需要更多类型、更多 plumbing。

AI 不会为了并发正确性去做这些。它只会为了“当前 prompt 能跑”去优化。

正确的做法是,所有对“影响渲染的状态”的修改,都必须发生在主循环里,仅此一条原则,没有例外。后台 worker 只负责产生数据,然后把数据以 message 的形式发送出去。主循环接收 message,再统一应用状态变更。在并发 UI 代码里,这是唯一不能被打破的规则。

}

不要共享可变状态。不要数据竞争。不要“99% 情况下能跑”。

把这些规则写进 CLAUDE.md。

- If you need to update state from async work, define a new AppMsg variant.

如果 AI 默认不会这样写代码。那规则文件就必须强制它只能这样写。


我现在准备怎么做

我正在用 Rust 重写 k10s。不是因为 Rust “更强”。而是因为——这是我真正“能掌控”的语言。我已经写了足够多的 Rust,以至于很多时候,代码哪里不对劲,我甚至在还没说清原因之前,就已经能本能地察觉到。而这种“直觉”,恰恰是 vibe-coding 永远替代不了的东西。AI 会给你一份“看起来很合理”的代码。但你必须自己具备一种嗅觉:知道它什么时候其实是一坨垃圾。

另一个变化则更简单:这一次,我会亲手完成设计工作。而且是在写任何代码之前。不是那种空泛的大纲文档。而是拥有明确的接口、消息类型、所有权规则。

之前那些总被 AI 做错的架构决策,现在我会在第一条 prompt 发出去之前,先白纸黑字地写清楚。

至于这样做,最终能不能避免这次重构再次“被自己的复杂度压垮”……拭目以待!

从“拥抱 AI”到“AI 原生”,我们正站在生产力变革的奇点。

由 CSDN 与奇点智能研究院联合举办的「2026 全球产品经理大会」将于7 月 17-18 日在北京正式召开。本次大会精心设计了十二个深度专题,旨在通过最前沿的实战案例,拆解 AI 原生时代的进化密码。

目前大会正式开启演讲议题与优质分享嘉宾招募。

你的每一次真实分享,都在为 AI 原生时代的产品实战手册添砖加瓦。

我们在北京,期待听见你的声音。

议题 & 嘉宾推荐/自荐方式:hemiao@csdn.net

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
《主角》直到小白鞋被玷污自杀,胡三元才知,黄正经的色心有多重

《主角》直到小白鞋被玷污自杀,胡三元才知,黄正经的色心有多重

楼兰娱姐
2026-05-12 11:13:26
锁定欧冠资格,佩莱格里尼:打进欧冠是贝蒂斯的巨大功绩

锁定欧冠资格,佩莱格里尼:打进欧冠是贝蒂斯的巨大功绩

懂球帝
2026-05-13 08:25:44
Model Y高速跑最短,达成率却最高,这事儿到底哪不对劲

Model Y高速跑最短,达成率却最高,这事儿到底哪不对劲

蓝色海边
2026-05-12 11:03:55
南京审计大学:将依据调查结果,依规依纪依法严肃处置

南京审计大学:将依据调查结果,依规依纪依法严肃处置

澎湃新闻
2026-05-12 18:00:09
用合法手段,干违法行为

用合法手段,干违法行为

我是历史其实挺有趣
2026-05-13 08:26:19
世界杯还没开踢,中国球迷先“退票”了

世界杯还没开踢,中国球迷先“退票”了

每日经济新闻
2026-05-11 22:56:12
挤走董卿、靠爹上位、央视“穷鬼”,龙洋的私生活谣言有多离谱?

挤走董卿、靠爹上位、央视“穷鬼”,龙洋的私生活谣言有多离谱?

猪小艳吖
2026-05-12 03:50:15
蛇鼠一窝!小S庆功宴具俊晔给S妈按摩,两人状态超级差,小S哭到脸肿

蛇鼠一窝!小S庆功宴具俊晔给S妈按摩,两人状态超级差,小S哭到脸肿

八卦王者
2026-05-12 15:24:17
客场0胜5负何妨?骑士预定天王山胜利,4-2翻盘三大要素已经聚齐

客场0胜5负何妨?骑士预定天王山胜利,4-2翻盘三大要素已经聚齐

老梁体育漫谈
2026-05-13 00:03:25
成都蓉城VS津门虎:廖力生+杨明洋坐镇 罗慕洛领衔 国足新星冲锋

成都蓉城VS津门虎:廖力生+杨明洋坐镇 罗慕洛领衔 国足新星冲锋

零度眼看球
2026-05-13 06:49:19
克拉克谈与詹姆斯友谊:他懂我面对的压力

克拉克谈与詹姆斯友谊:他懂我面对的压力

赛场速报局
2026-05-13 08:03:15
王励勤多次劝说无果!樊振东深夜发声,国乒藏着怎样的现实?

王励勤多次劝说无果!樊振东深夜发声,国乒藏着怎样的现实?

运动探索
2026-05-12 11:08:54
美国AI巨头助乌克兰,俄军进入高危时刻

美国AI巨头助乌克兰,俄军进入高危时刻

桂系007
2026-05-12 17:32:49
不会复刻2020欧洲杯,德拉富恩特:世界杯一定会召满26人

不会复刻2020欧洲杯,德拉富恩特:世界杯一定会召满26人

懂球帝
2026-05-12 17:18:42
40亿索赔压顶,国际足联高管访京,5亿赞助或打水漂

40亿索赔压顶,国际足联高管访京,5亿赞助或打水漂

纵拥千千晚星
2026-05-12 23:35:07
油价再这么涨下去,恐怕全世界都要买电车了

油价再这么涨下去,恐怕全世界都要买电车了

流苏晚晴
2026-05-10 20:25:18
国家一级女演员陈丽云被逮捕!

国家一级女演员陈丽云被逮捕!

许三岁
2026-03-28 09:24:30
床上的这一瞬,比任何姿势都管用:是疲惫时的一个拥抱

床上的这一瞬,比任何姿势都管用:是疲惫时的一个拥抱

精彩分享快乐
2026-05-13 07:05:03
靠《浪姐7》走红的她,还是走到了这一步,将一手好牌打得稀烂

靠《浪姐7》走红的她,还是走到了这一步,将一手好牌打得稀烂

喵喵娱乐团
2026-05-12 15:04:49
太神奇了!场场三分命中率五成以上,苦熬七年,终于能拿亿元合同

太神奇了!场场三分命中率五成以上,苦熬七年,终于能拿亿元合同

球毛鬼胎
2026-05-12 21:38:02
2026-05-13 09:04:49
CSDN incentive-icons
CSDN
成就一亿技术人
26533文章数 242284关注度
往期回顾 全部

科技要闻

谷歌剧透安卓重大升级 Gemini深度集成底层

头条要闻

牛弹琴:印度的大麻烦来了 CNN的报道更是触目惊心

头条要闻

牛弹琴:印度的大麻烦来了 CNN的报道更是触目惊心

体育要闻

骑士终于玩明白了?

娱乐要闻

白鹿风波升级!掉粉20万评论区沦陷

财经要闻

深圳夫妻囤芯片,身家飙涨320亿

汽车要闻

吉利银河“TT”申报图曝光 电动尾翼+激光雷达

态度原创

本地
房产
时尚
公开课
军事航空

本地新闻

用苏绣的方式,打开江西婺源

房产要闻

穗八条引爆楼市!万博宝藏红盘,五一劲销出圈

没八卦、纯素人、不惊艳,可她赢麻了

公开课

李玫瑾:为什么性格比能力更重要?

军事要闻

知情人士披露:美国或考虑恢复对伊朗军事行动

无障碍浏览 进入关怀版