第 24 章:插件系统

个人公众号
1
2
卷四:纵深
[20] 配置 -> [21] 记忆 -> [22] 自治 -> [23] 多智能体 -> [24] 插件系统 <- you are here

QwenPaw 有两种扩展机制——Skill(技能)和 Plugin(插件)。技能我们已经在第 14 章和第 16 章详细讲过。这一章看 Plugin 系统——它和 Skill 有什么区别?插件怎么被发现和加载?插件能注册什么?


Plugin vs Skill——两种扩展机制

1
2
3
4
5
6
7
8
9
10
11
12
13
Skill(技能)
目的:扩展 LLM 的知识("知道怎么做")
格式:SKILL.md + references/ + scripts/
加载:注入到系统提示词
谁能写:任何人(Markdown 文档)
来源:内置、技能市场、手动创建

Plugin(插件)
目的:扩展 QwenPaw 的功能("能做什么")
格式:Python 模块 + plugin.json
加载:动态 import,调用 register() 方法
谁能写:Python 开发者
来源:插件目录、pip 安装

Skill 是”文档”,Plugin 是”代码”。Skill 让 LLM 学会新能力,Plugin 让 QwenPaw 获得新功能。

插件的生命周期

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1. 发现:PluginLoader.discover_plugins() 扫描插件目录
- 查找包含 plugin.json 的子目录
- 解析 PluginManifest

2. 加载:PluginLoader.load_plugin()
- importlib 动态导入插件模块
- 调用 plugin.register(api)

3. 注册:PluginApi 提供注册方法
- register_provider() 注册新的 LLM Provider
- register_startup_hook() 注册启动钩子
- register_shutdown_hook() 注册关闭钩子
- register_control_command() 注册控制命令

4. 运行:钩子在对应生命周期被调用
- startup hooks 按 priority 排序执行
- shutdown hooks 按 priority 排序执行

PluginManifest——插件的元数据

plugin.json 定义插件的元数据:

1
2
3
4
5
6
7
8
9
10
11
12
{
"id": "my-plugin",
"name": "My Plugin",
"version": "1.0.0",
"description": "Does something useful",
"author": "Developer",
"entry": {
"backend": "my_plugin/main.py"
},
"dependencies": [],
"min_version": "0.1.0"
}

插件注册 API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 插件代码示例
class MyPlugin:
def register(self, api):
# 注册自定义 Provider
api.register_provider(
provider_id="my-llm",
provider_class=MyProvider,
label="My LLM Service",
base_url="https://api.my-llm.com/v1",
)

# 注册启动钩子
async def on_startup():
logger.info("My plugin started")
api.register_startup_hook("my_startup", on_startup, priority=100)

PluginRegistry——单例注册表

PluginRegistry 用单例模式管理所有注册:

1
2
3
4
5
class PluginRegistry:
_providers: Dict[str, ProviderRegistration]
_startup_hooks: List[HookRegistration]
_shutdown_hooks: List[HookRegistration]
_control_commands: List[ControlCommandRegistration]

钩子按 priority 排序——数字越小越早执行。

插件发现目录

PluginLoader 扫描的目录:

  1. 配置中指定的插件路径
  2. ~/.qwenpaw/plugins/
  3. 其他自定义路径

每个包含 plugin.json 的子目录被视为一个插件。

工程权衡

为什么 Plugin 和 Skill 要分开?

Skill 是轻量级的——Markdown 文档,不需要编程能力。Plugin 是重量级的——Python 代码,能注册 Provider、钩子、命令。分开让两种用户群体都能扩展 QwenPaw:非程序员用 Skill,程序员用 Plugin。

为什么用动态 import 而非 pip 安装?

插件的代码量通常很小,放在目录里比发布到 PyPI 更简单。动态 import 让用户可以直接放文件到插件目录,不需要 pip install。但也支持 pip 安装——通过 entry_points 注册。

自检

  • 知道 Plugin 扩展功能(注册 Provider、钩子),Skill 扩展知识(注入提示词)
  • 知道插件通过 plugin.json + register(api) 注册
  • 知道 PluginRegistry 是单例,管理所有注册
  • 知道钩子按 priority 排序执行

下一章我们看命令行与部署——从终端启动到 Docker 容器。