夜雨聆风学习资料网

ARTICLE · 1062076

大模型时代,软件设计为什么不能再从“需求”开始?

大模型时代,软件设计为什么不能再从“需求”开始?

大模型越来越强以后,一个很自然的想法是:

需求写清楚,让 AI 一条一条设计、一条一条实现,不就可以了吗?

个人经过2026年上半年的疯狂vibe coding后做下来发现,恰恰相反。

vibe coding 非常爽,看到之前各种idea和想法飞快的实现是一种比打游戏还上瘾的事儿,但是半年之后要为前面的自我放飞买单了。

“AI 越强,越不能按需求碎片直接生成设计”

强大的LLM可以非常快地把每一个局部需求设计得“看起来合理”,但如果这些局部设计分别发明自己的实体、状态、存储和规则,最后得到的往往不是一个系统,而是一堆彼此重叠、自相矛盾的局部系统。

贴一段当时的prompt,当时虽然已经意识到这个问题但解决的并不彻底,为后期的反复重构挖了深坑。

按照航天级别的要求,按产品设计和软件工程的角度梳理当前的系统设计的单一事实源缺失、模块职责不清、接口契约不清、状态流混乱、全局一致性逻辑闭环、"负空间"——本该存在却缺失的连接边、“数值语义”(尤其是 rank tie、分档边界、关键因子缺失这类值路径)等问题,基于第一性原理原则,注意收敛避免无限发散,从数据流转逻辑、时序逻辑、状态生命周期、事件序列图角度迭代多轮审核,最后汇总问题等待确认再处理

所以,LLM 时代的软件设计,需要改变的不是“怎么让 AI 写更多设计文档”,而是:

谁有权决定什么。


一、真正的问题不是设计不够详细,而是“决定权散落了”

以前的软件开发慢。一个需求从分析、设计到开发可能需要几周甚至几个月。这种速度天然限制了错误扩散。

但 Agent 可以在一天之内连续完成几十个需求。这时候,一个错误的设计机制会被极速放大。

这是我项目中做的一个同步功能

有这样几个需求:

  • 离线可以继续编辑;

  • 联网后自动上传;

  • 上传失败可以恢复;

  • 多设备同时修改不能丢数据;

  • 冲突内容必须可以找回。

如果让 AI 针对每个需求分别设计,很容易得到:

离线编辑
→ 一套 pending 状态

自动上传
→ 一套 upload queue

失败恢复
→ 一套 retry record

多设备冲突
→ 一套 conflict state

历史恢复
→ 又一套 revision state

每一块单独看都成立。

放在一起却会出现一个致命问题:

到底哪一个才是真实状态?

于是系统开始出现:

  • 多份状态;

  • 多份账本;

  • 多套重试逻辑;

  • 多个“事实来源”;

  • 无法解释的恢复路径。

这也是当前这个百万行级别项目复杂度突然失控的真正原因。

不是代码写得太差。

而是:

下层拥有了本来应该属于上层的决定权。


二、设计的第一原则:每一层只能决定下一层无权决定的事情

一个更稳定的设计方法,是把整个系统按照四层组织:

系统
 ↓
子系统 / 领域
 ↓
能力
 ↓
需求

最重要的不是这四个名字。

而是:

越往上,决定越稳定、越全局;
越往下,只允许引用和补充,不允许重新发明。

可以把它理解成一套“设计宪法”。


三、第一层:系统设计,只决定全局规则

系统层不要写几十页功能描述。它只需要决定那些下层绝对不能各自决定的问题。

例如:

  • 系统由哪些部分组成?
  • 谁拥有什么数据?
  • 什么对象拥有稳定身份?
  • 哪一份数据是权威来源?
  • 跨端一致性是什么模型?
  • 哪些协议是唯一接口?
  • 系统发生崩溃后必须保证什么?

例如一个文件型知识系统,可以先确定:客户端、同步服务、账号与权益、发布分享、后台管理,然后定义一些整个系统只能有一份答案的问题:

  • Space 是什么?
  • Device 是什么?
  • Entry 是什么?
  • Version 是什么?
  • 谁拥有它?
  • 哪里保存权威数据?
  • 允许不允许复制第二份账本?

