Skip to content

Latest commit

 

History

History
424 lines (262 loc) · 12.9 KB

File metadata and controls

424 lines (262 loc) · 12.9 KB

Vibecoding 复盘:把一个 Rust 迁移项目主要交给 AI 去做,真正要准备什么、会踩什么坑

这份文档要解决什么问题

这不是一份“AI 很强”“Rust 很严格”的感想录,也不是开发流水账。

这份文档只回答 3 个问题:

  1. 如果想主要靠 vibecoding 把一个 Rust 项目做出来,开始前到底要准备什么。
  2. 在这个仓库里,哪些工程约束是真正救命的,少了会立刻失控。
  3. 这次实际踩过哪些坑,后面如果再做一次,哪些地方必须提前规避。

先说结论:

Rust 项目可以大量用 vibecoding 做,但前提不是“AI 一直写”,而是“你先把项目变成一个有边界、有门禁、有回滚点的系统”。

如果没有这套系统,AI 写得越快,项目只会越快跑偏。

一、先别写代码,先把地基搭出来

如果要全程 vibecoding,这个仓库里真正有价值的,不是 AI 一次写了多少行,而是下面这些基础设施先落好了。

1. 工具链必须固定,不要让 AI 在漂浮环境里工作

这个仓库里先固定的是:

  • Rust toolchain:1.94.1
  • 组件:rustfmtclippyrust-analyzerrust-srcrust-docs
  • 扩展工具:justcargo-nextestcargo-llvm-covcargo-deny
  • 性能辅助:cargo-sweepsccachecargo-watchmold

对应文档和入口已经在:

为什么这一步这么关键?

因为 AI 最怕的不是不会写,而是在不同机器、不同版本、不同命令结果下继续沿着错的方向写

如果工具链不固定,AI 看到一次能过、下一次不过,就会开始“补丁式”修复,最后把项目修成一团偶然成立的东西。

2. 验证命令必须先收口,不然 AI 没有“完成”的客观定义

这个仓库最重要的不是“有测试”,而是验证入口已经提前统一

  • just env-check
  • just verify-basic
  • just verify
  • git diff --check

这是 vibecoding 里最容易被低估的一步。

如果没有这套命令,AI 每次说“应该好了”时,你根本没有一个统一的裁决标准。

在这个项目里,真正有用的经验不是“多写测试”,而是:

  • 先定义哪条命令代表“基础可交付”
  • 再定义哪条命令代表“完整门禁”
  • 然后所有完成声明都以这两条命令为准

没有这个前提,AI 会持续输出“语义上像完成、工程上其实没完成”的结果。

3. Git hooks 不是装饰,是防失控装置

这个仓库里最容易被忽略、但其实非常有用的是 Git hooks:

  • pre-commit:拦 cargo fmt --all --check
  • commit-msg:拦提交标题格式
  • pre-push:拦 just verify-basic

路径在:

vibecoding 最大的风险之一,是你以为“先 commit 再说”。

但如果 hook 已经在仓库里,AI 和人都会被迫接受同一套节奏:

  • 先格式化
  • 先保证提交标题规范
  • 先过基础门禁
  • 然后再允许进入 Git 历史

这会显著减少“先提交一个半成品再慢慢补”的坏习惯。

4. 文档基线不是额外负担,是 AI 的控制面

如果是手工开发,很多边界可以放脑子里。 但如果是 vibecoding,脑子里的边界不算边界,写进仓库里的边界才算边界

这个仓库里真正发挥控制作用的文档,不是 README,而是这些:

这些文件的作用不是“写给别人看”,而是防止 AI 把项目目标自行脑补成另一个东西。

二、如果再来一次,我会怎么做:一套更靠谱的方法论

方法 1:先定义阶段,不要先定义功能列表

最容易失败的方式是上来列一堆功能:

  • 抓取
  • 通知
  • AI
  • MCP
  • 多领域
  • 多输出
  • 多存储

这会让 AI 默认把项目理解成“功能填空题”。

更好的方式是先定义阶段:

  • 当前阶段只做主链路闭环
  • 当前阶段只做真实运行、真实日志、真实验证
  • 当前阶段不追 Python 100% 对齐
  • 当前阶段做完后进入维护模式

