Articles · AI Engineering

AI 时代,为什么设计原则、设计模式与 DDD 仍然重要

AI 降低了代码生产成本,却没有消除软件设计的复杂性。本文从 SOLID、设计模式与 DDD 出发,讨论如何把领域语义、模块边界和业务不变量转化为 Coding Agent 可以遵循并验证的工程约束。

AI 正在显著降低软件实现的成本:生成类、接口、API、数据库访问代码和测试,比过去更快。但代码生成速度提升,并不意味着系统复杂性同步下降。恰恰相反,当实现变得廉价,系统可能更快地产生大量模块、抽象和调用路径。如果缺乏明确的领域边界与架构约束,AI 可以很快地把一个错误的理解扩展成一套看似完整、实际上难以演进的软件。

因此,我更愿意把 AI 时代的软件工程理解为一次工作重心的迁移:

实现越来越便宜,正确地定义问题、建立抽象、约束变化并验证结果,反而更加重要。

SOLID 等设计原则、设计模式和领域驱动设计(DDD)并没有过时。它们分别处理不同层次的问题,也可以成为 Coding Agent 的工程约束基础。

一、设计原则:约束模块如何变化

通常所说的六大设计原则,是 SOLID 五项原则加上迪米特法则。它们不是要求开发者机械地拆分类,而是帮助我们控制模块之间的变化关系。

原则核心问题AI 工程中的意义
单一职责(SRP)一个模块为什么会变化?避免把多个业务职责堆进同一个服务或类
开闭原则(OCP)新需求是否必须修改稳定代码?让新工具、新模型和新策略通过扩展接入
里氏替换(LSP)不同实现是否遵守同一契约?确保不同 Runtime Adapter 的行为可以替换
接口隔离(ISP)调用方是否被迫依赖无关能力?给 Agent 提供职责清晰、权限明确的工具接口
依赖倒置(DIP)业务逻辑是否绑定具体基础设施?让业务层不依赖特定模型、数据库或 Agent 框架
迪米特法则(LoD)一个模块是否知道了太多内部细节?限制跨模块穿透访问,减少修改的连锁影响

例如,一个业务服务直接创建 DeepAgents 实例,后续切换到 Pi 或其他 Runtime 时,业务代码可能需要跟着修改。引入稳定的 Runtime 接口与适配器,可以把变化限制在基础设施边界内。

但抽象并非越多越好。如果目前只有一个实现,也没有明确的变化需求,提前设计多层接口可能只是增加理解成本。原则的价值在于识别变化原因,而不是为了符合形式而增加类和文件。

二、设计模式:为反复出现的变化提供结构

设计原则描述约束,设计模式则提供处理常见设计问题的可复用结构。在 Agent 系统里,常见模式有清晰的落点:

模式典型应用
Strategy(策略)模型路由、安全策略、计费策略
Adapter(适配器)统一 DeepAgents、Pi、不同模型供应商的接口
Factory(工厂)根据配置创建 Agent、工具或 Provider
Chain of Responsibility(责任链)输入检查、授权、风险审核与工具执行前检查
Decorator(装饰器)为工具增加鉴权、限流、日志、重试和指标
Observer(观察者)收集任务状态、工具调用与审计事件
State(状态)管理任务的等待、运行、审批、成功和失败状态
Command(命令)将设备操作或业务动作封装为可授权、可追踪的命令

例如,工具调用链可以组织为:

Agent
  ↓
Tool Gateway
  ↓
身份校验 → Policy Strategy → 风险检查
  ↓
Command 执行
  ↓
结果反馈与审计

这些模式能够帮助我们分离变化,但模式本身并不保证架构正确。把简单逻辑拆成十几个对象,也可能让系统更难理解。选择模式前,应先确认要隔离的变化是什么,以及这种变化是否真的会发生。

三、DDD:先弄清楚业务到底是什么

设计原则和模式解决了模块组织问题,但它们不能替代业务建模。DDD 的价值在于明确领域语言、业务规则、限界上下文和数据所有权。

以 Token 中转平台为例,表面链路可能只是“用户请求模型,平台转发并扣费”。实际业务却包含不同概念:

  • UsageRecord:一次模型调用产生的用量事实;
  • BillingPolicy:如何把用量转换为费用;
  • Account:当前账户额度与状态;
  • LedgerEntry:一笔不可随意覆盖的账务记录;
  • Settlement:一个结算周期内的核算结果。

如果不先区分这些概念,AI 很容易生成一个包含充值金额、赠送额度、消费金额和供应商成本的通用 balance 字段。原型可能很快跑通,但在退款、奖励、额度过期、并发扣费和供应商对账出现后,系统就会暴露出概念混乱的问题。

领域建模可以进一步识别限界上下文,例如 Identity、Billing、Account、Routing、Provider 和 Settlement。它们不必一开始就拆成独立微服务;模块化单体也可以拥有清晰的领域边界。关键是明确谁负责什么规则、谁拥有哪份数据,以及跨上下文如何交换信息。

