乐于分享
好东西不私藏

Skill 插件系统深度拆解:QwenPaw 的能力扩展引擎【第四篇】

本文最后更新于2026-04-27,某些文章具有时效性,若有错误或已失效,请在下方留言或联系老夜

Skill 插件系统深度拆解:QwenPaw 的能力扩展引擎【第四篇】

一、先说结论:Skill 才是这个系统的真正价值

很多人一开始会把注意力放在 Agent 上,这是个误区。

在 QwenPaw 里:

❗Agent 决定流程,但 Skill 决定“能力上限”


🧠 一个关键公式

系统能力 = Agent能力 × Skill能力

👉 如果没有 Skill:

• 
Agent 再聪明也只能“聊天”
• 
无法操作现实世界

二、Skill 的本质是什么?

一句话:

Skill = 可被 Agent 调用的函数(带元数据)


但 QwenPaw 在这个基础上做了三层增强:


✅ 1. 自动发现(Auto Discovery)

不需要手动注册:

放进目录 → 自动加载

✅ 2. 安全控制(Guard)

• 
Tool Guard(调用限制)
• 
File Guard(文件访问控制)
• 
Skill Scan(代码扫描)

✅ 3. 调用协议标准化

所有 Skill 都遵循统一接口:

输入 → 执行 → 输出

📌 这三点,让它从“函数”变成了“插件系统”


三、源码结构:Skill 在哪里?


📂 核心目录

qwenpaw/└── skill/    ├── base.py    ├── registry.py    ├── loader.py

👉 三个关键模块:

文件
作用
base.py
Skill 基类
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

控制:

• 
哪些 Skill 可以被调用
• 
调用频率


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 没被加载

原因:

• 
目录不对
• 
文件没 import


❌ 2. description 写太抽象

结果:

• 
Agent 永远不调用


❌ 3. 返回结构太复杂

结果:

• 
LLM 无法理解


❌ 4. 依赖外部服务但没处理异常

结果:

• 
Agent 崩溃 / 卡死


十一、本篇总结(最关键认知)


🧠 1️⃣ Skill 是系统能力的“唯一扩展点”


🧠 2️⃣ Skill 是否被调用,取决于 description


🧠 3️⃣ Skill 设计好坏,直接决定系统好不好用



👉 下一篇预告(Day 5)

我们进入一个“隐形但极其关键”的系统:

👉 Memory 与上下文系统(为什么 Agent 能“记住”)

包括:

• 
Memory 如何存储
• 
Dream(记忆整理机制)
• 
上下文裁剪(Token控制)
• 
Memory vs RAG 的本质区别

这一篇会帮你解决一个核心问题:

👉 为什么你的 Agent “用两次就变傻”