让 AI 帮你写代码,最怕的不是它”不会写”,而是它每次写出来的风格都不一样、经常偏离你的本意、改着改着就把项目搞乱。问题的根源,往往不是 AI 能力不够,而是你没把规矩和图纸先给它。
这篇文章给出一个可以落地的 AI 开发规范,核心只有三步:
- 先写 AGENTS.md——给 AI 立一份”项目宪法”;
- 再建 docs 目录——按产品、架构、后端、前端、测试、运维等角色,把设计文档先写下来;
- 最后把数据库定清楚——表要少、关联要少、结构要清晰,因为它直接决定上层服务的逻辑。
说明:下文说的”AI 编码代理(AI Coding Agent)”,指的是能自己读代码、改代码、跑命令的 AI 编程助手,比如 Codex、Claude Code 这类工具。它们都认 AGENTS.md 这种项目级约定文件。
〇、一句话和一张全景图
用 AI 开发的正确姿势,不是”给一句话就让它闷头写代码”,而是”先立规矩、先出图纸、先定数据,最后才动手实现”。
整个流程可以画成下面这张全景图:
flowchart TB
subgraph P0["第 0 步:立规矩"]
A0["AGENTS.md<br/>项目约定"]
end
subgraph P1["第 1 步:文档先行"]
D0["docs/ 目录<br/>按角色分文档"]
D1["产品 PRD"]
D2["架构设计"]
D3["接口设计"]
D4["数据库设计"]
D5["测试设计"]
D6["运维与安全"]
D0 --> D1
D0 --> D2
D0 --> D3
D0 --> D4
D0 --> D5
D0 --> D6
end
subgraph P2["第 2 步:建库与写码"]
DB["数据库<br/>表清晰、关联少"]
CODE["代码<br/>按文档实现"]
end
subgraph P3["第 3 步:测试与上线"]
TEST["测试"]
OPS["部署上线"]
end
A0 --> D0
D0 --> DB
D0 --> CODE
DB --> CODE
CODE --> TEST
TEST --> OPS
OPS -.->|"复盘,反哺约定"| A0
这张图的要点是:规矩在最上面,文档在中间,代码在最下面。AI 每写一行代码,都能在文档里找到依据;项目做完一轮,再把经验反哺回 AGENTS.md,形成闭环。另外,版本控制和发布流程是贯穿全程的两条”基建”——一条保证随时能回退,一条保证上线不翻车,后面会各用一节专门讲。
一、第一步:先写 AGENTS.md,给 AI 立一份”项目宪法”
它是什么
AGENTS.md 是放在项目根目录下的一个约定文件,写的是”这个项目该怎么写代码、文件放哪、用什么技术、做完要做什么”。AI 编码代理每次开工前会先读它,照着里面写的规则办事。
打个比方:你要请一队施工队装修,开工前一定会先发一份《施工守则》——”水管走顶、电线走地、墙面先找平再刷漆”。没有这份守则,每个师傅都会按自己的习惯来,装出来就乱了。AGENTS.md 就是给 AI 施工队的那份守则。
它的目的:四个字——一致、不跑偏
- 保持风格一致:把代码规范写死,AI 就不会这次用这种写法、下次换另一种;
- 少返工:把技术栈、目录结构、命名规则提前讲清,AI 就不会自己”发挥”出一套新的;
- 防止越界:明确告诉 AI”哪些能做、哪些不能做、做完要干什么”,避免它擅自 push、乱删文件;
- 可传承:项目换了 AI、换了人来维护,约定都在文件里,不用靠口头交代。
放哪些内容
一份最小可用的 AGENTS.md,通常包含五块:项目是什么、目录结构、编码规范、开发流程、交付规则。下面是一个可以直接抄的示例:
# AGENTS.md
# 这份文件是给 AI 编码代理看的"项目约定"。AI 每次开工前都应该先读它。
## 1. 项目是什么
# 一句话让 AI 快速进入语境,而不是让它瞎猜。
这是一个博客系统:前端 Nuxt 3,后端 Go + Gin,数据库 PostgreSQL。
## 2. 目录结构(固定约定)
# 写死目录,AI 就不会到处乱建文件。
web/ # 前端代码
server/ # 后端代码
docs/ # 设计文档,所有需求都先落到这里,再动手写代码
## 3. 编码规范
# 把团队标准写死,AI 生成的代码才能保持统一风格。
- 后端接口一律返回 {code, message, data} 三段结构;
- 所有数据库表必须有 id 主键和 created_at 字段;
- 错误统一走 errors 包,禁止在业务代码里直接 panic。
## 4. 开发流程
# 告诉 AI 先做什么、后做什么,避免一上来就闷头写代码。
1. 先读 docs/ 下对应的设计文档,没有文档就先补文档;
2. 按文档实现功能;
3. 写完运行测试,全部通过后再提交。
## 5. 交付规则
# 明确"完成"的标准,防止 AI 半途而废或越权操作。
- 改完必须 git add + commit,提交说明用中文简述改动;
- 未经确认,不要 push 到生产分支。
注意:AGENTS.md 里写的是”项目约定”,不是”一次性指令”。它要足够通用,让 AI 在整个项目生命周期里都能复用;临时性的”帮我做个登录页”这种话,直接写在对话里就行,不用塞进 AGENTS.md。
二、第二步:建 docs 目录,把每个角色的设计文档先写下来
为什么”文档先行”
常规软件开发流程里,产品、设计、架构、后端、前端、测试、运维每个角色,在动手前都要产出自己的”图纸”。用 AI 开发也一样:让 AI 先把各角色的文档写出来,人审完再写代码。 这能解决两个老大难:
- 人和 AI 对需求的理解对齐:文档说清楚了”到底做什么”,代码才不会跑偏;
- 文档就是后续代码的依据:AI 写代码时,直接引用文档里的接口、字段和用例,前后不会打架。
docs 目录长什么样
按”角色”来组织,一个角色一个子目录,每个子目录一份核心文档:
docs/
├── 00-需求/
│ └── PRD.md # 产品经理:要做什么、为什么做、边界在哪
├── 01-架构/
│ └── architecture.md # 架构师:系统怎么分层、服务怎么拆、数据怎么流
├── 02-数据库/
│ └── database.md # 数据:有哪些表、字段、关系,为什么这样设计
├── 03-接口/
│ └── api.md # 后端:每个接口的路径、入参、出参、错误码
├── 04-前端/
│ └── ui.md # 前端/设计:页面结构、交互、状态怎么管理
├── 05-测试/
│ └── test-plan.md # 测试:用例、验收标准、自动化怎么跑
├── 06-运维/
│ └── deploy.md # 运维:部署方式、环境、监控、回滚
└── 07-安全/
└── security.md # 安全:权限、数据脱敏、风险点
每个角色写什么
一张表对应清楚”哪个角色、产出哪份文档、文档里必须写清什么”:
| 角色 | 文档 | 必须写清的内容 |
|---|---|---|
| 产品经理 | docs/00-需求/PRD.md | 用户故事、功能清单、优先级、不做的事 |
| 架构师 | docs/01-架构/architecture.md | 分层、模块、服务边界、技术选型 |
| 数据/后端 | docs/02-数据库/database.md | 表结构、字段、关系、索引 |
| 后端工程师 | docs/03-接口/api.md | 版本、方法、路径、参数、返回、错误码(详见下文) |
| 前端/设计师 | docs/04-前端/ui.md | 页面、交互、组件、状态管理 |
| 测试工程师 | docs/05-测试/test-plan.md | 用例、验收标准、自动化策略 |
| 运维/SRE | docs/06-运维/deploy.md | 部署、环境、监控、回滚 |
| 安全工程师 | docs/07-安全/security.md | 权限、脱敏、漏洞风险 |
顺序也很重要:先需求,再架构,再数据库,再接口,再前端,最后测试和运维。前面的是后面的依据,反着来就会来回返工。
为什么把数据库放在接口前面?因为接口本质上是”对数据库里数据的一系列操作”:表和字段还没定,接口的参数、返回就定不下来。先定表,再定接口,前端的页面数据也就有了来源。至于安全,它是横切关注点——虽然单独放在最后评审,但权限、脱敏这些要求应当贯穿前面每一份文档,而不是最后才想起来补。
接口文档要写到什么程度:一份完整规范
接口(API)是前端和后端之间签的”合同”。 合同写得不细,两边各做各的,联调时就会打架。所以 docs/02-接口/api.md 不只是”列几个接口名”,还要把下面这些规则一起定死——其中版本管理是最容易漏、但最要命的一条。
1. 版本管理:接口也要有版本号
接口一旦发布,外面可能有一堆老客户端、老脚本还在调用。你不能今天改个路径、删个字段,就让所有调用方全断掉。解决办法就是给接口加版本。
最常用的做法是把版本号放进 URL 前缀,比如 /api/v1/users 里的 v1。要不要升版本,看这次改动”破不破坏兼容”:
flowchart TD
A["接口需要改动"] --> B{"会破坏兼容吗?<br/>改路径 / 删字段 / 改语义"}
B -->|"否:只加字段、修 bug"| C["留在 v1,直接改"]
B -->|"是:破坏性改动"| D["新开 /v2"]
D --> E["v1 保留一段时间<br/>通知调用方迁移"]
简单记:加字段不升版本,改路径、删字段、改返回含义才升版本;升了版本,老版本 v1 要再保留一阵子,给调用方留出迁移时间。
2. 路径与 HTTP 方法:动作交给”动词”
路径里只用资源名词,具体动作交给 HTTP 方法去表达:
| 方法 | 含义 | 例子 |
|---|---|---|
| GET | 查询 | GET /api/v1/users 查用户列表 |
| POST | 新建 | POST /api/v1/users 创建用户 |
| PUT/PATCH | 修改 | PUT /api/v1/users/1001 改某个用户 |
| DELETE | 删除 | DELETE /api/v1/users/1001 删某个用户 |
3. 统一响应结构:所有接口一个模子
规定所有接口都返回同一套三段结构,前端就不用猜:
{ "code": 0, "message": "ok", "data": { "id": 1001 } }
code:0 表示成功,非 0 表示出错;message:给人看的提示语;data:真正的业务数据,出错时可以为空。
4. 错误码分段:一眼定位是哪个模块
错误码按模块分段,排错时看开头数字就知道方向:
| 段 | 含义 | 例子 |
|---|---|---|
| 1xxx | 通用错误 | 1001 参数错误 |
| 2xxx | 用户模块 | 2001 邮箱已存在 |
| 3xxx | 订单模块 | 3001 库存不足 |
5. 分页、排序与幂等:三个高频细节
- 分页:列表接口统一用
page、page_size两个参数; - 排序:统一用
sort=created_at_desc这类约定; - 幂等:下单、付款这类”不能重复执行”的写接口,要支持幂等键,客户端重试不会重复扣款。
6. 一个可直接套用的接口文档模板
把上面几条落地成 api.md 里的一段,长这样:
# 用户模块接口(docs/02-接口/api.md 片段)
## 0. 全局约定
- 版本:统一走 URL 前缀 /api/v1
- 认证:请求头 Authorization: Bearer <token>
- 统一响应:{ "code": 0, "message": "ok", "data": {...} }
## 1. 创建用户
POST /api/v1/users
请求体:
{ "name": "张三", "email": "zhangsan@example.com" }
成功响应(code=0):
{ "code": 0, "message": "ok", "data": { "id": 1001 } }
失败响应:
{ "code": 2001, "message": "邮箱已存在", "data": null }
错误码:
- 2001 邮箱已存在
- 2002 参数不合法
这份文档写清楚之后,前端照着调、后端照着写、测试照着验、AI 照着生成代码,四方用同一份”合同”,联调冲突会少一大半。
三、第三步:先定数据库——表越少、关联越少,上层逻辑越简单
为什么数据库决定上层逻辑
数据库是整个系统的”地基和管线图”。地基打歪了,上面的房子再怎么装修都别扭。具体到开发里:上层服务(后端接口)几乎每个功能都要读写数据库,如果表之间的关系又乱又多,服务里就会充满复杂的联表查询和”补丁式”的判断;反之,表结构清晰、关联少,服务逻辑自然就短、就直。
先认识”关系”
表之间的关系,本质上只有三种,用生活中的例子记:
| 关系 | 含义 | 例子 |
|---|---|---|
| 一对一 1:1 | 一个 A 对应一个 B | 一个用户对应一份实名资料 |
| 一对多 1:N | 一个 A 对应多个 B | 一个用户下多个订单 |
| 多对多 N:M | 多个 A 对应多个 B | 一个订单买多件商品,一件商品出现在多个订单 |
多对多关系不能直接用外键表达,必须拆成一张”中间表”,把它变成两个”一对多”。这是让关联变清晰的关键动作,下面例子里的 order_item 就是这种中间表。
三个设计原则
- 一张表只描述一种东西:用户表只存用户,订单表只存订单,不要互相塞字段;
- 关联越少越好:能用一张表,就不用两张;能不加外键关联,就不加;
- 价格等历史值要”快照”:订单里记下单时的单价,而不是每次都去商品表现查——这样以后商品涨价,历史订单也不会变。
表名怎么起:一眼看出属于哪个功能
表多了以后,光看表名就应该知道它属于哪个功能、给谁用。统一规则是:<模块前缀>_<表名>,全小写、下划线连接、单数、用英文。
| 模块 | 前缀 | 表名示例 |
|---|---|---|
| 用户 | user_ | user_account、user_profile |
| 商品 | product_ | product_info、product_sku |
| 订单 | order_ | order_main、order_item |
| 支付 | pay_ | pay_order、pay_refund |
这样在数据库里一排序,同一个模块的表自然聚在一起,谁也不会乱用别人模块的表。
字段名也要统一三条:
- 主键一律叫
id; - 时间字段统一
created_at、updated_at; - 外键叫
<目标表名单数>_id,比如user_id、order_id——注意外键别再重复加模块前缀,写成order_order_id就是画蛇添足。
还有三个”不要”:不要用拼音;不要单数复数混用(全单数或全复数,二选一);不要用数据库保留字当表名或字段名。
下面这个例子,就严格按这套命名规则来写。
一个具体例子:极简订单系统
只做”用户下单买东西”这一件事,四张表就够了,并按上面的规则起名:user_account(用户)、product_info(商品)、order_main(订单主表)、order_item(订单明细)。先看它们之间的关系(ER 图,读法:|| 这边是”一”,o{ 这边是”多”):
erDiagram
USER_ACCOUNT ||--o{ ORDER_MAIN : "一个用户下多个订单"
ORDER_MAIN ||--|{ ORDER_ITEM : "一个订单含多个明细"
PRODUCT_INFO ||--o{ ORDER_ITEM : "一个商品出现在多个明细"
USER_ACCOUNT {
bigint id PK
varchar name
varchar email UK
timestamptz created_at
}
PRODUCT_INFO {
bigint id PK
varchar title
numeric price
int stock
}
ORDER_MAIN {
bigint id PK
bigint user_id FK
numeric total_amount
varchar status
}
ORDER_ITEM {
bigint id PK
bigint order_id FK
bigint product_id FK
int quantity
numeric unit_price
}
对应到建表 SQL(PostgreSQL),每句都有注释,可以直接跑:
-- ============ 用户表(user_ 前缀 = 用户模块)============
-- 只保存"用户自己"的信息。一个用户可以有多个订单,
-- 所以本表不保存任何订单字段,避免用户和订单纠缠在一起。
CREATE TABLE user_account (
id BIGSERIAL PRIMARY KEY, -- 主键:自增,唯一标识一个用户
name VARCHAR(64) NOT NULL, -- 昵称
email VARCHAR(128) NOT NULL UNIQUE, -- 登录邮箱,唯一约束防止重复注册
created_at TIMESTAMPTZ NOT NULL DEFAULT now() -- 注册时间
);
-- ============ 商品表(product_ 前缀 = 商品模块)============
-- 商品被哪些订单购买,交给 order_item 记录,本表不直接关联订单。
CREATE TABLE product_info (
id BIGSERIAL PRIMARY KEY, -- 主键
title VARCHAR(128) NOT NULL, -- 商品名
price NUMERIC(10,2) NOT NULL, -- 售价,用 NUMERIC 存金额避免浮点误差
stock INT NOT NULL DEFAULT 0, -- 库存数量
created_at TIMESTAMPTZ NOT NULL DEFAULT now() -- 上架时间
);
-- ============ 订单主表(order_ 前缀 = 订单模块)============
-- 一个订单属于一个用户(多对一),通过 user_id 关联;
-- 订单里具体买了什么、各买几件,放到 order_item,本表只存订单汇总。
CREATE TABLE order_main (
id BIGSERIAL PRIMARY KEY, -- 主键
user_id BIGINT NOT NULL REFERENCES user_account(id), -- 下单用户,指向 user_account 表
total_amount NUMERIC(12,2) NOT NULL DEFAULT 0, -- 订单总金额
status VARCHAR(16) NOT NULL DEFAULT 'created',-- 状态:created/paid/shipped/done
created_at TIMESTAMPTZ NOT NULL DEFAULT now() -- 下单时间
);
-- ============ 订单明细表(order_ 前缀,连接订单与商品)============
-- 连接"订单"和"商品"的中间表:一条记录表示"某订单买了某商品几件"。
-- 用这张表把"多对多"拆成两个"一对多",是保持关联清晰的关键。
CREATE TABLE order_item (
id BIGSERIAL PRIMARY KEY, -- 主键
order_id BIGINT NOT NULL REFERENCES order_main(id), -- 属于哪个订单
product_id BIGINT NOT NULL REFERENCES product_info(id), -- 买的是哪个商品
quantity INT NOT NULL DEFAULT 1, -- 买了几件
unit_price NUMERIC(10,2) NOT NULL -- 下单时单价(快照,防改价影响历史订单)
);
这四张表一共只有三条关系,而且都是”一对多”:用户对订单、订单对明细、商品对明细。上层服务只要”查一个用户的订单 → 查订单的明细 → 拼出买了什么”,逻辑非常直,几乎没有联表陷阱。
关于外键:上面为了演示加了
REFERENCES(物理外键)。真实项目里,高并发场景很多人会改成”逻辑外键”——只保留user_id这种字段、不加数据库级约束,由服务层自己保证数据一致。要不要物理外键是权衡,但”字段关联要少、要清晰”这个原则不变。
四、把三步串成一条完整流程
把上面三步落成一条可执行的流程,一共七个阶段:
| 阶段 | 干什么 | 谁主导 | 产出 |
|---|---|---|---|
| 0. 立规矩 | 写 AGENTS.md | 开发者 | AGENTS.md |
| 1. 定需求 | 确认要做什么、边界在哪 | 产品经理 | PRD |
| 2. 出设计 | 架构、接口、前端、数据库、测试、运维文档 | 各角色 | docs/ 下文档 |
| 3. 定数据 | 设计表结构、字段、关系 | 数据/后端 | 建表 SQL |
| 4. 写代码 | AI 按文档实现功能 | AI + 后端/前端 | 代码 |
| 5. 测试验收 | 按测试文档跑用例、修问题 | 测试工程师 | 测试报告 |
| 6. 上线复盘 | 部署上线,把经验写回 AGENTS.md 和 docs | 运维 + 全员 | 更新后的约定与文档 |
下面这张时序图,展示了”人”和”AI”在一条流程里各自在什么节点出手:
sequenceDiagram
autonumber
participant H as 开发者
participant AI as AI 编码代理
participant A as AGENTS.md
participant D as docs/ 设计文档
participant DB as 数据库
participant C as 代码仓库
H->>AI: 下达需求,先读 AGENTS.md
AI->>A: 读取项目约定
A-->>AI: 返回规范与目录约定
AI->>H: 先输出 PRD,确认需求
H-->>AI: 确认或修改
AI->>D: 生成架构、接口、数据库、测试文档
H-->>AI: 逐份评审通过
AI->>DB: 按数据库文档建表
AI->>C: 按文档编写代码
AI->>C: 运行测试并修复
H-->>AI: 验收通过
AI->>A: 复盘后更新约定与文档
这张图里最关键的一个细节是:AI 不直接”写代码”,而是先经过”读规矩 → 出文档 → 人评审 → 建库 → 写码”这条链。每一环都有据可查,人才是最后的拍板者。
其中”写代码”和”上线”这两个环节,还各自藏着一套硬功夫:版本控制和发布流程。这两件事没做好,前面写得再规范,出问题时也会手忙脚乱。下面两节单独讲透。
五、版本控制:让每一次改动都可追踪、可回退
为什么 AI 开发尤其需要它
AI 写代码的特点是快、改动面大:一句话下去,它可能同时改了十几个文件。这带来一个致命问题——一旦改错了,你怎么回到”上一个好的状态”?
版本控制(最常用的是 Git)就是干这件事的:它像游戏的存档系统,每完成一小步就存一个档,随时能读档、对比、回退。没有它,AI 的”快”反而会变成”乱”。
分支怎么分:主线 + 短命功能分支
一个简单好用的策略是:
- main 分支:永远保持”能上线”的稳定状态,是唯一的生产来源;
- feature 分支:每做一个功能,从 main 拉一条短命分支,做完、测完、评审通过后再合回 main。
这条规则对 AI 尤其重要:让 AI 在功能分支上干活,而不是直接在 main 上乱写,坏了也影响不到主线。下面这张图演示了”主线 + 功能分支 + 打 tag”的完整动作:
gitGraph
commit id: "初始提交"
commit id: "feat: 登录功能"
branch feature/order
checkout feature/order
commit id: "feat: 订单功能"
commit id: "fix: 金额计算错误"
checkout main
merge feature/order tag: "v1.1.0"
commit id: "docs: 补充设计文档"
提交说明怎么写:Conventional Commits
AI 提交时,最容易写出 update、fix bug、改了一堆东西 这种没信息的说明。用 Conventional Commits(约定式提交) 把它规范成”类型 + 简述”:
feat: 新增用户登录接口
fix: 修复订单金额四舍五入错误
docs: 更新数据库设计文档
refactor: 重构订单查询逻辑
test: 补充订单回归用例
chore: 升级依赖版本
开头的词有固定含义:feat 新功能、fix 修 bug、docs 文档、refactor 重构、test 测试、chore 杂务。提交说明写清楚,将来”哪个改动引入了这个 bug”一眼就能定位。
版本号怎么定:SemVer
语义化版本号(SemVer) 用三段数字 主版本.次版本.修订版本 表达一次发布,比如 1.2.3:
| 段 | 什么时候加 | 例子 |
|---|---|---|
| 主版本(1.x.x) | 做了不兼容的破坏性改动 | 2.0.0 |
| 次版本(x.1.x) | 加了新功能,向后兼容 | 1.3.0 |
| 修订版本(x.x.1) | 只修 bug,不改功能 | 1.2.4 |
配合 tag(标签):每次发布时给对应提交打一个 tag(如 v1.2.3),再顺手维护一份 CHANGELOG,记下每个版本改了什么。这样”线上跑的是哪个版本、出问题回到哪个版本”,全都清清楚楚。
AI 场景下的三条硬规矩
- 一次提交只做一件事:禁止 AI 一口气提交几十个不相关文件;
- 提交说明必须规范:按上面
feat/fix/...的格式来,不许写”update”; - 每个可发布的版本都打 tag:没有 tag,回退就成了”大海捞针”。
六、发布流程:从代码到上线的”标准生产线”
三个环境,先把话说清
正式项目里,代码不是写完就直接上生产,而是依次经过三个环境:
| 环境 | 作用 | 谁在用 |
|---|---|---|
| dev(开发) | 日常开发、联调 | 开发、AI 编码代理 |
| staging(预发) | 上线前最后一次验收,尽量和生产一致 | 测试、产品 |
| prod(生产) | 真实用户在用 | 最终用户 |
AI 可以随意折腾 dev,但绝不能直接碰 prod。 这条边界要写进 AGENTS.md,用环境和权限把它卡死。
发布前必过的三道关
- 代码评审:AI 写的代码必须有人看过,确认没跑偏、没埋雷;
- 自动化测试:CI 流水线自动跑测试,不通过就拦下来;
- 构建产物校验:构建出的包要完整、可安装、版本号正确。
发布要”灰度先行”
最稳的发布方式不是”一下全量”,而是灰度发布:先把新版本放给一小部分用户,观察没问题,再逐步扩大到全量。新版本相当于”先让少数人试吃,再全场供应”。
下面这张图是一条完整的发布流水线:
flowchart TB
A["代码提交到 main"] --> B["CI:自动构建 + 跑测试"]
B --> C{"评审与测试通过?"}
C -->|否| B2["打回修复"]
B2 --> A
C -->|是| D["打 tag + 写发布说明"]
D --> E["部署到预发 staging"]
E --> F["灰度发布(小流量)"]
F --> G["监控观察指标与报错"]
G --> H{"指标正常?"}
H -->|否| I["回滚到上一稳定版本"]
H -->|是| J["全量发布到生产"]
回滚:出问题时的”后悔药”
发布前就一定要想好怎么回滚。 最常见的做法是:保留上一个版本的构建产物和 tag,一旦灰度或全量后发现异常,一键切回上一版本,而不是现场翻代码改。
发布后:监控 + 复盘
上线不是终点。发布后要盯监控指标(错误率、响应时间、业务量),有异常立即告警;问题处理完还要复盘,把原因和预防措施写回 AGENTS.md 和 docs,让下一次发布更稳。
AI 场景下的三条硬规矩
- AI 生成的代码必须过 CI:测试没通过,不许进入下一个环境;
- “发布”这个动作必须由人确认:AI 可以准备一切,但最后点”发布”的是人;
- 每次发布都要能回滚:先灰度、留好上一版本、随时能退。
七、有规范 vs 没规范:一张对比表
| 维度 | 没有规范(直接让它写) | 有规范(AGENTS.md + docs + 数据库先行) |
|---|---|---|
| 代码风格 | 每次都不一样,越改越乱 | 统一,新代码像老代码 |
| 需求对齐 | 经常跑偏,来回返工 | 文档先行,偏差小 |
| 数据库 | 表越建越多、关系纠缠 | 表少、关联少、逻辑直 |
| 可维护性 | 只有 AI 当时”自己知道” | 文档在,换人换 AI 都能接手 |
| 风险控制 | 容易越权、乱删乱改 | 交付规则明确,人可控 |
| 版本控制 | 提交混乱、无法回退 | 每次改动可追踪,按 tag 随时回退 |
| 发布流程 | 直接全量、出事干着急 | 灰度先行、监控到位、随时回滚 |
| 复盘沉淀 | 经验丢了 | 反哺回 AGENTS.md,越用越顺 |
一句话总结这张表:规范不是在约束 AI,而是在约束”混乱”。
八、几个容易踩的坑
- AGENTS.md 写得像说明书而不是约定:它应该写”规则和边界”,不是把整个项目文档塞进去;
- 文档写成流水账:每份文档都要”可执行”,接口文档要能直接照着写代码,不是空话;
- 数据库过度设计:一开始就上几十张表、各种多对多,服务还没写就已经很难改了。先做减法,表能少就少;
- 人完全撒手:AI 出完文档和代码,人必须逐份评审、逐项验收,AI 是”加速器”不是”替身”;
- 提交混乱:AI 一次提交改了几十个不相关文件,出问题没法定位、没法回退;
- 没有回滚预案:不灰度、不打 tag,直接全量上线,AI 改的代码一旦有问题只能干着急;
- 做完不复盘:不把踩过的坑写回 AGENTS.md,下一次同样的坑还会再踩一次。
九、总结
用 AI 开发,本质上还是软件工程的老规矩:先立约定、再出设计、定好数据、管好版本、走稳发布,最后写代码——只是把”执行”这一步交给 AI,把”决策和验收”留给人。
记住这五件事:AGENTS.md 立规矩,让 AI 每次都按同一套规则办事;docs 文档先行,让每个角色在动手前都有图纸、有依据;数据库设计清晰、关联少,让上层服务逻辑简单、好维护;版本控制可追踪、可回退,让每一次改动都有存档;发布流程灰度先行、随时能回滚,让上线不再心惊胆战。这套组合拳打下来,AI 就从”偶尔惊艳、经常跑偏”的工具,变成一支听话、稳定、能沉淀的开发队伍。