Files
2026_DesignAI/officefile/supplements/00-introduction/practice/setup-first-assistant/README.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

349 lines
8.4 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.
# 实践案例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(基础原理)**