这些一旦决定,下层不允许重新定义。

这一步的本质是:建立系统的不变量,而不是设计功能。


四、第二层:领域设计,是整个体系最重要的一层

所以一个相对复杂的系统真正应该作为“设计单位”的,不是需求,而是领域。

例如:同步域、编辑与保存域、知识组织域、账号与权益域、发布与分享域、服务运行域

每一个领域只需要回答五类问题:

① 有哪些实体,它们的稳定身份是什么?

② 有哪些持久事实?
   每个事实谁拥有?

③ 状态有哪些?
   状态从什么事实推导出来?

④ 与外部通过什么端口和协议交互?

⑤ 哪些不变量永远不能被破坏?

例如同步领域可以规定:

上传记录是事实;“正在上传”只是投影。

确认记录是事实;“已同步”由确认链推导。

冲突版本是事实;“发生冲突”由版本关系推导。

这时候,后面无论增加:自动同步、手动同步、后台同步、失败重试、历史恢复、多设备冲突,都不能重新发明另外一套“同步状态”,只能使用已有模型。

这就是避免系统碎片化的核心。


五、第三层:能力设计,才开始回答“这个功能怎么工作”

领域模型稳定以后,才进入具体能力。

例如:

打开文件
保存文件
附件分片上传
全文搜索
任务查询
同步恢复

能力设计不再发明系统模型。

而是回答:

它使用哪些已有实体?

经过哪些已有状态?

涉及哪些场景?

失败时走哪条状态路径?

恢复时如何回到稳定状态?

最终如何证明成功?

这时候场景和用户故事就非常重要。

但它们的身份发生了变化。

以前:

用户故事 → 生成设计。

现在:

用户故事 → 验证设计。

这是一个非常重要的变化。


六、第四层:需求只允许描述“增量”

到了具体需求,原则应该更加严格。

一条需求只允许:

引用上层模型
+
描述自己的差异
+
定义反例
+
定义验收

不允许出现新的:

核心实体
核心状态
持久事实
所有权模型
一致性模型

如果一个需求真的需要这些东西,就说明:

它不是一个局部需求变化,而是在修改领域模型。

那就必须回到第二层。

这条规则非常重要。

因为它阻止了复杂系统最常见的一种熵增:

偷偷在功能需求里修改架构。


七、因此:需求不是设计的“生成单位”

这可能是整套方法最值得记住的一句话:

需求是覆盖索引,不是设计生成单位。

需求负责告诉我们:系统必须覆盖什么?场景负责告诉我们:系统必须经历什么?测试负责告诉我们:系统是否真的做到了?

但:

系统本身应该如何存在,必须由更高层模型决定。


八、同步系统尤其不能按需求设计

同步、协同、支付、订单、权限、消息这类系统尤其如此。因为它们本质上不是普通 CRUD。

它们首先是:状态与一致性系统

以同步为例,第二层就必须回答四个问题。

1. 一致性模型是什么?

例如:单文件版本如何排序?跨设备变化如何建立因果关系?客户端游标什么时候允许前进?重复请求是否幂等?

这些不应该等到某一个“同步失败需求”才考虑。


2. 冲突是什么?

很多系统会本能地想:

AI 能不能自动合并?

但自动合并其实只是策略之一。更重要的问题是:

是否允许覆盖?
是否必须保留双方内容?
谁拥有最终决策权?
冲突本身是不是一种一等状态?

对于知识文件,很多时候:

不丢任何一方内容,比自动生成一个看起来正确的版本更重要。


3. 崩溃以后,什么仍然可信?

系统随时可能:

断电、进程崩溃
网络中断
请求超时
客户端重启
服务器重复执行

因此状态不能依赖:

“程序刚才执行到了哪一步。”

而应该依赖:

现在持久化世界中有哪些事实。

这是可靠系统和脆弱系统的根本区别。


4. 怎么证明它是正确的?

仅仅写几个正常测试远远不够。

应该验证:

断网
重复请求
乱序
崩溃
重启
多客户端竞争
部分成功
超时后重试

