refactor(cache): 重构工具缓存机制并优化LLM请求重试逻辑
将工具缓存的实现从`ToolExecutor`的装饰器模式重构为直接集成。缓存逻辑被移出`cache_manager.py`并整合进`ToolExecutor.execute_tool_call`方法中,简化了代码结构并使其更易于维护。 主要变更: - 从`cache_manager.py`中移除了`wrap_tool_executor`函数。 - 在`tool_use.py`中,`execute_tool_call`现在包含完整的缓存检查和设置逻辑。 - 调整了`llm_models/utils_model.py`中的LLM请求逻辑,为模型生成的空回复或截断响应增加了内部重试机制,增强了稳定性。 - 清理了项目中未使用的导入和过时的文档文件,以保持代码库的整洁。
This commit is contained in:
committed by
Windpicker-owo
parent
9e720ea80e
commit
a645e766ca
260
docs/plugins/PLUS_COMMAND_GUIDE.md
Normal file
260
docs/plugins/PLUS_COMMAND_GUIDE.md
Normal file
@@ -0,0 +1,260 @@
|
||||
# 增强命令系统使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
增强命令系统是MaiBot插件系统的一个扩展,让命令的定义和使用变得更加简单直观。你不再需要编写复杂的正则表达式,只需要定义命令名、别名和参数处理逻辑即可。
|
||||
|
||||
## 核心特性
|
||||
|
||||
- **无需正则表达式**:只需定义命令名和别名
|
||||
- **自动参数解析**:提供`CommandArgs`类处理参数
|
||||
- **命令别名支持**:一个命令可以有多个别名
|
||||
- **优先级控制**:支持命令优先级设置
|
||||
- **聊天类型限制**:可限制命令在群聊或私聊中使用
|
||||
- **消息拦截**:可选择是否拦截消息进行后续处理
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 1. 创建基础命令
|
||||
|
||||
```python
|
||||
from src.plugin_system import PlusCommand, CommandArgs, ChatType
|
||||
from typing import Tuple, Optional
|
||||
|
||||
class EchoCommand(PlusCommand):
|
||||
"""Echo命令示例"""
|
||||
|
||||
command_name = "echo"
|
||||
command_description = "回显命令"
|
||||
command_aliases = ["say", "repeat"] # 可选:命令别名
|
||||
priority = 5 # 可选:优先级,数字越大优先级越高
|
||||
chat_type_allow = ChatType.ALL # 可选:ALL, GROUP, PRIVATE
|
||||
intercept_message = True # 可选:是否拦截消息
|
||||
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
"""执行命令"""
|
||||
if args.is_empty():
|
||||
await self.send_text("❓ 请提供要回显的内容\\n用法: /echo <内容>")
|
||||
return True, "参数不足", True
|
||||
|
||||
content = args.get_raw()
|
||||
await self.send_text(f"🔊 {content}")
|
||||
|
||||
return True, "Echo命令执行成功", True
|
||||
```
|
||||
|
||||
### 2. 在插件中注册命令
|
||||
|
||||
```python
|
||||
from src.plugin_system import BasePlugin, create_plus_command_adapter, register_plugin
|
||||
|
||||
@register_plugin
|
||||
class MyPlugin(BasePlugin):
|
||||
plugin_name = "my_plugin"
|
||||
enable_plugin = True
|
||||
dependencies = []
|
||||
python_dependencies = []
|
||||
config_file_name = "config.toml"
|
||||
|
||||
def get_plugin_components(self):
|
||||
components = []
|
||||
|
||||
# 使用工厂函数创建适配器
|
||||
echo_adapter = create_plus_command_adapter(EchoCommand)
|
||||
components.append((EchoCommand.get_command_info(), echo_adapter))
|
||||
|
||||
return components
|
||||
```
|
||||
|
||||
## CommandArgs 类详解
|
||||
|
||||
`CommandArgs`类提供了丰富的参数处理功能:
|
||||
|
||||
### 基础方法
|
||||
|
||||
```python
|
||||
# 获取原始参数字符串
|
||||
raw_text = args.get_raw()
|
||||
|
||||
# 获取解析后的参数列表(按空格分割,支持引号)
|
||||
arg_list = args.get_args()
|
||||
|
||||
# 检查是否有参数
|
||||
if args.is_empty():
|
||||
# 没有参数的处理
|
||||
|
||||
# 获取参数数量
|
||||
count = args.count()
|
||||
```
|
||||
|
||||
### 获取特定参数
|
||||
|
||||
```python
|
||||
# 获取第一个参数
|
||||
first_arg = args.get_first("默认值")
|
||||
|
||||
# 获取指定索引的参数
|
||||
second_arg = args.get_arg(1, "默认值")
|
||||
|
||||
# 获取从指定位置开始的剩余参数
|
||||
remaining = args.get_remaining(1) # 从第2个参数开始
|
||||
```
|
||||
|
||||
### 标志参数处理
|
||||
|
||||
```python
|
||||
# 检查是否包含标志
|
||||
if args.has_flag("--verbose"):
|
||||
# 处理verbose模式
|
||||
|
||||
# 获取标志的值
|
||||
output_file = args.get_flag_value("--output", "default.txt")
|
||||
name = args.get_flag_value("--name", "Anonymous")
|
||||
```
|
||||
|
||||
## 高级示例
|
||||
|
||||
### 1. 带子命令的复杂命令
|
||||
|
||||
```python
|
||||
class TestCommand(PlusCommand):
|
||||
command_name = "test"
|
||||
command_description = "测试命令,展示参数解析功能"
|
||||
command_aliases = ["t"]
|
||||
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
if args.is_empty():
|
||||
await self.send_text("用法: /test <子命令> [参数]")
|
||||
return True, "显示帮助", True
|
||||
|
||||
subcommand = args.get_first().lower()
|
||||
|
||||
if subcommand == "args":
|
||||
result = f"""
|
||||
🔍 参数解析结果:
|
||||
原始字符串: '{args.get_raw()}'
|
||||
解析后参数: {args.get_args()}
|
||||
参数数量: {args.count()}
|
||||
第一个参数: '{args.get_first()}'
|
||||
剩余参数: '{args.get_remaining()}'
|
||||
"""
|
||||
await self.send_text(result)
|
||||
|
||||
elif subcommand == "flags":
|
||||
result = f"""
|
||||
🏴 标志测试结果:
|
||||
包含 --verbose: {args.has_flag('--verbose')}
|
||||
包含 -v: {args.has_flag('-v')}
|
||||
--output 的值: '{args.get_flag_value('--output', '未设置')}'
|
||||
--name 的值: '{args.get_flag_value('--name', '未设置')}'
|
||||
"""
|
||||
await self.send_text(result)
|
||||
|
||||
else:
|
||||
await self.send_text(f"❓ 未知的子命令: {subcommand}")
|
||||
|
||||
return True, "Test命令执行成功", True
|
||||
```
|
||||
|
||||
### 2. 聊天类型限制示例
|
||||
|
||||
```python
|
||||
class PrivateOnlyCommand(PlusCommand):
|
||||
command_name = "private"
|
||||
command_description = "仅私聊可用的命令"
|
||||
chat_type_allow = ChatType.PRIVATE
|
||||
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
await self.send_text("这是一个仅私聊可用的命令")
|
||||
return True, "私聊命令执行", True
|
||||
|
||||
class GroupOnlyCommand(PlusCommand):
|
||||
command_name = "group"
|
||||
command_description = "仅群聊可用的命令"
|
||||
chat_type_allow = ChatType.GROUP
|
||||
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
await self.send_text("这是一个仅群聊可用的命令")
|
||||
return True, "群聊命令执行", True
|
||||
```
|
||||
|
||||
### 3. 配置驱动的命令
|
||||
|
||||
```python
|
||||
class ConfigurableCommand(PlusCommand):
|
||||
command_name = "config_cmd"
|
||||
command_description = "可配置的命令"
|
||||
|
||||
async def execute(self, args: CommandArgs) -> Tuple[bool, Optional[str], bool]:
|
||||
# 从插件配置中获取设置
|
||||
max_length = self.get_config("commands.max_length", 100)
|
||||
enabled_features = self.get_config("commands.features", [])
|
||||
|
||||
if args.is_empty():
|
||||
await self.send_text("请提供参数")
|
||||
return True, "无参数", True
|
||||
|
||||
content = args.get_raw()
|
||||
if len(content) > max_length:
|
||||
await self.send_text(f"内容过长,最大允许 {max_length} 字符")
|
||||
return True, "内容过长", True
|
||||
|
||||
# 根据配置决定功能
|
||||
if "uppercase" in enabled_features:
|
||||
content = content.upper()
|
||||
|
||||
await self.send_text(f"处理结果: {content}")
|
||||
return True, "配置命令执行", True
|
||||
```
|
||||
|
||||
## 支持的命令前缀
|
||||
|
||||
系统支持以下命令前缀(在`config/bot_config.toml`中配置):
|
||||
|
||||
- `/` - 斜杠(默认)
|
||||
- `!` - 感叹号
|
||||
- `.` - 点号
|
||||
- `#` - 井号
|
||||
|
||||
例如,对于echo命令,以下调用都是有效的:
|
||||
- `/echo Hello`
|
||||
- `!echo Hello`
|
||||
- `.echo Hello`
|
||||
- `#echo Hello`
|
||||
|
||||
## 返回值说明
|
||||
|
||||
`execute`方法需要返回一个三元组:
|
||||
|
||||
```python
|
||||
return (执行成功标志, 可选消息, 是否拦截后续处理)
|
||||
```
|
||||
|
||||
- **执行成功标志** (bool): True表示命令执行成功,False表示失败
|
||||
- **可选消息** (Optional[str]): 用于日志记录的消息
|
||||
- **是否拦截后续处理** (bool): True表示拦截消息,不进行后续处理
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **命令命名**:使用简短、直观的命令名
|
||||
2. **别名设置**:为常用命令提供简短别名
|
||||
3. **参数验证**:总是检查参数的有效性
|
||||
4. **错误处理**:提供清晰的错误提示和使用说明
|
||||
5. **配置支持**:重要设置应该可配置
|
||||
6. **聊天类型**:根据命令功能选择合适的聊天类型限制
|
||||
|
||||
## 完整示例
|
||||
|
||||
完整的插件示例请参考 `plugins/echo_example/plugin.py` 文件。
|
||||
|
||||
## 与传统BaseCommand的区别
|
||||
|
||||
| 特性 | PlusCommand | BaseCommand |
|
||||
|------|-------------|-------------|
|
||||
| 正则表达式 | 自动生成 | 手动编写 |
|
||||
| 参数解析 | CommandArgs类 | 手动处理 |
|
||||
| 别名支持 | 内置支持 | 需要在正则中处理 |
|
||||
| 代码复杂度 | 简单 | 复杂 |
|
||||
| 学习曲线 | 平缓 | 陡峭 |
|
||||
|
||||
增强命令系统让插件开发变得更加简单和高效,特别适合新手开发者快速上手。
|
||||
@@ -1,89 +0,0 @@
|
||||
# 💻 Command组件详解
|
||||
|
||||
## 📖 什么是Command
|
||||
|
||||
Command是直接响应用户明确指令的组件,与Action不同,Command是**被动触发**的,当用户输入特定格式的命令时立即执行。
|
||||
|
||||
Command通过正则表达式匹配用户输入,提供确定性的功能服务。
|
||||
|
||||
### 🎯 Command的特点
|
||||
|
||||
- 🎯 **确定性执行**:匹配到命令立即执行,无随机性
|
||||
- ⚡ **即时响应**:用户主动触发,快速响应
|
||||
- 🔍 **正则匹配**:通过正则表达式精确匹配用户输入
|
||||
- 🛑 **拦截控制**:可以控制是否阻止消息继续处理
|
||||
- 📝 **参数解析**:支持从用户输入中提取参数
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Command组件的基本结构
|
||||
|
||||
首先,Command组件需要继承自`BaseCommand`类,并实现必要的方法。
|
||||
|
||||
```python
|
||||
class ExampleCommand(BaseCommand):
|
||||
command_name = "example" # 命令名称,作为唯一标识符
|
||||
command_description = "这是一个示例命令" # 命令描述
|
||||
command_pattern = r"" # 命令匹配的正则表达式
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str], bool]:
|
||||
"""
|
||||
执行Command的主要逻辑
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str, bool]:
|
||||
- 第一个bool表示是否成功执行
|
||||
- 第二个str是执行结果消息
|
||||
- 第三个bool表示是否需要阻止消息继续处理
|
||||
"""
|
||||
# ---- 执行命令的逻辑 ----
|
||||
return True, "执行成功", False
|
||||
```
|
||||
**`command_pattern`**: 该Command匹配的正则表达式,用于精确匹配用户输入。
|
||||
|
||||
请注意:如果希望能获取到命令中的参数,请在正则表达式中使用有命名的捕获组,例如`(?P<param_name>pattern)`。
|
||||
|
||||
这样在匹配时,内部实现可以使用`re.match.groupdict()`方法获取到所有捕获组的参数,并以字典的形式存储在`self.matched_groups`中。
|
||||
|
||||
### 匹配样例
|
||||
假设我们有一个命令`/example param1=value1 param2=value2`,对应的正则表达式可以是:
|
||||
|
||||
```python
|
||||
class ExampleCommand(BaseCommand):
|
||||
command_name = "example"
|
||||
command_description = "这是一个示例命令"
|
||||
command_pattern = r"/example (?P<param1>\w+) (?P<param2>\w+)"
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str], bool]:
|
||||
# 获取匹配的参数
|
||||
param1 = self.matched_groups.get("param1")
|
||||
param2 = self.matched_groups.get("param2")
|
||||
|
||||
# 执行逻辑
|
||||
return True, f"参数1: {param1}, 参数2: {param2}", False
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Command 内置方法说明
|
||||
```python
|
||||
class BaseCommand:
|
||||
def get_config(self, key: str, default=None):
|
||||
"""获取插件配置值,使用嵌套键访问"""
|
||||
|
||||
async def send_text(self, content: str, reply_to: str = "") -> bool:
|
||||
"""发送回复消息"""
|
||||
|
||||
async def send_type(self, message_type: str, content: str, display_message: str = "", typing: bool = False, reply_to: str = "") -> bool:
|
||||
"""发送指定类型的回复消息到当前聊天环境"""
|
||||
|
||||
async def send_command(self, command_name: str, args: Optional[dict] = None, display_message: str = "", storage_message: bool = True) -> bool:
|
||||
"""发送命令消息"""
|
||||
|
||||
async def send_emoji(self, emoji_base64: str) -> bool:
|
||||
"""发送表情包"""
|
||||
|
||||
async def send_image(self, image_base64: str) -> bool:
|
||||
"""发送图片"""
|
||||
```
|
||||
具体参数与用法参见`BaseCommand`基类的定义。
|
||||
@@ -9,7 +9,7 @@
|
||||
## 组件功能详解
|
||||
|
||||
- [🧱 Action组件详解](action-components.md) - 掌握最核心的Action组件
|
||||
- [💻 Command组件详解](command-components.md) - 学习直接响应命令的组件
|
||||
- [💻 Command组件详解](PLUS_COMMAND_GUIDE.md) - 学习直接响应命令的组件
|
||||
- [🔧 Tool组件详解](tool-components.md) - 了解如何扩展信息获取能力
|
||||
- [⚙️ 配置文件系统指南](configuration-guide.md) - 学会使用自动生成的插件配置文件
|
||||
- [📄 Manifest系统指南](manifest-guide.md) - 了解插件元数据管理和配置架构
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## 📖 什么是工具
|
||||
|
||||
工具是MoFox_Bot的信息获取能力扩展组件。如果说Action组件功能五花八门,可以拓展麦麦能做的事情,那么Tool就是在某个过程中拓宽了麦麦能够获得的信息量。
|
||||
工具是MoFox_Bot的信息获取能力扩展组件。如果说Action组件功能五花八门,可以拓展麦麦能做的事情,那么Tool就是在某个过程中拓宽了MoFox_Bot能够获得的信息量。
|
||||
|
||||
### 🎯 工具的特点
|
||||
|
||||
|
||||
Reference in New Issue
Block a user