我让 Claude 从架构文档一路干到代码,踩了三个坑才摸清边界

前言

上个月,我尝试了一件听起来很"丝滑"的事:把项目的架构设计文档丢给 Claude,让它自动生成总纲、概要设计、详细设计、开发规约,然后按模块逐个开发。

想象中:文档进 → PRD 出 → 代码跑,全程 AI 包办,我喝茶看报。

实际上:文档进 → 冲突出 → 反复修 → 上下文炸 → 重新喂,我比没 AI 还累。

这篇文章复盘我从"盲目乐观"到"摸清边界"的全过程------不是教你"怎么用 Claude",而是告诉你 Claude 在复杂工程场景下到底哪里行、哪里不行**,以及怎么把不行的部分补上。


背景:为什么会有这个想法

我们项目有一套比较完善的架构设计文档:系统分层、模块划分、数据流向、接口约定都有明确定义。但文档归文档,落地开发还是要人一行行写。

我就想:既然 Claude 号称能理解长文档、能写代码,能不能直接把架构文档喂给它,让它先产出全套设计文档(总纲→概设→详设→开发规约),再按模块逐个生成 PRD,最后根据各模块 PRD 写代码?

流程设计是这样的:

markdown 复制代码
架构设计文档(输入)
       ↓
Claude 生成《项目总纲》← 定范围、定目标、定约束
       ↓
Claude 生成《概要设计》← 模块划分、接口定义、数据流向
       ↓
Claude 生成《详细设计》← 类图、时序图、字段级定义
       ↓
Claude 生成《开发规约》← 命名规范、代码结构、异常处理约定
       ↓
按模块逐个生成《模块PRD》← 每个模块的技术方案、接口清单、数据模型
       ↓
按模块逐个开发 ← 基于对应的模块PRD生成代码

为什么要加"模块 PRD"这一步? 因为详设和开发规约是宏观约束,落到具体模块时,接口签名、参数校验规则、异常场景处理都需要一个更细粒度的"施工图纸"。我以为这个分层设计是加分项------先锁定方案,再写代码,逻辑上没毛病。

理想很丰满。然后现实开始教我做人。


第一坑:多文档并存时,Claude 的业务理解"串"了

现象

架构文档里对同一个业务概念,在不同章节可能有不同角度的描述。比如"用户订单状态流转",在总纲里是一句话带过,在概要设计里是个状态机图,在详细设计里是字段级的枚举定义。

当我把这些文档同时喂给 Claude 生成详设和开发规约时,问题来了:Claude 产出的详设里,订单状态枚举和概要设计里的状态机对不上------多了两个状态,少了一个状态转换路径。

更离谱的是,开发规约里定义的异常处理方式,和详设里接口的错误码设计互相矛盾:规约说"所有异常统一抛 BusinessException",详设里却在某个接口上写了"此接口需区分 ValidationException 和 BusinessException"。

诊断

我把架构文档、Claude 生成的总纲、概设、详设、规约全部拿出来横向对比,发现冲突集中在跨文档的业务规则一致性上:

冲突类型 出现频率 典型案例
枚举值不一致 概要设计定义 5 个状态,详设定义了 7 个
异常策略冲突 规约统一异常,详设按接口特化
命名不一致 同一个 DTO 在概设叫 OrderInfo,详设叫 OrderDetailDTO
接口参数遗漏 概设定义了分页参数,详设接口签名里丢了

根因

Claude 不是真正"理解"业务,它是在做跨文档的模式匹配。 当同一个概念在多份文档中以不同粒度、不同角度出现时,Claude 没有"这是同一件事"的强约束意识。它只是分别处理每份文档,然后"拼凑"输出。

换句话说:人类看文档会建立"同一个概念"的心智模型,Claude 不会。 它对每份文档的 attention 是均等的,不会自动识别"总纲里的'订单状态'和概设里的'订单状态机'是同一个东西"。

text 复制代码
人类的理解路径:
总纲"订单状态" → 概设"订单状态机" → 详设"OrderStatus枚举"
       ↓                ↓                   ↓
     三者是同一个概念,必须一致 ← 这是人类的直觉

Claude 的处理路径:
总纲"订单状态" → 独立理解 → 输出涉及订单状态的描述
概设"订单状态机" → 独立理解 → 输出涉及状态机的描述
详设"OrderStatus枚举" → 独立理解 → 输出枚举定义
       ↓
     三者之间没有强制一致性约束 ← 冲突的源头

第二坑:上下文长了,Claude 开始"忘记"参考文档

现象

