VibeCoding Let Me Sick:记一个简单的 VibeCoding 开发经历

前言

最近的一个新项目,我的游戏评测站,是完全使用 VibeCoding 开发的,这个工作流让我难受极了。

项目介绍

首先简单介绍一下我的这个项目吧,它非常的简单,就是一个游戏画廊,上面会列出我最近的游戏评价。每个评价都是一个卡片式样,由上方的游戏封面和下方的描述组成。

这个项目的灵感源自于两个事件,首先最直接的原因是我的朋友 @北依,他会不定期在他的动态上游戏评测海报,风格如前所述,非常的美观。这件事启发和鼓舞了我做类似的事。其次,其实我自己也一直非常希望输出一些东西,只有不断的输出,才能有意识地思考游戏的设计,维持游戏审美敏感度。

但是要产出一篇系统的评测,是一个很耽误时间的工作,首先我必须要针对游戏的方方面面去思考,例如美术如何,叙事如何,玩法如何等等,有的时候可能还需要讨论创新、优化、运营等等,得出我的主要观点后,我还需要旁征博引,给出解释说明和对比,最好还是需要附上一些截图和这方面做得好或差的游戏对比。总之就是需要得出一个非常成体系的文章,否则就是不写。毕竟没人有会喜欢写完隔个几天就加点新东西,或者在博客上一下子刷出三四篇相同的主题来。这样,写作就变成了一个时间和精力都非常重型,门槛很高的工作。

为了解决这个问题,一方面,我开发了 ChEER,还安装了语音输入工具 CapsWriter,帮助我更方便地写作,缓解文字输入跟不上大脑速度的问题;另一方面就是这个项目。对于一个游戏评测卡片,我只需要给出观点和评分,不需要给出充分的论证过程,只需要总结出 3,4 个最深刻的优点和缺点就可以了,这就大大减轻了工作量。当然,如果我觉得有必要,我也可以附上一篇长评。出于美观考虑,我们还可以在卡片上添加一些游戏背景图片。这就是我们的需求了。

当然你可能会好奇北依是怎么做的,难道不能问他要解决方案吗。答案是不能,因为他的工作流是自己从网上检索图片,然后在 affinity 中手动地调整文字和图片,甚至包括给图片做模糊。这样当然可以,甚至从效率上来说可能还更值得,但是这样不就不够 geek 了么。

然后简单介绍一下项目的技术选择吧,当然这也是和 AI 讨论出来的。首先,Typescript 肯定优于 JavaScipt;其次,由于这是一个接近静态网页的 Web App,我们希望框架框架尽可能的轻量。然而,它并不是一个静态网页,这是因为我们希望获得愉悦的、GUI 的编辑体验,如果为了添加一条评测,我必须要开启 VSCode,撰写条目,打包,然后上传,那门槛就根本没有降下来。所以,首先我们需要一个非常轻量的网页,使用 Astro 作为框架,因为 “它是最适合构建像博客、营销网站、电子商务网站这样的以内容驱动的网站的 Web 框架”,并且在数据库上也选择 Sqlite。然后我们需要一个非常简单的后端 GUI 交互,基于 Electron 以避免引入 Python 或者其他什么语言和库。后台使用 SSH 和服务器通信,避免复杂的鉴权问题。

所以,总结一下这个项目需要完成以下任务:

下面我们来讲其中的问题吧。

问题一: AI 无法准确的处理前端

有一种奇怪的论调是,AI 最先取代的是前端,因为后端有很多复杂的数据关系设计,但是前端只是一个看上去很漂亮的样式就可以了。诚然,如果你只是想要一个还凑合的页面,那可能确实还可以。但是如果你有一些比较精细化的需求,那你会发现 AI 非常难以实现你的目标。甚至可能比后端处理还要麻烦些。因为对于后端而言,一个数据经过处理后如何鉴定正确与否,相对是容易知道的,测试非常的好写。但是前端如果实现不及预期,或者 AI 在实现 Feat B 时破坏了 Feat A 的实现,那你很难通过一个 test 来约束 AI。

