老项目做 vibe coding 改造,别先开写:先把边界、契约和验收跑通

老项目做 vibe coding 改造,别先开写:先把边界、契约和验收跑通

摘要

老项目改造最容易被 vibe coding 带偏:看到一个现象就让 AI 写一个补丁,短期很快,长期却容易把历史行为、隐藏约束和回归风险搅在一起。本文不讨论某个具体兼容项目,而是整理一套更通用的方法:先做边界发现,再把旧行为写成契约,用可逆变更控制风险,最后用证据链和确定性规则验收。

这篇适合谁看

这篇主要写给正在用 AI 辅助改造老项目的开发者、技术负责人和工具链建设者。

你面对的项目可能是一个多年运行的后台页面,也可能是一套无人敢大改的业务流程、一个缺少测试的前端工程,或者一段依赖历史环境的脚本。它们的共同点不是技术栈旧,而是:很多行为已经变成了业务约定,却没有被写进文档和测试。

所以这篇不会展开某个具体适配细节,而是回答一个更通用的问题:

当 AI 能很快给出代码时,我们怎样避免把老项目改得更不可控?

我的结论是:老项目 vibe coding 不能以“写代码”为起点,而要以四个交付物为起点。

边界地图 -> 行为契约 -> 可逆变更记录 -> 证据验收清单

代码只是这四件事之后的结果。

一开始最容易误判:老项目不是代码仓库,而是历史行为集合

新项目里,需求通常可以从产品说明、接口文档、设计稿和测试用例里推出来。

老项目不一样。很多真正重要的规则藏在这些地方:

  • 某个字段为什么能为空;
  • 某个按钮为什么要先弹确认;
  • 某个列表为什么默认只查最近一段时间;
  • 某个失败提示为什么不能换文案;
  • 某个导入流程为什么允许部分成功;
  • 某个页面为什么必须保留一个看似多余的隐藏字段;
  • 某个旧接口为什么返回字符串,而不是标准 JSON;
  • 某个用户习惯为什么已经依赖了一个“历史缺陷”。

AI 不知道这些背景。它看到的是当前代码、当前错误、当前提示词,所以它很容易给出“局部合理”的改法。

例如你告诉 AI:

这个保存按钮点了没有反应,请帮我修复。

AI 可能会补事件绑定、改提交逻辑、重构表单校验、增加 loading 状态。每一段代码单独看都可能合理,但它没有回答三个更关键的问题:

  • 保存按钮原来在什么条件下允许点击?
  • 失败时应该保持旧提示,还是可以换成新提示?
  • 这个页面有没有被其他入口复用?

老项目改造的风险不在于 AI 写错一行代码,而在于我们没有先定义“什么叫没改坏”。

通用方法:先产出四个交付物

我现在做老项目改造,会先要求自己把问题压成四个小文档。它们不需要复杂,但必须能被复核。

交付物解决什么问题最小内容
边界地图防止不知道影响范围就开改入口、页面族、接口、数据对象、用户角色、外部依赖
行为契约防止把历史行为当成可随意优化的代码触发条件、输入、输出、副作用、异常分支、不得改变项
可逆变更记录防止补丁越改越散、难以回退变更点、原因、开关、回滚方式、关联证据
证据验收清单防止 AI 或人工凭感觉判断成功观测点、命令、截图、日志、断言、人工确认项

这四个交付物的作用,是把“边写边试”变成“有边界地探索”。

vibe coding 仍然可以很快,但快的是生成候选方案,而不是跳过判断。

第一步:边界发现,不要让 AI 在未知范围里补丁扩散

老项目里,一个现象经常横跨多个边界。

比如一个“提交失败”可能涉及:

  • 页面按钮状态;
  • 前端校验规则;
  • 表单字段序列化;
  • 老接口参数名;
  • 后端兼容分支;
  • 权限或角色判断;
  • 缓存和历史数据;
  • 用户原有操作习惯。

如果只盯着报错点,很容易把补丁写在最方便的位置,却不是最应该的位置。

我会先做一张边界地图:

边界要问的问题记录示例
入口边界用户从哪里进入?是否有多个入口?list -> editdashboard -> quickEdit
页面边界同一组件是否被多个页面复用?edit.htmlcopy.html共用表单
数据边界哪些字段是展示字段,哪些字段会提交?displayName展示,entityId提交
接口边界接口是否容忍旧参数、空值、字符串编码?status可空,type只能是旧枚举
权限边界不同角色看到的按钮和流程是否不同?普通用户只读,维护用户可编辑
环境边界行为是否依赖浏览器、插件、缓存或配置?本地正常,测试环境缓存旧资源
习惯边界用户是否依赖某个历史表现?失败后保留已输入内容

边界地图不追求完整设计,它只回答一个问题:

这次修改最远可能影响到哪里?

如果这个问题答不出来,先不要让 AI 扩写代码。

第二步:把旧行为写成行为契约

老项目改造里,“优化”是一个危险词。

很多看起来可以优化的地方,可能早就被用户、数据、接口或脚本依赖了。我们要先把旧行为写成契约,明确哪些可以改,哪些不能改。

一个行为契约可以很轻量:

contract:legacy-form-savescope:page_family:/example/order/*entry:edit-formtrigger:action:click save buttonpreconditions:-required fields have values-user has edit permissioninput:visible_fields:-displayName-amounthidden_fields:-entityId-versionexpected_behavior:success:-submit legacy parameter names unchanged-show success message-keep redirect target unchangedfailure:-keep user input on page-show original validation category-do not retry automaticallymust_not_change:-submitted field names-empty-value compatibility-permission branch-failure message categoryevidence:-request payload snapshot-response status-page state after success-page state after failure

这个契约不需要一次写完。它可以随着排查逐步补齐。

但只要写出来,AI 的任务就变了:它不再是“请帮我修一下”,而是“请在不破坏这些契约的前提下,给出最小变更”。

提示词会变得更具体:

请根据下面的行为契约分析修复方案。 要求: 1. 不改变 must_not_change 中的任何行为; 2. 优先给出最小改动; 3. 标出每个改动需要哪条证据验证; 4. 如果证据不足,先列出需要补充的观测点,不要直接写代码。

这比直接贴一段报错让 AI 猜,要稳定得多。

第三步:变更必须可逆,不能只看当前页面修好了没有

老项目里最怕“补丁堆叠”。

今天为一个页面加一个兜底,明天为另一个入口加一个特判,后天再补一段兼容逻辑。单看每次都不大,合在一起就会变成没人敢删的逻辑。

所以我建议每个改动都写进可逆变更记录:

变更为什么改限制范围如何关闭验收证据
保留旧参数名接口仍按旧字段读取/example/order/*配置开关legacyParamMode=false请求 payload 对比
增加空值兼容历史数据存在空枚举仅编辑页保存删除兼容分支或关闭开关空值样本保存成功
延迟初始化组件旧脚本加载顺序不稳定仅指定页面族恢复同步初始化初始化日志和页面截图

可逆不一定等于每个改动都要做功能开关。它至少要回答:

  • 这个改动在哪里生效;
  • 为什么不能全局生效;
  • 如果误伤,怎么快速退回;
  • 哪条证据证明它确实需要存在。

如果一个改动说不清这些内容,它就不适合在老项目里扩散。

第四步:AI 负责推理和生成,PASS/FAIL 由证据规则决定

vibe coding 最大的价值,是把探索速度拉起来。

你可以让 AI 帮你:

  • 从日志里找异常分支;
  • 对比新旧请求参数;
  • 推断可能断点;
  • 生成最小补丁;
  • 补一组回归用例;
  • 把现场现象整理成检查清单。

但 AI 不应该替你决定“通过”。

老项目验收至少要分成三层:

层级AI 可以做什么不能交给 AI 的判断
证据收集整理日志、截图、请求、响应、页面状态不能仅凭描述判断现场已通过
规则匹配对照契约指出缺失证据和风险不能把推测当成验收结论
PASS/FAIL生成检查表、解释失败原因最终结果必须由断言、命令、截图或人工确认项落地

一个更稳的验收格式是:

检查项:保存失败后保留用户输入 证据来源:浏览器截图 + 表单字段快照 通过规则:失败提示出现后,displayName、amount、entityId 保持原值 AI 角色:对比快照并指出差异 最终结论:由测试记录人勾选 PASS/FAIL

这里 AI 可以辅助观察,但不能绕过规则。

什么时候应该停止写代码,先补观测能力

老项目改造中,有几种情况不适合继续让 AI 写补丁。

信号继续写代码的风险应该先补什么
失败现象不稳定每次修复都可能修到假问题版本标记、环境标记、复现步骤
无法确认旧行为可能把历史契约改没旧版本截图、请求样本、用户确认项
不知道改动是否生效会把部署问题误判成代码问题构建版本、加载日志、资源校验
同类问题反复出现会形成散落特判问题分类表、共享适配层、回归矩阵
修好 A 后破坏 B说明边界没有圈住影响范围表、相邻场景测试

这些时候,最有效的下一步往往不是继续补代码,而是增加观测点:

  • 页面显示当前构建版本;
  • 关键流程输出结构化日志;
  • 请求和响应可以脱敏导出;
  • 重要字段有前后快照;
  • 回归清单能标记已验证、待复验、禁止重复修;
  • 每个补丁能对应到一个契约和一条证据。

观测能力看起来不像功能,但它能减少大量假成功和假失败。

一个通用的老项目改造流程

下面这套流程适合多数老项目 vibe coding 改造。

1. 记录现象 - 用户动作 - 当前结果 - 期望结果 - 是否稳定复现 2. 画边界 - 入口 - 页面或模块 - 数据对象 - 接口 - 权限 - 环境 3. 写契约 - 触发条件 - 输入输出 - 副作用 - 异常分支 - 不得改变项 4. 让 AI 分析 - 先找断点 - 再给最小改动 - 标出风险 - 不足证据先补证据 5. 小步修改 - 限定范围 - 保留回滚方式 - 记录变更原因 6. 证据验收 - 正向路径 - 失败路径 - 相邻路径 - 旧行为保持 7. 沉淀规则 - 更新契约 - 更新清单 - 更新回归矩阵

这套流程的重点不是多写文档,而是让每次 AI 生成的代码都有约束、有边界、有验收。

一个可直接复用的提示词

下面这段可以在老项目改造时直接使用。

你现在是老项目改造审查员。 请不要先写代码,先基于我提供的现象、代码片段、日志和截图,完成以下分析: 1. 这次问题涉及哪些边界? - 入口边界 - 页面或模块边界 - 数据边界 - 接口边界 - 权限边界 - 环境边界 - 用户习惯边界 2. 旧行为契约是什么? - 触发条件 - 输入 - 输出 - 副作用 - 异常分支 - 不得改变项 3. 当前证据能支持哪个判断? - 已确认事实 - 合理推断 - 仍缺失的证据 4. 如果要修改,请给出最小变更方案: - 改动点 - 限制范围 - 回滚方式 - 可能误伤的相邻场景 5. 最后输出验收清单: - 正向路径 - 失败路径 - 相邻路径 - 旧行为保持 - PASS/FAIL 由什么证据决定 如果证据不足,请先列出需要补充的观测点,不要直接生成补丁。

这段提示词的核心,是把 AI 从“代码生成器”拉回到“证据和约束的协作者”。

最后的检查清单

每次老项目改造前,我会用下面这份清单做自查:

  • 是否知道这次修改的最远影响范围;
  • 是否记录了入口、页面、数据、接口、权限、环境边界;
  • 是否把旧行为写成了可复核契约;
  • 是否明确了哪些行为不能改;
  • 是否让 AI 先分析证据,而不是直接写补丁;
  • 是否把 AI 的推断和已确认事实分开;
  • 是否让每个改动都有范围、原因和回滚方式;
  • 是否至少验证了正向路径、失败路径和相邻路径;
  • 是否确认加载的是新版本,而不是旧资源或缓存;
  • 是否有一条确定性规则决定 PASS/FAIL;
  • 是否把新的经验沉淀回契约、清单或回归矩阵。

老项目做 vibe coding,不是不能快。

真正的问题是:如果没有边界、契约和证据,AI 会把“写得快”变成“返工也快”。

把这三件事补上以后,AI 才更像一个可靠的改造助手,而不是一个不断制造局部补丁的自动补全工具。