按模块开发时,我的流程是先让 Claude 生成该模块的 PRD(接口清单、数据模型、异常处理约定),审阅通过后再让它写代码。总纲 + 概设 + 详设 + 开发规约全部作为上下文持续存在。

开发第二个模块时也不错。但到第三个模块,问题来了------不仅是代码偏了,连模块 PRD 本身都开始偏了

  • 模块 3 的 PRD 里,接口路径风格从 /api/v1/order 变成了 /order/api/v1
  • 异常处理方式退化成了 Claude 自己的"默认习惯",完全忽略了规约里"统一抛 BusinessException"的约定
  • 我需要在每次对话开头反复说"请参考之前提供的《开发规约》",它才能勉强回到正轨

PRD 偏了,代码必然偏。 这个问题比代码写歪更致命------因为 PRD 在我眼里是"审阅过的施工图",我默认它是正确的。结果代码写出来跑不通才往回追,发现 PRD 本身就和规约冲突了。

诊断

统计了一下,开发 5 个模块的过程中,我明确提醒 Claude "参考之前文档"的次数

复制代码
模块 1:0 次(文档刚喂,新鲜)
模块 2:1 次(开始出现小偏离)
模块 3:3 次(大量偏离,需要反复强调)
模块 4:4 次(几乎每次输出后都要纠正)
模块 5:放弃治疗,手动修改

根因

这背后是两个问题叠加:

问题一:上下文窗口的"稀释效应"

Claude 的上下文窗口虽然大,但不是所有内容的"权重"都一样。当对话轮数增加,早期的参考文档逐渐被推到上下文深处,Claude 对这些内容的"注意力"自然降低。

text 复制代码
对话开始时:
[架构文档][总纲][概设][详设][规约][用户指令1] ← Claude 注意力均匀

对话进行中(第 5 轮):
[架构文档]...[总纲]...[概设]...[详设]...[规约][指令1][代码1][指令2][代码2][指令3]...
  ↑ 距离当前轮次越来越远,注意力越来越弱

问题二:Claude 的"渐进式漂移"

每次生成代码时,Claude 会参考最近生成的代码风格。当它生成的代码和规约有微小偏差时,下一轮它会把自己的偏差当作"正确示例"继续放大------这是一个自我强化的漂移过程。

text 复制代码
轮次 1:生成代码,95% 符合规约 ✅
轮次 2:参考轮次 1 的代码 + 部分规约 → 90% 符合规约 ⚠️
轮次 3:参考轮次 2 的代码 + 少量规约 → 80% 符合规约 ⚠️
轮次 4:参考轮次 3 的代码 + 几乎忘记规约 → 60% 符合规约 ❌

问题三(更深也更隐蔽):核心业务逻辑偏差

前面说的主要是格式、风格层面的偏离------这类问题肉眼看得出来。但更让我头疼的是业务逻辑层面的偏差------代码编译通过、风格符合规约、接口签名全对,但跑起来的行为是错的。

这类问题很难举一个"漂亮的代码例子",因为它本质上不是某一行写错了,而是Claude 对整个业务场景的理解停留在文档的文本层面,缺少业务方脑子里的"隐含知识"

举个例子:PRD 里写了"下单时校验库存并扣减",Claude 生成的代码确实做了这两件事------先查库存、再扣库存,代码结构没问题。但实际跑起来发现,高并发下会出现超卖。因为业务方默认的期望是"校验和扣减是原子的"------这个对业务方来说是常识,PRD 里不需要写。但对 Claude 来说,"先查再扣"和"原子扣减"是两种不同的实现方式,它只会选它见过更多的那个。

再比如订单状态流转------PRD 里写了标准路径 PENDING → PAID → SHIPPED。Claude 按这个写了状态机,没问题。但业务方后来提到"已支付但超时未发货的订单,客服可以介入取消",这是个隐藏分支,不在 PRD 里。Claude 不可能知道,生成的代码就没处理这个场景。

核心矛盾 :PRD 写的是"显式规则",但真实业务里存在大量"隐式规则"------业务方的默认假设、历史遗留逻辑、口头交代的边界条件。这些东西不会出现在任何文档里,但对 Claude 来说,文档之外的世界不存在

这类问题比格式偏离危险太多------风格偏了肉眼看得到,业务逻辑偏了要跑完整测试、看真实数据才能发现。对于复杂业务场景,Claude 写出"看起来完全正确但逻辑错误"的代码,是比语法错误更隐蔽的坑。


第三坑:你以为"增量开发",Claude 在"重新发明"

现象

