第 16 章:造一个新技能

个人公众号
1
2
卷三:工坊实战
[15] 造新工具 -> [16] 造新技能 <- you are here

上一章造了一把工具——注册 Python 函数让 LLM 调用。这次我们造一个技能——用 Markdown 文档教 LLM 做复杂任务。工具是”能做什么”,技能是”知道怎么做”。


目标

造一个 weather 技能——让 Agent 能查天气。不注册新函数,而是通过 SKILL.md 告诉 LLM 怎么用已有的工具获取天气信息。

技能 vs 工具的区别(复习)

1
2
3
4
5
6
7
工具:Python 函数,LLM 通过 function calling 调用
注册:toolkit.register_tool_function(fn)
扩展:LLM "能做什么"

技能:Markdown 文档,注入到系统提示词
注册:toolkit.register_agent_skill(skill_dir)
扩展:LLM "知道怎么做"

技能不注册新函数。它告诉 LLM “你可以用已有的工具做 X,步骤如下”。

第一步:创建技能目录

src/qwenpaw/agents/skills/ 下创建 weather-en/

1
2
3
4
skills/weather-en/
SKILL.md # 必须:技能指令
references/ # 可选:参考文档
api_reference.md # 天气 API 的参数说明

第二步:编写 SKILL.md

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
---
name: weather
description: Use this skill when the user asks about weather
conditions, forecasts, or temperature for any location.
metadata:
builtin_skill_version: "1.0"
qwenpaw:
emoji: "🌤️"
---

# Weather Skill

## When to use
When the user asks about current weather, forecasts,
or meteorological data for any city or location.

## How to use

### Step 1: Get weather data
Use the wttr.in API which accepts city names directly:

execute_shell_command: curl -s “wttr.in/London?format=j1”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

### Step 2: Parse the JSON response
The response contains:
- `current_condition`: Current temp, humidity, description
- `weather`: 3-day forecast array

### Step 3: Format the response
Present weather in a clear format:
- Temperature (C and F)
- Condition (sunny, cloudy, rainy)
- Humidity percentage
- Wind speed and direction

## Notes
- wttr.in is free, no API key needed
- If city not recognized, ask user to clarify
- Always include both Celsius and Fahrenheit

YAML 前置元数据的必填字段:

  • name:技能标识符
  • description:告诉 LLM 什么场景下应该使用这个技能

第三步:添加参考文档

references/api_reference.md

1
2
3
# wttr.in API Reference

## Current weather + forecast

curl -s “wttr.in/{location}?format=j1”

1
2
3
4
5
6

## Response fields (format=j1)
- `current_condition[0].temp_C`: Celsius
- `current_condition[0].humidity`: Percentage
- `current_condition[0].weatherDesc[0].value`: Description
- `current_condition[0].windspeedKmph`: Wind km/h

第四步:注册技能

技能目录在 skills/ 下后,import_builtin_skills() 会自动扫描发现它。只要目录名是 <name>-<language> 格式(如 weather-en),就会被发现并导入到技能池。

不需要手动注册——skills_manager.py 的正则 ^(?P<name>.+)-(?P<language>en|zh)$ 会匹配 weather-en

第五步:测试

启动 QwenPaw,问 Agent 天气相关的问题:

1
2
3
4
5
用户:上海今天天气怎么样?
Agent:(读取 SKILL.md,按照步骤执行)
(调用 execute_shell_command: curl -s "wttr.in/Shanghai?format=j1")
(解析 JSON,格式化输出)
Agent:上海目前气温 28°C(82°F),多云,湿度 72%...

技能的工作原理(内部机制)

1
2
3
4
5
6
7
8
9
1. Agent 启动时,_register_skills() 发现 weather-en 目录
2. toolkit.register_agent_skill("skills/weather-en/") 被调用
3. 解析 SKILL.md 的 YAML 前置元数据 -> name + description
4. 把技能信息追加到系统提示词:
"## weather
Use this skill when the user asks about weather...
Check 'skills/weather-en/SKILL.md' for how to use."
5. LLM 看到提示后,需要时用 read_file 读取完整 SKILL.md
6. 按照指令用 execute_shell_command (curl) 获取天气数据

工程要点

  • SKILL.md 的 description 是关键——它决定了 LLM 什么时候”想到”用这个技能。写得太模糊会误触发,太窄会忘记用。
  • 步骤要具体——“调用天气 API” 不如 curl -s "wttr.in/CityName?format=j1" 具体。
  • scripts/ 用于复杂逻辑——如果需要 Python 脚本辅助,放在 scripts/ 下,SKILL.md 中用 cd {this_skill_dir} && python scripts/xxx.py 引用。
  • 安全扫描——enable_skill() 会运行 SkillScanner。确保脚本中没有 eval()subprocess(shell=True) 等高危模式。

自检

  • 创建了 skills/weather-en/ 目录和 SKILL.md
  • SKILL.md 有 YAML 前置元数据(name、description)
  • 理解了技能通过提示注入扩展 LLM 知识
  • 知道 LLM 用已有工具(execute_shell_command)执行技能指令

下一章我们接入一个新模型——新增一个 LLM Provider。