游戏发行技术平台设计方案(七):工程规范与 AI 协作
系列第七篇。前面六章讲的是”系统怎么设计”(上一篇:稳定性与运维),这一章讲这套系统是怎么被持续改对的。
而这一章有一个前提必须放在最前面:这套系统的编码主力是 AI。 最近两年,这套平台的服务端、后台前端、数据报表,主要由一个人借助 AI 完成——所以”工程规范”要解决的问题也变了:不是”怎么让人写得更快”,而是“怎么让 AI 的产出可以被验证、被信任、被持续集成进生产系统”。
依然四段:业务背景 → 方案设计 → 关键取舍 → 真实经验。
一、业务背景
写代码不再是瓶颈,”改对”才是
这套系统有一个不太常规的特点:代码量远大于团队规模。
原因很直接——大量编码工作由 AI 承担。这带来一个结构性变化:
- 过去:写代码慢,所以”想清楚再写”是自然约束
- 现在:写代码很快,所以”想清楚”和”验证”成了唯一的瓶颈
如果没有配套的规范,AI 提效会直接转化成两类风险:
- 改错但看不出来:代码读起来合理、能跑、测试没覆盖到,问题留到线上
- 改对但不敢改:没人敢动一个”不知道边界在哪”的模块,提效反而变成维护恐惧
核心矛盾
速度来自”让 AI 大胆改”,安全来自”每一步都可验证”。两者必须同时成立——只有速度会失控,只有安全会停摆。
这一章的所有设计,都是在给”快速改动”配一套可验证的护栏。
二、方案设计
2.1 研发流程:把”评审”设成提交闸门
流程是固定的七步:
flowchart LR
P["计划"] --> I["实现"] --> R["评审"] --> F["修复"] --> RP["评审通过"] --> V["验证"] --> C["提交"]
R -.->|"未通过"| F
V -.->|"失败"| F
配套三条硬规则:
① 评审是闸门,不是建议
未评审的代码不允许提交。
这一条要写成规则而不是习惯,因为它反直觉:AI 产出代码的速度让人本能地想”先提交、回头再看”——但”回头”通常不会发生,而且改动会持续叠加在未评审的基础上。
② 证明,而不是声称
不允许”我改好了”这种结论。要求是跑测试、跑构建,并把输出贴出来。
对 AI 协作者来说这一条尤其重要:AI 非常擅长生成”看起来对”的说明,而只有执行输出是它无法编造的。
③ 先计划,再写码
多步改动必须先说清意图(改哪些文件、为什么、怎么验证),再动手。
原因:计划阶段发现的问题,修改成本是零;实现之后才发现方向错了,成本是全部返工。
2.2 动手前的核对:Pre-Action Gate
在改任何既有逻辑之前,有四步固定动作:
- 读文件——不假设内容(”我以为它长这样”是错误的高发区)
- 搜调用方——改这个函数,谁在依赖它
- 核对——”需求里说的”和”代码里实际是”是否一致
- 不一致就立刻上报,不允许静默选一个
第 4 条值得展开,因为它是最容易被”好心”违反的一条:
当”用户/需求说的”和”代码里的实现”不一致时,AI(或人)的本能是选一个看起来更合理的继续做。这是最贵的错误——因为这意味着改动的基线本身就是错的,后面所有工作都建立在错误假设上。
正确的做法是把矛盾摆出来,附带判断依据(如果旧实现有测试和文档支撑,可能是需求方记错了;如果旧实现是历史遗留,那需求方的描述可能就是目标)。把判断权交回给最有上下文的人。
另外,破坏性操作(删除、重命名、改表结构)要额外走一次安全检查——这类操作不可逆,值得多花一分钟确认。
2.3 规格驱动:每个东西只有一个真相源
“改对”的前提是”知道什么是对的”。所以每个关键产物都有一个唯一的真相源:
| 产物 | 真相源 |
|---|---|
| 数据库结构(业务库 + 分析库) | 一份 schema 定义文件 |
| SDK 接口契约 | 一份 OpenAPI 契约文件 |
| 后台权限与菜单 | 一份权限数据样例 |
规则很硬:
- schema 定义文件是唯一权威,模块文档只是它的派生摘要
- 接口契约是唯一权威,实现要对着契约写
- 数据库变更除了迁移文件,还要汇总到一份变更日志(新内容追加在最顶部)——因为生产环境的执行要可追溯、可重放
契约先行的收益在小团队 + AI 协作下被放大:
- 前后端可以真正并行(契约冻结 = 接口冻结)
- AI 有明确的边界,不需要”猜”接口长什么样
- 评审有依据——评审时对照的是契约,而不是”我觉得应该这样”
2.4 文档体系:模块卡 + 日期文档 + 折叠回写
文档分三层,各司其职:
flowchart TB
IDX["模块索引<br/>(入口:这个功能归哪个模块)"] --> CARD["模块上下文卡<br/>(当前真相:规则/端点/坑)"]
CARD --> HIS["日期文档<br/>(历史:为什么这么改、否决过什么)"]
HIS -.->|"折叠回写:只留耐久知识"| CARD
① 模块上下文卡(当前真相)
每个功能模块一张卡,结构固定:
- 元信息:权威引用(指向真相源文件)、相关历史文档、关键词
- 范围:这个模块负责什么、不负责什么
- 关键业务规则:可以快速读完的规则清单
- 端点表 / 表字段焦点 / 代码入口
- 常见 bug 向量 ← 这一节最有价值
“常见 bug 向量”不是”怎么用”,而是”这里曾经怎么错过“:
- 不要相信请求里传来的参数作为归因依据(要以游戏配置为准)
- 忘了缓存里也会存”未命中”这个结论
- 改了路由就要检查权限名(因为权限名从路由派生)
- 把数据范围问题当成权限问题排查
这些是踩过的坑的沉淀。 它的作用是让下一个会话(无论是人还是 AI)不再重犯同一个错误——这比任何”使用说明”都值钱。
② 日期文档(历史)
每个功能的方案、推演过程、被否决的选项、实施步骤,都留在按日期归档的文档里。
它的定位是历史,不是当前真相——所以规则明确:日期文档与模块卡冲突时,以模块卡和代码为准。
③ 折叠回写(fold-back)
功能上线、验证通过之后,有一个固定动作:把”耐久知识”从日期文档折叠回模块卡。
- 折叠什么:范围与职责、稳定的业务规则、关键表字段、关键端点与流程、代码入口、常见失败模式、重要错误码与不变量
- 留下什么:长篇推理、被否决的备选方案、分步实施计划、大段 SQL/代码片段
这一步是文档体系能长期活着的原因:没有它,模块卡会过期、日期文档会变成唯一入口,最后所有人都在读三个月前的实施计划。
④ 一条反直觉的写法要求
文档不为了限制每行字数而折行——因为折行会打断句子,而这份文档的首要读者是 AI。
这个要求本身很说明问题:文档的读者变了,写法也要跟着变。 人读的是排版,AI 读的是语义完整性。
2.5 面向 AI 的协作约定
AI 参与的研发流程,有一个闭环:
需求 → 设计数据结构 → 出实现方案 → 编码 → 按方案评审代码 → 测试环境验证 → 上线
注意其中的评审方式:不是”通读一遍代码找问题”,而是对照实现方案逐条检查”方案里说的,代码里有没有做对”。
这个区别很重要:通读代码只能发现”看起来不对”的地方,而对照方案评审能发现”漏做”——漏做是最难被通读发现的缺陷(因为缺的东西不会跳出来说”我不在”)。
除了流程,还有三条约定写进了仓库:
① 意图路由表
把常见意图和对应的处理方式列成表,强制匹配:
| 用户表达 | 处理方式 |
|---|---|
| 报错 / 不工作 / 崩溃 | 先做根因调查,不直接改代码 |
| 评审 / 检查 | 走评审流程 |
| 发布 / 合并 | 走发布流程 |
| 新功能 / 设计 | 先出方案评审,再写代码 |
理由写在表头:“很多模型不会自己推断意图,这张表就是强制执行机制。”
② 模型分工
按任务类型分配模型:规划和理解用更强的模型,编码用性价比更高的模型。
原因:规划错了代价最大(返工全量),编码是可以被评审和测试兜住的环节。把算力花在错误代价最高的地方。
③ 规范必须写进仓库,不能只存在人脑里
这条是上面所有约定的前提:规范写在人脑里,AI 读不到;写进仓库文件,人和 AI 共用同一套约束。
2.6 分支、提交与发布
提交信息用约定式提交(类型 + 范围 + 描述),比如”新增后台订单页”“修复归因解析异常”“更新依赖”。
分支模型简单直接:
- 集成分支作为基线
- 功能分支按
feature/日期_描述命名 - 紧急修复走
hotfix/日期_描述 - 合并前先 rebase(保持线性历史,避免”合并提交淹没真实改动”)
PR 描述必须包含:做了什么 / 为什么、关联任务、测试步骤、配置变更说明;界面改动附截图;CI 必须通过。
涉及业务规则的改动还要额外说明三件事:
- 规格对齐:对应哪个规格文件(改了什么契约)
- 错误码语义:新增/变更的错误码含义(比如”支付被禁用”对应哪个码)
- 性能说明:如果是查询优化,说明合并了哪些重复查询
这三条不是形式主义——业务规则的改动是”评审时最需要上下文”的一类改动。
2.7 测试:业务规则必须有断言
测试策略按”风险”排优先级,而不是按”覆盖率”:
最高优先级是业务规则断言,例如:
- 游戏开关”禁用支付”时,下单接口必须返回指定的错误码
- “禁用注册”时,所有注册路径必须返回指定的提示语
- 初始化接口必须返回客户端需要的所有开关标记
为什么这类测试最重要?因为它们是”配置驱动行为”的规则——开关一旦被误改,影响的是全部接入的游戏,而且从代码上完全看不出来。
另外两条实践:
- 测试环境隔离:多人(多 AI 会话)并行开发时,各自有独立的测试库配置,互不干扰
- 接口契约测试定期跑(第六章的健康检查):保证”线上接口仍然符合契约”
2.8 把事故变成工具和清单
第六章讲过一个内存耗尽的事故,根因是两个 Service 的构造器循环依赖。
事故修完之后,做了三件”复盘产物”:
- 一个依赖检查脚本:能扫描服务间依赖、打印依赖图、给出修复建议
- 一套依赖管理规则:优先构造器注入;出现双向依赖时,在其中一个方向改为动态解析;用接口或事件替代双向依赖
- 一份 AI 代码审查清单:审查服务类时检查——构造器参数是否都必要、是否存在双向类型提示、能否用接口替代具体类、动态解析是否只用于打破循环
“教训 → 工具 → 清单”是事故复盘的完整闭环。 只写一份复盘文档,同样的错误还会再来;变成工具和清单,它才真正被防住。
三、关键取舍
| 决策 | 选择 | 放弃的方案 | 理由 |
|---|---|---|---|
| 评审时机 | 提交前闸门 | 事后抽查 | AI 产码速度快,事后抽查永远追不上新增量 |
| 验证方式 | 贴测试/构建输出 | 口头说明”已修复” | 只有执行输出无法被编造 |
| 文档结构 | 模块卡(真相)+ 日期文档(历史) | 一份大文档 / 只有日期文档 | 既要”快速进入状态”,又要”可追溯推理过程” |
| 文档内容 | 指文件路径 | 粘贴代码片段 | 片段会漂移,路径不会 |
| 文档读者 | AI 优先(不折行) | 人类排版优先 | 主要读者已变成 AI,语义完整性优先于版面 |
| 规范载体 | 写进仓库文件 | 口头约定 / 存在人脑 | AI 读不到人脑里的规范 |
| 意图识别 | 显式路由表 | 依赖模型自行理解 | 不同模型推断能力差异大,显式表才可靠 |
| 模型分工 | 规划用强模型、编码用性价比模型 | 全流程同一个模型 | 规划错误的返工成本最高,算力要花在刀刃上 |
| 循环依赖 | 脚本检测 + 审查清单 | 靠评审经验发现 | 人和模型都会漏,工具不会 |
| 数据库变更 | 迁移文件 + 汇总变更日志 | 只有迁移文件 | 生产执行要可追溯、可重放 |
| 分支历史 | 合并前 rebase | 保留合并提交 | 线性历史让”这次改了什么”一眼可见 |
四、真实经验
1. 把评审设成闸门之后,返工反而变少了
一开始的直觉是”评审会拖慢速度”,实际数据是相反的:返工减少的幅度大于评审占用的时间。
原因在于返工的分布:未评审的改动一旦提交,问题会在”下一个功能开发到一半”的时候暴露——那时候的修复成本是当时的 N 倍,因为你已经忘了上下文、而且新代码已经建立在错误基础上。
2. “需求说的”和”代码里的”不一致时,静默选择是最贵的错误
预动作核对的第 4 条规则来自实际教训:曾经出现过”需求描述某个开关的行为,代码里是另一个行为”,改动方按需求描述改了——结果发现需求描述记错了,旧实现是对的,改出了一次线上问题。
现在的要求是:发现不一致就停下来上报,把判断依据列出来,让有上下文的人决定。 这一分钟的成本,能省掉一次回滚。
3. 文档写”怎么用”不如写”这里曾经怎么错”
模块卡里最有价值的一节是”常见 bug 向量”。原因很实际:
- “怎么用”这类内容,读代码和契约也能得到,而且更准确
- “这里曾经怎么错”只有踩过的人知道,不写下来就必然重犯
判断一份技术文档值不值钱,就看它有没有写”别人不知道而你知道”的东西。
4. 规范写进仓库,AI 才遵守得到
这条是被迫学会的:一开始很多约定靠口头传达和”大家应该都知道”。AI 加入协作后立刻失效——AI 不会读心,它只读文件。
把流程、路由表、审查清单、命名规则全部写进仓库的规范文件之后,人和 AI 的行为才真正对齐。
顺带的好处是:新人上手也是读同一份文件。
5. 事故要变成工具,不能只变成文档
循环依赖那次事故,如果只写一份复盘文档,下一个 AI 会话(或下一个人)大概率会再犯——因为没人会在写代码前先去翻三个月的复盘文档。
变成”一个能跑的检查脚本 + 一份审查清单”之后,它才进入了每次改动的必经路径。
复盘的正确终点不是文档,是工具和清单。
6. 大段代码不要进文档
早期文档里贴了很多代码片段,结果是:代码改了、文档没改,读文档的人比不读的人错得更离谱。
现在的规则是:只写文件路径 + 一句话说明这个文件负责什么,具体实现永远去读代码。
文档和代码的边界是:文档负责”为什么”和”在哪里”,代码负责”是什么”。
下一篇
(八)演进路线:从三方 SDK 过渡到自研的路径规划——这套系统不是一天建成的,最后一章讲”如果重来一次,或者要继续往前走,路怎么走” → 继续阅读
本文基于实际项目整理,已脱敏。文中不含任何公司业务数据、配置或凭据。