開発/設計

「能跑起来却已经坏了」你能察觉吗?深度试用五大 AI 编码工具后,我看清了 Vibe Coding 的三个陷阱

上周,Vibe Coding 检定正式启动。「让 AI 来写代码」这件事,已经迈入了可以被认证为资格的时代。

这篇文章能帮你搞清楚什么

  • 正式进入正文前先抓住核心结论
  • 这件事会怎样改变开发者接下来的工作方式
  • 下一篇最值得继续打开的相关文章
「能跑起来却已经坏了」你能察觉吗?深度试用五大 AI 编码工具后,我看清了 Vibe Coding 的三个陷阱
目次

Vibe Coding 变成了「检定」。但我们真的在谈论质量吗?

上周,Vibe Coding 检定正式启动了。「让 AI 来写代码」这件事,已经迈入了可以被认证为资格的时代。

说实话,我当时浑身一震。

不是因为高兴。是因为害怕。毕竟这半年来,我一直抱着「能跑就行」的心态一路狂奔。检定的出现,意味着「正确用法」与「错误用法」之间被划下了一道界线。我自己写的代码到底在哪一边?我突然变得很不安。

一边做 CS(客户成功)的工作,一边开始用 AI 制作业务工具,已经是一年前的事了。最开始只是用 Cursor 做代码补全。等到我开始和 Claude Code 搭配使用之后,开发速度直接起飞。表格联动、Slack Bot、内部仪表板,那些我一直想做却做不出的东西,一个接一个地成形。那种快感真的爽到不行。

不过现在回头看,质量管理被我彻底抛在了脑后。

所以这次,我把五大 AI 编码工具拿来横向对比。Claude Code、Cursor、GitHub Copilot、Windsurf、Devin,这五款工具我都深度试用过,同时翻出自己以前写过的代码重新审视了一遍。结果,三个明确的陷阱浮出了水面。

如果要给这种现象起个名字,我会叫它「能跑起来却已经坏了」综合征。测试能通过、画面也能正常显示、用户也没投诉。但一旦掀开盖子看里面,要么藏着安全漏洞,要么埋着没人解释得清的逻辑。表面上看一切健康,但拍 X 光会发现骨头早就裂了。

TechRadar 在 2026 年版的 Vibe Coding 工具比较中,也把「质量与安全的取舍」当作了主要议题。看来连专业的工具评测媒体,也开始正视「速度背后的风险」了。

这篇文章里,我会基于自己实际踩过的坑,分享这三个陷阱以及对应的解决方法。最后我还会介绍一种叫 VibeContract 的新方法。无论你是打算考检定的人,还是处在「先做出能跑的东西就行」阶段的人,都建议读一读。

以三角形布局展示三个陷阱(安全漏洞、无法解释的代码、没有测试的沙堡),中央标注「能跑起来却已经坏了」综合征的整体地图。每个顶点附带

陷阱 1:安全漏洞「看不见」

第一个陷阱,是 AI 生成的代码里藏着安全问题。而且是那种光做功能验证绝对发现不了的问题。

我说说自己的亲身经历。半年前我做了个 Slack Bot,请 Claude Code 帮我写一个把咨询内容保存到数据库的功能,它返回了一段看起来很漂亮的代码。数据能正确保存,也能搜索。我当时心想:完美啊。

三个月后,一位精通安全的同事看了一眼,丢下一句:「你这个没做 SQL 注入(在用户输入中混入恶意 SQL 语句的攻击)防护啊。」

我瞬间血液倒流。

# AI 生成的代码(危险示例)
# 直接把用户输入嵌入到 SQL 语句中
query = f"INSERT INTO messages (content) VALUES ('{user_input}')"
cursor.execute(query)

# 安全的写法(参数绑定)
# 用占位符的话,输入值会被自动转义
query = "INSERT INTO messages (content) VALUES (%s)"
cursor.execute(query, (user_input,))

会读代码的专业工程师可能会说「这不是常识吗」。我懂,我懂。但在 Vibe Coding 的世界里,有一大堆像我这种「曾经离开过代码」的人。我们已经忘了「参数绑定」这个概念,甚至有些人压根就没听过。

