Skill 插件系统深度拆解:QwenPaw 的能力扩展引擎【第四篇】
一、先说结论:Skill 才是这个系统的真正价值
很多人一开始会把注意力放在 Agent 上,这是个误区。
在 QwenPaw 里:
❗Agent 决定流程,但 Skill 决定“能力上限”
🧠 一个关键公式
系统能力 = Agent能力 × Skill能力
👉 如果没有 Skill:
二、Skill 的本质是什么?
一句话:
Skill = 可被 Agent 调用的函数(带元数据)
但 QwenPaw 在这个基础上做了三层增强:
✅ 1. 自动发现(Auto Discovery)
不需要手动注册:
放进目录 → 自动加载
✅ 2. 安全控制(Guard)
✅ 3. 调用协议标准化
所有 Skill 都遵循统一接口:
输入 → 执行 → 输出
📌 这三点,让它从“函数”变成了“插件系统”
三、源码结构:Skill 在哪里?
📂 核心目录
qwenpaw/└── skill/ ├── base.py ├── registry.py ├── loader.py
👉 三个关键模块:
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
四、Skill 是如何被加载的?(源码级)
🧭 启动时流程(接 Day2)
app.start() ↓load_skills() ↓scan directory ↓import module ↓register skill
🔍 关键步骤拆解
1️⃣ 扫描目录
scan("skills/")
👉 找到所有 Python 文件
2️⃣ 动态导入
importlib.import_module()
👉 关键点:
❗这里没有显式引用,是“动态加载”
3️⃣ 注册 Skill
registry.register(skill)
📌 到这里:
Skill 才真正“进入系统”
五、Skill 的定义(源码级写法)
✍️ 一个最小 Skill 示例
from qwenpaw.skill import BaseSkillclassWeatherSkill(BaseSkill): name ="get_weather" description ="获取天气信息"defrun(self, city:str):returnf"{city} 天气晴朗"
🧠 必须包含的三个要素
1️⃣ name(唯一标识)
name ="get_weather"
👉 Agent 就是靠这个调用你
2️⃣ description(给 LLM 看)
description ="获取天气信息"
📌 非常重要:
LLM 是通过这个“理解你能做什么”
3️⃣ run()(执行逻辑)
defrun(self,...):
👉 真正执行的地方
六、Skill 调用全链路(重点)
🧭 完整路径
用户请求 ↓Agent(LLM推理) ↓选择 Skill(基于 description) ↓Skill Selector ↓Tool Guard(安全检查) ↓执行 run() ↓返回结果
🔥 关键点:Skill 是“被 LLM 选中的”
不是:
if xxx: call skill
而是:
LLM 判断 → 调用哪个 Skill
📌 这也是很多人调不通的原因:
❗description 写得差 = 永远不会被调用
七、Skill Guard 机制(企业级必须理解)
🛡 三层防护
1️⃣ Tool Guard
控制:
2️⃣ File Guard
限制:
3️⃣ Skill Scan
在加载时:
📌 架构意义:
让 Agent 能“安全地自动执行”
八、二次开发:如何接入企业系统(实战)
我们来写一个真实一点的 Skill:
👉 调用内部 API(比如 CRM)
✍️ 示例:查询客户信息
import requestsfrom qwenpaw.skill import BaseSkillclassCRMQuerySkill(BaseSkill): name ="query_customer" description ="根据客户ID查询客户信息"defrun(self, customer_id:str): resp = requests.get(f"http://internal-api/customer/{customer_id}")return resp.json()
🧠 Agent 会这样用:
用户说:
“帮我查一下客户 1001 的信息”
LLM 推理:
→ 发现 description 匹配 → 调用 query_customer
📌 效果:
👉 自然语言 → 企业系统调用
九、Skill 设计的高级技巧(架构师级)
🎯 1. description 要“像人话”
❌ 不好:
获取数据
✅ 好:
根据客户ID查询客户详细信息(姓名、电话、订单)
🎯 2. 参数要简单
❌ 不好:
defrun(self, data:dict)
✅ 好:
defrun(self, customer_id:str)
👉 因为:
LLM 更容易正确调用
🎯 3. 返回值要“可读”
❌ 不好:
return{"code":0,"data":{...}}
✅ 好:
returnf"客户姓名:{name},电话:{phone}"
🎯 4. 一个 Skill 只做一件事
不要:
一个 Skill 做 5 件事
👉 否则:
LLM 无法正确选择
十、开发者最容易踩的坑
❌ 1. Skill 没被加载
原因:
❌ 2. description 写太抽象
结果:
❌ 3. 返回结构太复杂
结果:
❌ 4. 依赖外部服务但没处理异常
结果:
十一、本篇总结(最关键认知)
🧠 1️⃣ Skill 是系统能力的“唯一扩展点”
🧠 2️⃣ Skill 是否被调用,取决于 description
🧠 3️⃣ Skill 设计好坏,直接决定系统好不好用
👉 下一篇预告(Day 5)
我们进入一个“隐形但极其关键”的系统:
👉 Memory 与上下文系统(为什么 Agent 能“记住”)
包括:
这一篇会帮你解决一个核心问题:
👉 为什么你的 Agent “用两次就变傻”
夜雨聆风