这又点像是写作、数学的区别。尽管许多人宣称“AI 首先击败了文科生”,但事实是,直到今天,AI 都不能够写出很美丽的句子。它只能“稳稳的接住你”。如果你的需求只是让 AI 表达出你想表达的意思,那今天的 AI 干得很好。但是如果你希望 AI 能遵从你的风格,使用一些恰当的示例,或者锤炼一些词句,那这个过程就会变得困难重重。你会发现 AI 总是有它自己的想法,它总是会不遵从你的指令,而你没有任何办法去检测这种不遵从,你唯一的办法就是自己读一遍,然后仔细思考如何更改组织结构和格式。

事实上,直到今天,使用世界上最先进的模型质疑,chatGPT5.5,我都不能够得到一个非常良好的 README。正常来说 Readme 应该是给使用仓库的其他人使用的。它应该包含是,我们这个项目是什么,采用了什么技术架构,实现了什么样的功能,还有哪些已知没实现的 feature 和未修复的 bug 等等。但 AI 总是容易将它当成 AGENTS.md,把上下文中的一些细节,甚至是给你的建议加进去。例如下面这个例子

图 1

可以注意到的是,AI 大量使用了“不再默认读取…”、“推荐使用 JSON”这类无意义词句,仿佛读者仍然是你。实际上对于其他阅读和使用者来说,根本无需关心你曾经是如何设计的,也早就应该在描述能力的时候说明了只读取当前活动页面。更重要的是,该项目的逻辑全部是基于 json 的。不是推荐,而是要使用其他格式必须二次开发。

AI 如今在前端领域也是类似的。我其实亲眼见到过不少同学在他们的 presentation 中直接使用 AI 生成的前端或 PPT。但是具体到我们这个项目而言,我还是有一定审美追求的。正如我不可能将上述那个 Readme 直接 publish。而且我们已经有朋友的图片作为参考了,所以我们更不可能端出来一个丑陋的东西出来。

我一开始的做法非常的简单,既然 GPT 有多模态,那么我直接让他读取图片,然后使用代码修改不就好了?我建了一个空仓库,然后让 CODEX5.4 (当时还没有 5.5)去阅读图片,然后制作一个生成器,要求是我可以传进去 JSON 文件,然后它输出卡片给我,结果几乎是完全不可用的。尽管它可以识别得出来图片中的主要元素:分数、标题、优点和缺点、红色和黑色的字体……但是它几乎没有办法正确处理那些细节,例如背景图片的高斯模糊,例如图片比例,如 LOGO 的左边距,文字是否居中等等。当然可以理解 AI 无法猜测对齐方式,但是毫无排版也是事实。

所以我最后采用了另一种方案解决问题,首先,我除了朋友提供的原图,还自己画了一个草稿解释卡片的布局。

图 2

然后要求 AI 只使用 HTML 完成一个最简产品 MVP。我再结合阅读 HTML 源码,实际告诉它缺少了什么元素,或者什么元素存在问题。最后当完成一个可以的卡片的样式以后,再要求它根据这个式样去实现整个项目。如果我不这样做的话,整个工作就会被多个地方卡住:首先,我脑子里的思路能否真的转化成准确而又严谨的文字描述(还好,我们这个项目有朋友的图片直接作为参考)?其二,我的 prompt 是否被 AI 正确理解并实现?其三,AI 的实现出现了问题,如何定位并修改?通过使用 MVP,我们可以避免具体业务逻辑的干扰,减轻前两个问题的压力;通过阅读 HTML 源码,则可以直接辅助 AI 定位问题,是 xx 元素出了问题,而不用靠 AI 猜或者通过“左下角的那个元素”这种含混不清的表达来指代。

其实这一步就不是在原教旨的 VibeCoding 了。但是如果不这样做,项目如何推进呢。 下面对比一下原型和(目前的)实际实现:

图 3

业务原型,可以看到上半的标题位置采用了左对齐的方式,仍然不够美观。

图 4

现在的设计,将游戏名和总结的位置对调了。这一版的问题是,时间戳仍然会和缺点抢位置。

问题二: AI 无法做好 UX

这部分主要出现在后台 GUI。

图 5
图 6