阶段比功能列表更重要,因为它定义了什么可以不做

方法 2:每次只允许一个“主目标”+ 一个“副目标”

如果让 AI 同时做太多事,它会天然开始顺手扩 scope。

这次项目里,多次出现过这种倾向:

  • 本来只是改日志
  • 顺手改输出模型
  • 顺手改过滤逻辑
  • 再顺手改文档和示例配置

最后一次提交虽然看起来“很完整”,但中间如果不持续校准,很容易从单一任务膨胀成半个里程碑。

更稳的规则是:

  • 主目标:这轮真正要交付的东西
  • 副目标:允许顺带完成的一类小修
  • 超出这两类,一律下轮再说

方法 3:所有功能改动都走同一条链

如果要 vibecoding,推荐固定为一条机械流程:

  1. 先找边界文档
  2. 先看现有测试/fixture
  3. 先补失败测试
  4. 再写实现
  5. 再补示例配置或运行入口
  6. 再改文档
  7. 最后跑统一验证

这条链不是仪式感,而是为了防止 AI 先把代码写散,再补文档和测试时已经收不回来了。

方法 4:把“真实运行”独立出来,不要拿 fixture 成功替代真实可用

这次项目里一个很典型的问题就是:

  • 本地 fixture 跑通了
  • 但用户问的是“真实抓取今天新闻”
  • 如果继续只拿 fixture 讲结果,其实已经偏题了

所以一个很重要的方法论是:

  • fixture 用来保回归
  • 真实运行用来保产品语义

两者不能互相替代。

如果你做的是抓取/聚合/通知类项目,这条尤其重要。

三、这次真的踩过的坑,不是理论上的坑

下面这些坑,不是泛泛经验,而是这次仓库里实际撞到过的。

坑 1:文档口径漂移,而且漂移得非常快

这次实际出现过的情况包括:

  • README 写 8 个 crate,但实际已经 11 个
  • README、roadmap、runtime-stability 里的测试数不一致
  • 某些文档还在写“进入收尾阶段”,另一些文档已经写“收口完成”
  • 配置迁移指南和真实当前能力不一致

这说明一件事:

AI 不会自动维护文档一致性。

只要你不主动做“状态校准”回合,文档会越来越像一层旧皮。

处理方法:

  • 定期做专门的口径校准轮次
  • 把 README、roadmap、migration-guide、closeout/status 文档一起比对
  • 不要等功能做完才想起来统一口径

坑 2:stdout 和日志混在一起,会直接毁掉机器可读输出

这次真实出现过:

  • CLI 用 --output json
  • 但 tracing 也往 stdout 打
  • 最后 stdout 里是“日志 + JSON 混在一起”
  • 机器端根本没法直接解析

这类问题很典型:

  • 功能上“看起来没问题”
  • 手工看也能看懂
  • 但产品上其实已经坏了

最后的修法是:

  • tracing 全部改到 stderr
  • stdout 只保留真正的结构化输出
  • 另外提供 --run-log 写完整结构化日志

这里的经验是:

vibecoding 特别容易做出“人类看起来像能用、程序接起来其实不能用”的半成品。

坑 3:commit hook 会在最后一刻教育你

这次真实发生过:

  • 代码和文档都准备好了
  • git commitcommit-msg hook 拦下
  • 原因是提交标题不符合 <type>(<scope>): <summary>

这类坑很小,但很典型。

如果你不提前知道仓库的 hook 规则,AI 会在最后一刻被这种“流程问题”卡住,然后浪费一轮重新提交。

所以经验很明确:

  • 开始前先看 .githooks/
  • 别把 hook 当最后才处理的事情
  • 提交格式本身也是开发环境的一部分

坑 4:Clippy 对测试文件一样不客气

这次新加测试时,just verify 没过,不是功能错,而是:

  • 测试里用了 expect
  • 测试文件没有处理 missing_docs
  • clippy -D warnings 和 workspace lint 一起拦住了

这类坑说明:

在 Rust 项目里,测试文件不是“随便写”的临时脚本,它同样受工程质量约束。

如果准备全程 vibecoding,最好一开始就约定:

  • 测试要么显式允许某些 lint
  • 要么就按生产级规范写

否则每次新增测试都会在最后一轮门禁里返工。