问题的本质并不是「AI 会写危险代码」,而是「Vibe Coder 这边缺乏判断危险与否的知识」。鸿沟就在这里。

实际上不止 SQL 注入。跨站脚本攻击(XSS,把恶意脚本嵌入网页的攻击)也得小心。API Key 硬编码同样是典型风险。我那个 Slack Bot 也是后来才发现 API Key 被直接写在代码里。明明只需要把它挪到环境变量就好,但如果你不知道,它就会一直被晾在那里。

根据 TechRadar 的对比文章,最新的 Agent 型工具开始内置安全警告功能。Claude Code 和 Cursor 在代码生成阶段就具备了风险提示能力。不过目前各家工具的支持程度并不一致。

以表格对比五大工具(Claude Code、Cursor、Copilot、Windsurf、Devin)是否具备安全警告功能。区分已支持、部分支持、未支持

解决方法:把「生成」和「检查」拆到不同的会话里

先把容易踩的坑告诉你。在同一个会话里让 AI「帮我检查一下这段代码的安全性」,效果其实很差。原因是,AI 倾向于把自己写的代码当成「符合意图的产物」。这就像自己给自己的作品打分,自然容易宽容。

我的做法是这样的:代码生成完之后,开一个新的会话,告诉它「请站在攻击者的角度,对这段代码指出 3 个安全风险」。仅仅切断上下文,回到的回答严格程度就完全不一样。

Claude Code 可以用 /clear 重置;Cursor 可以开一个新的 Composer 窗口;GitHub Copilot 可以另开一个聊天面板。这个技巧在任何工具里都适用。

陷阱 2:「能跑但说不清为什么能跑」的代码不断繁殖

第二个陷阱。在我看来,这个最可怕。

AI 生成的代码能跑、测试也能过,但当有人问你「这段逻辑为什么这么写?」的时候,写代码的本人却答不上来。这才是真正的危机。

我自己就在内部仪表板上吃过大亏。当时让 Cursor 帮我写销售数据的汇总逻辑,三个月后业务规则要调整,我直接傻眼了。

代码有 200 多行。注释全是 AI 自动生成的英文。函数名清一色是 process_datacalculate_result 之类的通用名。到底处理了什么、怎么处理的,根本无从追溯。

我以前做 CS 的,所以特别能理解这种感觉。这跟「客户忘了工具怎么用」是同一种结构。「写的时候自己懂」、「时间一久就变成另一个人」。明明是自己写的(准确说是让 AI 写的)代码,三个月后的自己却看不懂了。

# NG 模式:AI 容易生成的过于通用的代码
# 三个月后的自己完全看不懂含义
def process_data(data):
    result = [x for x in data if x['status'] == 'active']
    return sum(item['amount'] for item in result)

# 改进模式:保留「做什么、为什么」
# 月度营收汇总:2026 年 4 月规则调整,对象范围将变更
def calculate_active_monthly_revenue(transactions):
    # 仅汇总 active 的交易(已解约、待处理的排除)
    active_deals = [t for t in transactions
                    if t['status'] == 'active']
    return sum(deal['amount'] for deal in active_deals)

这就是「能跑起来却已经坏了」的典型。现在它能跑没错,但等你想改的那一瞬间,它会以「不知道该怎么改」的形式塌掉。技术债(把代码质量往后拖,导致未来维护成本急速膨胀)就这么悄无声息地堆积起来了。

顺带一提,GitHub Copilot 的新版指标 API 现在已经可以测量 PR 的吞吐量、合并时间,甚至还能追踪 AI 生成的 PR 的采纳率。我们已经进入了一个可以用这些指标去监控「无法解释的代码有没有混进生产环境」的时代。

解决方法:写给「三个月后的自己」看的注释

让 AI 生成完代码之后,用自己的话补上注释。仅这一步,情况就会发生质变。

诀窍在于不要写「代码说明」,而是写「业务上的原因」。「为什么这个处理是必要的」、「什么时候可能需要变更」、「这是给谁用的功能」。不需要写得像工程师那样高大上。我作为 CS 出身,写注释的感觉更像是在写交接文档。

