SOLID 原则的 AI 时代重构:从面向对象到 Agent 协作
TL;DR
本文核心观点:
- 设计原则的演进 — 传统 SOLID 原则诞生于面向对象时代,旨在解决类级别设计的耦合问题;在 AI-Native 时代,软件系统的核心单元已从类演变为 Agent,需要全新的设计原则。
- 抽象层次的跃迁 — SOLID 原则在 2000-2020 年间指导了数以百万计的软件设计,但在 AI-Native 时代,Agent 不是更好的类,而是完全不同的抽象层次,其局限性日益明显。
- 新 SOLID 原则 — 本文提出新 SOLID 原则(SCP/OCP-P/LAP/ISP/DIP),将设计哲学从”对象协作”升维到”Agent 协作”,通过 Capability Contract、Intent Router 和抽象层依赖倒置驾驭这种转变。
- 核心洞察 — 一个 Agent 应该只负责一种核心能力,Agent 的输出应该忠实反映其内部推理过程,复杂性来自协作而非单个 Agent 的能力。
SOLID 原则回顾
在重构之前,让我们快速回顾 Robert C. Martin 在 2000 年提出的 SOLID 原则:
单一职责原则 (SRP)
一个类应该只有一个引起它变化的原因。
开闭原则 (OCP)
对扩展开放,对修改关闭。
里氏替换原则 (LSP)
子类型必须能够替换其基类型而不改变程序正确性。
接口隔离原则 (ISP)
客户端不应该被迫依赖它们不使用的接口。
依赖倒置原则 (DIP)
高层模块不应该依赖低层模块,两者都应该依赖抽象。
面向对象时代的 SOLID 局限
SOLID 原则在 2000-2020 年间指导了数以百万计的软件设计,但在 AI-Native 时代,它们的局限性日益明显:
💡 Key Insight
传统思维追求 100% 确定性,但 AI 系统天然是概率性的——这一根本差异渗透到从执行模型到状态管理的每一个设计维度。
局限一:假设了确定性的执行模型
传统 SOLID 假设:
- 方法调用是同步且确定的
- 返回值是可预测的
- 副作用是可控的
但 Agent 的行为是概率性的:
- 同样的输入可能产生不同输出
- 执行时间不确定
- 可能调用外部工具产生不可预测副作用
局限二:忽视了上下文和状态管理
传统设计将状态封装在对象内部,但 Agent 需要:
- 上下文窗口管理:有限的 token 预算
- 长期记忆:跨会话的信息保持
- 工作记忆:当前任务的临时状态
局限三:无法处理涌现行为
传统设计追求可预测性,但 Agent 系统的一个重要特性是涌现——整体行为不等于部分之和。
当多个 Agent 协作时,会产生设计者未明确编程的行为。SOLID 原则无法指导这种涌现系统的设计。
局限四:接口定义过于静态
传统接口是编译时契约:
但 Agent 的能力是动态的:
- 通过 prompt 工程可以”教授”新能力
- 工具调用列表可以动态扩展
- 不同模型版本能力差异巨大
局限五:忽视了反馈和学习循环
传统软件是”编写一次,运行多次”,但 AI 系统需要:
- 从反馈中学习
- 持续优化 prompt
- 版本化管理模型和策略
| 维度 | 传统软件 | AI-Native 系统 |
|---|---|---|
| 正确性 | 确定性 | 概率性 |
| 扩展方式 | 继承/组合 | Prompt 工程 + 工具注册 |
| 状态管理 | 对象字段 | 上下文 + 记忆 |
| 接口 | 静态类型 | 动态能力描述 |
| 演化 | 版本发布 | 持续学习 |
AI-Native 时代的 SOLID 重构
面对上述局限,我们需要一套新的设计原则。这不是对 SOLID 的否定,而是在更高抽象层次上的重构。
💡 Key Insight
Agent 不是更好的类,而是完全不同的抽象层次——这一认知转变是理解新 SOLID 原则的前提。
从 Class 到 Agent:抽象层次的跃迁
关键区别:
| 特性 | Class | Agent |
|---|---|---|
| 激活方式 | 方法调用 | Intent + Context |
| 执行逻辑 | 确定性代码 | LLM + Tool Calling |
| 状态管理 | 字段封装 | Context Window + Memory |
| 能力扩展 | 继承/组合 | Prompt 调整 + Tool 注册 |
| 交互模式 | Request/Response | 多轮对话 + 自主决策 |
从 Interface 到 Intent:契约形式的转变
传统接口定义”能做什么”:
Intent 定义”意图和期望结果”:
核心转变总结
新 SOLID:适用于 Agent 协作的设计原则
基于上述分析,我提出适用于 AI-Native 开发的新 SOLID 原则:
💡 Key Insight
一个 Agent 应该只负责一种核心能力,并通过清晰的 Capability Contract 定义其边界——这是避免”上帝 Agent”反模式的关键。
S - 单一能力原则 (SCP)
一个 Agent 应该只负责一种核心能力,并通过清晰的 Capability Contract 定义其边界。
核心思想:
- 每个 Agent 专注于一个领域(如数据查询、代码生成、客户服务)
- 避免”上帝 Agent”试图做所有事情
- 通过 Capability Contract 明确声明能力范围
对比表格:
| 传统 SRP | 新 SCP |
|---|---|
| 单一变化原因 | 单一核心能力 |
| 职责 = 业务功能 | 能力 = 领域专精 + 工具组合 |
| 通过类拆分实现 | 通过 Agent 专业化 + Contract 定义 |
| 编译时检查 | 运行时 Capability 匹配 |
O - 提示工程开闭原则 (OCP-P)
Agent 的核心行为应该通过 Prompt 模板扩展,而非修改代码。
核心思想:
- 将行为逻辑外置到 Prompt 模板
- 通过 Prompt 变量和模板继承实现扩展
- 支持 A/B 测试和动态行为切换
L - 忠实表达原则 (LAP)
Agent 的输出应该忠实反映其内部推理过程,而非隐藏或伪造。
核心思想:
- Agent 应该”展示其工作”(show your work)
- 区分”推理过程”和”最终输出”
- 便于调试、审计和信任建立
对比表格:
| 传统 LSP | 新 LAP |
|---|---|
| 子类型可替换父类型 | 输出应忠实反映内部过程 |
| 关注类型兼容性 | 关注透明度和可审计性 |
| 编译时类型检查 | 运行时推理链验证 |
| 防止继承误用 | 防止”幻觉”和不可信输出 |
I - 意图隔离原则 (ISP)
复杂的用户请求应该被分解为独立的 Intent,每个 Intent 由专门的 Agent 或 Tool 处理。
核心思想:
- 使用 Intent Router 分解复合请求
- 每个 Intent 对应单一、明确的目标
- 避免强迫一个 Agent 处理它不擅长的任务
D - 抽象层依赖倒置 (DIP)
Agent 不应该直接依赖具体的 LLM 或工具实现,而应该依赖抽象的 Capability Interface。
核心思想:
- 定义 Capability 抽象接口
- LLM、工具、记忆系统都实现这些接口
- 支持灵活替换(模型升级、工具切换)
实战:应用新 SOLID 设计 Agent 系统
让我们通过一个完整的实例来演示如何应用新 SOLID 原则设计一个多 Agent 系统。
场景:智能客服系统
我们需要设计一个能够处理多种客户请求的智能客服系统:
- 订单查询
- 退款处理
- 技术支持
- 产品推荐
系统设计
完整代码实现
以下代码展示了一个简化但完整的多 Agent 客服系统实现,涵盖 Intent 路由、Agent 专业化分工和 Capability 抽象接口。
Capability 接口定义:
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import List, Optional
@dataclass
class Capability:
name: str
description: str
input_types: List[str]
output_type: str
class CapabilityContract(ABC):
@abstractmethod
def get_capabilities(self) -> List[Capability]:
pass
@abstractmethod
def can_handle(self, intent: str) -> bool:
pass
OrderQueryAgent 实现:
class OrderQueryAgent(CapabilityContract):
def get_capabilities(self) -> List[Capability]:
return [
Capability(
name="order_query",
description="根据订单号或用户信息查询订单状态",
input_types=["order_id", "user_id"],
output_type="OrderInfo"
)
]
def can_handle(self, intent: str) -> bool:
return intent in ["query_order", "check_status"]
async def execute(self, context: dict) -> dict:
order_id = context.get("order_id")
# 查询逻辑
return {"status": "shipped", "eta": "2-3 days"}
Intent Router:
class IntentRouter:
def __init__(self, agents: List[CapabilityContract]):
self.agents = agents
def route(self, user_input: str) -> tuple[str, CapabilityContract]:
intent = self.classify_intent(user_input)
for agent in self.agents:
if agent.can_handle(intent):
return intent, agent
raise ValueError(f"No agent can handle intent: {intent}")
def classify_intent(self, text: str) -> str:
# 简化的意图分类逻辑
keywords = {"order": "query_order", "refund": "process_refund"}
for key, intent in keywords.items():
if key in text.lower():
return intent
return "general_inquiry"
LLM 抽象层 (DIP 实现):
class LLMProvider(ABC):
@abstractmethod
async def complete(self, prompt: str, context: dict) -> str:
pass
class OpenAIProvider(LLMProvider):
def __init__(self, api_key: str):
self.api_key = api_key
async def complete(self, prompt: str, context: dict) -> str:
# OpenAI API 调用实现
response = await openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
新 SOLID 原则应用总结
在这个实战示例中,我们应用了新 SOLID 原则:
| 原则 | 应用位置 | 具体实现 |
|---|---|---|
| SCP | OrderQueryAgent, RefundAgent | 每个 Agent 专注单一能力,通过 CapabilityContract 定义边界 |
| OCP-P | PromptTemplate 继承体系 | 通过模板继承扩展行为,无需修改代码 |
| LAP | AgentResponse.reasoning | 要求 LLM 输出推理过程,展示其工作 |
| ISP | IntentRouter | 将复合请求分解为独立 Intent,路由到专门 Agent |
| DIP | LLMProvider, ToolProvider, MemoryProvider | Agent 依赖抽象接口,可灵活替换实现 |
反直觉洞察
在实践新 SOLID 原则的过程中,有一些反直觉的洞察值得分享:
💡 Key Insight
AI 系统天然是概率性的,试图消除不确定性反而会设计出脆弱的系统——拥抱概率性,才是设计 AI-Native 系统的正确姿态。
洞察一:”确定性”是一种奢望,拥抱概率性
💡 Key Insight
传统思维追求 100% 确定性,但 AI 系统天然是概率性的。
反直觉做法:
- 不要试图用复杂规则消除不确定性
- 而是设计”不确定性友好”的架构
- 让系统能够表达”我不确定”并优雅降级
洞察二:Prompt 是比代码更重要的”代码”
💡 Key Insight
Prompt 工程不是临时技巧,而是核心工程实践。
反直觉做法:
- 像对待代码一样对待 Prompt:版本控制、测试、Code Review
- Prompt 模板化、参数化、继承化
- 建立 Prompt 设计规范
洞察三:Agent 越”笨”,系统越聪明
💡 Key Insight
试图让一个 Agent 做所有事情会导致”上帝 Agent”反模式。
反直觉做法:
- 让每个 Agent 尽可能”笨”和专注
- 复杂性来自协作,而非单个 Agent 的能力
- 像设计生态系统一样设计 Agent 系统
洞察四:上下文管理比算法更重要
💡 Key Insight
在 AI-Native 系统中,如何管理上下文(context window)往往比算法选择更重要。
反直觉做法:
- 投入大量精力优化上下文压缩和选择
- 建立记忆层次结构(工作记忆/短期记忆/长期记忆)
- 主动遗忘和总结是必要的能力
洞察五:测试 AI 系统需要新范式
💡 Key Insight
传统单元测试假设确定性,但 AI 系统需要新的测试范式。
反直觉做法:
- 使用”属性测试”而非”值测试”
- 建立评估基准(evaluation benchmark)
- 人工在环(human-in-the-loop)是必要的
工具链与最佳实践
推荐工具链
| 类别 | 工具 | 用途 |
|---|---|---|
| LLM 抽象 | LangChain, LlamaIndex | 统一不同 LLM 接口 |
| Prompt 管理 | LangSmith, PromptLayer | Prompt 版本控制和测试 |
| Agent 框架 | AutoGen, CrewAI, OpenAI Agents SDK | 多 Agent 协调 |
| 评估 | TruLens, RAGAS, Arize | Agent 性能评估 |
| 监控 | Langfuse, Weights & Biases | 生产监控和调试 |
| 记忆 | Chroma, Pinecone, Weaviate | 向量存储 |
最佳实践清单
SCP - 单一能力原则
- 每个 Agent 有明确的 Capability Contract
- 避免 Agent 的能力列表超过 5 个
- 定期审查 Agent 的边界是否清晰
OCP-P - 提示工程开闭原则
- 所有 Prompt 使用模板化
- Prompt 变更通过 A/B 测试验证
- 建立 Prompt 设计规范文档
LAP - 忠实表达原则
- 关键 Agent 必须输出 reasoning chain
- 建立 confidence score 阈值机制
- 高不确定性时主动寻求人工介入
ISP - 意图隔离原则
- 使用专门的 Intent Router
- 复合意图自动分解
- 每个 Intent 对应单一明确的 Agent
DIP - 抽象层依赖倒置
- LLM、工具、记忆都通过接口依赖
- 支持运行时切换实现
- 建立清晰的 capability 注册机制
设计审查清单
在部署 Agent 系统前,问自己这些问题:
架构层面:
- 每个 Agent 的能力边界是否清晰?
- 如果替换底层 LLM,需要修改多少代码?
- 系统的涌现行为是否可预测和可控?
运维层面:
- 如何监控 Agent 的 confidence score 分布?
- 失败时如何优雅降级?
- 如何追踪和调试多 Agent 协作流程?
安全层面:
- 工具调用的权限边界在哪里?
- 如何防止 Prompt 注入攻击?
- 敏感数据如何在上下文中流转?
结语
从 SOLID 到新 SOLID:一场范式转移
Robert C. Martin 在 2000 年提出 SOLID 原则时,软件世界正从过程式编程向面向对象编程转变。那些原则帮助数以百万计的开发者写出了更好的代码。
💡 Key Insight
设计原则是手段,不是目的——原则是为了解决特定问题,而非教条;在 AI-Native 时代,接受概率性、拥抱涌现性,比固守确定性思维更能设计出健壮的系统。
今天,我们站在另一个范式转移的门槛上:从面向对象到 AI-Native。
这不是对过去的否定,而是在更高抽象层次上的重构。
| 面向对象时代 | AI-Native 时代 | |
|---|---|---|
| 核心问题 | 如何组织代码 | 如何协调智能 |
| 设计单元 | Class | Agent |
| 主要挑战 | 耦合、内聚 | 涌现、不确定性 |
| 解决手段 | 多态、封装 | Intent、Context、Tool Calling |
| 关键技能 | 算法、数据结构 | Prompt 工程、系统设计 |
关键启示
-
Agent 不是更好的类,而是完全不同的抽象——不要试图用面向对象思维套在 Agent 上
-
设计原则是手段,不是目的——原则是为了解决特定问题,而非教条
-
在不确定性中设计——接受概率性,拥抱涌现性
-
Prompt 是第一公民——像对待代码一样对待 Prompt
-
协作产生智慧——让多个简单 Agent 协作,胜过单个复杂 Agent
展望未来
新 SOLID 原则不是终点,而是起点。随着 AI 技术的演进,我们可能需要在以下几个方面继续探索:
- 自适应系统:Agent 能够动态调整自己的能力边界
- 联邦学习:跨系统、跨组织的 Agent 协作
- 伦理和治理:如何在设计阶段就嵌入负责任的 AI 原则
正如 Charlie Munger 所说:“弄清楚什么是有效的方法,然后去实践它。”
新 SOLID 原则是我们在 AI-Native 软件开发实践中总结出的有效方法。希望它能帮助你在构建 Agent 系统时少走弯路。
深度阅读时间:约 14 分钟
延伸阅读
- Robert C. Martin - 《Clean Architecture》
- Andrew Ng - AI Agent 设计模式系列
- OpenAI - Function Calling Best Practices
- Anthropic - Contextual AI Design Patterns
系列导航
“The best time to plant a tree was 20 years ago. The second best time is now.”
开始构建你的 AI-Native 系统吧。
💬 评论
💡 使用 GitHub 账号登录 即可参与讨论