Agent Teams 开发规范
一人创始人 + Agent Teams 的工程纪律 · 规范驱动开发 · 防止系统债务
核心原则
纯 Agent Teams 的最大风险不是"写不出来",而是:
- 多个 Agent 产生风格不一致的代码
- 数据模型被反复改坏
- 业务规则散落在不同模块
- 测试覆盖虚高,但关键交易路径没测到
- Agent 为了通过测试修改测试,而不是修业务
- 创始人没有足够时间 review 所有实现细节
所以必须把开发方式设计成"规范驱动",而不是"任务驱动"。
一、Agent 角色分工
| 角色 | Agent | 职责 | 能否写代码 |
|---|---|---|---|
| Architect | 架构 Agent | 维护架构文档、ADR、模块边界、数据所有权 | ❌ |
| Backend | 后端 Agent × N | 实现业务模块(auth/user/catalog/inventory/order/payment/coupon/delivery/asset) | ✅ |
| Frontend | 前端 Agent | 实现小程序/后台/配送端页面 | ✅ |
| QA | 测试 Agent | 写验收测试、边界测试、回归测试、异常场景测试 | ✅(仅测试代码) |
| Security | 安全 Agent | 检查权限、敏感数据保护、支付安全、注入风险 | ❌ |
| Reviewer | 审查 Agent | 只做 code review,不写代码 | ❌ |
关键约束:Architect、Security、Reviewer 三个角色只审不写。写代码的 Agent 不能审查自己的代码。
二、任务定义格式(必须)
每个开发任务必须按以下模板定义,不允许 Agent 自由发挥:
markdown
## 任务:{任务名}
### 需求说明
{用户视角的需求描述,1-3 句话}
### 数据表变更
- 新增表:{表名},字段:{关键字段}
- 修改表:{表名},新增字段:{字段名}
- 迁移脚本:migrations/{序号}_{描述}.sql
### 接口契约
POST /api/{path}
Request: {JSON 结构}
Response: {JSON 结构}
错误码: {错误码}
### 状态机影响
- 影响的状态:{订单/支付/库存/优惠券/配送} 状态机
- 合法转换:{from} → {to}
- 禁止转换:{from} → {to}(应返回 409 Conflict)
### 验收标准
- [ ] {可验证的条件 1}
- [ ] {可验证的条件 2}
- [ ] {可验证的条件 3}
### 失败场景(至少 3 条)
1. {场景描述} → 期望:{行为}
2. {场景描述} → 期望:{行为}
3. {场景描述} → 期望:{行为}
### 测试要求
- [ ] 单元测试:{模块}.{函数} 覆盖率 ≥ 80%
- [ ] 集成测试:{场景}
- [ ] 幂等测试:{重复调用的预期行为}
- [ ] 并发测试:{并发场景}
### 回滚方式
{如果上线后出问题,如何回滚}三、编码规范(强制)
3.1 模块边界规则
✅ 允许:
- 模块 A 调用模块 B 的公开 interface
- 模块 A 读取模块 B 的表(只读)
- shared/ 被所有模块引用
❌ 禁止:
- 模块 A 直接写模块 B 的表(必须通过 B 的 interface)
- 模块 A 引用模块 B 的内部类型(internal 不导出)
- 循环引用(A → B → A)3.2 错误处理规则
go
// ✅ 正确:错误向上传递,每层 wrap
func (s *OrderService) Create(ctx context.Context, req CreateOrderReq) (*Order, error) {
lockResult, err := s.inventorySvc.Lock(ctx, items)
if err != nil {
return nil, fmt.Errorf("inventory lock: %w", err)
}
// ...
}
// ✅ 正确:Handler 层统一转换 HTTP 状态码
func (h *OrderHandler) Create(c *gin.Context) {
order, err := h.svc.Create(c.Request.Context(), req)
if errors.Is(err, inventory.ErrInsufficientStock) {
c.JSON(409, gin.H{"error": "insufficient_stock"})
return
}
// ...
}
// ❌ 禁止:吞掉错误
result, _ := svc.DoSomething() // 忽略 error
// ❌ 禁止:Handler 层直接操作 DB
db.Exec("UPDATE orders SET ...") // Handler 不应触碰数据层3.3 数据库操作规则
go
// ✅ 必须用参数化查询
db.Exec("UPDATE orders SET status = $1 WHERE order_no = $2", status, orderNo)
// ✅ UPDATE/DELETE 必须带 WHERE 条件
// ✅ 写操作必须检查 RowsAffected
// ❌ 禁止:拼接 SQL 字符串
query := "SELECT * FROM orders WHERE order_no = '" + orderNo + "'"3.4 幂等规则
所有 mutation 端点必须设计为幂等:
go
// 支付回调(幂等)
func (s *PaymentService) HandleCallback(ctx context.Context, body []byte) error {
// 1. 先去重检查
existing, err := s.repo.FindByWechatTxnID(ctx, notif.TransactionID)
if existing != nil && existing.Status == "paid" {
return nil // 重复回调,直接返回成功
}
// 2. 更新(带乐观锁或唯一约束)
rows, err := s.repo.UpdateStatus(ctx, notif.OutTradeNo, "paid", notif.TransactionID)
if rows == 0 {
// 可能已被并发处理
return s.verifyAlreadyPaid(ctx, notif.OutTradeNo)
}
// 3. 后续操作(不影响支付状态)
// ...
}四、Code Review 检查清单
Reviewer Agent 对每个 PR 必须检查:
| # | 检查项 |
|---|---|
| 1 | 接口契约是否与任务定义一致 |
| 2 | 数据表变更是否在 migration 中 |
| 3 | 是否违反模块边界(跨模块直接写表) |
| 4 | 所有 mutation 是否幂等 |
| 5 | UPDATE/DELETE 是否有 WHERE 条件 |
| 6 | 是否检查 RowsAffected |
| 7 | 错误是否被吞掉(_, _ := 模式) |
| 8 | 支付/退款/库存操作是否有 audit_logs |
| 9 | 是否有 SQL 注入风险(字符串拼接) |
| 10 | 手机号/地址是否脱敏输出 |
| 11 | 状态转换是否合法(调 CanTransitionTo) |
| 12 | 测试是否覆盖失败场景(非仅 happy path) |
五、测试规范
5.1 测试分层
| 层 | 工具 | 覆盖目标 |
|---|---|---|
| 单元测试 | Go testing | 每个模块的 service 层 ≥ 80% |
| 集成测试 | Go testing + testcontainers-go | 关键交易路径(下单→支付→回调→确认) |
| 幂等测试 | Go testing | 重复支付回调、重复下单、重复退款 |
| 并发测试 | Go testing | 50 并发抢同一库存 |
| 状态机测试 | Go testing | 所有合法转换 + 所有非法转换被拒绝 |
5.2 异常场景测试(必须覆盖)
| # | 场景 | 测试方法 |
|---|---|---|
| 1 | 支付回调到达两次 | 两次调 HandleCallback,第二次返回成功且不改数据 |
| 2 | 支付成功时订单已取消 | 回调返回成功但不确认库存 |
| 3 | 超时释放时订单已支付 | 检查状态 → 不释放 |
| 4 | 库存不足时下单 | 返回 ErrInsufficientStock,优惠券不锁定 |
| 5 | 优惠券已过期时下单 | 返回错误,库存不锁定 |
| 6 | 并发锁定同一库存 | 一个成功,其余因 CAS 冲突重试或返回错误 |
| 7 | 退款时微信返回失败 | 记录 refund_failed,触发告警 |
| 8 | 数据库连接断开 | 事务回滚,返回 500 |
| 9 | Valkey 不可用 | 降级到直接查 DB(不影响业务) |
| 10 | Token 过期时请求 | 返回 401 |
六、开发流程
关键约束
- 一次只改一个垂直切片。例如"微信支付回调"只涉及 payment 和 order 两个模块,不能同时改 inventory 或 coupon。
- 禁止 Agent 自由发挥大模块。任务必须由 Architect Agent 定义好。
- 测试先于实现。QA Agent 在 Dev Agent 开始前写好验收测试骨架。
- Agent 不能为了通过测试修改测试。测试由 QA Agent 维护,Dev Agent 只能看不能改测试文件。
七、Git 规范
Commit Message 格式
{type}({module}): {简短描述}
{详细说明(可选)}
Refs: #{任务编号}类型:feat / fix / refactor / test / docs / chore
示例:
feat(payment): implement WeChat callback idempotency
- Add wechat_txn_id UNIQUE constraint
- Add idempotent check before status update
- Add outbox event on payment success
Refs: #TASK-005分支策略
main ← 始终可部署
├── task/TASK-001 ← 每个任务一个分支
├── task/TASK-002
└── ...八、禁止事项
| # | 禁止 |
|---|---|
| 1 | Agent 直接修改其他模块的表 |
| 2 | Agent 修改 shared/ 或 migrations/ 未经 Architect 审批 |
| 3 | Agent 修改状态机定义 |
| 4 | Agent 在 Handler 层写业务逻辑 |
| 5 | Agent 写没有 WHERE 的 UPDATE/DELETE |
| 6 | Agent 吞掉错误或返回裸 internal error |
| 7 | Agent 为通过测试修改测试文件 |
| 8 | Agent 合并自己的 PR 不经 Review |
| 9 | Agent 一次 PR 涉及 3 个以上模块 |
| 10 | 任何人在未定义任务的情况下让 Agent 直接写代码 |