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>
This commit is contained in:
2026-05-25 14:00:56 +08:00
parent af083069d0
commit 219232de74
91 changed files with 39365 additions and 10 deletions
@@ -0,0 +1,198 @@
# 00.1 为什么要读这本书
## 核心问题
> 当AI能帮我们写代码、做分析、出方案时,我们为什么还要学习原理?
> 在技术快速迭代的当下,什么样的知识才值得投资时间?
---
## 概念讲解
### AI的"黑箱"问题
随着大模型(LLM)的普及,AI系统变得越来越强大,但也越来越不透明。这种现象被称为**黑箱化**:
```
输入 ──→ [ AI黑箱 ] ──→ 输出
↑ ↑
看不见 理解不了
```
**黑箱化的三个层次**
1. **算法黑箱**:神经网络内部数百万参数的决策过程难以解释
2. **工具黑箱**:封装好的API调用,不知道内部如何工作
3. **认知黑箱**:连问"为什么"的能力都丧失了
### 空间智能的特殊性
空间分析与一般的智能任务有几个关键区别:
| 维度 | 一般AI任务 | 空间AI任务 |
|-----|-----------|-----------|
| 数据结构 | 文本、图像为主 | 栅格、矢量、图 |
| 关系类型 | 语义关系 | 空间关系(拓扑、距离、方向) |
| 不确定性 | 语义歧义 | 位置误差、尺度效应、边界模糊 |
| 可视化 | 辅助理解 | 核心分析手段 |
| 领域知识 | 可迁移 | 强依赖地理学、生态学等 |
这些特殊性意味着:
- 通用AI模型不能直接解决空间问题
- 需要理解空间分析的本质才能有效设计AI系统
- 验证空间AI的结果需要空间思维
### 原理学习的持久价值
**技术迭代的两个速度**
```
易变层(命令、框架、API)── 半衰期:6-18个月
├─ 示例:QGIS 2.x → 3.x 界面大变
├─ 示例:LangChain → LangGraph 架构演进
└─ 示例:OpenAI API 格式频繁更新
稳定层(设计思想、原理、模式)── 半衰期:10-20年
├─ 示例:图算法在空间分析中的应用
├─ 示例:模块化设计原则
└─ 示例:Human-in-the-Loop理念
```
**投资回报分析**
| 知识类型 | 学习难度 | 过时风险 | 长期价值 |
|---------|---------|---------|---------|
| 具体命令操作 | 低 | 高 | 低 |
| 框架使用方法 | 中 | 中 | 中 |
| 设计原理 | 中 | 低 | 高 |
| 底层思想 | 高 | 极低 | 极高 |
---
## 设计原理
### 为什么选择Claude Code作为脚手架
Claude Code有几个特点使其成为学习AI原理的理想工具:
1. **透明性**:可以看到AI的思考过程(function call、tool use
2. **可扩展性**Skill、Agent、Hook的设计模式清晰
3. **工具中性**:不绑定特定平台,可迁移原理
### "脚手架"比喻的含义
```
┌─────────────────────────────────────┐
│ 建筑物的结构 │ ← 持久的原理知识
│ (空间智能的原理) │
├─────────────────────────────────────┤
│ ╔═════════╗ │
│ ║ 脚手架 ║ │ ← 临时的学习工具
│ ╚═════════╝ │ ← Claude Code
└─────────────────────────────────────┘
```
脚手架的作用:
- **支撑学习过程**:让你能到达原本够不到的高度
- **可拆卸**:学会后可以移除,知识已内化
- **可复用**:用于学习不同的知识领域
---
## 案例分析:ENAgent项目
ENAgent是一个生态网络分析智能体系统,用它来说明原理学习的重要性。
### 问题背景
生态网络分析包括多个步骤:
1. 生态源地识别
2. 阻力面构建
3. 最小累积阻力(MCR)分析
4. 生态廊道提取
5. 网络优化
6. 结果评估
传统做法:每个步骤用不同工具,手动操作,容易出错。
### AI解决方案
如果只关注"怎么做",可能会写:
```python
# 这种代码只会调用,不理解原理
def ecological_analysis(input_data):
result = some_ai_model.generate_analysis(input_data)
return result
```
**问题**
- 结果不对时不知道为什么
- 无法调整参数适应不同场景
- 换个模型就不会用了
### 理解原理的做法
理解每个步骤的原理后:
```python
def ecological_analysis_with_principles(
landcover: GeoDataFrame,
species_params: Dict,
resistance_weights: Dict,
checkpoints: List[str] = None
) -> AnalysisResult:
"""
基于原理的生态网络分析
原理1:生态源地识别基于多准则评估
原理2:阻力面反映物种移动的空间异质性
原理3:MCR本质是图上的最短路径问题
原理4:廊道提取需要考虑连接性和宽度
Args:
landcover: 土地利用覆盖数据
species_params: 目标物种的景观偏好参数
resistance_weights: 各土地类型的阻力权重
checkpoints: HITL审查点,人类介入的关键决策
"""
# 每一步都理解原理,知道为什么这样做
...
```
**优势**
- 可以解释每个决策的理由
- 能根据具体问题调整方法
- 工具变化时原理保持不变
---
## 反思与延伸
### 思考问题
1. **自我诊断**:你目前学习新技术的方式是什么?更偏向"怎么做"还是"为什么"
2. **知识审计**:列出你掌握的技能,哪些是易变层,哪些是稳定层?
3. **迁移测试**:如果从QGIS换成ArcGIS,从OpenAI换成Claude,你的哪些知识可以直接迁移?
4. **黑箱体验**:回想一次你使用AI但无法理解结果的经历,缺少什么知识才能理解?
### 延伸阅读
- **《如何解题》** (Polya) - 数学思维的本质
- **《系统化思维导论》** (Gerald Weinberg) - 理解复杂系统
- **《技术的本质》** (Brian Arthur) - 技术演进的规律
---
## 关键要点
1. **黑箱化是AI时代的普遍风险**,主动学习原理可以抵抗
2. **空间智能有独特性**,需要专门的理解,不能完全依赖通用AI
3. **投资稳定层知识**,半衰期长,迁移性强
4. **Claude Code是脚手架**,帮助理解原理而非替代思考
5. **ENAgent案例说明**:理解原理让你能设计、调试、改进系统
> "授人以鱼不如授人以渔。在AI时代,授人以AI不如授人以理解AI的能力。"
@@ -0,0 +1,407 @@
# 00.2 空间智能是什么
## 核心问题
> 机器如何"理解"空间?空间智能与GIS有什么本质区别?
> 为什么空间分析不能简单套用通用AI模型?
---
## 概念讲解
### 空间认知的层次
理解空间智能,首先需要理解人类如何认知空间,然后看机器如何模拟。
```
┌─────────────────────────────────────────────────────────┐
│ 空间认知金字塔 │
├─────────────────────────────────────────────────────────┤
│ │
│ Level 4: 空间推理与决策 │ ← 最高级
│ - 推理未知区域的属性 │
│ - 基于空间约束做决策 │
│ - 理解因果关系 │
│ │
│ Level 3: 空间关系理解 │
│ - 拓扑关系(相邻、包含、重叠) │
│ - 距离与方向 │
│ - 空间模式识别 │
│ │
│ Level 2: 空间表征能力 │
│ - 地图阅读 │
│ - 比例尺理解 │
│ - 2D ↔ 3D 转换 │
│ │
│ Level 1: 空间感知 │ ← 基础
│ - 位置识别 │
│ - 距离估计 │
│ - 导航本能 │
│ │
└─────────────────────────────────────────────────────────┘
```
### 从GIS到空间智能
GIS(地理信息系统)和空间智能的关系:
| 维度 | GIS | 空间智能 |
|-----|-----|---------|
| **目标** | 管理、分析、可视化空间数据 | 自动化空间决策 |
| **操作者** | 人类 | 人类 + AI系统 |
| **确定性** | 算法确定,结果可重现 | 常涉及概率和不确定性 |
| **适应性** | 需要人工调整参数 | 可根据反馈自我调整 |
| **知识编码** | 隐式(在操作者脑中) | 显式(在系统中) |
**关键区别**GIS是工具,空间智能是能力。
```
GIS 用户 → [GIS软件] → 空间分析结果
人类提供所有空间知识
空间智能用户 → [智能体] → 空间决策
系统内置空间知识 + 人类提供约束
```
### 空间推理的本质
空间推理是空间智能的核心。它包括:
**1. 拓扑推理**
```python
# 拓扑关系的九交模型(DE-9IM
def spatial_relationship(A, B):
"""
判断两个空间对象的关系
"""
# A的内部、边界、外部 与 B的内部、边界、外部 的交集
intersections = [
A.interior B.interior, # I∩I
A.interior B.boundary, # I∩B
A.interior B.exterior, # I∩E
A.boundary B.interior, # B∩I
A.boundary B.boundary, # B∩B
A.boundary B.exterior, # B∩E
A.exterior B.interior, # E∩I
A.exterior B.boundary, # E∩B
A.exterior B.exterior, # E∩E
]
# 根据交集模式判断关系:contains, overlaps, touches等
return classify_relationship(intersections)
```
**2. 距离推理**
不仅仅是欧氏距离,还要考虑:
- **功能距离**:时间成本、经济成本
- **阻力距离**:穿越不同地形的代价
- **网络距离**:沿道路网络的路径长度
**3. 方向推理**
```python
# 方向关系的主方向模型
def directional_relationship(source, target):
"""
判断target相对于source的方向
"""
angles = {
'N': (0, 45), 'NE': (45, 90), 'E': (90, 135),
'SE': (135, 180), 'S': (180, 225), 'SW': (225, 270),
'W': (270, 315), 'NW': (315, 360)
}
angle = compute_angle(source, target)
return get_direction(angles, angle)
```
---
## 设计原理
### 空间智能的两种范式
**范式1:符号主义空间AI**
```
空间知识规则库 ──→ 逻辑推理引擎 ──→ 结论
↑ ↓
└──────────────────────────┘
反馈学习
```
特点:
- 知识显式编码
- 推理过程可解释
- 适合结构化问题
**范式2:联结主义空间AI**
```
空间数据 → [神经网络] → 空间决策
训练数据
```
特点:
- 从数据中学习模式
- 适合感知类任务
- 可解释性较弱
**混合范式**(本书重点):
```
符号知识 + 数据驱动 → 混合推理 → 可解释的决策
↓ ↓ ↓
专家经验 深度学习 HITL验证
```
### 为什么不能直接套用通用AI
通用大模型在空间任务上的局限:
| 任务类型 | 通用LLM表现 | 空间智能系统 |
|---------|------------|-------------|
| 空间关系判断 | 需要坐标输入,容易出错 | 内置空间算子 |
| 距离计算 | 理解困难 | 几何计算精确 |
| 地图阅读 | 需要视觉模型 | 多模态融合 |
| 空间优化 | 搜索空间大,效率低 | 专用算法 |
**原因**
1. 空间关系不是语言关系,不能完全用语言描述
2. 空间计算需要几何算法,LLM不擅长
3. 空间数据有特殊结构(拓扑、尺度),需要专门处理
---
## 代码示例
### 简单空间推理演示
```python
from shapely.geometry import Point, Polygon
import geopandas as gpd
class SpatialReasoner:
"""
一个简单的空间推理器示例
演示AI如何理解和使用空间关系
"""
def __init__(self):
self.knowledge_base = {
# 关于空间关系的常识
"containment": "包含关系是不对称的:A包含B不意味着B包含A",
"adjacency": "相邻关系是对称的:A与B相邻意味着B与A相邻",
"proximity": "邻近关系会随距离阈值变化"
}
def analyze_spatial_config(self, features: gpd.GeoDataFrame) -> dict:
"""
分析一组空间特征之间的配置关系
"""
results = {
'topology': self._analyze_topology(features),
'clustering': self._detect_clusters(features),
'accessibility': self._compute_accessibility(features)
}
return results
def _analyze_topology(self, features: gpd.GeoDataFrame) -> dict:
"""
分析拓扑关系:谁包含谁,谁与谁相邻
"""
topology = {}
for i, feat_i in features.iterrows():
for j, feat_j in features.iterrows():
if i >= j:
continue
geom_i = feat_i.geometry
geom_j = feat_j.geometry
relation = None
if geom_i.contains(geom_j):
relation = 'contains'
elif geom_i.within(geom_j):
relation = 'within'
elif geom_i.touches(geom_j):
relation = 'touches'
elif geom_i.intersects(geom_j):
relation = 'overlaps'
if relation:
topology[f"{i}-{j}"] = relation
return topology
def _detect_clusters(self, features: gpd.GeoDataFrame, threshold=1000) -> list:
"""
检测空间聚类:哪些对象聚集在一起
"""
clusters = []
used = set()
for i, feat_i in features.iterrows():
if i in used:
continue
cluster = [i]
used.add(i)
for j, feat_j in features.iterrows():
if j in used:
continue
if feat_i.geometry.distance(feat_j.geometry) <= threshold:
cluster.append(j)
used.add(j)
if len(cluster) > 1:
clusters.append(cluster)
return clusters
def _compute_accessibility(self, features: gpd.GeoDataFrame) -> dict:
"""
计算可达性:从一个点到其他点的便利程度
"""
centroid = features.union_all().centroid
accessibility = {}
for i, feat in features.iterrows():
distance = feat.geometry.distance(centroid)
accessibility[i] = {
'distance_to_center': distance,
'accessibility_score': 1 / (1 + distance / 1000)
}
return accessibility
def infer_from_spatial_relation(self, observed_relation: str) -> str:
"""
基于观察到的空间关系进行推理
"""
inferences = {
"如果A包含B,且B包含C": "则A可能包含C(传递性)",
"如果A与B相邻,且B与C相邻": "A和C可能相邻或很近",
"如果一组对象形成聚类": "它们可能有相似的性质"
}
return inferences.get(observed_relation, "无法推理")
# 使用示例
if __name__ == "__main__":
# 创建一些简单的空间对象
features = gpd.GeoDataFrame({
'name': ['park', 'building', 'lake', 'plaza'],
'geometry': [
Point(0, 0).buffer(100), # park
Point(50, 50).buffer(30), # building (inside park)
Point(200, 0).buffer(80), # lake (near park)
Point(150, 50).buffer(40) # plaza
]
})
reasoner = SpatialReasoner()
analysis = reasoner.analyze_spatial_config(features)
print("=== 空间推理分析结果 ===")
print(f"拓扑关系: {analysis['topology']}")
print(f"聚类: {analysis['clustering']}")
print(f"可达性: {analysis['accessibility']}")
```
输出示例:
```
=== 空间推理分析结果 ===
拓扑关系: {'0-1': 'contains', '0-2': 'touches'}
聚类: [[2, 3]]
可达性: {0: {'distance_to_center': 33.5, 'accessibility_score': 0.97}, ...}
```
---
## 案例分析
### 真实项目:生态廊道识别中的空间推理
在ENAgent项目中,识别生态廊道需要复杂的空间推理:
**推理链条**
1. **前提1**:源地A和B之间存在潜在廊道
2. **前提2**:廊道需要满足最小宽度要求
3. **前提3**:廊道上的阻力值不应超过阈值
4. **前提4**:廊道应该连接相似的生境类型
5. **结论**A和B之间的最优廊道是...
**AI系统如何执行**
```python
def find_ecological_corridor(source_a, source_b, landscape):
"""
基于空间推理的生态廊道识别
"""
# 1. 计算MCR表面(空间计算)
mcr_surface = compute_mcr(landscape, source_a, source_b)
# 2. 提取最小阻力路径(图算法)
path = extract_least_cost_path(mcr_surface, source_a, source_b)
# 3. 验证宽度约束(空间关系)
width = calculate_corridor_width(path, landscape)
if width < MIN_CORRIDOR_WIDTH:
# 推理:如果太窄,尝试次优路径
path = extract_next_best_path(mcr_surface, source_a, source_b)
# 4. 评估生境连续性(领域知识)
continuity = assess_habitat_continuity(path, landscape)
if continuity < threshold:
# 推理:生境不连续,廊道可能无效
return None
return path
```
这个例子展示了:
- **空间计算**MCR、距离计算
- **图算法**:最短路径
- **领域知识**:最小宽度、生境连续性
- **推理逻辑**:约束不满足时的回溯
---
## 反思与延伸
### 思考问题
1. **自我评估**:你能在脑海中"想象"一个空间场景的拓扑关系吗?机器如何做到同样的事?
2. **设计挑战**:如果要设计一个"智能地图助手",它应该具备哪些空间推理能力?
3. **局限分析**:当前的空间智能系统在哪些空间推理任务上仍然不如人类?
4. **未来想象**:如果机器具备完全的空间智能,它能做什么现在做不到的事?
### 延伸阅读
- **《空间认知与计算》** - 认知科学与GIS的交叉
- **"Spatial Cognition"** (Kluwer Academic Publishers) - 空间认知的经典教材
- **QGIS文档** - 理解实际软件中的空间算子实现
---
## 关键要点
1. **空间认知有多个层次**,从感知到推理逐级递进
2. **GIS ≠ 空间智能**:前者是工具,后者是能力
3. **空间推理的核心**:拓扑关系、距离推理、方向推理
4. **通用AI不能直接解决空间问题**,需要专门的空间算子
5. **混合范式**结合符号知识和数据驱动是当前最佳实践
@@ -0,0 +1,427 @@
# 00.3 自主设计的含义
## 核心问题
> "自动"和"自主"有什么本质区别?
> 在设计工作中,AI应该扮演什么角色?工具还是伙伴?
> Human-in-the-Loop不是落后,而是高级的设计哲学?
---
## 概念讲解
### 自动 vs 自主
这两个词经常被混用,但在AI系统设计中有重要区别:
```
┌─────────────────────────────────────────────────────────────┐
│ 自动化(Automation) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 设定 → [固定脚本] → 执行 → 结果 │
│ ↑ ↓ │
│ 预定义规则 完全确定 │
│ │
│ 特点: │
│ - 按预定规则执行 │
│ - 遇到异常停止 │
│ - 重复性任务 │
│ - 人类设定后不再介入 │
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 自主化(Autonomy) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 目标 → [智能体] → 观察 → 决策 → 行动 → 反馈 │
│ ↑ ↑ ↑ ↓ │
│ 高层意图 持续学习 适应调整 环境变化 │
│ │
│ 特点: │
│ - 追求目标而非执行步骤 │
│ - 能处理意外情况 │
│ - 从经验中学习 │
│ - 在约束下自主决策 │
│ │
└─────────────────────────────────────────────────────────────┘
```
### 理解的层级
自主系统的智能程度可以分层:
```
Level 0: 无智能 (No Intelligence)
└── 简单机械,完全由外部控制
Level 1: 反应式智能 (Reactive Intelligence)
└── 基于当前状态直接反应,无记忆
例如:恒温器、简单的自动门
Level 2: 基于规则的智能 (Rule-based Intelligence)
└── 遵循预定义规则,有分支逻辑
例如:专家系统、决策树
Level 3: 学习型智能 (Learning Intelligence)
└── 能从数据中学习,改进性能
例如:机器学习模型
Level 4: 自主智能 (Autonomous Intelligence)
└── 设定目标,规划执行,处理意外
例如:自动驾驶、智能体系统
Level 5: 协作智能 (Collaborative Intelligence)
└── 与人类协同,理解意图和上下文
例如:设计伙伴AI
```
### 设计智能的演进
从CAD工具到AI设计伙伴的演进:
```
1980s: CAD时代
└── 数字化绘图,提高效率
设计师 → [绘图工具] → 图纸
2000s: 参数化设计时代
└── 规则驱动,生成变体
设计师 → [参数+规则] → [生成器] → 多方案
2010s: 优化时代
└── 目标驱动,搜索最优解
设计师 → [目标函数] → [优化算法] → 最优方案
2020s: AI生成时代
└── 意图驱动,智能生成
设计师 → [意图描述] → [AI模型] → 设计方案
未来: 协作设计时代
└── 人机协同,共同创造
设计师 ⇄ [AI伙伴] ⇄ 设计结果
共享理解
```
---
## 设计原理
### Human-in-the-Loop (HITL) 的设计哲学
HITL不是"半自动"的妥协,而是深思熟虑的设计选择。
**为什么需要HITL**
1. **空间问题的复杂性**
- 多目标权衡(生态 vs 经济 vs 社会)
- 隐性知识无法完全编码
- 价值判断需要人类
2. **责任归属**
- 重大决策不能完全交给机器
- 设计师需要对结果负责
- 伦理考量需要人类判断
3. **信任建立**
- 逐步建立对AI的信任
- 可解释性增强信任
- 控制感增强接受度
**HITL的三种模式**
```python
# 模式1: 决策前审查 (Pre-decision Review)
def hitl_pre_review(agent_decision, human_expert):
"""
人类在AI决策前审查
"""
proposal = agent.generate_proposal()
approval = human_expert.review(proposal)
if approval:
return agent.execute(proposal)
else:
feedback = human_expert.provide_feedback()
return agent.regenerate(feedback)
# 模式2: 关键点介入 (Checkpoint Intervention)
def hitl_checkpoint(workflow, checkpoints):
"""
在关键决策点人类介入
"""
for step in workflow:
result = step.execute()
if step.name in checkpoints:
# 只在关键点需要人类确认
if not human.confirm(result):
result = human.modify(result)
return result
# 模式3: 异常处理 (Exception Handling)
def hitl_exception(agent, task):
"""
AI正常运行,异常时人类介入
"""
try:
return agent.execute(task)
except UncertainSituation as e:
# AI遇到不确定情况,请求人类帮助
return human.resolve(e)
```
### ENAgent的三个审查点
ENAgent项目的HITL设计:
```
┌────────────────────────────────────────────────────────────┐
│ ENAgent 工作流程 │
├────────────────────────────────────────────────────────────┤
│ │
│ 1. 数据准备 │
│ └── 自动化执行 │
│ │
│ 2. 生态源地识别 ──→ [审查点1] ──→ 确认/调整源地 │
│ (AI识别) (人类专家) (最终决策) │
│ │
│ 3. 阻力面构建 ──→ [审查点2] ──→ 确认/调整权重 │
│ (AI建议) (人类专家) (最终参数) │
│ │
│ 4. MCR分析 │
│ └── 自动化执行 │
│ │
│ 5. 廊道提取 ──→ [审查点3] ──→ 确认/优化廊道 │
│ (AI识别) (人类专家) (最终方案) │
│ │
│ 6. 结果评估 │
│ └── AI + 人类共同评估 │
│ │
└────────────────────────────────────────────────────────────┘
```
**为什么选择这三个点?**
| 审查点 | 原因 | 人类贡献 |
|-------|------|---------|
| 源地识别 | 需要本地知识,遥感可能误判 | 地面实况,专家经验 |
| 阻力权重 | 价值判断,物种特性不同 | 生态学知识,实地经验 |
| 廊道优化 | 多目标权衡,不能完全量化 | 规划要求,社会因素 |
---
## 代码示例
### HITL工作流示意
```python
from typing import Callable, Optional
from dataclasses import dataclass
from enum import Enum
class ReviewDecision(Enum):
APPROVE = "approve"
MODIFY = "modify"
REJECT = "reject"
@dataclass
class ReviewResult:
decision: ReviewDecision
feedback: Optional[str] = None
modifications: Optional[dict] = None
class HumanReviewer:
"""
人类审查者的抽象接口
实际实现可以是CLI界面、Web界面等
"""
def review(self, proposal: dict, context: str) -> ReviewResult:
"""
审查AI的提案
Args:
proposal: AI生成的提案
context: 审查上下文信息
Returns:
审查决定
"""
print(f"\n=== 审查点: {context} ===")
print(f"AI提案: {proposal}")
# 实际实现中,这里会显示GUI或调用外部接口
decision = input("决策 (approve/modify/reject): ")
if decision == "approve":
return ReviewDecision.APPROVE
elif decision == "modify":
feedback = input("修改意见: ")
return ReviewDecision(ReviewDecision.MODIFY, feedback=feedback)
else:
return ReviewDecision(ReviewDecision.REJECT)
class HITLWorkflow:
"""
带人类审查的自主工作流
"""
def __init__(self, reviewer: HumanReviewer):
self.reviewer = reviewer
self.checkpoints = []
def add_checkpoint(self, name: str, condition: Callable = None):
"""
添加审查点
Args:
name: 审查点名称
condition: 触发审查的条件函数
"""
self.checkpoints.append({
'name': name,
'condition': condition or (lambda _: True)
})
def run(self, steps: list) -> dict:
"""
执行工作流,在审查点进行人类介入
Args:
steps: 工作流步骤列表
Returns:
最终结果
"""
context = {}
for i, step in enumerate(steps):
# 执行步骤
step_name = step.get('name', f'step_{i}')
step_func = step['execute']
print(f"\n执行步骤: {step_name}")
result = step_func(context)
context[step_name] = result
# 检查是否需要审查
for checkpoint in self.checkpoints:
if checkpoint['name'] == step_name:
if checkpoint['condition'](context):
review_result = self.reviewer.review(
result, step_name
)
if review_result.decision == ReviewDecision.REJECT:
# 拒绝,重新执行
print("提案被拒绝,重新执行...")
return self.run(steps)
elif review_result.decision == ReviewDecision.MODIFY:
# 修改,更新上下文
print(f"应用修改: {review_result.feedback}")
context[step_name] = self._apply_modifications(
result, review_result.modifications
)
# APPROVE: 继续执行
return context
def _apply_modifications(self, original: dict, modifications: dict) -> dict:
"""应用人类修改"""
if modifications:
original.update(modifications)
return original
# 使用示例:生态网络分析的HITL工作流
if __name__ == "__main__":
# 创建审查者
reviewer = HumanReviewer()
# 创建工作流
workflow = HITLWorkflow(reviewer)
# 添加审查点
workflow.add_checkpoint('identify_sources')
workflow.add_checkpoint('build_resistance')
workflow.add_checkpoint('extract_corridors')
# 定义工作流步骤
def step_load_data(context):
return {'data_loaded': True}
def step_identify_sources(context):
# 模拟AI识别源地
return {
'sources': [
{'id': 1, 'area': 1500, 'type': 'forest'},
{'id': 2, 'area': 800, 'type': 'wetland'}
],
'confidence': 0.85
}
def step_build_resistance(context):
# 模拟AI构建阻力面
return {
'weights': {
'forest': 1,
'grassland': 10,
'urban': 100,
'water': 50
}
}
def step_extract_corridors(context):
# 模拟AI提取廊道
return {
'corridors': [
{'from': 1, 'to': 2, 'length': 3500, 'quality': 'high'}
]
}
steps = [
{'name': 'load_data', 'execute': step_load_data},
{'name': 'identify_sources', 'execute': step_identify_sources},
{'name': 'build_resistance', 'execute': step_build_resistance},
{'name': 'extract_corridors', 'execute': step_extract_corridors},
]
# 执行工作流
result = workflow.run(steps)
print("\n=== 工作流完成 ===")
print(result)
```
---
## 反思与延伸
### 思考问题
1. **角色定位**:在你自己的工作中,你希望AI扮演什么角色?工具、助手还是伙伴?
2. **审查点设计**:如果要为你熟悉的工作流程设计HITL,你会选择哪些审查点?为什么?
3. **信任边界**:在什么情况下你会完全信任AI的决策?在什么情况下必须人类介入?
4. **责任归属**:如果HITL系统做出了错误决策导致损失,责任应该如何划分?
### 延伸阅读
- **"Human-in-the-Loop Machine Learning"** - HITL的系统论述
- **"Human-Centered AI"** (Ben Shneiderman) - 以人为本的AI设计
- **"Designing Autonomous Agents"** - 自主智能体设计理论
---
## 关键要点
1. **自动 ≠ 自主**:自动执行预定义步骤,自主追求目标并适应环境
2. **智能有层级**:从反应式到协作式,逐级递进
3. **HITL不是妥协**:而是深思熟虑的设计选择,在复杂、重要的决策中必不可少
4. **审查点选择是关键**:选择需要人类独特能力的决策点
5. **从工具到伙伴**:AI在设计中角色的演进,目标是协作而非替代
@@ -0,0 +1,429 @@
# 00.4 Claude Code作为脚手架
## 核心问题
> 为什么选择Claude Code作为学习工具?
> 如何"借力打力",用AI来学习AI
> 工具更新换代时,如何保持知识的可迁移性?
---
## 概念讲解
### Claude Code是什么
Claude Code是Anthropic推出的命令行AI开发助手,但它本质上是一个**学习工具**。
**核心特点**
```
┌─────────────────────────────────────────────────────────────┐
│ Claude Code 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户 ──→ [Claude Code CLI] ──→ Claude API ──→ 响应 │
│ │ │ │
│ │ │ │
│ └──── 三个核心概念 ────────────────────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Agent │ │ Skill │ │ Hook │ │
│ │ (智能体) │ │ (技能) │ │ (钩子) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
```
**对比其他工具**
| 维度 | Copilot | ChatGPT | Claude Code |
|-----|---------|---------|-------------|
| 主要界面 | IDE插件 | Web界面 | 命令行 |
| 工作方式 | 代码补全 | 对话 | 对话+执行 |
| 可扩展性 | 有限 | 有限 | 高(Skill系统) |
| 透明度 | 低 | 中 | 高(显示思考) |
| 工具链集成 | IDE内 | 需复制粘贴 | 直接执行 |
### 为什么选择Claude Code
**1. 透明性**
Claude Code可以看到AI的思考过程:
```
用户: 帮我分析这个生态网络
Claude Code:
思考: 用户想要分析生态网络,我需要:
1. 识别这是一个空间分析任务
2. 确定需要的数据类型
3. 选择合适的分析方法
4. 调用相关技能
动作: 调用 skill:ecological-analysis
输入: {...}
结果: {...}
```
这种透明性对学习很重要——你可以看到AI**如何分解问题**。
**2. 可扩展性**
```yaml
# .claude/skills/spatial-analysis.md
---
description: 空间分析技能
---
当用户需要进行空间分析时:
1. 确定分析类型(缓冲区分析、叠加分析等)
2. 检查所需数据
3. 执行分析
4. 可视化结果
```
你可以定义自己的技能,学习如何将领域知识编码为AI可以理解和执行的形式。
**3. 工具中性**
```
Claude Code
├─ 可以调用 QGIS
├─ 可以调用 ArcGIS
├─ 可以调用 Python脚本
└─ 可以调用任何命令行工具
```
学习的是**如何编排工具**,而不是特定工具的用法。
### 三个核心概念
#### 1. Agent(智能体)
Agent是具有目标、能自主行动的系统:
```python
# Agent的抽象结构
class Agent:
def __init__(self, goal, tools, memory):
self.goal = goal # 目标
self.tools = tools # 可用工具
self.memory = memory # 记忆
def perceive(self, observation):
"""感知环境"""
pass
def decide(self):
"""决定下一步行动"""
pass
def act(self):
"""执行行动"""
pass
def reflect(self):
"""反思和学习"""
pass
```
**设计问题**
- Agent应该有多大的自主性?
- 如何让Agent的目标与人类意图对齐?
- 如何处理Agent的失败?
#### 2. Skill(技能)
Skill是能力的封装:
```yaml
# skill示例
---
name: extract-ecological-sources
description: 从土地利用数据中提取生态源地
parameters:
- landcover_data: GeoDataFrame
- min_patch_size: float
- suitability_threshold: float
returns:
- sources: GeoDataFrame
- statistics: dict
---
## 执行逻辑
1. 读取土地利用数据
2. 计算每个斑块的适宜性
3. 筛选满足条件的斑块
4. 按面积排序,选择前N个
```
**设计问题**
- 如何定义技能的边界?
- 技能之间如何组合?
- 如何让技能可复用?
#### 3. Hook(钩子)
Hook是事件驱动的扩展点:
```yaml
# hook示例
---
name: pre-tool-use
description: 在工具调用前执行
trigger:
- event: ToolUse
condition: tool_name == "ecological-analysis"
action: |
1. 验证输入数据的坐标系
2. 检查数据完整性
3. 记录分析参数用于审计
---
## 价值
- 防止错误的分析
- 建立可追溯性
- 注入质量控制
```
**设计问题**
- 哪些事件需要hook
- 如何在自动化和控制之间平衡?
- 如何避免过度使用hook导致系统僵化?
---
## 设计原理
### 工具中性原则
**核心思想**:学习的是设计模式,而非特定工具。
### 指月之辨:工具与真理的关系
**禅宗寓言**:佛经记载,佛法如标指,真理如明月。指非月也,是指月之指也。
**寓意**
- 手指(工具)指向月亮(真理/原理)
- 我们需要借助手指才能看到月亮
- 但手指不是月亮本身,不要执着于手指
**对应到学习**
```
┌─────────────────────────────────────────────────────────────┐
│ │
│ 手指 (指) 月亮 (月) │
│ ↓ ↓ │
│ 工具 原理/真理 │
│ - Claude Code - 状态机设计 │
│ - LangGraph - 模块化思维 │
│ - 具体框架 - 设计模式 │
│ - 命令语法 - AI本质 │
│ │
└─────────────────────────────────────────────────────────────┘
```
**实践启示**
1. **借指观月,而非指为月**
- 通过工具学习原理,而非学习工具本身
- Claude Code 是"指",帮助我们指向"月"AI原理)
2. **手指过河,筏喻登山**
- 工具如竹筏,渡河后应舍弃
- 学会原理后,工具可以更换
3. **莫执着于一指**
- 不固守单一工具
- 不同工具可指向同一真理
- 工具中性:多工具对比学习
> "授人以鱼不如授人以渔。但更重要的是:不要把渔具当成目的。
> 渔具是指向智慧之鱼的'指',真正的'月'是理解如何独立思考、
> 如何在新工具出现时快速学习、如何构建持久的认知框架。"
```
┌─────────────────────────────────────────────────────────────┐
│ 抽象层(持久知识) │
│ │
│ 工作流编排 │ 状态管理 │ 技能组合 │
│ │
├─────────────────────────────────────────────────────────────┤
│ 实现层(易变知识) │
│ │
│ Claude Code │ LangGraph │ LangChain │ ... │
│ │
└─────────────────────────────────────────────────────────────┘
```
**实践方法**
1. **学习概念,而非命令**
- 理解"状态机"比记住LangGraph的语法更重要
- 理解"技能抽象"比记住Skill格式更重要
2. **关注接口,而非实现**
- 定义清晰的输入输出
- 理解组件之间的交互模式
3. **多工具对比**
- 用不同工具实现同一任务
- 理解不同设计的trade-off
### 借力打力:用AI学习AI
```
你的学习路径
1. 向Claude Code提问
"解释一下状态机在Agent系统中的作用"
2. 让它生成示例
"给我一个简单的状态机示例代码"
3. 让它解释代码
"逐行解释这段代码在做什么"
4. 让它出题测试
"出几道关于状态机的问题测试我的理解"
5. 让它点评你的答案
"这是我的理解,请点评并指出不足"
```
---
## 代码示例
### Claude Code基础操作
```bash
# 1. 启动Claude Code
claude
# 2. 基本对话
> 你好,请介绍一下空间智能的概念
# 3. 执行命令
> 列出当前目录的文件
# Claude会自动执行 ls 命令
# 4. 读取文件
> 读取 README.md 的内容
# 5. 使用技能
> /spatial-analysis 分析这个区域的生态网络
# 6. 创建新技能
> 创建一个名为"buffer-analysis"的技能
```
### 创建一个简单的技能
文件:`.claude/skills/hello-spatial.md`
```yaml
---
name: hello-spatial
description: 向用户问好并介绍空间分析基础
---
当用户请求空间分析入门介绍时,使用此技能。
## 执行步骤
1. 询问用户的空间分析背景
2. 根据背景调整解释深度
3. 提供一个简单的空间分析示例
4. 推荐进一步学习资源
## 示例对话
用户: "我是空间分析的初学者"
AI: "欢迎!空间分析是关于..."
```
---
## 实践示例:Claude Code的第一个空间任务
```bash
# 场景:用Claude Code分析一个简单的空间问题
> 我有一个包含公园位置的CSV文件,想找出距离每个居民区最近的车公园
# Claude Code的响应过程:
# 1. 理解任务 - 这是一个最近邻分析问题
# 2. 确定工具 - 使用geopandas和scipy
# 3. 编写代码 - 生成Python脚本
# 4. 执行分析 - 运行脚本
# 5. 展示结果 - 可视化输出
让我帮您完成这个最近邻分析。
首先,让我读取您的数据:
[读取 parks.csv]
然后,我将:
1. 计算每个居民区到所有公园的距离
2. 找出最近的车公园
3. 计算平均服务距离
4. 生成可视化地图
[生成并执行 Python 代码]
结果:
- 平均最近距离:850米
- 服务覆盖率:78%
- 需要新建公园的区域:[列表]
```
---
## 反思与延伸
### 思考问题
1. **工具选择**:你目前使用的AI工具是什么?它在哪些方面帮助/阻碍了你的学习?
2. **知识迁移**:如果Claude Code不再维护,你学到的哪些知识可以迁移到其他工具?
3. **透明性**:你认为AI系统应该有多透明?完全透明是否会降低效率?
4. **自主性**:在使用AI工具时,你希望在多大程度上保持控制权?
### 实践练习
1. **安装Claude Code**
```bash
npm install -g @anthropic/claude-code
```
2. **创建你的第一个技能**
- 选择你熟悉的领域
- 定义技能的输入输出
- 编写执行逻辑
3. **与Claude对话**
- 询问一个你不懂的AI概念
- 让它用多种方式解释
- 测试你的理解
### 延伸阅读
- **[Claude Code官方文档](https://claudecode.io/zh)** - 最权威的参考资料
- **"Tools for Thought"** (Richard Wurman) - 思考工具的历史
- **"Building Software with AI"** - AI辅助软件开发的实践
---
## 关键要点
1. **Claude Code是学习工具**,不只是生产力工具
2. **透明性、可扩展性、工具中性**是其核心优势
3. **Agent、Skill、Hook**三个概念构成核心抽象
4. **关注抽象层**的知识,实现层会变化
5. **借力打力**:用AI来学习AI是最高效的方式
@@ -0,0 +1,111 @@
# 第一部分:导论
## 本部分目标
建立读者对AI在空间领域应用的宏观认知,理解:
- 为什么在AI时代需要理解原理而非仅仅学习操作
- 空间智能的独特性及其与通用AI的区别
- 自主设计的真正含义及其在设计实践中的价值
- Claude Code如何作为学习工具而不仅是生产力工具
---
## 章节导航
| 章节 | 文件 | 核心问题 | 实践 |
|-----|------|---------|------|
| 00.1 | [为什么要读这本书](./00.1-why-this-book.md) | AI只是工具吗?原理知识为何重要? | ENAgent项目介绍 |
| 00.2 | [空间智能是什么](./00.2-what-is-spatial-intelligence.md) | 机器如何"理解"空间? | 空间推理演示 |
| 00.3 | [自主设计的含义](./00.3-what-is-autonomous-design.md) | 自动与自主有何区别? | HITL工作流示意 |
| 00.4 | [Claude Code作为脚手架](./00.4-claude-code-as-scaffold.md) | 如何借力AI学习AI | Claude Code基础操作 |
---
## 学习路径
```
开始阅读
├─ 你怀疑AI的可靠性?
│ └─ 重点阅读 00.1
├─ 你想了解空间AI的独特性?
│ └─ 重点阅读 00.2
├─ 你对Agent和自动化感兴趣?
│ └─ 重点阅读 00.3
└─ 你想快速上手实践?
└─ 直接跳到 00.4
```
---
## 前置知识
**必需**
- 基本的GIS概念(图层、坐标系、矢量/栅格)
- Python编程基础
** helpful but not required**
- 机器学习的基本概念
- 工作流自动化经验
---
## 预计学习时间
| 阅读类型 | 时间估计 |
|---------|---------|
| 快速浏览 | 2-3小时 |
| 理解性阅读 | 6-8小时 |
| 完成所有实践 | 12-15小时 |
---
## 章节亮点
### 00.1 为什么要读这本书
- 揭示"命令依赖症"的危害
- 解释为什么AI知识半衰期越来越短
- 提出持久认知框架的构建方法
### 00.2 空间智能是什么
- 从人类空间认知到机器空间智能
- GIS与空间智能的本质区别
- 空间推理的两种范式
### 00.3 自主设计的含义
- 澄清常见误解:自动 ≠ 自主
- HITLHuman-in-the-Loop)的设计哲学
- 从工具到伙伴的关系转变
### 00.4 Claude Code作为脚手架
- Claude Code的独特优势
- Agent、Skill、Hook的直观理解
- 工具中性原则:如何不被特定工具绑定
---
## 实践案例00:搭建你的第一个空间AI助手
在阅读完所有章节后,你将能够:
1. 配置Claude Code环境
2. 创建一个简单的空间查询Skill
3. 理解Agent如何调用工具完成任务
4. 建立对后续学习的信心
详见 [practice/setup-first-assistant](./practice/setup-first-assistant/)
---
## 思考问题
在开始阅读前,请思考:
1. 你目前使用AI的方式是什么?遇到的最大困扰是什么?
2. 你认为"理解原理"和"学会操作"哪个更重要?为什么?
3. 空间分析与一般的智能任务有什么不同?
4. 你期待AI在设计工作中扮演什么角色?
带着这些问题阅读,会更有收获。
@@ -0,0 +1,348 @@
# 实践案例00:搭建你的第一个空间AI助手
## 目标
通过本实践,你将:
1. 配置Claude Code环境
2. 创建一个简单的空间查询技能
3. 理解Agent如何调用工具
4. 建立对后续学习的信心
---
## 步骤1:环境准备
### 安装Claude Code
```bash
# 使用npm安装
npm install -g @anthropic-ai/claude-code
# 验证安装
claude --version
```
### 配置API密钥
```bash
# 设置API密钥
claude config set api_key your_anthropic_api_key
# 或使用环境变量
export ANTHROPIC_API_KEY=your_key
```
### 安装Python依赖
```bash
# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Linux/Mac
# 或
venv\Scripts\activate # Windows
# 安装依赖
pip install geopandas shapely matplotlib pandas
```
---
## 步骤2:创建空间查询技能
### 2.1 创建技能目录
```bash
mkdir -p .claude/skills
```
### 2.2 编写技能文件
创建 `.claude/skills/spatial-query.md`
```markdown
---
name: spatial-query
description: 执行基础空间查询和分析
parameters:
- data_file: 空间数据文件路径
- query_type: 查询类型(buffer/intersect/nearest
- distance: 缓冲距离(用于buffer查询)
---
## 空间查询技能
当用户需要进行空间查询时,使用此技能。
### 支持的查询类型
1. **buffer**: 缓冲区分析
2. **intersect**: 相交分析
3. **nearest**: 最近邻查找
### 执行流程
1. 读取空间数据
2. 根据查询类型执行相应操作
3. 返回结果和统计信息
4. 可选:生成可视化
```
---
## 步骤3:实现技能逻辑
创建 `examples/spatial_helper.py`
```python
"""
简单的空间分析助手
演示AI如何理解并执行空间任务
"""
import geopandas as gpd
from shapely.geometry import Point
import matplotlib.pyplot as plt
class SpatialHelper:
"""空间分析助手类"""
def __init__(self, data_path=None):
self.data = None
if data_path:
self.load_data(data_path)
def load_data(self, path):
"""加载空间数据"""
try:
self.data = gpd.read_file(path)
return f"成功加载 {len(self.data)} 个空间要素"
except Exception as e:
return f"加载失败: {str(e)}"
def buffer_analysis(self, distance, crs=None):
"""缓冲区分析"""
if self.data is None:
return "请先加载数据"
if crs:
# 转换到适合距离计算的坐标系
self.data = self.data.to_crs(crs)
buffered = self.data.buffer(distance)
result = gpd.GeoDataFrame(geometry=buffered, crs=self.data.crs)
return {
'count': len(result),
'total_area': result.geometry.area.sum(),
'geometry': result
}
def intersect_analysis(self, other_data):
"""相交分析"""
if self.data is None:
return "请先加载数据"
intersection = self.data.intersection(other_data)
valid_results = intersection[~intersection.is_empty]
return {
'intersecting_count': len(valid_results),
'geometries': valid_results
}
def nearest_neighbor(self, point, n=1):
"""最近邻查找"""
if self.data is None:
return "请先加载数据"
if isinstance(point, (tuple, list)):
point = Point(point)
distances = self.data.geometry.distance(point)
nearest_indices = distances.nsmallest(n).index
results = []
for idx in nearest_indices:
results.append({
'index': idx,
'distance': distances[idx],
'geometry': self.data.loc[idx].geometry
})
return results
def summarize(self):
"""数据摘要"""
if self.data is None:
return "请先加载数据"
return {
'count': len(self.data),
'crs': str(self.data.crs),
'bounds': self.data.total_bounds,
'geometry_types': self.data.geometry.type.value_counts().to_dict()
}
def visualize(self, output_path=None):
"""可视化"""
if self.data is None:
return "请先加载数据"
fig, ax = plt.subplots(figsize=(10, 10))
self.data.plot(ax=ax, alpha=0.5, edgecolor='k')
ax.set_title('Spatial Data Visualization')
ax.set_axis_off()
if output_path:
plt.savefig(output_path, bbox_inches='tight', dpi=300)
return f"图表已保存到 {output_path}"
plt.show()
return "图表已显示"
# 创建一个示例数据集用于测试
def create_sample_data():
"""创建示例空间数据"""
import numpy as np
np.random.seed(42)
# 创建一些随机点
points = [Point(np.random.uniform(-100, 100),
np.random.uniform(-100, 100))
for _ in range(20)]
# 转换为GeoDataFrame
gdf = gpd.GeoDataFrame({
'id': range(20),
'value': np.random.randint(1, 100, 20),
'category': np.random.choice(['A', 'B', 'C'], 20)
}, geometry=points, crs='EPSG:4326')
# 保存为GeoJSON
gdf.to_file('sample_data.geojson', driver='GeoJSON')
return gdf
if __name__ == "__main__":
# 创建示例数据
print("创建示例数据...")
create_sample_data()
# 测试SpatialHelper
print("\n初始化空间助手...")
helper = SpatialHelper('sample_data.geojson')
print("\n数据摘要:")
print(helper.summarize())
print("\n缓冲区分析:")
buffer_result = helper.buffer_analysis(10)
print(f"缓冲区数量: {buffer_result['count']}")
print(f"总缓冲面积: {buffer_result['total_area']:.2f}")
print("\n最近邻查找:")
nearest = helper.nearest_neighbor((0, 0), n=3)
for i, n in enumerate(nearest, 1):
print(f" {i}. 距离: {n['distance']:.2f}")
print("\n生成可视化...")
print(helper.visualize('spatial_visualization.png'))
```
---
## 步骤4:在Claude Code中使用
### 4.1 启动Claude Code
```bash
cd /path/to/CC4SI
claude
```
### 4.2 与Claude对话
```
你: 我有一个空间数据文件sample_data.geojson,帮我分析一下
Claude: 让我先读取这个文件看看...
[读取 sample_data.geojson]
这是一个包含20个点要素的GeoJSON文件,坐标系统为WGS84 (EPSG:4326)。
每个点都有id、value和category属性。
你想要进行什么分析?
你: 找出距离原点最近的3个点
Claude: 我来帮你找出距离原点最近的点。
[调用 spatial-query 技能]
结果:
1. 最近点 (id=7): 距离约 15.2 单位
2. 第二近点 (id=12): 距离约 23.8 单位
3. 第三近点 (id=3): 距离约 31.5 单位
需要我生成可视化吗?
```
---
## 步骤5:理解工作原理
### AI系统的思考过程
```
用户请求 ──→ [意图识别] ──→ [任务分解]
│ │
↓ ↓
这是空间查询 需要执行:
任务 1. 加载数据
2. 计算距离
3. 排序取前N
│ │
↓ ↓
[选择技能] ──→ [调用工具]
│ │
↓ ↓
spatial-query spatial_helper.py
│ │
└───────┬───────┘
[整合结果]
[返回用户]
```
### 关键概念验证
| 概念 | 实践体现 |
|-----|---------|
| Agent | Claude Code作为智能体,理解意图并协调执行 |
| Skill | spatial-query技能封装了空间分析能力 |
| Tool | spatial_helper.py是具体实现工具 |
---
## 反思问题
1. **理解验证**:你能在脑海中复述一遍AI执行这个任务的流程吗?
2. **扩展思考**:如果要让这个助手支持更多空间操作,应该如何设计?
3. **局限性**:当前实现有哪些不足?如何改进?
4. **迁移应用**:这个模式可以应用到你的专业领域吗?
---
## 下一步
完成这个实践后,你已经:
- ✅ 配置了Claude Code环境
- ✅ 创建了第一个空间分析技能
- ✅ 理解了Agent的基本工作方式
准备好进入下一章:**01-foundations(基础原理)**