Claude Code 我会让它「用中文加上注释,把业务逻辑的背景也写进去」;Copilot 可以在 Inline Chat 里说「请用一句中文说明这个函数的目的」。即便换了工具,靠 prompt 上的小技巧也能搞定。

陷阱 3:没测试就往上堆的「沙堡」

第三个,是我栽得最惨的一个陷阱。

Vibe Coding 最爽的瞬间,是看着功能一个接一个被做出来的时候,对吧?「帮我做个登录功能」、「再加个仪表板」、「CSV 导出也加上」。每问 AI 一次,画面就丰富一分,成就感爆棚。

但你没写测试。手动确认一句「跑通了,OK」,就直接奔向下一个功能。

这就是沙堡。底座稳不稳都没确认,就一层层往上堆。某一天,我对登录功能的校验稍微改了一下,结果 CSV 导出莫名其妙坏了。追这个原因花了我半天多的时间。

左右并排对比「没有测试堆起来的沙堡」和「带测试堆起来的砖城堡」的插图。沙堡上半部分正在塌陷

整整半天啊。一个功能做出来才半小时,结果 debug 花了 24 倍的时间。「能跑就行」的精神,最后吞掉的是我自己的时间。

工程师圈里有句话,叫「没有测试的代码就是遗留代码」。我曾经因为觉得自己拼不过专业工程师而放下了代码,但现在我能切身体会到这句话的分量。没有测试的代码,就是你不敢去改的代码,是你害怕去碰的代码。

解决方法:把「一个功能一个测试」当成习惯

不必追求完美的测试覆盖率(即整体代码中被测试覆盖的比例)。如果对 Vibe Coder 提这种要求,没人愿意写代码了。

我的规则是:「每加一个功能,就请 AI 至少写一个测试」。

# 添加功能时的 prompt 示例
# 关键是从一开始就指明「测试也一起写」

# NG:只提功能需求
# →「帮我做一个用户注册功能」

# OK:连测试条件也一并指定
# →「请做一个用户注册功能。
#     同时帮我把测试也写出来。
#     测试要验证以下几点:
#     1. 能正常完成注册
#     2. 邮箱重复时会报错
#     3. 必填项为空时会报错」

仅此而已,沙堡就会变成砖城堡。一旦有了测试,下次加新功能时就能自动校验「之前能跑的部分有没有被搞坏」。我那损失的半天,本可以靠 prompt 里多加一行就避免掉。

Claude Code 的话,可以直接在终端里无缝运行测试,非常方便。Cursor 加一句「请运行测试并显示结果」就行;Copilot 打开测试文件后点一下「Run」即可。无论用哪款工具,写测试的门槛都已经低很多了。

VibeContract:用「契约」守护 Vibe Coding 质量的新思路

读到这里,你是不是想说:「三个陷阱我懂了,但每次都要自己一项项检查太麻烦」?我也是这样想的。

这里我想介绍一个叫 VibeContract(Vibe 契约)的概念。它把自然语言写下的「意图」当作代码的「契约」来对待。这是研究者社区提出的方法,正面切入了 Vibe Coding 特有的质量问题。

它的机制分四步走。

  1. 用自然语言写下「这个功能应该做什么」(创建契约)
  2. 让 AI 生成代码
  3. 验证生成的代码是否与「契约」一致
  4. 用测试和运行时检查,持续监控契约是否被违反

你可能会想「这和需求定义有啥区别?」我一开始也是这么想的。但区别非常明确:传统的需求定义是给人看的文档;VibeContract 是给 AI 拿去做验证的结构化契约。关键在于,它能自动确认「写下的内容」与「代码实际做的事」是否一致。

实战:用户注册功能的 VibeContract

具体怎么用?我把自己实际操作的例子分享一下。

首先,用自然语言写下契约。

# vibecontract.yaml
# 用户注册功能的契约书(用自然语言写)
feature: 用户注册
contracts:
  - "邮箱必须唯一。重复时返回错误"
  - "密码不少于 8 个字符。必须包含字母和数字"
  - "注册成功后发送欢迎邮件"
  - "只使用已经做过 SQL 注入防护的查询"
  - "API Key 从环境变量中读取。不允许写死在代码里"

