Appearance
技术架构与部署设计:先决定怎么长期维护
Last updated: 2026-07-05
产品定义回答“做什么”,技术架构和部署设计回答“怎么长期维护”。
AI 可以很快写出一个能跑的实现,但团队需要的不只是能跑。团队需要知道模块边界在哪里、数据如何流动、外部调用如何失败、部署后如何排查问题、未来扩展时哪些地方可以改、哪些地方不能碰。
这就是为什么团队级 AI 开发必须先做技术设计。不是为了写文档,而是为了把长期维护成本前置到编码之前。
为什么不能直接让 AI 开写
在个人项目里,直接让 AI 实现一个功能通常没问题。团队项目的问题是:智能体会做很多局部合理、整体冲突的决定。
例如:
- 一个任务里把业务逻辑写在 Controller,另一个任务里写在 Service。
- 一个模块直接访问另一个模块的表,另一个模块又通过接口调用。
- 一个外部调用设置 3 秒超时,另一个外部调用无限等待。
- 一处缓存配置数据,另一处直接读库,失效策略不一致。
- 本地能跑,但部署后没有日志、指标、健康检查和回滚路径。
这些问题单独看都不一定是 bug,但放在团队里会不断增加维护成本。技术设计的目的,就是在 AI 大量生成代码前,先给它铺好轨道。
技术设计要产出什么
技术设计不需要一开始就追求大而全。最小可用版本至少要覆盖七类决策:
| 决策 | 要回答的问题 | 为什么重要 |
|---|---|---|
| 架构形态 | 模块化单体、微服务、前后端边界如何划分 | 决定代码组织和团队协作边界 |
| 模块边界 | 哪些模块存在,谁依赖谁,跨模块怎么调用 | 防止局部实现互相穿透 |
| 数据模型 | 核心实体、状态实体、配置实体如何拆分 | 防止后续接口和页面被错误模型拖住 |
| 外部调用 | 超时、重试、降级、幂等、错误映射如何处理 | 防止线上故障被外部服务放大 |
| 部署形态 | 本地、测试、生产如何运行,组件职责是什么 | 防止“能开发”但“不能运维” |
| 可观测性 | 日志、指标、链路、健康检查如何设计 | 防止出问题时只能猜 |
| 演进路径 | 什么时候拆分、扩容、引入队列或新组件 | 防止现在的实现堵死未来 |
这些产出最终要进入规格文档、CLAUDE.md、模块 README、任务模板或 review checklist。只有进入执行系统,设计才会影响代码。
先定架构形态
架构形态是团队对复杂度的第一层选择。常见原则是:除非有明确理由,不要一开始就选择最复杂的方案。
例如,早期团队通常可以选择模块化单体:
markdown
架构决策:当前采用模块化单体。
原因:
- 团队规模小,部署和调试成本要低。
- 业务边界还在变化,过早拆服务会放大沟通成本。
- 通过清晰模块边界,为未来拆分服务保留入口。
执行规则:
- 跨模块调用走 Service 接口。
- 禁止直接访问其他模块的 Mapper/Repository。
- 模块之间共享 DTO 必须放在明确的接口层。为什么这样设计:架构决策不只是“选一种形态”,还要推导出可执行的代码规则。否则 AI 不知道这个决策对每个文件意味着什么。
再定模块和依赖边界
模块边界决定团队能否并行工作。边界不清时,AI 会为了完成当前任务直接穿透其他模块,短期省事,长期难拆。
模块设计至少写清楚:
- 每个模块负责什么。
- 每个模块不负责什么。
- 对外暴露哪些 Service/API。
- 内部存储是否允许被其他模块访问。
- 跨模块数据通过 ID、DTO 还是事件传递。
一个可执行的模块边界说明可以这样写:
markdown
用户模块:
- 负责用户资料、状态、基础权限判断。
- 不负责业务资源授权。
- 对外只暴露 UserQueryService 和 UserStatusService。
- 其他模块不得直接读取 user 表。为什么这样设计:AI 写代码时会优先找最快路径。模块边界让“最快路径”不能绕过长期结构。
数据模型要先于接口
数据模型是系统最难改的部分。接口可以包一层,页面可以重做,错误的数据模型会影响查询、权限、统计、迁移和扩展。
团队做数据设计时,至少区分三类实体:
| 类型 | 含义 | 设计重点 |
|---|---|---|
| 主业务实体 | 代表业务核心对象 | 字段稳定、语义清晰、生命周期明确 |
| 附属配置实体 | 描述规则、选项、策略 | 允许扩展,但要有结构约束 |
| 状态衍生实体 | 记录运行状态、统计、进度 | 支持高频变化,避免污染主表 |
为什么这样设计:AI 很容易把所有字段塞进一张表,或者把动态配置拆得过碎。先定义实体类型,可以让后续实现更稳。
常见规则:
- 高频查询字段用独立列,不藏在 JSON 里。
- 多变配置可以用 JSON/KV,但必须有版本和类型约束。
- 高频更新状态不要和低频主数据混在一起。
- 分页查询必须有稳定排序字段。
- 大表预期、索引策略和归档策略要提前说明。
外部调用要按失败设计
外部服务一定会慢、会错、会超时、会返回不符合预期的数据。技术设计不能只写“调用某 API”,还要写失败时系统如何表现。
外部调用设计至少包含:
- 超时:连接超时、读取超时分别是多少。
- 重试:哪些错误可重试,最多重试几次,是否退避。
- 幂等:重试是否会造成重复写入或重复扣费。
- 降级:外部服务不可用时,用户看到什么。
- 错误映射:底层错误如何转换成业务错误。
- 日志与追踪:请求 ID、外部响应码、耗时如何记录。
为什么这样设计:AI 默认容易写“理想路径代码”。团队系统需要的是故障路径也可控。
部署设计不是上线前才想
部署设计应该在编码前就进入技术方案。因为很多代码决策会受到部署形态影响。
例如:
- 单实例部署时,本地内存缓存可能能跑;多实例部署时就会不一致。
- 本地文件存储开发方便;容器化部署后需要考虑挂载、备份和权限。
- 长任务同步执行简单;生产环境可能需要队列、超时和任务状态。
- 没有健康检查,编排系统无法判断服务是否可用。
最小部署设计至少写清楚:
| 项目 | 要说明什么 |
|---|---|
| 环境 | 本地、测试、生产分别怎么启动 |
| 组件 | 前端、后端、数据库、缓存、对象存储、外部服务各自职责 |
| 请求链路 | 用户请求经过哪些组件,哪里可能慢 |
| 配置 | 环境变量、密钥、连接串如何管理 |
| 健康检查 | 服务如何证明自己可用 |
| 日志指标 | 出问题时从哪里定位 |
| 回滚 | 发布失败后如何恢复 |
为什么这样设计:团队不是只交付代码,还要交付一个能运行、能排查、能恢复的系统。
把设计写进 CLAUDE.md
技术设计最终要转成智能体能执行的规则。适合进入 CLAUDE.md 的内容包括:
- 架构形态和原因。
- 模块划分和依赖方向。
- 分层职责。
- 外部调用的统一处理方式。
- 缓存、事务、错误码、日志规范。
- 数据库字段、索引、分页、迁移约定。
- 部署环境和运行命令。
- 明确不做的复杂度。
示例:
markdown
## 架构规则
- 当前系统采用模块化单体,不拆微服务。
- 跨模块调用只能走 Service 接口,禁止直接访问其他模块 Repository。
- Controller 只做参数校验、权限检查和统一返回,不写业务逻辑。
## 外部调用
- 所有外部 HTTP 调用必须设置连接超时和读取超时。
- 可重试调用必须保证幂等。
- 不允许在 Controller 中直接调用外部服务。为什么这样设计:技术方案只有写进智能体默认上下文,才能在每次任务里稳定生效。否则每个工程师都要重复解释,且很容易漏掉。
常见失败模式
| 失败模式 | 结果 | 修正方式 |
|---|---|---|
| 只写“用某技术栈” | AI 不知道模块和依赖边界 | 写清架构形态、模块职责和调用规则 |
| 不做数据设计 | 表结构随页面长出来 | 先拆核心实体、配置实体、状态实体 |
| 不设计失败路径 | 外部服务异常时系统不可控 | 统一超时、重试、降级、错误映射 |
| 部署后置 | 本地能跑,生产难运维 | 编码前定义环境、组件、健康检查和日志 |
| 设计不沉淀 | 每次会话重新解释 | 写入 CLAUDE.md、模块 README 和 review checklist |
最小模板
markdown
# 技术架构与部署设计
## 架构形态
- 当前选择:
- 为什么:
- 明确不选择:
## 模块边界
- 模块列表:
- 依赖方向:
- 禁止事项:
## 数据模型
- 主业务实体:
- 配置实体:
- 状态实体:
- 索引和分页约定:
## 外部调用
- 超时:
- 重试:
- 幂等:
- 降级:
- 日志:
## 部署设计
- 本地环境:
- 测试环境:
- 生产环境:
- 健康检查:
- 回滚方式:
## 需要写入 CLAUDE.md 的规则
-这个模板的目标不是一次想完所有细节,而是在 AI 写代码前,先把最容易造成长期维护成本的决策显性化。