指令查询插件 v2.1
让 LLM 成为用户的智能指令助手 | 性能优化版
🎯 核心功能
为 LLM 提供实时指令查询能力,让 LLM 能够:
- ✅ 纠正错误指令 - 用户输错时自动查询正确写法
- ✅ 引导正确使用 - 用户不会用时查询详细用法
- ✅ 推荐相关功能 - 智能推荐相关指令
💡 应用场景
场景 1:用户输错指令
👤 用户:/钩鱼
🤖 LLM:[调用 search_command("钩鱼")]
🤖 LLM:姐姐,是 /钓鱼 哦,不是钩鱼~
场景 2:用户不知道怎么用
👤 用户:怎么玩钓鱼啊
🤖 LLM:[调用 get_command_detail("/钓鱼")]
🤖 LLM:钓鱼游戏有这些指令:
• /钓鱼 - 开始钓鱼
• /我的背包 - 查看渔获
• /鱼类图鉴 - 查看图鉴
场景 3:用户找功能
👤 用户:有没有抽奖功能
🤖 LLM:[调用 search_command("抽奖")]
🤖 LLM:有的!你可以用:
• /抽奖 - 参与抽奖
• /创建抽奖 - 创建抽奖活动
🛠️ LLM 工具函数
1. search_command(keyword)
搜索指令 - 支持模糊搜索、关键词匹配
# 参数
keyword: str # 搜索关键词(指令名/功能描述/插件名)
# 返回示例
{
"success": true,
"message": "找到 3 条与 '钓鱼' 相关的指令",
"results": [
{
"command": "/钓鱼",
"description": "开始钓鱼游戏",
"plugin": "钓鱼游戏插件",
"aliases": ["/fishing", "/fish"]
}
]
}
使用场景:
- 用户输入错误指令,需要纠正
- 用户想找某个功能
- 用户记不清指令名称
2. get_command_detail(command_name)
查询指令详情 - 获取指令的完整信息
# 参数
command_name: str # 指令名称(可带或不带 / 前缀)
# 返回示例
{
"success": true,
"command": "/钓鱼",
"description": "开始钓鱼游戏",
"plugin": "钓鱼游戏插件",
"aliases": ["/fishing", "/fish"],
"similar_commands": ["/我的背包", "/鱼类图鉴"]
}
使用场景:
- 用户询问某个指令怎么用
- LLM 需要获取详细信息来回答用户
- 推荐相关指令
3. list_plugin_commands(plugin_name)
列举插件指令 - 查看插件的所有功能
# 参数
plugin_name: str # 插件名称(可选,不传返回所有插件列表)
# 返回示例(指定插件)
{
"success": true,
"plugin": "钓鱼游戏插件",
"command_count": 3,
"commands": [
{
"command": "/钓鱼",
"description": "开始钓鱼游戏",
"aliases": ["/fishing"]
}
]
}
# 返回示例(不指定插件)
{
"success": true,
"message": "系统共有 15 个插件",
"plugins": ["钓鱼游戏插件", "抽奖插件", ...],
"hint": "使用 list_plugin_commands 并指定 plugin_name 参数查看具体插件的指令"
}
使用场景:
- 用户询问某个插件有什么功能
- LLM 需要了解插件的完整功能列表
- 查看系统中所有可用插件
🧪 测试命令
为了方便调试和演示,插件提供了测试命令:
| 命令 | 别名 | 说明 |
|---|---|---|
/测试指令搜索 <关键词> |
/test_search |
测试搜索功能 |
/测试指令详情 <指令名> |
/test_detail |
测试详情查询 |
/测试插件列表 [插件名] |
/test_plugins |
测试插件查询 |
/刷新指令缓存 |
/refresh_cache |
手动刷新缓存 |
/指令查询帮助 |
/query_help |
显示帮助信息 |
测试示例
# 搜索指令
/测试指令搜索 钓鱼
# 查询指令详情
/测试指令详情 钓鱼
# 查看所有插件
/测试插件列表
# 查看指定插件的指令
/测试插件列表 钓鱼游戏
📋 返回格式设计
精简原则
所有返回数据都遵循 精简实用 的原则:
- ✅ 只返回必要的信息
- ✅ 结构清晰,易于解析
- ✅ 避免冗余数据
- ✅ 支持错误提示和建议
标准返回结构
{
"success": true/false, // 操作是否成功
"message": "...", // 提示信息(可选)
"data_field": ..., // 实际数据
"suggestions": [...], // 建议(失败时可选)
"hint": "..." // 使用提示(可选)
}
🎨 特性亮点
1. 智能缓存 + 自动刷新
- 首次启动时缓存所有指令
- 后续查询秒级响应
- 自动检测插件变化,热加载时自动重建缓存
- 支持手动刷新缓存命令
- 减少重复计算
2. 模糊匹配
支持多种匹配策略:
- 精确匹配(优先)
- 命令名包含关键词
- 描述包含关键词
- 插件名包含关键词
3. 别名支持
- 自动识别指令别名
- 为别名建立索引
- 查询时会显示原始指令
4. 相关推荐
查询指令详情时,自动推荐同插件的其他指令
🔧 技术实现
核心架构
CommandQueryPlugin
├── _build_handler_index() # 构建 Hash Map 索引 (O(M))
├── _should_refresh_cache() # 检测插件变化
├── _get_all_commands() # 获取并缓存所有指令 (O(N+M))
├── _search_similar_commands() # 模糊搜索算法
├── search_command() # LLM工具:搜索指令
├── get_command_detail() # LLM工具:查询详情
├── list_plugin_commands() # LLM工具:列举插件指令
└── refresh_cache() # 命令:手动刷新缓存
性能优化
问题:原版 O(N²) 嵌套循环
# 每个插件都遍历全局注册表
for star in all_stars: # N 个插件
for handler in star_handlers_registry: # M 个 handler
if handler.module_path == star.module_path:
# 处理...
- 时间复杂度:O(N × M)
- 36 插件 × 350 handlers = 12,600 次比较
优化:Hash Map 索引 + 直接查找
# 一次性构建索引
handler_index = {module_path: [handlers...]} # O(M)
# 直接查找
for star in all_stars: # O(N)
handlers = handler_index[star.module_path] # O(1)
# 处理...
- 时间复杂度:O(N + M)
- 36 + 350 = 386 次操作
- 性能提升 97%!
缓存失效机制
- 自动检测插件数量变化
- 热加载/卸载插件时自动重建缓存
- 支持手动刷新命令
数据结构
# 指令信息结构
{
"command": "/钓鱼", # 指令名
"description": "开始钓鱼游戏", # 描述
"plugin": "钓鱼游戏插件", # 所属插件
"aliases": ["/fishing"], # 别名列表
"is_alias_of": "/钓鱼" # 别名指向(仅别名有)
}
📦 安装使用
- 将插件放入 AstrBot 的
data/plugins/目录 - 重启 AstrBot
- 插件会自动加载并注册 LLM 工具
- LLM 会自动根据用户需求调用相应工具
🆕 版本历史
v2.1.0 (2024-12-29)
性能优化 - 向 Linus Torvalds 致敬
- ⚡ 重大性能优化:使用 Hash Map 索引,时间复杂度从 O(N²) 降到 O(N+M)
- 🔄 智能缓存失效:自动检测插件变化,热加载时自动重建缓存
- ✨ 新增
/刷新指令缓存命令 - 支持手动刷新 - 📊 性能提升 97%(12,600 → 386 次操作)
- 🔥 解决热加载插件后缓存不更新的问题
v2.0.0 (2024-12-23)
重大重构 - 从统计工具变为实时助手
- ✨ 新增
search_command- 模糊搜索指令 - ✨ 新增
get_command_detail- 查询指令详情 - ✨ 新增
list_plugin_commands- 列举插件指令 - ✨ 全新的测试命令系统
- ♻️ 完全重构核心架构
- 📝 精简返回格式,避免上下文污染
v1.1.0
- 概览模式和详细模式
- 插件分类系统
- 按分类查询
v1.0.0
- 基础指令查询功能
📄 许可证
MIT License
作者: 珈百璃
版本: 2.1.0
更新日期: 2024-12-29
特别感谢: Linus Torvalds 的代码评审启发