接下来给 AI 下指令。重点来了。

请按照这份 vibecontract.yaml 中的契约,
实现用户注册功能。
同时为每条契约生成对应的测试。
还要包含用来检查契约是否被违反的校验函数。

针对 AI 生成的代码,再去和契约文件做比对。如果没实现邮箱唯一性校验,就会被识别为「契约违反」。我在 Slack Bot 里漏掉的 SQL 注入防护,如果当时写进契约里,就绝对不会被忽略。

这种方法最大的价值是:在不杀掉 Vibe Coding 那种「速度感」的前提下,把「质量」守住。写契约只要 5 分钟,但这 5 分钟可以为三个月后省下半天的 debug。性价比一目了然。

周边基础设施也在跟上

让人高兴的是,支撑 VibeContract 的技术基础也在逐渐成熟。

Microsoft Agent Framework 已经进入 RC1(候选发布版第一版)。框架里内置了会话管理、容错性设计等模式。Claude 与 Copilot 也作为一级提供方完成集成。当 Agent 那一层的基础设施完善之后,契约校验的自动化也就触手可及。

GitHub Copilot 的新版指标 API 同样不容忽视。2026 年 2 月的更新里,PR 吞吐量、合并时间,以及 AI 创建的 PR 的采纳率,都可以被测量。4 月 2 日老版 API 将停用,全面迁移到新的 Usage Metrics API。质量从「靠感觉」变成「靠数字」的时代,正在真正到来。

用 4 步流程图展示 VibeContract 的运行机制:「编写契约 → 代码生成 → 契约比对 → 测试监控」。每一步附带具体示例

总结:跨越「能跑就行」的那条线

回顾一下 Vibe Coding 的三个陷阱。

  • 看不见的安全漏洞:把生成和检查拆到不同会话里。让 AI 从攻击者视角做 review 非常有效
  • 能跑但说不清的代码不断增加:为三个月后的自己,用中文写下业务逻辑的「为什么」
  • 没有测试的沙堡:每加一个功能,至少一个测试。在 prompt 中加上「测试也一起写」,效果立竿见影

再加上第四件武器:VibeContract。用自然语言把「意图」当作契约写下来,仅凭这一点,就能用机制守住 AI 生成代码的质量。

我曾是「能跑就行」的信徒。直到今天,这份心情也没变过。一开始就追求完美的代码是错的,那样反而什么都做不出来,本末倒置。

但这半年我学到的是:「能跑就行」和「可以无视质量」是两码事。如果对「能跑起来却已经坏了」的状态不管不顾,总有一天,你亲手做出来的东西会反过来背叛你。三个月前我就在那个仪表板上亲身体验过。那天为修复花掉的半天,那种焦灼感我现在都记得。

Vibe Coding 之所以能成为一项检定,是因为「用 AI 写代码这件事」获得了社会层面的认可。也正因如此,「质量管理」这一环更应该作为技能的一部分慢慢培养起来。

那种「顶尖工程师附体」的感觉是真实的。曾经我以为自己拼不过的技术,如今透过 AI,就在自己手里。但要把这股力量变成「不会塌的代码」,最终还是要靠自己的判断和习惯。

「能跑就行」之外,还有「值得被信赖的代码」。朝着那个方向,我自己也还在一步步走。打算考检定的人也好,刚开始动手的人也好,希望你都能试试今天分享的这些方法。

我花掉半天的失败,读完这篇文章的你,应该能用 3 分钟规避。如果你能察觉到「能跑起来却已经坏了」,那本身就是成长的证据。一起加油吧。

ゲン
Written byゲンCS × Vibe Coder

正直、一度エンジニアは諦めました。新卒で入った開発会社でバケモノみたいに優秀な人たちに囲まれて、「あ、私はこっち側じゃないな」って悟ったんです。その後はカスタマーサクセスに転向して10年。でもCursorとClaude Codeに出会って、全部変わりました。完璧なコードじゃなくていい。自分の仕事を自分で楽にするコードが書ければ、それでいいんですよ。週末はサウナで整いながら次に作るツールのこと考えてます。