DDD 最重要的产物不只是实体类,而是业务语言与不变量。

  1. 同一笔充值不能重复入账;
  2. 账务流水不能被普通更新随意覆盖,更正需要通过可追踪的冲正或调整;
  3. 并发扣费不能突破账户允许的额度边界;
  4. 用量事实、计费结果和实际结算成本不能被混为同一个数字。

这些规则应落在领域模型、数据库约束、事务边界和测试中,而不只是写在需求文档或 Prompt 里。

四、AI 时代的关键变化:从生成代码转向生成可验证的实现

AI 可以生成符合某些设计模式的代码,但这并不意味着它理解了业务边界。代码能够编译,也不代表领域规则正确;测试通过,也不代表测试覆盖了真正重要的不变量。

因此,Coding Agent 的工程流程应该从“根据需求生成代码”进一步发展为:

需求
 ↓
领域分析:概念、边界、业务不变量
 ↓
架构设计:模块职责、依赖方向、接口契约
 ↓
Coding Agent:实现代码与测试
 ↓
自动验证:类型、架构、业务规则、集成行为
 ↓
反馈:修复、重试、重新验证

这要求我们把设计思想分成两类:

可以机器验证的约束,应尽量转化为工具和自动化检查:

  • 依赖规则:禁止基础设施模块反向依赖领域层;
  • 接口契约:不同 Runtime Adapter 必须满足共同的行为约定;
  • 数据库约束:通过唯一键、事务和幂等机制避免重复入账;
  • 业务不变量:用单元测试、属性测试和并发测试验证额度与状态转换;
  • 运行时权限:每次敏感工具调用都必须经过可信授权入口。

需要结合语境判断的设计决策,则由开发者和 Agent 协同审查:一个模块是否真的只有一个变化原因、某个抽象是否值得存在、限界上下文划分是否符合业务语言,以及某种模式是否增加了不必要的复杂度。工具可以提供证据、检测风险,但不能把所有设计判断简化成一条静态规则。

五、把设计约束放进 Agent Runtime,而不只放进 Prompt

如果希望 Coding Agent 长期遵守架构规则,单纯在系统提示词里写“遵循 SOLID 和 DDD”是不够的。提示词是一种指导,不是强制边界。

  • 上下文层:提供领域词汇表、模块职责、架构决策记录和代码规范;
  • 规划层:要求任务先识别影响的领域、接口与不变量;
  • 执行层:通过工具权限、分支隔离和受控工作区约束修改范围;
  • 验证层:执行测试、静态分析、架构依赖检查和契约测试;
  • 反馈层:把失败信息反馈给 Agent,允许其修复后重新验证;
  • 审查层:对业务边界变更、数据迁移和高风险操作保留人工判断。

Prompt 让 Agent“知道”规则,工具和验证机制让 Agent“必须面对”规则的执行结果。比如,Agent 修改 Billing 模块后,如果架构测试发现它直接依赖 Provider 的数据库实现,流水线就应失败;如果改动扣费逻辑,就必须运行并发扣费和幂等性测试。这样,设计约束才从口头要求变成工程闭环。

六、三者如何协同:先建模,再约束,最后选择实现模式

DDD:定义业务语义与边界
          ↓
设计原则:约束模块职责与依赖
          ↓
设计模式:组织具体实现与变化点
          ↓
Coding Agent:生成代码与测试
          ↓
Harness:执行检查并反馈结果

这不是严格的单向流水线。实现与测试会不断暴露领域模型中的歧义,领域建模也可能反过来调整模块边界。但这三个层次不应混淆:

  • DDD 回答:系统里的业务概念是什么,规则归谁负责?
  • 设计原则回答:模块之间应该如何依赖,变化应被限制在哪里?
  • 设计模式回答:面对某类重复出现的设计问题,可以采用什么结构?
  • Harness 回答:如何让 Agent 按照约束工作,并用可重复的证据验证结果?

结语:设计能力将成为 AI 工程的放大器

AI 并没有让软件设计失去价值,而是改变了设计价值的体现方式。当代码需要大量手工编写时,开发者的时间经常消耗在实现细节;当 AI 能够快速生成实现时,真正的瓶颈更可能转向问题定义、领域语义、架构边界、验证标准和反馈闭环。

设计原则避免模块关系失控,设计模式帮助隔离变化,DDD 保证系统围绕正确的业务概念组织,而 Harness 则把这些思想转化为 Coding Agent 能够执行、接受检查并持续修正的工程过程。

AI 负责加速实现;工程设计负责定义什么才算正确;验证机制负责提供证据。

未来更有价值的能力,不只是让 Agent 写出更多代码,而是让它在清晰的领域模型和架构约束下,持续生成可理解、可验证、可演进的软件。