就我们的图片来说,这个后台界面虽然也实现了功能,但是它的 UI 设计并不美观易用:

  • 中间的表单太长了,导致必须要翻页。而实际上,其中有很多项目,例如 分数发行商 等等,它们完全不值得单独占一行;
  • 预览放在左侧,不够大
  • API KEY 是用于封面搜索的,但是没有放到和封面相关的部分。反而是将预览和同步塞了过来。并且作为一个很小的,只用配置一次的项,占用了过大版面。
  • 标题没有居中,并将选择项目目录和当前项目目录放在同一个地方。
  • 尽管图片上看不出来,但是 AI 甚至遗漏了删除功能。

也许有人会说这个不叫 AI 做不好 UX。预览大一点还是小一点。这些东西根本没所谓。或者说,在没有给出一个明确的标准之前,AI 本来就只能给出平庸的设计。这种说法我是不能苟同的。我们今天回望 Gen AI 的初期,我们会发现人们在学习各种提示词工程,例如要给 AI 附上示例啦,要 AI 扮演专家啦等等。今天的 AI 或者说 Agent 几乎不需要这样做,通过提高模型智能称呼和 Context Engineering 或者 Harness Engineering 一类的东西,AI 就可以默认给你出一个还不错的水平。而对于这个项目来说,如果我必须要自己一步步设计好 UX,或者在创建后台之后一步步修改 UX,其实是很消耗精力的,你必须退回到 prompt engineering 的时代,逐条列出 AI 的错误,以及如何修改。首先,对与人来说,这就是在设计 UI 的同时还需要顾虑到现有代码做文章,同时,还必须检查 UX 的可用性,不然就总是会在处理其他问题的时候,被打断(例如这里的遗漏删除功能的问题)。其次,对于 AI 来说,它们总是倾向于将已有代码视为既成事实,从而在修改的过程中屎上加屎。写成类似这样的代码:

1
2
3
4
5
6
7
8
9
# before(bad design)
a= b
c= d
# after
if enable_ something:
a= b
c= d
else:
do_ something_ else()

问题三: AI 难以处理复杂的部署工况

另外一个比较难以处理的问题,就是 AI 难以处理复杂的部署工况。

首先需要说明的是,我的 Docker 水平并不高。尽管我大概的知道怎么是 Docker,怎么是容器,并且确定我的项目应该基于容器。但是你让我去写一个 Dockerfile 或者更改 compose 文件,我是没有这个能力的。

然后我们考虑这个部署流程中和其中会碰到的问题:

  1. 首先,开发整个项目
  2. 其次,撰写 DockerFile 等部署文件并编译
  3. 最后,上传到服务器,并启动服务

这里面的每一步 AI 都可以犯错,项目可能实现不正确,DockerFile 可能逻辑不正确,然后 Proxy 或者其他配套使用的 App……每一个都在增加犯错的可能性。要知道,要是部署这些东西本身没有那么多繁杂又细节的操作,也就不会出现“在我电脑上能跑呀”这种哏、或者 CI/CD、Infrastructure Technician 这类术语了。

AI 在处理这个问题上的时候有两种模式。第一种模式是 AI 修 Bug,我执行。这种相对来说会更安全一些(并不太多,因为秉持 VibeCoding 的精神,我几乎不做任何检查)。我会要求 AI 它编写出一个完整的结果,并静态检查一遍(“检查代码,确保不包含任何逻辑错误”),然后我们执行代码的过程之中遇到的任何报错,都直接扔给 AI 去修。理论上来说,这是完全的 VibeCoding 实践,但是实践中感受并不好,因为每一次你都会预期它改好了,但是新的问题总是会源源不断的冒出来。从而出现后面会提到的 AI 工作的简短时间片无所事事的问题。更糟糕的是,在部署这一步中,你还需要应对部署安装流程运行时的简短时间片。你不能走开(否则很容易退出专注的心流状态)但是你也不能做点什么,你已经把所有的工作让渡给 AI 了。有的时候,有些工作你还必须手动处理,因为你没有告诉 AI 相关的上下文。例如你开着代理呢。那你就得自己独立去猜和解决问题,或者再开个网页问问 chat?无论如何,你是在处理既充满重复性又充满不确定性的工作。