甚至可以用 TLA+、Quint 等轻量形式化模型描述关键状态关系,再通过故障注入和模拟测试验证实现。

因为这种领域:

真正昂贵的不是多写一点设计,而是上线以后才发现状态模型错了。


九、三种经典方法,其实分别解决三个不同问题

传统软件工程里已经有很多成熟方法。

它们没有过时。

只是应该重新组合。

DDD:解决“谁拥有什么”

领域驱动设计关注:边界、概念、所有权、上下文

非常适合作为第二层结构。


场景驱动设计:解决“用户能不能走通”,用户旅程、Use Case、时序图非常适合检查:正常路径、失败路径、恢复路径、跨领域路径。

但它们适合作为:验证模型。不适合作为:系统模型。


ADD / ATAM:解决“什么质量要求会改变架构”

例如:离线、并发、恢复、安全、性能、容量

这些要求不能等到开发以后再优化。它们往往从第一层就决定:架构应该长什么样。

因此更合理的组合是:

DDD - 决定结构
ADD - 决定重大架构策略
Scenario - 验证模型是否覆盖真实世界

它们并不是三选一。而是三个正交维度。


十、LLM 时代,设计真正发生的变化

过去我们担心:工程师忘记设计。

未来更应该担心:Agent 设计得太快。

一个 Agent 可以连续生成:需求分析、数据结构、接口、状态、代码、测试

如果不给它结构约束,它会非常自然地在每一个局部问题里创造局部最优解。

最终形成:局部正确,整体错误

所以 LLM 时代的软件设计,并不是减少架构。

反而需要更明确地区分:什么必须由人或者上层架构决定;什么可以交给 Agent 自主完成。


十一、可以直接落地成一套简单规则

如果要把整篇文章压缩成一个团队可以执行的标准,我会只保留下面三条。

规则一

一个持久事实只能有一个所有者。如果两处都认为自己拥有事实:

系统迟早出现双账本。


规则二

下层不得创造上层未定义的新状态。

如果能力设计突然需要一种新状态:先回到领域模型。


规则三

需求负责证明“覆盖”,不负责创造“世界”。

每个需求最终必须能够指向:

所属能力
→ 所属领域
→ 使用的系统规则
→ 对应场景
→ 验证证据

形成完整链条:

System
  ↓
Domain
  ↓
Capability
  ↓
Requirement
  ↓
Scenario
  ↓
Test
  ↓
Evidence

而不是:

Requirement
  ↓
AI
  ↓
Code


十二、最终真正需要管理的,不再是文档

传统的软件管理系统主要管理:需求、任务、Bug、测试用例、文档,但这些都只是表象。

LLM 时代真正值得管理的是五种东西:

Intent      为什么做
Model       世界如何工作
Constraint  什么不能违反
Decision    为什么这样选择
Evidence    凭什么相信做对了

代码可以重新生成。任务可以重新拆分。测试可以重新生成。甚至很多设计文档也可以重新生成。

但是:模型、约束、决定和证据不能丢。

这才是复杂软件在 Agent 时代真正需要保存的“工程状态”。


最后

大模型正在迅速降低代码生产成本。

但这并不意味着软件工程会越来越不需要设计。

恰恰相反。

当一个 Agent 可以在几个小时里完成过去几周的工作时,我们必须更加明确:哪些事情允许它自己决定?

以及:哪些事情必须在它开始工作之前,就已经被系统确定下来?

所以未来好的软件设计体系,不应该要求人把每一步都告诉 AI。

也不应该简单地把一堆需求扔给 AI。

更合理的方式是:上层决定世界,下层解决问题。

系统层定义不变量。

领域层定义事实与状态。

能力层定义行为。

需求层定义增量与验收。

然后让 Agent 在这些边界之内自由发挥。

这可能才是真正适合大模型时代的软件工程。

Codex astra能力越来越强,工作结果反而更差

“LLM工作台” 复杂项目使用AI的踩坑经验分享

证明可以加速,理解不能批发

----------
我是oceanbj,一个全力奔跑去拥抱AI的践行者,分享opc过程中的踩坑的一些经验和思考,欢迎你来碰撞交流。

相关学习资料