共计 2650 个字符,预计需要花费 7 分钟才能阅读完成。
Cursor Skill 架构浅析
Cursor 的 Skill 系统本质是插件机制,通过 Python 模块化扩展实现功能注入。当用户输入匹配特定意图时,Cursor 会动态加载对应的 Skill 模块,执行预定义的 execute() 入口函数。整个过程涉及三个关键组件:

- 意图识别层:基于用户输入的自然语言解析(如 ” 今天天气怎样 ” 触发 weather_skill)
- 技能执行层:各 Skill 独立实现业务逻辑,返回结构化响应
- 结果渲染层:Cursor 统一处理 Markdown/HTML 等输出格式
天气查询 Skill 开发实战
1. 环境准备
确保已安装最新版 Cursor IDE 和 Python 3.8+,新建 weather_skill 目录并创建以下文件结构:
weather_skill/
├── __init__.py
├── main.py # Skill 主逻辑
└── schemas.py # 数据模型定义
2. API 集成实现
使用 OpenWeatherMap 免费版 API(需注册获取 API_KEY),通过 requests 实现数据获取:
# main.py
import os
from typing import Optional
import requests
from pydantic import BaseModel
class WeatherResponse(BaseModel):
city: str
temp: float
description: str
humidity: int
class WeatherSkill:
BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
def __init__(self):
self.api_key = os.getenv("OWM_API_KEY")
def get_weather(self, city: str) -> Optional[WeatherResponse]:
"""获取指定城市天气数据"""
try:
params = {
"q": city,
"appid": self.api_key,
"units": "metric",
"lang": "zh_cn"
}
resp = requests.get(self.BASE_URL, params=params, timeout=5)
resp.raise_for_status()
data = resp.json()
return WeatherResponse(
city=city,
temp=data["main"]["temp"],
description=data["weather"][0]["description"],
humidity=data["main"]["humidity"]
)
except Exception as e:
print(f"API 请求失败: {str(e)}")
return None
3. 自然语言交互设计
在 __init__.py 中注册 Skill 并实现意图匹配:
# __init__.py
from typing import Dict, Any
from .main import WeatherSkill
skill = WeatherSkill()
def execute(params: Dict[str, Any]) -> str:
"""Cursor 标准入口函数"""
if "city" not in params:
return "请指定查询城市,例如:' 上海天气如何 '"result = skill.get_weather(params["city"])
if not result:
return "天气查询失败,请稍后重试"
return (f"## {result.city}天气情况 \n"
f"- 温度:{result.temp}℃\n"
f"- 湿度:{result.humidity}%\n"
f"- 天气状况:{result.description}"
)
4. 增强健壮性
添加缓存和重试机制提升稳定性:
# 在 WeatherSkill 类中追加
from datetime import datetime, timedelta
import functools
from tenacity import retry, stop_after_attempt
class WeatherSkill:
# ... 原有代码...
@functools.lru_cache(maxsize=32)
@retry(stop=stop_after_attempt(3))
def get_weather(self, city: str) -> Optional[WeatherResponse]:
"""带缓存和重试的天气查询"""
# ... 原有实现...
生产环境注意事项
API 密钥安全管理
- 永远不要硬编码密钥:使用环境变量或密钥管理服务(如 AWS Secrets Manager)
- 最小权限原则:为 API_KEY 设置仅限必要接口的访问权限
- 监控异常调用:通过日志分析异常访问模式
性能优化建议
- 使用 aiohttp 替换 requests 实现异步请求
- 对高频查询城市实施本地缓存(如 Redis)
- 设置合理的 HTTP 超时(建议连接 5 秒 / 读取 10 秒)
单元测试要点
# test_weather.py
import pytest
from unittest.mock import patch
from .main import WeatherSkill
@patch('requests.get')
def test_get_weather_success(mock_get):
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {"main": {"temp": 25, "humidity": 60},
"weather": [{"description": "晴朗"}]
}
skill = WeatherSkill()
result = skill.get_weather("北京")
assert result.city == "北京"
assert result.temp == 25
扩展思考方向
- 多语言支持:
- 根据用户系统语言自动切换响应语言
-
使用 gettext 实现本地化字符串管理
-
服务集成:
- 结合地图 API 实现位置自动推断
- 接入预警 API 提供极端天气提醒
开发完成后,将整个目录放入 Cursor 的 skills 文件夹即可自动加载。通过 @cursor 命令测试你的新 Skill 吧!
小贴士:实际开发中建议使用 Cookiecutter 模板规范项目结构,更多示例可参考 Cursor 官方 Skill 仓库。
正文完
