Files
2026_DesignAI/officefile/supplements/01-foundations/01.1-modular-intelligence.md
T
pengxiao 219232de74 refactor: 重组项目目录结构
以讲义内容为骨架迁移到标准目录格式:
- officefile/ 主内容(12章 + 附录 + CC4SI补充)
- dofile/ 代码示例(11个Python脚本)
- data/ 图片资源
- output/ 生成输出(忽略)
- Archive/ 归档旧目录(忽略)
- .claude/skills/ 保留markdown-to-docx工具链
- .pandoc/ 保留CSL和本地化配置

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 14:00:56 +08:00

563 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 01.1 智能的模块化视角
## 核心问题
> 为什么智能系统需要模块化设计?
> 技能(Skill)的本质是什么?如何设计可复用的智能组件?
> 函数式组合思想如何应用于AI系统?
---
## 概念讲解
### 模块化的必要性
随着系统复杂度增加,模块化变得必不可少:
```
复杂度与模块化的关系
低复杂度 ──→ [单体脚本] ──→ 可维护
简单直接
中复杂度 ──→ [函数库] ──→ 需要组织
按功能分类
高复杂度 ──→ [模块化系统] ──→ 必须模块化
清晰边界,可组合
```
**模块化的收益**
| 收益类型 | 说明 | 例子 |
|---------|------|------|
| 可理解性 | 每个模块可独立理解 | 理解缓冲区分析不需要理解投影变换 |
| 可测试性 | 模块可单独测试 | 测试空间索引不需要完整工作流 |
| 可复用性 | 模块可在不同场景使用 | 缓冲区算法用于多个项目 |
| 可替换性 | 模块可用等价实现替换 | QGIS ↔ ArcGIS 同一功能 |
| 可维护性 | 修改局限在模块内 | 修复bug不影响其他模块 |
### 函数式组合思想
函数式编程的核心:**组合小函数构建复杂行为**
```
简单函数 ──┬─── buffer(geom, distance)
├─── intersect(a, b)
├─── centroid(geom)
└─── distance(a, b)
↓ 组合
complex_operation = pipe(
load_data,
clean_geometry,
buffer(100),
intersect(study_area),
calculate_area,
format_output
)
```
**关键特性**
1. **纯函数**:相同输入→相同输出,无副作用
2. **高阶函数**:函数可以作为参数和返回值
3. **不可变数据**:数据不修改,而是创建新版本
### 技能即能力封装
在Claude Code中,技能(Skill)是智能的模块化单元:
```yaml
# 技能的结构
---
name: skill-name # 技能名称
description: 技能描述 # 何时使用
parameters: # 输入参数
- param1: type
- param2: type
returns: # 输出
- result: type
---
## 技能逻辑
具体的执行步骤...
```
**技能设计的三个层次**
```
Level 1: 原子技能
└── 单一功能,不可再分
例如:buffer, intersect, dissolve
Level 2: 组合技能
└── 由原子技能组合而成
例如:site_selection = buffer + intersect + rank
Level 3: 工作流技能
└── 完整的决策流程
例如:ecological_network_analysis
```
---
## 设计原理
### 模块化的设计原则
**1. 单一职责原则 (SRP)**
每个模块只做一件事,做好一件事:
```python
# 好的设计:每个函数职责单一
def calculate_distance(geom1, geom2):
"""只计算距离"""
return geom1.distance(geom2)
def format_distance(distance, unit='m'):
"""只格式化输出"""
if distance > 1000:
return f"{distance/1000:.2f} km"
return f"{distance:.0f} m"
# 使用
dist = calculate_distance(point_a, point_b)
formatted = format_distance(dist)
# 不好的设计:混合了计算和格式化
def calculate_and_format_distance(geom1, geom2):
distance = geom1.distance(geom2)
# 格式化逻辑混在一起
if distance > 1000:
return f"{distance/1000:.2f} km"
return f"{distance:.0f} m"
```
**2. 开闭原则 (OCP)**
对扩展开放,对修改关闭:
```python
# 使用抽象基类实现扩展性
from abc import ABC, abstractmethod
class SpatialOperation(ABC):
"""空间操作的抽象基类"""
@abstractmethod
def execute(self, data):
pass
class BufferOperation(SpatialOperation):
"""缓冲区操作"""
def __init__(self, distance):
self.distance = distance
def execute(self, data):
return data.buffer(self.distance)
class IntersectOperation(SpatialOperation):
"""相交操作"""
def __init__(self, other_data):
self.other_data = other_data
def execute(self, data):
return data.intersection(self.other_data)
# 可以添加新操作而不修改现有代码
class UnionOperation(SpatialOperation):
"""合并操作"""
def execute(self, data):
return data.union(self.other_data)
```
**3. 依赖倒置原则 (DIP)**
依赖抽象而非具体实现:
```python
# 好的设计:依赖抽象
class WorkflowProcessor:
def __init__(self, operation: SpatialOperation):
self.operation = operation # 依赖抽象
def process(self, data):
return self.operation.execute(data)
# 可以轻松替换具体实现
processor = WorkflowProcessor(BufferOperation(100))
# 不好的设计:依赖具体实现
class WorkflowProcessor:
def __init__(self, buffer_distance):
self.buffer_distance = buffer_distance
def process(self, data):
# 硬编码了具体操作
return data.buffer(self.buffer_distance)
```
### 技能接口设计
良好的技能接口设计:
```python
from typing import Protocol, TypeVar, Generic
T = TypeVar('T')
class SkillInput(Protocol[T]):
"""技能输入协议"""
def validate(self) -> bool:
"""验证输入有效性"""
...
class SkillOutput(Protocol[T]):
"""技能输出协议"""
def to_dict(self) -> dict:
"""转换为可序列化格式"""
...
class Skill(Generic[T]):
"""技能基类"""
name: str
description: str
def can_handle(self, input_data: T) -> bool:
"""判断是否能处理此输入"""
pass
def execute(self, input_data: T) -> SkillOutput[T]:
"""执行技能"""
pass
def estimate_cost(self, input_data: T) -> float:
"""估算执行成本(时间/资源)"""
pass
```
---
## 代码示例
### 模块化的空间分析系统
```python
"""
模块化空间分析系统示例
展示如何用函数式组合构建复杂分析
"""
from typing import Callable, List, Any, TypeVar
from functools import reduce
import geopandas as gpd
T = TypeVar('T')
class SpatialPipeline:
"""空间分析流水线"""
def __init__(self):
self.steps: List[Callable] = []
def add_step(self, step: Callable, name: str = None):
"""添加处理步骤"""
step.name = name or step.__name__
self.steps.append(step)
return self
def execute(self, initial_data):
"""执行流水线"""
result = initial_data
for step in self.steps:
print(f"执行步骤: {getattr(step, 'name', step.__name__)}")
result = step(result)
return result
def pipe(*functions):
"""函数式组合工具"""
return reduce(lambda f, g: lambda x: g(f(x)), functions)
# === 原子操作 ===
def load_data(path: str) -> gpd.GeoDataFrame:
"""加载数据"""
print(f"加载: {path}")
return gpd.read_file(path)
def clean_geometry(gdf: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
"""清理几何"""
print("清理几何")
# 修复无效几何
gdf['geometry'] = gdf.geometry.buffer(0)
return gdf[gdf.geometry.is_valid]
def reproject(gdf: gpd.GeoDataFrame, target_crs: str = 'EPSG:3857') -> gpd.GeoDataFrame:
"""重投影"""
print(f"重投影到: {target_crs}")
return gdf.to_crs(target_crs)
def buffer(gdf: gpd.GeoDataFrame, distance: float) -> gpd.GeoDataFrame:
"""缓冲区分析"""
print(f"缓冲距离: {distance}")
return gdf.buffer(distance)
def intersect(gdf: gpd.GeoDataFrame, other: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
"""相交分析"""
print("相交分析")
return gdf.overlay(other, how='intersection')
def calculate_area(gdf: gpd.GeoDataFrame) -> float:
"""计算面积"""
area = gdf.geometry.area.sum()
print(f"总面积: {area:.2f} 平方米")
return area
# === 高阶操作 ===
def make_buffer(distance: float) -> Callable:
"""缓冲操作工厂函数"""
return lambda gdf: buffer(gdf, distance)
def make_reproject(crs: str) -> Callable:
"""重投影工厂函数"""
return lambda gdf: reproject(gdf, crs)
def make_intersect(other_data: gpd.GeoDataFrame) -> Callable:
"""相交工厂函数"""
return lambda gdf: intersect(gdf, other_data)
# === 使用示例 ===
def example_pipeline_usage():
"""流水线使用示例"""
# 方式1:使用Pipeline类
pipeline = SpatialPipeline()
pipeline.add_step(load_data, "加载数据")
pipeline.add_step(clean_geometry, "清理几何")
pipeline.add_step(lambda gdf: reproject(gdf, 'EPSG:3857'), "重投影")
pipeline.add_step(lambda gdf: buffer(gdf, 100), "缓冲")
pipeline.add_step(calculate_area, "计算面积")
# result = pipeline.execute("data.geojson")
# 方式2:使用函数式组合
analysis_pipeline = pipe(
load_data,
clean_geometry,
lambda gdf: reproject(gdf, 'EPSG:3857'),
lambda gdf: buffer(gdf, 100),
calculate_area
)
# result = analysis_pipeline("data.geojson")
return pipeline
# === 技能封装 ===
class BufferSkill:
"""缓冲区技能"""
name = "buffer_analysis"
description = "执行缓冲区分析"
def __init__(self, distance: float, unit: str = 'm'):
self.distance = distance
self.unit = unit
def execute(self, data: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
"""执行技能"""
# 确保在合适的坐标系中
if data.crs and data.crs.is_geographic:
data = data.to_crs('EPSG:3857')
result = data.buffer(self.distance)
return gpd.GeoDataFrame(
geometry=result,
crs=data.crs
)
def __repr__(self):
return f"BufferSkill(distance={self.distance}{self.unit})"
class SiteSelectionSkill:
"""选址技能:组合多个原子操作"""
name = "site_selection"
description = "基于多准则的选址分析"
def __init__(self,
distance_from_road: float,
distance_from_water: float,
min_area: float):
self.road_distance = distance_from_road
self.water_distance = distance_from_water
self.min_area = min_area
def execute(self,
sites: gpd.GeoDataFrame,
roads: gpd.GeoDataFrame,
water: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
"""
执行选址分析
组合操作:
1. 找到距离道路指定范围内的区域
2. 排除距离水体太近的区域
3. 筛选面积满足要求的区域
"""
# 1. 道路缓冲
road_buffer = roads.buffer(self.road_distance)
# 2. 水体缓冲(排除区)
water_buffer = water.buffer(self.water_distance)
# 3. 找到满足条件的site
suitable = sites[
sites.geometry.intersects(road_buffer.union_all()) &
~sites.geometry.intersects(water_buffer.union_all())
]
# 4. 面积筛选
suitable = suitable[suitable.geometry.area >= self.min_area]
return suitable
if __name__ == "__main__":
# 示例:构建一个选址分析流水线
print("=== 模块化空间分析系统 ===\n")
# 创建技能
buffer_skill = BufferSkill(distance=500, unit='m')
print(f"创建技能: {buffer_skill}")
# 技能可以独立测试
print("\n技能的核心优势:")
print("1. 可理解性 - 每个技能职责单一")
print("2. 可测试性 - 独立测试每个技能")
print("3. 可复用性 - 在不同场景中使用")
print("4. 可组合性 - 小技能组合成大技能")
```
---
## 案例分析
### QGIS插件架构分析
QGIS的模块化设计是学习的好例子:
```
QGIS架构
├── Core (核心库)
│ ├── QgsGeometry - 几何操作
│ ├── QgsVectorLayer - 矢量图层
│ ├── QgsRasterLayer - 栅格图层
│ └── QgsProcessing - 处理框架
├── Providers (数据提供者)
│ ├── OGR Provider - 矢量数据
│ ├── GDAL Provider - 栅格数据
│ └── PostGIS Provider - 数据库
├── Plugins (插件)
│ ├── 每个插件独立模块
│ ├── 通过接口访问核心功能
│ └── 可单独安装/卸载
└── Processing Algorithms (处理算法)
├── 算法库(600+算法)
├── 可组合使用
└── 模型构建器
```
**关键设计模式**
1. **Provider模式**:数据访问抽象
2. **Plugin模式**:功能扩展
3. **Algorithm模式**:处理步骤封装
**AI系统的启发**
```python
# 类似QGIS的AI技能架构
class AISkillRegistry:
"""AI技能注册表"""
def __init__(self):
self.skills = {}
def register(self, skill):
"""注册技能"""
self.skills[skill.name] = skill
def get(self, name: str):
"""获取技能"""
return self.skills.get(name)
def list_by_category(self, category: str):
"""按类别列出技能"""
return [s for s in self.skills.values()
if s.category == category]
# 使用
registry = AISkillRegistry()
registry.register(BufferSkill(distance=100))
registry.register(SiteSelectionSkill(...))
# 查找和使用技能
buffer = registry.get("buffer_analysis")
result = buffer.execute(data)
```
---
## 反思与延伸
### 思考问题
1. **边界划分**:如何确定一个模块的边界?太小的模块和太大的模块各有什么问题?
2. **接口设计**:设计一个技能接口时,应该考虑哪些因素?
3. **复用性**:什么代码值得复用?什么不值得?
4. **组合爆炸**:当模块数量很大时,如何管理模块之间的依赖?
### 实践练习
1. **重构练习**:找一个你写的复杂函数,将其拆分为多个小函数
2. **接口设计**:为你熟悉的空间分析操作设计技能接口
3. **组合挑战**:用5个以下的基本操作组合出10个不同的分析流程
### 延伸阅读
- **"Refactoring"** (Martin Fowler) - 重构与模块化
- **"The Art of Unix Programming"** - 模块化哲学
- QGIS Plugin开发指南
---
## 关键要点
1. **模块化是管理复杂性的核心方法**
2. **函数式组合让小函数构建大功能**
3. **技能是智能的封装单元**
4. **良好的接口设计是模块化的关键**
5. **QGIS的架构是学习的优秀范例**