🔄 系统思维 / 系统边界
🧱 系统边界
划分什么在系统内、什么在系统外——微服务划分、Agent 职责、团队组织的本质问题
什么是系统边界?
每个系统都存在于更大的环境中。边界是你划的那条线——线内是"系统",线外是"环境"。但这条线不是客观存在的,它是你选择画出来的。你画在哪里,决定了你能看到什么、能影响什么。
🔑 边界的三重含义
- 物理边界:服务器、数据库、网络分区——什么跑在哪里
- 逻辑边界:模块、接口、API 契约——什么和什么耦合
- 组织边界:团队、责任、决策权——谁管什么
这三者是联动的——改变一个,其他两个也会跟着变。
Conway's Law:边界复制组织
🏛️ Melvin Conway, 1967
"设计系统的组织,其产生的设计等同于组织的沟通结构。"
这不是比喻,是观察:微服务的边界 = 团队的边界。如果你的组织有三个团队(前端、后端、基础设施),你的系统大概率也是三块。如果两个团队之间沟通困难,对应的两个服务之间集成也会有摩擦。
真实案例:Amazon 的 Two-Pizza Team
Jeff Bezos 的"两个披萨团队"原则(团队规模不超过两个披萨能喂饱的人数,约 6-10 人)不仅仅是一个管理技巧——它是一个系统边界设计决策。每个团队拥有一个服务的完整生命周期(设计、开发、部署、运维),团队边界 = 服务边界 = API 边界。Amazon 从单体应用拆分出数百个微服务的过程,本质上是组织边界先变,系统边界跟着变。
数据:截至 2024 年,Amazon 拥有超过 2000 个微服务,每个由一个独立团队负责。这些服务之间通过 API 通信,没有直接的数据库共享。
微服务边界的划分原则
📐 领域驱动设计 (DDD) 的 Bounded Context
Eric Evans 在《Domain-Driven Design》(2003) 中提出的 Bounded Context 是系统边界划分最系统化的方法:
- 按业务能力划分(而非技术层):订单服务、支付服务、库存服务,而非"API层"、"服务层"、"数据层"
- 每个 Context 有自己的模型:"用户"在订单 Context 中是"买家",在客服 Context 中是"投诉者"——同一个概念,不同模型
- Context 之间通过事件/API 通信:而非共享数据库
- Anti-Corruption Layer:在边界处做翻译,防止一个 Context 的概念污染另一个
⚠️ 过早拆分 vs 过晚拆分的代价
| 过早拆分 | 过晚拆分 |
| 短期代价 | 高(网络调用、数据同步、运维复杂度) | 低(一切在同一个进程里) |
| 长期代价 | 低(边界清晰,可以独立演进) | 极高(大泥球,改一个东西影响全局) |
| 团队规模 | 需要足够的团队来独立维护每个服务 | 团队沟通成本随人数平方增长 |
| 信号 | 3人团队维护5个微服务 = 过早 | 修改一个功能需要协调3个团队 = 过晚 |
经验法则:从单体开始,当你的团队沟通成本 > 微服务运维成本时,才拆分。Martin Fowler 的"单体优先"(MonolithFirst) 策略。
多 Agent 系统的边界
🤖 Agent 职责边界划分
多 Agent 系统的边界划分本质上和微服务一样——每个 Agent 是一个"服务",有自己的工具集、记忆和目标:
- 按能力划分:Research Agent(搜索+阅读)、Code Agent(编码+测试)、Review Agent(审查+优化)
- 按领域划分:Frontend Agent、Backend Agent、DevOps Agent
- 按层级划分:Coordinator Agent(规划和分配)、Worker Agent(执行具体任务)
边界不清的症状:两个 Agent 反复传递上下文、一个任务需要3个Agent串联才能完成、Agent之间的工具集高度重叠。
# Agent 边界设计:清晰的职责划分
# Bad: 边界模糊——每个Agent什么都能做
class OmnipotentAgent:
"""一个Agent拥有所有工具——边界模糊"""
tools = ["search", "code", "deploy", "review", "email", "database"]
# 问题:工具选择困难、上下文膨胀、职责不清
# Good: 按能力划分边界
class ResearchAgent:
"""专注信息获取和分析"""
tools = ["web_search", "web_fetch", "read_file", "summarize"]
boundary = "只负责信息收集和分析,不做执行"
class CodeAgent:
"""专注代码编写和测试"""
tools = ["read_file", "write_file", "exec", "test_runner"]
boundary = "只负责代码变更,不做部署"
class DevOpsAgent:
"""专注部署和运维"""
tools = ["deploy", "monitor", "rollback", "scale"]
boundary = "只负责运行时操作,不改变代码"
# 边界之间的通信协议
class AgentProtocol:
"""Agent 之间的通信契约 = API 契约"""
def research_to_code(self, research_result):
"""Research → Code 的接口"""
return {
"spec": research_result.summary, # 需求规格
"references": research_result.sources, # 参考资料
"constraints": research_result.constraints # 约束条件
}
def code_to_devops(self, code_result):
"""Code → DevOps 的接口"""
return {
"artifact": code_result.build_path, # 部署物
"config": code_result.config, # 配置
"health_check": code_result.health_url # 健康检查
}
边界决策框架
🎮 边界划分互动工具
根据你的团队规模和项目复杂度,判断应该使用什么架构
边界与耦合度
📊 耦合度光谱
| 耦合类型 | 描述 | 修改影响 | 例子 |
| 数据耦合(最弱) | 只共享数据结构 | 改数据格式影响对方 | API 返回 JSON |
| 标记耦合 | 共享控制标记 | 改标记含义影响对方 | Feature flag |
| 控制耦合 | 一个模块控制另一个的流程 | 改流程影响对方 | Orchestrator 调用 Worker |
| 公共耦合 | 共享全局数据 | 改全局数据影响所有 | 共享数据库表 |
| 内容耦合(最强) | 直接访问对方内部 | 改任何东西都可能破坏 | 共享内存、直接 import 内部模块 |
目标:边界之间追求数据耦合,边界内部允许更强的耦合。
🎯 边界设计原则
- 高内聚,低耦合——边界内紧密相关,边界间松散连接
- 信息隐藏——暴露接口,隐藏实现。Agent 不需要知道另一个 Agent 的内部推理
- 自治性——边界内的实体可以独立做出决策,不依赖外部
- 可替代性——可以替换边界内的实现而不影响边界外
- 按演进速率划分——变化频率相似的东西放在同一个边界内