当然是有办法解决上述模式的问题的,那就是第二种模式,完全让渡给 AI,要求 AI 全权处理,我们给它通过验证。这种时候就又有几个问题,第一是隐私问题。我们很可能得让渡一些原本不打算让 AI 知道的信息。例如我们真实文字产出、服务器 IP 地址、个人姓名等;其次还有安全问题,我们得允许 AI 执行一些本来在沙箱内不应该能执行的工作,这其中的极端情况甚至包括直接让 AI 与服务器交互!最后,正如上一节所述,在部署的时候,为了稳定可靠地解决某个原因众多的报错,它很有可能会产生一些防御性的代码,从而直接破坏我们在项目的开发过程中一直追求的那种可持续性,更进一步地阻碍人类去阅读,甚至可以说阻碍 AI 去阅读,因为用众多的防御性编程掩盖了真实的生产环境中具体哪一个真正生效,那么后续的 AI 也没有办法检查问题出现在哪。这个问题不是靠提高 AI 的 context 能力能解决的,因为总有一些东西是 AI 无法掌控的,我们也无法掌握的,也就谈不上告诉 AI,这种时候他就需要去猜,然后一步一步的试,然后改正。如果某步试了没有效果,就很容易被被保留形成屎山甚至引入新问题。如果删除呢,又有可能改乱(这时就体现出版本管理的重要性了)。

问题四: AI 工作时无所事事的我

这个问题前面已经说过了就稍微再点一下就可以了。现在的时代,Chat 的输入输出已经比较快速了。但是 agent 需要阅读上下文,撰写代码,编译,修报错,这个处理的时间是人能明显感知的。一个稍微有些复杂度和操作的问题,处理个一两分钟再正常不过。如果一个问题极为复杂,那么处理几十分钟也是有可能的。这段时间就会变得特别的空虚。因为你一直在等待一个不知什么时候会结束的事,如果这段时间去刷手机或者刷知乎,你的注意力就被转移到了其他的地方。接下来你要面对的就是为了吸引力人的注意力而极致优化信息流,你要从中脱身,然后再重新进入代码状态。

图 7

有人此时可能会说,既然如此,那我们在这段时间去阅读代码,了解具体项目情况不就好了吗。首先,无论你在读什么,你都是在看和刚才的问题没啥相关性的东西;其次,阅读是随时会被中断的,这给人的感觉是非常不好,因为你在在做无用功,你既没有收获快乐,也没有收获认知;此外,你也只能阅读,不能修改或调试,以免发生文件权限冲突或者修改冲突之类的,这就更进一步限制了阅读代码的便利性。还有,由于 VibeCoding 本身确实是快速迭代的,你现在一个小时改的代码可能比以前一天都多,那阅读特定的代码的实用性也就下降了,因为很有可能之后就会因为添加或修改需求,让 AI 把整个逻辑重写。

问题五:我对这个项目一无所知

最后,这个项目开发完了,然后呢?我对它的了解并不比其他任何外人更多。是,是我指定的 Docker,是我指定的 pnpm,是我同意的 Astro 框架……但是也就仅此而已了。我没有对其中的任何细节有深入了解。所以我后期想要调试,二次开发,我仍然得要依赖 VibeCoding,或者花大功夫去把代码读通,然后去做修改。这个过程我必要要忍受 AI 的 trash,包括过度封装、过度防御性编程、遗留代码,以及真正的 bug。总的来说,我该付出的工作一点没少,但是我做出了点什么东西的成就感反倒是被大大稀释了。

总结

所以总的来说,VibeCoding 当然不是没有任何好处的,但是它的代价在这个过程中被隐藏了。作为一个程序员,我希望绝对掌控我的程序;作为一个开发者,我希望能持续专注在开发过程中;作为一个“老板”和 PM,我希望能提高工作效率和代码质量;我希望能作为一个人类,我希望保护我的隐私。这些东西都是绝对纯粹的 VibeCoding 无法带给我的,它们是 VibeCoding 哲学的 tradeoff。现阶段来说,和 AI 配合的最好方式,可能仍然是一半一半的开发吧。