完成模块 1 后,我想让 Claude 开发模块 2,并期望它复用模块 1 的基础设施代码(如公共工具类、BaseController、统一异常处理器等)。

结果 Claude 在模块 2 里重新写了一套异常处理逻辑,和模块 1 里已经写好的完全重复,实现方式还不一样。

诊断

我对比了两个模块的代码:

rust 复制代码
模块 1(手动定义的基础设施):
├── BaseController.java
├── GlobalExceptionHandler.java  ← 统一异常处理
├── BusinessException.java
└── Result.java                  ← 统一返回体

模块 2(Claude 生成的代码):
├── OrderController.java         ← 没继承 BaseController
├── OrderExceptionHandler.java   ← 又写了一套异常处理!
└── OrderResult.java             ← 又定义了一套返回体!

模块 2 不仅没有复用模块 1 的基础设施,还重复发明了功能等价但实现不同的组件

根因

Claude 没有"项目已经有什么"的全局视图。每次交互它只能看到你喂给它的上下文。我没把模块 1 的代码结构喂给它,它自然不知道基础设施已经存在。

这不是 Claude 的错,是我的 prompt 策略没跟上。 我以为"按模块开发"是自然而然的增量过程,但对 Claude 来说,每次都是重新开始。


改进方案:我是怎么把这件事做对的

复盘之后,我调整了策略,重新走了一遍流程。以下是实测有效的改进方案

改进一:建立"单一事实来源"------文档合并 + 显式约束

核心思路 :不让 Claude 同时读多份文档,而是由我先把文档合并成一份结构化的"事实来源",消除多文档之间的歧义。

markdown 复制代码
# 项目事实来源(喂给 Claude 的 unified spec)

## 业务实体定义
- 订单状态:PENDING / CONFIRMED / PROCESSING / SHIPPED / COMPLETED / CANCELLED(共6个,不可增减)
- 支付状态:UNPAID / PAID / REFUNDING / REFUNDED
- ...

## 统一异常策略(强制)
- 所有 Controller 抛出的异常统一使用 BusinessException
- 参数校验失败使用 ValidationException(ExceptionHandler 中统一处理)
- **禁止**在业务代码中 catch 后 return null,必须抛异常

## 命名规范(强制)
- DTO 命名:{Entity}{Action}DTO(如 OrderCreateDTO)
- Service 接口命名:I{Entity}Service
- Controller 路径:/api/v1/{entity}

效果:多文档冲突问题基本消除。因为冲突的源头(同一个概念在不同文档中有不同描述)被我在预处理阶段消除了。

改进二:分层 Prompt 策略------每轮强制注入"锚点"

核心思路:不在对话开头一次性喂完所有文档。而是每轮对话都强注入当前模块需要的"最小规则集"。

text 复制代码
改进前(一次性注入):
[总纲 + 概设 + 详设 + 规约] → 对话 1 → 对话 2 → 对话 3 → ...
                                  ↑ 锚点逐渐丢失

改进后(每轮注入):
对话 1:[当前模块详设 + 规约摘要] → 生成模块 1 代码
对话 2:[当前模块详设 + 规约摘要 + 模块 1 接口清单] → 生成模块 2 代码
对话 3:[当前模块详设 + 规约摘要 + 模块 1/2 接口清单] → 生成模块 3 代码

每轮注入的"规约摘要"控制在 200 行以内,只包含和当前模块相关的规则。宁可多花 30 秒整理上下文,也不让 Claude 在 5000 行的上下文里自己找规则。

效果:偏离率从模块 3 开始就回升的曲线,变成了始终保持 90%+ 的一致性。

改进三:基础设施"锁定"------先让 Claude 知道有什么,再让它写

核心思路:在开发每个模块之前,显式告诉 Claude 项目已有的基础设施。

text 复制代码
# 每个模块开发前的 prompt 模板

## 已有基础设施(直接使用,不要重新发明)
- 异常处理:GlobalExceptionHandler(路径:com.xxx.exception.GlobalExceptionHandler)
- 统一返回体:Result<T>(路径:com.xxx.common.Result)
- 基础 Controller:BaseController(路径:com.xxx.controller.BaseController)
  → 所有新 Controller 必须继承 BaseController

## 已有模块接口清单(如需调用)
- 用户模块:UserService.getById(Long id)
- 权限模块:AuthService.checkPermission(Long userId, String resource)

效果:重复造轮子的问题彻底消失。而且因为 Claude 知道了已有的接口,模块间的调用代码也是一次生成对的。

改进四:加入校验节点------不要让 Claude 的产出直接进代码库

