219232de74
以讲义内容为骨架迁移到标准目录格式: - 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>
349 lines
8.4 KiB
Markdown
349 lines
8.4 KiB
Markdown
# 实践案例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(基础原理)**
|