坑 5:真实抓取一做,多来源重复马上出现

一开始只做 fixture 时,看不出来什么问题。 一旦上真实 RSS 源和多领域源:

  • 同一新闻会在多个来源桶里重复出现
  • 不同来源名称不同,但标题完全一样
  • 如果不做去重,输出会显得很蠢

这次真实跑多领域配置时,抓到 25 条,去重后变成 21/22 条,实际移除了 3 到 4 条重复新闻。

这里的经验是:

真实数据的复杂度,永远高于 fixture。

所以:

  • fixture 证明“链路能跑”
  • 真实抓取才会逼你补“产品必须有的逻辑”

坑 6:领域分类不是“加个字段”那么简单

最开始做领域分类时,很容易以为:

  • 标题里有 OpenAI / Anthropic / AI,就算 AI

但真实数据一上来就冲突了:

  • “OpenAI 的生命科学模型”到底算 AI 还是 Science?
  • “财政部长讨论 Mythos AI 风险”到底算 AI 还是 Finance?
  • “政府接入 Anthropic 模型”到底算 AI 还是 World?

这次实际修了至少一轮优先级,最后才把:

  • Finance n- Health
  • Sports
  • World
  • Ai
  • Science
  • Technology
  • Business

这样一套优先级排顺。

这说明:

分类逻辑不是技术问题,是业务定义问题。

编译器不会告诉你该怎么分,只能靠真实样本和业务判断反复校准。

坑 7:AI 默认会不断扩大任务边界

这次最明显的体验是:

  • 你问一个需求
  • AI 很自然会把它延展到“顺手再补一些周边”

例如:

  • 先补运行日志
  • 再补来源保底
  • 再补领域保底
  • 再补去重
  • 再补文档
  • 再补示例配置

这些事单看都合理,但如果没人持续收边界,项目会被“合理的顺手优化”拖着一直往前滚。

这不是 AI 的恶意,而是默认倾向。

所以真正重要的不是让 AI 更积极,而是你要不断问:

  • 这个改动是不是当前主目标的一部分?
  • 如果不是,为什么不是下一轮再做?

四、如果以后还想全程 vibecoding,我会要求先准备的东西

必须准备 1:一份仓库级规则文件

至少写清:

  • 当前阶段目标
  • 不做什么
  • 允许跑什么命令
  • 文档同步要求
  • 完成标准

在这个仓库里,这个角色就是 AGENTS.md

必须准备 2:一份环境总入口

你必须让任何新会话都能快速知道:

  • 工具链版本
  • 扩展工具
  • Git hooks
  • 验证命令

在这个仓库里,对应的是:

必须准备 3:一套 fixture 和最小真实运行入口

没有 fixture,AI 会靠想象写逻辑。 没有真实运行入口,AI 会把 fixture 成功误当成产品成功。

这两者必须同时存在。

必须准备 4:停止规则

这是最关键的一条。

如果没有停止规则,vibecoding 的默认终点就是:

  • “再补一点点”
  • “这个也顺手做了吧”
  • “既然已经做到这里,不如再加一个”

最后项目永远处在“差一点更完整”的状态。

这个仓库最后能收住,不是因为功能做完了,而是因为补了 project-completion.md,明确把项目切到维护模式。

五、这次实验最值得记住的不是“AI 帮我写了多少”,而是这几点

1. AI 适合冲实现,不适合天然收边界

边界、阶段和停止条件,必须由人先定。

2. Rust 编译器能防低级错,但防不了方向错

产品是不是越来越像你要的东西,要靠文档、真实运行和人工判断,不靠编译器。

3. 真实运行永远要单独做

只做 fixture 成功,最后一定会误判项目成熟度。

4. 文档同步不是收尾动作,而是控制动作

对 vibecoding 项目来说,文档不是总结,而是防项目失控的控制面。

5. 练手项目最重要的能力不是“继续做”,而是“及时完结”

如果这次项目真的只是为了验证:

能不能主要依靠 vibecoding 做出一个 Rust 项目

那答案已经够明确了:

能。

但更重要的附加结论是:

如果没有环境约束、验证门禁、文档基线和停止规则,vibecoding 最后练到的不是工程能力,而是如何把项目做散。