这是最关键的一步。 改进后的流程中,我在三个节点设了人工校验:

text 复制代码
1. 详设产出校验:逐项对比概设,检查枚举值、接口签名、异常策略的一致性
2. 规约产出校验:和详设交叉验证,重点看异常处理是否自相矛盾
3. 模块代码校验:CheckStyle / ArchUnit 自动检查 + 核心业务逻辑走查
   → 重点走查:金额计算、状态流转、权限判断、优惠券/积分等敏感规则
   → Claude 最容易在这些地方写出"看起来对、逻辑错"的代码

效果:校验成本远低于修复成本。花 10 分钟校验比花 2 小时修 BUG 划算得多。


改进后的完整流程

text 复制代码
                    架构设计文档
                         ↓
              ┌─ 人工整理为"统一事实来源" ─┐
              │  (消除多文档冲突)          │
              └─────────────────────────┘
                         ↓
         ┌──────────────────────────────┐
         │ Claude 生成总纲                │
         │ Claude 生成概设                │
         │ Claude 生成详设 ──→ 人工校验节点①
         │ Claude 生成开发规约 ──→ 人工校验节点②
         └──────────────────────────────┘
                         ↓
         ┌──────────────────────────────┐
         │ 按模块生成 PRD + 开发            │
         │  (分层 prompt 策略)            │
         │                                │
         │ 模块 1: [规约摘要] → PRD → 代码  │
         │ 模块 2: [规约摘要+模块1接口] →   │
         │         PRD → 代码              │
         │ 模块 3: [规约摘要+模块1/2接口] → │
         │         PRD → 代码              │
         │ 每个模块 PRD + 代码 → 校验节点③  │
         └──────────────────────────────┘

核心认知:Claude 是"高级执行者",不是"架构师"

做完这次实战,我最深的体会是:

环节 Claude 能做的 Claude 做不好的 人必须做的
理解业务 从文档中提取描述 跨文档保持一致性 定义"唯一事实来源"
产出设计 基于模板大量产出 保证设计之间的约束不冲突 校验跨文档一致性
写代码 单模块内高质量产出结构代码 核心业务规则容易遗漏或写错 定义业务规则 + 关键路径走查
复用代码 给了接口清单就能用 不知道已有什么 维护"已有组件清单"
业务逻辑 能生成"看起来对"的代码 金额/状态/权限等敏感逻辑易出错 重点走查 + 单元测试覆盖

一句话总结 :Claude 能高质量地执行一个被明确定义的任务,但无法在没有人类"约束框架"的情况下自主保证大型工程的一致性。你的工作不是"让 Claude 替代你写代码",而是为 Claude 搭建一个它不会跑偏的执行环境


适用场景建议

基于这次经历,我给不同规模的工程需求一个建议:

场景规模 推荐方式 关键动作
单模块独立开发 Claude 直接上,效果好 给清楚需求和上下文即可
2-3 个关联模块 Claude + 规约注入 每个模块都要注入核心规则
5+ 模块协同 Claude + 统一事实来源 + 分层 prompt 前置工作比开发工作还重要
系统级重构 不建议全靠 Claude 先用 Claude 做分析和评审,开发自己来

本文基于真实项目经历写成。AI 工具的能力边界是试出来的,不是听来的。如果你也正在尝试用 AI 辅助复杂工程开发,欢迎交流踩坑经验------踩过的坑才是真正的护城河。

相关推荐
Zane19941 小时前
并发 vs 并行:别再傻傻分不清了,一文讲透 Java 并发编程的第一课
java·后端
神奇小汤圆1 小时前
线程池拒绝策略CallerRunsPolicy反而卡死了主线程
后端
神奇小汤圆1 小时前
Jaws:从零构建一个”五脏俱全”的 Java RPC 框架
后端
Csvn2 小时前
📊 SQL 入门 Day 10:递归 CTE — 破解无限层级查询的终极武器
后端·sql
echohelloworld112 小时前
HarmonyOS开发实战:小分享-CreateSelectPage创建分享类型选择器
后端
啊湘2 小时前
天气查询API接口 按月Token鉴权 实时天气 物联网可用 文档齐全
java·后端·struts
用户69371750013842 小时前
从代码生产者到 AI 协作者:软件工程师的角色重构
android·前端·后端
Java内核笔记2 小时前
告别十亿美元的错误 : Spring Boot 4 空安全 (JSpecify) 实战
java·spring boot·后端
码栈研说3 小时前
Go 语言大白话入门 10 - 排序与常用数据操作
后端·程序员