better:优化文档
This commit is contained in:
927
MaiBot插件开发文档.md
927
MaiBot插件开发文档.md
@@ -12,896 +12,83 @@ MaiBot 是一个基于大语言模型的智能聊天机器人,采用现代化
|
||||
- **热加载机制**:支持动态加载和卸载插件
|
||||
- **依赖管理**:内置依赖检查和解析机制
|
||||
- **拦截控制**:Command组件支持消息拦截控制
|
||||
- **双目录支持**:区分用户插件和系统内置插件
|
||||
|
||||
## 🧩 主要组件
|
||||
### 📂 插件目录说明
|
||||
|
||||
### 1. 插件(Plugin)
|
||||
> ⚠️ **重要**:请将你的自定义插件放在项目根目录的 `plugins/` 文件夹下!
|
||||
|
||||
插件是功能的容器,每个插件可以包含多个组件。插件通过继承 `BasePlugin` 类实现:
|
||||
MaiBot支持两个插件目录:
|
||||
|
||||
```python
|
||||
from src.plugin_system import BasePlugin, register_plugin
|
||||
- **`plugins/`** (项目根目录):**用户自定义插件目录**,这是你应该放置插件的位置
|
||||
- **`src/plugins/builtin/`**:**系统内置插件目录**,包含核心功能插件,请勿修改
|
||||
|
||||
@register_plugin
|
||||
class MyPlugin(BasePlugin):
|
||||
plugin_name = "my_plugin"
|
||||
plugin_description = "我的插件"
|
||||
plugin_version = "1.0.0"
|
||||
plugin_author = "开发者"
|
||||
config_file_name = "config.toml" # 可选配置文件
|
||||
```
|
||||
**优先级**:用户插件 > 系统内置插件(同名时用户插件会覆盖系统插件)
|
||||
|
||||
### 2. Action组件
|
||||
## 📚 文档导航
|
||||
|
||||
#### Action的核心概念
|
||||
### 🚀 快速入门
|
||||
- [🚀 快速开始指南](docs/plugins/quick-start.md) - 5分钟创建你的第一个插件
|
||||
- [📋 开发规范](docs/plugins/development-standards.md) - 代码规范和最佳实践
|
||||
|
||||
Action是给麦麦在回复之外提供额外功能的智能组件,**由麦麦的决策系统自主选择是否使用**,具有随机性和拟人化的调用特点。Action不是直接响应用户命令,而是让麦麦根据聊天情境智能地选择合适的动作,使其行为更加自然和真实。
|
||||
### 📖 核心概念
|
||||
- [🧩 插件系统概述](docs/plugins/plugin-system-overview.md) - 插件架构和组件类型
|
||||
- [⚡ Action组件详解](docs/plugins/action-components.md) - 智能动作组件开发指南
|
||||
- [💻 Command组件详解](docs/plugins/command-components.md) - 命令组件开发指南
|
||||
- [🔧 工具系统详解](docs/plugins/tool-system.md) - 扩展麦麦信息获取能力的工具组件
|
||||
|
||||
**Action的特点**:
|
||||
- 🧠 **智能激活**:麦麦根据多种条件智能判断是否使用
|
||||
- 🎲 **随机性**:增加行为的不可预测性,更接近真人交流
|
||||
- 🤖 **拟人化**:让麦麦的回应更自然、更有个性
|
||||
- 🔄 **情境感知**:基于聊天上下文做出合适的反应
|
||||
### 🔌 API参考
|
||||
- [📡 消息API](docs/plugins/api/message-api.md) - 消息发送和处理接口
|
||||
- [💾 数据库API](docs/plugins/api/database-api.md) - 数据持久化接口
|
||||
- [🤖 LLM API](docs/plugins/api/llm-api.md) - 大语言模型调用接口
|
||||
- [⚙️ 配置API](docs/plugins/api/config-api.md) - 配置管理接口
|
||||
- [🛠️ 工具API](docs/plugins/api/utility-api.md) - 实用工具接口
|
||||
|
||||
#### Action的两层决策机制
|
||||
### 🔧 高级功能
|
||||
- [🔗 插件依赖管理](docs/plugins/advanced/dependency-management.md) - 插件间依赖处理
|
||||
- [⏱️ 插件生命周期](docs/plugins/advanced/plugin-lifecycle.md) - 加载、执行、卸载流程
|
||||
- [🎛️ 动态配置](docs/plugins/advanced/dynamic-configuration.md) - 运行时配置更新
|
||||
|
||||
Action采用**两层决策机制**来优化性能和决策质量:
|
||||
### 📋 开发指南
|
||||
- [🏗️ 项目结构](docs/plugins/guides/project-structure.md) - 推荐的插件项目结构
|
||||
- [🐛 调试和测试](docs/plugins/guides/debugging-testing.md) - 插件调试技巧
|
||||
- [📊 性能优化](docs/plugins/guides/performance-optimization.md) - 插件性能最佳实践
|
||||
|
||||
##### 第一层:激活控制(Activation Control)
|
||||
**激活决定麦麦是否"知道"这个Action的存在**,即这个Action是否进入决策候选池。**不被激活的Action麦麦永远不会选择**。
|
||||
### 💡 示例和模板
|
||||
- [📚 完整示例](docs/plugins/examples/complete-examples.md) - 各种类型的插件示例
|
||||
- [🏗️ 插件模板](docs/plugins/templates/) - 快速开始的插件模板
|
||||
|
||||
> 🎯 **设计目的**:在加载许多插件的时候降低LLM决策压力,避免让麦麦在过多的选项中纠结。
|
||||
## 🎯 推荐学习路径
|
||||
|
||||
**激活类型说明**:
|
||||
- `NEVER`:从不激活,Action对麦麦不可见
|
||||
- `ALWAYS`:永远激活,Action总是在麦麦的候选池中
|
||||
- `LLM_JUDGE`:通过LLM智能判断当前情境是否需要激活此Action
|
||||
- `RANDOM`:基于随机概率决定是否激活
|
||||
- `KEYWORD`:当检测到特定关键词时激活
|
||||
### 🌟 新手入门
|
||||
1. 阅读 [🚀 快速开始指南](docs/plugins/quick-start.md)
|
||||
2. 了解 [🧩 插件系统概述](docs/plugins/plugin-system-overview.md)
|
||||
3. 学习 [⚡ Action组件详解](docs/plugins/action-components.md)
|
||||
4. 了解 [🔧 工具系统详解](docs/plugins/tool-system.md)
|
||||
5. 实践 [📚 完整示例](docs/plugins/examples/complete-examples.md)
|
||||
|
||||
**聊天模式控制**:
|
||||
- `FOCUS`:仅在专注聊天模式下可激活
|
||||
- `NORMAL`:仅在普通聊天模式下可激活
|
||||
- `ALL`:所有模式下都可激活
|
||||
### 💪 进阶开发
|
||||
1. 掌握 [💻 Command组件详解](docs/plugins/command-components.md)
|
||||
2. 学习 [🔌 API参考](docs/plugins/api/) 各模块
|
||||
3. 了解 [🔧 高级功能](docs/plugins/advanced/)
|
||||
4. 遵循 [📋 开发规范](docs/plugins/development-standards.md)
|
||||
|
||||
##### 第二层:使用决策(Usage Decision)
|
||||
**在Action被激活后,使用条件决定麦麦什么时候会"选择"使用这个Action**。
|
||||
### 🚀 专家级别
|
||||
1. 深入 [🔗 插件依赖管理](docs/plugins/advanced/dependency-management.md)
|
||||
2. 掌握 [📊 性能优化](docs/plugins/guides/performance-optimization.md)
|
||||
3. 贡献 [🏗️ 插件模板](docs/plugins/templates/)
|
||||
|
||||
这一层由以下因素综合决定:
|
||||
- `action_require`:使用场景描述,帮助LLM判断何时选择
|
||||
- `action_parameters`:所需参数,影响Action的可执行性
|
||||
- 当前聊天上下文和麦麦的决策逻辑
|
||||
## 🎉 快速开始
|
||||
|
||||
##### 两层决策机制示例
|
||||
想立即开始开发?跳转到 [🚀 快速开始指南](docs/plugins/quick-start.md),5分钟内创建你的第一个MaiBot插件!
|
||||
|
||||
假设有一个"发送表情"Action:
|
||||
## 💬 社区和支持
|
||||
|
||||
```python
|
||||
class EmojiAction(BaseAction):
|
||||
# 第一层:激活控制
|
||||
focus_activation_type = ActionActivationType.RANDOM # 专注模式下随机激活
|
||||
normal_activation_type = ActionActivationType.KEYWORD # 普通模式下关键词激活
|
||||
activation_keywords = ["表情", "emoji", "😊"]
|
||||
|
||||
# 第二层:使用决策
|
||||
action_require = [
|
||||
"表达情绪时可以选择使用",
|
||||
"增加聊天趣味性",
|
||||
"不要连续发送多个表情"
|
||||
]
|
||||
```
|
||||
|
||||
**决策流程**:
|
||||
1. **第一层激活判断**:
|
||||
- 普通模式:只有当用户消息包含"表情"、"emoji"或"😊"时,麦麦才"知道"可以使用这个Action
|
||||
- 专注模式:随机激活,有概率让麦麦"看到"这个Action
|
||||
|
||||
2. **第二层使用决策**:
|
||||
- 即使Action被激活,麦麦还会根据`action_require`中的条件判断是否真正选择使用
|
||||
- 例如:如果刚刚已经发过表情,根据"不要连续发送多个表情"的要求,麦麦可能不会选择这个Action
|
||||
|
||||
> 💡 **性能优化**:这种设计确保了当插件数量很多时,LLM只需要在少数被激活的Action中做选择,而不是在所有Action中纠结。
|
||||
|
||||
#### Action必须项清单
|
||||
|
||||
每个Action类都**必须**包含以下属性,缺少任何一项都可能导致Action无法正常工作:
|
||||
|
||||
##### 1. 激活控制必须项(第一层决策)
|
||||
```python
|
||||
# 专注模式下的激活类型 - 控制何时让麦麦"看到"这个Action
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
|
||||
# 普通模式下的激活类型 - 控制何时让麦麦"看到"这个Action
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
|
||||
# 启用的聊天模式 - 限制Action在哪些模式下可激活
|
||||
mode_enable = ChatMode.ALL
|
||||
|
||||
# 是否允许与其他Action并行执行
|
||||
parallel_action = False
|
||||
```
|
||||
|
||||
##### 2. 基本信息必须项
|
||||
```python
|
||||
# Action的唯一标识名称
|
||||
action_name = "my_action"
|
||||
|
||||
# Action的功能描述
|
||||
action_description = "描述这个Action的具体功能和用途"
|
||||
```
|
||||
|
||||
##### 3. 使用决策必须项(第二层决策)
|
||||
```python
|
||||
# Action参数定义 - 告诉LLM执行时需要什么参数
|
||||
action_parameters = {
|
||||
"param1": "参数1的说明",
|
||||
"param2": "参数2的说明"
|
||||
}
|
||||
|
||||
# Action使用场景描述 - 帮助LLM判断何时"选择"使用
|
||||
action_require = [
|
||||
"使用场景描述1",
|
||||
"使用场景描述2"
|
||||
]
|
||||
|
||||
# 关联的消息类型 - 说明Action能处理什么类型的内容
|
||||
associated_types = ["text", "emoji", "image"]
|
||||
```
|
||||
|
||||
#### 完整的Action示例
|
||||
|
||||
```python
|
||||
from src.plugin_system import BaseAction, ActionActivationType, ChatMode
|
||||
|
||||
class GreetingAction(BaseAction):
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "greeting"
|
||||
action_description = "向用户发送问候消息,增加互动友好性"
|
||||
|
||||
# 关键词配置(用于KEYWORD激活类型)
|
||||
activation_keywords = ["你好", "hello", "hi"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# LLM判断提示词(用于LLM_JUDGE激活类型)
|
||||
llm_judge_prompt = """
|
||||
判定是否需要使用问候动作的条件:
|
||||
1. 用户刚加入群聊或开始对话
|
||||
2. 用户表达了友好的问候意图
|
||||
3. 适合增加互动友好性的场合
|
||||
|
||||
请回答"是"或"否"。
|
||||
"""
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"greeting_type": "问候类型,如formal(正式)或casual(随意)",
|
||||
"target_user": "问候的目标用户,可选"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户刚进入聊天",
|
||||
"检测到问候关键词",
|
||||
"适合增加友好互动的场合"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 麦麦决定使用此Action时执行的逻辑
|
||||
greeting_type = self.action_data.get("greeting_type", "casual")
|
||||
target_user = self.action_data.get("target_user", "")
|
||||
|
||||
if greeting_type == "formal":
|
||||
message = f"您好{target_user}!很高兴见到您!"
|
||||
else:
|
||||
message = f"嗨{target_user}~很开心见到你!😊"
|
||||
|
||||
await self.send_text(message)
|
||||
return True, "执行问候动作成功"
|
||||
```
|
||||
|
||||
### 3. Command组件
|
||||
|
||||
Command是直接响应用户明确指令的组件,与Action不同,Command是被动触发的,当用户输入特定格式的命令时立即执行。Command支持正则表达式匹配和消息拦截:
|
||||
|
||||
```python
|
||||
from src.plugin_system import BaseCommand
|
||||
|
||||
class MyCommand(BaseCommand):
|
||||
command_pattern = r"^/hello\s+(?P<name>\w+)$"
|
||||
command_help = "打招呼命令"
|
||||
command_examples = ["/hello 世界"]
|
||||
intercept_message = True # 拦截后续处理
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
name = self.matched_groups.get("name", "世界")
|
||||
await self.send_text(f"你好,{name}!")
|
||||
return True, f"已向{name}问候"
|
||||
```
|
||||
|
||||
> **Action vs Command 核心区别**:
|
||||
> - **Action**:
|
||||
> - 采用**两层决策机制**(激活控制 + 使用决策)
|
||||
> - 麦麦主动决策使用,具有随机性和智能性
|
||||
> - 需要通过激活控制来管理LLM的决策负担
|
||||
> - **必须在类中定义所有必须项**
|
||||
> - **Command**:
|
||||
> - 用户主动触发,确定性执行
|
||||
> - 通过正则表达式直接匹配用户输入
|
||||
> - 无需激活机制,匹配即执行
|
||||
> - 用于提供具体功能和服务
|
||||
|
||||
## 🚀 快速开始
|
||||
|
||||
### 1. 创建插件目录
|
||||
|
||||
在项目的 `src/plugins/` 文件夹下创建你的插件目录:
|
||||
|
||||
```
|
||||
src/plugins/
|
||||
└── my_plugin/
|
||||
├── plugin.py # 插件主文件
|
||||
├── config.toml # 配置文件(可选)
|
||||
└── README.md # 说明文档(可选)
|
||||
```
|
||||
|
||||
### 2. 编写插件主文件
|
||||
|
||||
创建 `plugin.py` 文件:
|
||||
|
||||
```python
|
||||
from typing import List, Tuple, Type
|
||||
from src.plugin_system import (
|
||||
BasePlugin, register_plugin, BaseAction, BaseCommand,
|
||||
ComponentInfo, ActionActivationType, ChatMode
|
||||
)
|
||||
|
||||
# 定义一个简单的Action
|
||||
class GreetingAction(BaseAction):
|
||||
# 激活控制必须项
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# 基本信息必须项
|
||||
action_name = "greeting"
|
||||
action_description = "向用户发送问候消息"
|
||||
|
||||
# 关键词配置
|
||||
activation_keywords = ["你好", "hello"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# 功能定义必须项
|
||||
action_parameters = {}
|
||||
action_require = ["用户发送问候语时使用"]
|
||||
associated_types = ["text"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
await self.send_text("你好!很高兴见到你!")
|
||||
return True, "执行问候动作"
|
||||
|
||||
# 定义一个简单的Command
|
||||
class InfoCommand(BaseCommand):
|
||||
command_pattern = r"^/info$"
|
||||
command_help = "显示插件信息"
|
||||
command_examples = ["/info"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
await self.send_text("这是我的第一个插件!")
|
||||
return True, "显示插件信息"
|
||||
|
||||
# 注册插件
|
||||
@register_plugin
|
||||
class MyFirstPlugin(BasePlugin):
|
||||
plugin_name = "first_plugin"
|
||||
plugin_description = "我的第一个插件"
|
||||
plugin_version = "1.0.0"
|
||||
plugin_author = "我的名字"
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
return [
|
||||
# Action组件 - 所有信息从类属性读取
|
||||
(GreetingAction.get_action_info(), GreetingAction),
|
||||
# Command组件 - 仍需要手动指定name和description
|
||||
(InfoCommand.get_command_info(
|
||||
name="info",
|
||||
description="显示插件信息"
|
||||
), InfoCommand),
|
||||
]
|
||||
```
|
||||
|
||||
### 3. 创建配置文件(可选)
|
||||
|
||||
创建 `config.toml` 文件:
|
||||
|
||||
```toml
|
||||
[plugin]
|
||||
name = "first_plugin"
|
||||
version = "1.0.0"
|
||||
enabled = true
|
||||
|
||||
[greeting]
|
||||
enable_emoji = true
|
||||
custom_message = "欢迎使用我的插件!"
|
||||
|
||||
[logging]
|
||||
level = "INFO"
|
||||
```
|
||||
|
||||
### 4. 启动机器人
|
||||
|
||||
将插件放入 `src/plugins/` 目录后,启动MaiBot,插件会自动加载。
|
||||
|
||||
## 📚 完整说明
|
||||
|
||||
### 插件生命周期
|
||||
|
||||
1. **发现阶段**:系统扫描 `src/plugins/` 目录,查找Python文件
|
||||
2. **加载阶段**:导入插件模块,注册插件类
|
||||
3. **实例化阶段**:创建插件实例,加载配置文件
|
||||
4. **注册阶段**:注册插件及其包含的组件
|
||||
5. **运行阶段**:组件根据条件被激活和执行
|
||||
|
||||
### Action组件详解
|
||||
|
||||
Action组件是麦麦智能决策系统的重要组成部分,它们不是被动响应用户输入,而是由麦麦根据聊天情境主动选择执行。这种设计使麦麦的行为更加拟人化和自然,就像真人聊天时会根据情况做出不同的反应一样。
|
||||
|
||||
#### 激活类型
|
||||
|
||||
Action的激活类型决定了麦麦在什么情况下会考虑使用该Action:
|
||||
|
||||
- `NEVER`:从不激活,通常用于临时禁用
|
||||
- `ALWAYS`:麦麦总是会考虑使用此Action
|
||||
- `LLM_JUDGE`:通过LLM智能判断当前情境是否适合使用
|
||||
- `RANDOM`:基于随机概率决定是否使用,增加行为的不可预测性
|
||||
- `KEYWORD`:当检测到特定关键词时会考虑使用
|
||||
|
||||
#### 聊天模式
|
||||
|
||||
- `FOCUS`:专注聊天模式
|
||||
- `NORMAL`:普通聊天模式
|
||||
- `ALL`:所有模式
|
||||
|
||||
#### Action示例
|
||||
|
||||
```python
|
||||
class AdvancedAction(BaseAction):
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = True
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "advanced_help"
|
||||
action_description = "智能帮助系统,主动为用户提供帮助和指导"
|
||||
|
||||
# 关键词配置
|
||||
activation_keywords = ["帮助", "help"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# LLM判断提示词
|
||||
llm_judge_prompt = "当用户需要帮助时回答'是',否则回答'否'"
|
||||
|
||||
# 随机激活概率
|
||||
random_activation_probability = 0.3
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"query": "用户的问题或需求"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户明确请求帮助",
|
||||
"检测到用户遇到困难"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
query = self.action_data.get("query", "")
|
||||
|
||||
# 麦麦主动决定帮助用户时执行的逻辑
|
||||
await self.send_text(f"我来帮助你解决:{query}")
|
||||
await self.send_type("emoji", "😊")
|
||||
|
||||
# 存储执行记录
|
||||
await self.api.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display=f"麦麦主动帮助用户:{query}",
|
||||
action_done=True,
|
||||
thinking_id=self.thinking_id
|
||||
)
|
||||
|
||||
return True, f"麦麦已主动帮助处理:{query}"
|
||||
```
|
||||
|
||||
### Command组件详解
|
||||
|
||||
#### 正则表达式匹配
|
||||
|
||||
Command使用正则表达式匹配用户输入,支持命名组捕获:
|
||||
|
||||
```python
|
||||
class UserCommand(BaseCommand):
|
||||
# 匹配 /user add 用户名
|
||||
command_pattern = r"^/user\s+(?P<action>add|del|info)\s+(?P<username>\w+)$"
|
||||
command_help = "用户管理命令"
|
||||
command_examples = [
|
||||
"/user add 张三",
|
||||
"/user del 李四",
|
||||
"/user info 王五"
|
||||
]
|
||||
intercept_message = True
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
action = self.matched_groups.get("action")
|
||||
username = self.matched_groups.get("username")
|
||||
|
||||
if action == "add":
|
||||
return await self._add_user(username)
|
||||
elif action == "del":
|
||||
return await self._delete_user(username)
|
||||
elif action == "info":
|
||||
return await self._show_user_info(username)
|
||||
|
||||
return False, "无效的操作"
|
||||
```
|
||||
|
||||
#### 消息拦截控制
|
||||
|
||||
- `intercept_message = True`:拦截消息,不进行后续处理
|
||||
- `intercept_message = False`:不拦截,继续处理其他组件
|
||||
|
||||
### 配置系统
|
||||
|
||||
插件支持TOML配置文件,配置会自动加载到插件实例:
|
||||
|
||||
```python
|
||||
class ConfigurablePlugin(BasePlugin):
|
||||
config_file_name = "config.toml"
|
||||
|
||||
def some_method(self):
|
||||
# 获取配置值,支持嵌套键访问
|
||||
max_items = self.get_config("limits.max_items", 10)
|
||||
custom_message = self.get_config("messages.greeting", "默认消息")
|
||||
```
|
||||
|
||||
配置文件格式:
|
||||
|
||||
```toml
|
||||
[limits]
|
||||
max_items = 20
|
||||
timeout = 30
|
||||
|
||||
[messages]
|
||||
greeting = "欢迎使用配置化插件!"
|
||||
error = "操作失败"
|
||||
|
||||
[features]
|
||||
enable_debug = true
|
||||
```
|
||||
|
||||
### 错误处理
|
||||
|
||||
插件应该包含适当的错误处理:
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
try:
|
||||
# 执行逻辑
|
||||
result = await self._do_something()
|
||||
return True, "操作成功"
|
||||
except ValueError as e:
|
||||
logger.error(f"{self.log_prefix} 参数错误: {e}")
|
||||
await self.send_text("参数错误,请检查输入")
|
||||
return False, f"参数错误: {e}"
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 执行失败: {e}")
|
||||
await self.send_text("操作失败,请稍后重试")
|
||||
return False, f"执行失败: {e}"
|
||||
```
|
||||
|
||||
## 🔌 API说明
|
||||
|
||||
### 消息API
|
||||
|
||||
插件可以通过 `self.api` 访问各种API功能:
|
||||
|
||||
#### 基础消息发送
|
||||
|
||||
```python
|
||||
# 发送文本消息
|
||||
await self.send_text("这是文本消息")
|
||||
|
||||
# 发送特定类型消息
|
||||
await self.send_type("emoji", "😊")
|
||||
await self.send_type("image", image_url)
|
||||
|
||||
# 发送命令消息
|
||||
await self.send_command("命令名", {"参数": "值"})
|
||||
```
|
||||
|
||||
#### 高级消息发送
|
||||
|
||||
```python
|
||||
# 向指定群聊发送消息
|
||||
await self.api.send_text_to_group("消息内容", "群ID", "qq")
|
||||
|
||||
# 向指定用户发送私聊消息
|
||||
await self.api.send_text_to_user("消息内容", "用户ID", "qq")
|
||||
|
||||
# 向指定目标发送任意类型消息
|
||||
await self.api.send_message_to_target(
|
||||
message_type="text",
|
||||
content="消息内容",
|
||||
platform="qq",
|
||||
target_id="目标ID",
|
||||
is_group=True,
|
||||
display_message="显示消息"
|
||||
)
|
||||
```
|
||||
|
||||
#### 消息查询
|
||||
|
||||
```python
|
||||
# 获取聊天类型
|
||||
chat_type = self.api.get_chat_type() # "group" 或 "private"
|
||||
|
||||
# 获取最近消息
|
||||
recent_messages = self.api.get_recent_messages(count=5)
|
||||
```
|
||||
|
||||
### 数据库API
|
||||
|
||||
插件可以使用数据库API进行数据持久化:
|
||||
|
||||
#### 通用查询
|
||||
|
||||
```python
|
||||
# 查询数据
|
||||
results = await self.api.db_query(
|
||||
model_class=SomeModel,
|
||||
query_type="get",
|
||||
filters={"field": "value"},
|
||||
limit=10,
|
||||
order_by=["-time"]
|
||||
)
|
||||
|
||||
# 创建记录
|
||||
new_record = await self.api.db_query(
|
||||
model_class=SomeModel,
|
||||
query_type="create",
|
||||
data={"field1": "value1", "field2": "value2"}
|
||||
)
|
||||
|
||||
# 更新记录
|
||||
updated_count = await self.api.db_query(
|
||||
model_class=SomeModel,
|
||||
query_type="update",
|
||||
filters={"id": 123},
|
||||
data={"field": "new_value"}
|
||||
)
|
||||
|
||||
# 删除记录
|
||||
deleted_count = await self.api.db_query(
|
||||
model_class=SomeModel,
|
||||
query_type="delete",
|
||||
filters={"id": 123}
|
||||
)
|
||||
|
||||
# 计数
|
||||
count = await self.api.db_query(
|
||||
model_class=SomeModel,
|
||||
query_type="count",
|
||||
filters={"active": True}
|
||||
)
|
||||
```
|
||||
|
||||
#### 原始SQL查询
|
||||
|
||||
```python
|
||||
# 执行原始SQL
|
||||
results = await self.api.db_raw_query(
|
||||
sql="SELECT * FROM table WHERE condition = ?",
|
||||
params=["value"],
|
||||
fetch_results=True
|
||||
)
|
||||
```
|
||||
|
||||
#### Action记录存储
|
||||
|
||||
```python
|
||||
# 存储Action执行记录
|
||||
await self.api.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display="显示的动作描述",
|
||||
action_done=True,
|
||||
thinking_id="思考ID",
|
||||
action_data={"key": "value"}
|
||||
)
|
||||
```
|
||||
|
||||
### LLM API
|
||||
|
||||
插件可以调用大语言模型:
|
||||
|
||||
```python
|
||||
# 获取可用模型
|
||||
models = self.api.get_available_models()
|
||||
|
||||
# 使用模型生成内容
|
||||
success, response, reasoning, model_name = await self.api.generate_with_model(
|
||||
prompt="你的提示词",
|
||||
model_config=models["某个模型"],
|
||||
request_type="plugin.generate",
|
||||
temperature=0.7,
|
||||
max_tokens=1000
|
||||
)
|
||||
|
||||
if success:
|
||||
await self.send_text(f"AI回复:{response}")
|
||||
else:
|
||||
await self.send_text("AI生成失败")
|
||||
```
|
||||
|
||||
### 配置API
|
||||
|
||||
```python
|
||||
# 获取全局配置
|
||||
global_config = self.api.get_global_config()
|
||||
|
||||
# 获取插件配置
|
||||
plugin_config = self.api.get_config("section.key", "默认值")
|
||||
```
|
||||
|
||||
### 工具API
|
||||
|
||||
```python
|
||||
# 获取当前时间戳
|
||||
timestamp = self.api.get_current_timestamp()
|
||||
|
||||
# 格式化时间
|
||||
formatted_time = self.api.format_timestamp(timestamp, "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# JSON处理
|
||||
json_str = self.api.dict_to_json({"key": "value"})
|
||||
data = self.api.json_to_dict(json_str)
|
||||
|
||||
# 生成UUID
|
||||
uuid = self.api.generate_uuid()
|
||||
|
||||
# 哈希计算
|
||||
hash_value = self.api.calculate_hash("text", "md5")
|
||||
```
|
||||
|
||||
### 流API
|
||||
|
||||
```python
|
||||
# 获取当前聊天流信息
|
||||
chat_stream = self.api.get_service("chat_stream")
|
||||
if chat_stream:
|
||||
stream_id = chat_stream.stream_id
|
||||
platform = chat_stream.platform
|
||||
|
||||
# 群聊信息
|
||||
if chat_stream.group_info:
|
||||
group_id = chat_stream.group_info.group_id
|
||||
group_name = chat_stream.group_info.group_name
|
||||
|
||||
# 用户信息
|
||||
user_id = chat_stream.user_info.user_id
|
||||
user_name = chat_stream.user_info.user_nickname
|
||||
```
|
||||
|
||||
### 心流API
|
||||
|
||||
```python
|
||||
# 等待新消息
|
||||
has_new_message = await self.api.wait_for_new_message(timeout=30)
|
||||
|
||||
# 获取观察信息
|
||||
observations = self.api.get_service("observations")
|
||||
```
|
||||
|
||||
## 🔧 高级功能
|
||||
|
||||
### 插件依赖管理
|
||||
|
||||
```python
|
||||
@register_plugin
|
||||
class DependentPlugin(BasePlugin):
|
||||
plugin_name = "dependent_plugin"
|
||||
plugin_description = "依赖其他插件的插件"
|
||||
dependencies = ["core_actions", "example_plugin"] # 依赖列表
|
||||
|
||||
def get_plugin_components(self):
|
||||
# 只有依赖满足时才会加载
|
||||
return [...]
|
||||
```
|
||||
|
||||
### 并行Action
|
||||
|
||||
```python
|
||||
class ParallelAction(BaseAction):
|
||||
parallel_action = True # 允许与其他Action并行执行
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 这个Action可以与其他并行Action同时执行
|
||||
return True, "并行执行完成"
|
||||
```
|
||||
|
||||
### 动态配置更新
|
||||
|
||||
```python
|
||||
class DynamicPlugin(BasePlugin):
|
||||
def get_plugin_components(self):
|
||||
# 根据配置动态决定加载哪些组件
|
||||
components = []
|
||||
|
||||
if self.get_config("features.enable_greeting", True):
|
||||
components.append((GreetingAction.get_action_info(), GreetingAction))
|
||||
|
||||
if self.get_config("features.enable_commands", True):
|
||||
components.append((SomeCommand.get_command_info(), SomeCommand))
|
||||
|
||||
return components
|
||||
```
|
||||
|
||||
### 自定义元数据
|
||||
|
||||
```python
|
||||
class MetadataAction(BaseAction):
|
||||
@classmethod
|
||||
def get_action_info(cls, name=None, description=None):
|
||||
info = super().get_action_info(name, description)
|
||||
# 添加自定义元数据
|
||||
info.metadata = {
|
||||
"category": "utility",
|
||||
"priority": "high",
|
||||
"custom_field": "custom_value"
|
||||
}
|
||||
return info
|
||||
```
|
||||
|
||||
## 📋 开发规范
|
||||
|
||||
### 1. 命名规范
|
||||
|
||||
- 插件名使用小写字母和下划线:`my_plugin`
|
||||
- 类名使用大驼峰:`MyPlugin`、`GreetingAction`
|
||||
- 方法名使用小写字母和下划线:`execute`、`send_message`
|
||||
|
||||
### 2. 文档规范
|
||||
|
||||
- 所有插件类都应该有完整的文档字符串
|
||||
- Action和Command的描述要清晰明确
|
||||
- 提供使用示例和配置说明
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
- 所有异步操作都要包含异常处理
|
||||
- 使用日志记录错误信息
|
||||
- 向用户返回友好的错误消息
|
||||
|
||||
### 4. 配置管理
|
||||
|
||||
- 敏感配置不要硬编码在代码中
|
||||
- 提供合理的默认值
|
||||
- 支持配置热更新
|
||||
|
||||
### 5. 性能考虑
|
||||
|
||||
- 避免在初始化时执行耗时操作
|
||||
- 合理使用缓存减少重复计算
|
||||
- 及时释放不需要的资源
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
### 1. 插件结构
|
||||
|
||||
```
|
||||
src/plugins/my_plugin/
|
||||
├── __init__.py # 空文件或简单导入
|
||||
├── plugin.py # 主插件文件
|
||||
├── actions/ # Action组件目录
|
||||
│ ├── __init__.py
|
||||
│ ├── greeting.py
|
||||
│ └── helper.py
|
||||
├── commands/ # Command组件目录
|
||||
│ ├── __init__.py
|
||||
│ ├── admin.py
|
||||
│ └── user.py
|
||||
├── utils/ # 工具函数
|
||||
│ ├── __init__.py
|
||||
│ └── helpers.py
|
||||
├── config.toml # 配置文件
|
||||
└── README.md # 说明文档
|
||||
```
|
||||
|
||||
### 2. 模块化设计
|
||||
|
||||
```python
|
||||
# actions/greeting.py
|
||||
from src.plugin_system import BaseAction
|
||||
|
||||
class GreetingAction(BaseAction):
|
||||
# ... 实现细节
|
||||
|
||||
# commands/admin.py
|
||||
from src.plugin_system import BaseCommand
|
||||
|
||||
class AdminCommand(BaseCommand):
|
||||
# ... 实现细节
|
||||
|
||||
# plugin.py
|
||||
from .actions.greeting import GreetingAction
|
||||
from .commands.admin import AdminCommand
|
||||
|
||||
@register_plugin
|
||||
class MyPlugin(BasePlugin):
|
||||
def get_plugin_components(self):
|
||||
return [
|
||||
(GreetingAction.get_action_info(), GreetingAction),
|
||||
(AdminCommand.get_command_info(), AdminCommand),
|
||||
]
|
||||
```
|
||||
|
||||
### 3. 配置分层
|
||||
|
||||
```toml
|
||||
# config.toml
|
||||
[plugin]
|
||||
name = "my_plugin"
|
||||
version = "1.0.0"
|
||||
enabled = true
|
||||
|
||||
[components]
|
||||
enable_greeting = true
|
||||
enable_admin = false
|
||||
|
||||
[greeting]
|
||||
message_template = "你好,{username}!"
|
||||
enable_emoji = true
|
||||
|
||||
[admin]
|
||||
allowed_users = ["admin", "moderator"]
|
||||
```
|
||||
|
||||
### 4. 日志实践
|
||||
|
||||
```python
|
||||
from src.common.logger import get_logger
|
||||
|
||||
logger = get_logger("my_plugin")
|
||||
|
||||
class MyAction(BaseAction):
|
||||
async def execute(self):
|
||||
logger.info(f"{self.log_prefix} 开始执行动作")
|
||||
|
||||
try:
|
||||
# 执行逻辑
|
||||
result = await self._do_something()
|
||||
logger.debug(f"{self.log_prefix} 执行结果: {result}")
|
||||
return True, "成功"
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 执行失败: {e}", exc_info=True)
|
||||
return False, str(e)
|
||||
```
|
||||
- 📖 **文档问题**:如果发现文档错误或需要改进,请提交Issue
|
||||
- 🐛 **Bug报告**:在GitHub上报告插件系统相关的问题
|
||||
- 💡 **功能建议**:欢迎提出新功能建议和改进意见
|
||||
- 🤝 **贡献代码**:欢迎提交PR改进插件系统
|
||||
|
||||
---
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
MaiBot的插件系统提供了强大而灵活的扩展能力,通过Action和Command两种组件类型,开发者可以轻松实现各种功能。系统提供了丰富的API接口、完善的配置管理和错误处理机制,让插件开发变得简单高效。
|
||||
|
||||
遵循本文档的指导和最佳实践,你可以快速上手MaiBot插件开发,为机器人添加强大的自定义功能。
|
||||
|
||||
如有问题或建议,欢迎提交Issue或参与讨论!
|
||||
**开始你的MaiBot插件开发之旅吧!** 🚀
|
||||
@@ -1,12 +1,3 @@
|
||||
- **智能化 MaiState 状态转换**:
|
||||
- 当前 `MaiState` (整体状态,如 `OFFLINE`, `NORMAL_CHAT` 等) 的转换逻辑 (`MaiStateManager`) 较为简单,主要依赖时间和随机性。
|
||||
- 未来的计划是让主心流 (`Heartflow`) 负责决策自身的 `MaiState`。
|
||||
- 该决策将综合考虑以下信息:
|
||||
- 各个子心流 (`SubHeartflow`) 的活动状态和信息摘要。
|
||||
- 主心流自身的状态和历史信息。
|
||||
- (可能) 结合预设的日程安排 (Schedule) 信息。
|
||||
- 目标是让 Mai 的整体状态变化更符合逻辑和上下文。 (计划在 064 实现)
|
||||
|
||||
- **参数化与动态调整聊天行为**:
|
||||
- 将 `NormalChatInstance` 和 `HeartFlowChatInstance` 中的关键行为参数(例如:回复概率、思考频率、兴趣度阈值、状态转换条件等)提取出来,使其更易于配置。
|
||||
- 允许每个 `SubHeartflow` (即每个聊天场景) 拥有其独立的参数配置,实现"千群千面"。
|
||||
@@ -33,12 +24,6 @@
|
||||
- 管理日程或执行更复杂的分析任务。
|
||||
- 目标:提升 HFC 的自主决策和行动能力,即使会增加一定的延迟。
|
||||
|
||||
- **基于历史学习的行为模式应用**:
|
||||
- **学习**: 分析过往聊天记录,提取和学习具体的行为模式(如特定梗的用法、情境化回应风格等)。可能需要专门的分析模块。
|
||||
- **存储与匹配**: 需要有效的方法存储学习到的行为模式,并开发强大的 **匹配** 机制,在运行时根据当前情境检索最合适的模式。**(匹配的准确性是关键)**
|
||||
- **应用与评估**: 将匹配到的行为模式融入 HFC 的决策和回复生成(例如,将其整合进 Prompt)。之后需评估该行为模式应用的实际效果。
|
||||
- **人格塑造**: 通过学习到的实际行为来动态塑造人格,作为静态人设描述的补充或替代,使其更生动自然。
|
||||
|
||||
- **标准化人设生成 (Standardized Persona Generation)**:
|
||||
- **目标**: 解决手动配置 `人设` 文件缺乏标准、难以全面描述个性的问题,并生成更丰富、可操作的人格资源。
|
||||
- **方法**: 利用大型语言模型 (LLM) 辅助生成标准化的、结构化的人格**资源包**。
|
||||
@@ -57,23 +42,10 @@
|
||||
- 考虑引入基于事件关联、相对时间线索和绝对时间锚点的检索方式。
|
||||
- 可能涉及设计新的事件表示或记忆结构。
|
||||
|
||||
|
||||
- **实现 SubHeartflow 级记忆缓存池:**
|
||||
- 在 `SubHeartflow` 层级或更高层级设计并实现一个缓存池,存储已检索的记忆/信息。
|
||||
- 避免在 HFC 等循环中重复进行相同的记忆检索调用。
|
||||
- 确保存储的信息能有效服务于当前交互上下文。
|
||||
|
||||
- **基于人格生成预设知识:**
|
||||
- 开发利用 LLM 和人格配置生成背景知识的功能。
|
||||
- 这些知识应符合角色的行为风格和可能的经历。
|
||||
- 作为一种"冷启动"或丰富角色深度的方式。
|
||||
|
||||
|
||||
## 开发计划TODO:LIST
|
||||
|
||||
- 人格功能:WIP
|
||||
- 对特定对象的侧写功能
|
||||
- 图片发送,转发功能:WIP
|
||||
- 幽默和meme功能:WIP
|
||||
- 小程序转发链接解析
|
||||
- 自动生成的回复逻辑,例如自生成的回复方向,回复风格
|
||||
1.更nb的工作记忆,直接开一个play_ground,通过llm进行内容检索,这个play_ground可以容纳巨量信息,并且十分通用化,十分好。
|
||||
634
docs/plugins/action-components.md
Normal file
634
docs/plugins/action-components.md
Normal file
@@ -0,0 +1,634 @@
|
||||
# ⚡ Action组件详解
|
||||
|
||||
## 📖 什么是Action
|
||||
|
||||
Action是给麦麦在回复之外提供额外功能的智能组件,**由麦麦的决策系统自主选择是否使用**,具有随机性和拟人化的调用特点。Action不是直接响应用户命令,而是让麦麦根据聊天情境智能地选择合适的动作,使其行为更加自然和真实。
|
||||
|
||||
### 🎯 Action的特点
|
||||
|
||||
- 🧠 **智能激活**:麦麦根据多种条件智能判断是否使用
|
||||
- 🎲 **随机性**:增加行为的不可预测性,更接近真人交流
|
||||
- 🤖 **拟人化**:让麦麦的回应更自然、更有个性
|
||||
- 🔄 **情境感知**:基于聊天上下文做出合适的反应
|
||||
|
||||
## 🎯 两层决策机制
|
||||
|
||||
Action采用**两层决策机制**来优化性能和决策质量:
|
||||
|
||||
### 第一层:激活控制(Activation Control)
|
||||
|
||||
**激活决定麦麦是否"知道"这个Action的存在**,即这个Action是否进入决策候选池。**不被激活的Action麦麦永远不会选择**。
|
||||
|
||||
> 🎯 **设计目的**:在加载许多插件的时候降低LLM决策压力,避免让麦麦在过多的选项中纠结。
|
||||
|
||||
#### 激活类型说明
|
||||
|
||||
| 激活类型 | 说明 | 使用场景 |
|
||||
|---------|-----|---------|
|
||||
| `NEVER` | 从不激活,Action对麦麦不可见 | 临时禁用某个Action |
|
||||
| `ALWAYS` | 永远激活,Action总是在麦麦的候选池中 | 核心功能,如回复、表情 |
|
||||
| `LLM_JUDGE` | 通过LLM智能判断当前情境是否需要激活此Action | 需要智能判断的复杂场景 |
|
||||
| `RANDOM` | 基于随机概率决定是否激活 | 增加行为随机性的功能 |
|
||||
| `KEYWORD` | 当检测到特定关键词时激活 | 明确触发条件的功能 |
|
||||
|
||||
#### 聊天模式控制
|
||||
|
||||
| 模式 | 说明 |
|
||||
|-----|-----|
|
||||
| `ChatMode.FOCUS` | 仅在专注聊天模式下可激活 |
|
||||
| `ChatMode.NORMAL` | 仅在普通聊天模式下可激活 |
|
||||
| `ChatMode.ALL` | 所有模式下都可激活 |
|
||||
|
||||
### 第二层:使用决策(Usage Decision)
|
||||
|
||||
**在Action被激活后,使用条件决定麦麦什么时候会"选择"使用这个Action**。
|
||||
|
||||
这一层由以下因素综合决定:
|
||||
- `action_require`:使用场景描述,帮助LLM判断何时选择
|
||||
- `action_parameters`:所需参数,影响Action的可执行性
|
||||
- 当前聊天上下文和麦麦的决策逻辑
|
||||
|
||||
### 🎬 决策流程示例
|
||||
|
||||
假设有一个"发送表情"Action:
|
||||
|
||||
```python
|
||||
class EmojiAction(BaseAction):
|
||||
# 第一层:激活控制
|
||||
focus_activation_type = ActionActivationType.RANDOM # 专注模式下随机激活
|
||||
normal_activation_type = ActionActivationType.KEYWORD # 普通模式下关键词激活
|
||||
activation_keywords = ["表情", "emoji", "😊"]
|
||||
|
||||
# 第二层:使用决策
|
||||
action_require = [
|
||||
"表达情绪时可以选择使用",
|
||||
"增加聊天趣味性",
|
||||
"不要连续发送多个表情"
|
||||
]
|
||||
```
|
||||
|
||||
**决策流程**:
|
||||
1. **第一层激活判断**:
|
||||
- 普通模式:只有当用户消息包含"表情"、"emoji"或"😊"时,麦麦才"知道"可以使用这个Action
|
||||
- 专注模式:随机激活,有概率让麦麦"看到"这个Action
|
||||
|
||||
2. **第二层使用决策**:
|
||||
- 即使Action被激活,麦麦还会根据`action_require`中的条件判断是否真正选择使用
|
||||
- 例如:如果刚刚已经发过表情,根据"不要连续发送多个表情"的要求,麦麦可能不会选择这个Action
|
||||
|
||||
## 📋 Action必须项清单
|
||||
|
||||
每个Action类都**必须**包含以下属性:
|
||||
|
||||
### 1. 激活控制必须项
|
||||
|
||||
```python
|
||||
# 专注模式下的激活类型
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
|
||||
# 普通模式下的激活类型
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
|
||||
# 启用的聊天模式
|
||||
mode_enable = ChatMode.ALL
|
||||
|
||||
# 是否允许与其他Action并行执行
|
||||
parallel_action = False
|
||||
```
|
||||
|
||||
### 2. 基本信息必须项
|
||||
|
||||
```python
|
||||
# Action的唯一标识名称
|
||||
action_name = "my_action"
|
||||
|
||||
# Action的功能描述
|
||||
action_description = "描述这个Action的具体功能和用途"
|
||||
```
|
||||
|
||||
### 3. 功能定义必须项
|
||||
|
||||
```python
|
||||
# Action参数定义 - 告诉LLM执行时需要什么参数
|
||||
action_parameters = {
|
||||
"param1": "参数1的说明",
|
||||
"param2": "参数2的说明"
|
||||
}
|
||||
|
||||
# Action使用场景描述 - 帮助LLM判断何时"选择"使用
|
||||
action_require = [
|
||||
"使用场景描述1",
|
||||
"使用场景描述2"
|
||||
]
|
||||
|
||||
# 关联的消息类型 - 说明Action能处理什么类型的内容
|
||||
associated_types = ["text", "emoji", "image"]
|
||||
```
|
||||
|
||||
## 🔧 激活类型详解
|
||||
|
||||
### KEYWORD激活
|
||||
|
||||
当检测到特定关键词时激活Action:
|
||||
|
||||
```python
|
||||
class GreetingAction(BaseAction):
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
|
||||
# 关键词配置
|
||||
activation_keywords = ["你好", "hello", "hi", "嗨"]
|
||||
keyword_case_sensitive = False # 不区分大小写
|
||||
```
|
||||
|
||||
### LLM_JUDGE激活
|
||||
|
||||
通过LLM智能判断是否激活:
|
||||
|
||||
```python
|
||||
class HelpAction(BaseAction):
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.LLM_JUDGE
|
||||
|
||||
# LLM判断提示词
|
||||
llm_judge_prompt = """
|
||||
判定是否需要使用帮助动作的条件:
|
||||
1. 用户表达了困惑或需要帮助
|
||||
2. 用户提出了问题但没有得到满意答案
|
||||
3. 对话中出现了技术术语或复杂概念
|
||||
|
||||
请回答"是"或"否"。
|
||||
"""
|
||||
```
|
||||
|
||||
### RANDOM激活
|
||||
|
||||
基于随机概率激活:
|
||||
|
||||
```python
|
||||
class SurpriseAction(BaseAction):
|
||||
focus_activation_type = ActionActivationType.RANDOM
|
||||
normal_activation_type = ActionActivationType.RANDOM
|
||||
|
||||
# 随机激活概率
|
||||
random_activation_probability = 0.1 # 10%概率激活
|
||||
```
|
||||
|
||||
### ALWAYS/NEVER激活
|
||||
|
||||
```python
|
||||
class CoreAction(BaseAction):
|
||||
focus_activation_type = ActionActivationType.ALWAYS # 总是激活
|
||||
normal_activation_type = ActionActivationType.NEVER # 在普通模式下禁用
|
||||
```
|
||||
|
||||
## 🎨 完整Action示例
|
||||
|
||||
### 智能问候Action
|
||||
|
||||
```python
|
||||
from src.plugin_system import BaseAction, ActionActivationType, ChatMode
|
||||
|
||||
class SmartGreetingAction(BaseAction):
|
||||
"""智能问候Action - 展示关键词激活的完整示例"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "smart_greeting"
|
||||
action_description = "智能问候系统,基于关键词触发,支持个性化问候消息"
|
||||
|
||||
# 关键词配置
|
||||
activation_keywords = ["你好", "hello", "hi", "嗨", "问候", "早上好", "晚上好"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"username": "要问候的用户名(可选)",
|
||||
"greeting_style": "问候风格:casual(随意)、formal(正式)、friendly(友好)"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户发送包含问候词汇的消息时使用",
|
||||
"检测到新用户加入时使用",
|
||||
"响应友好交流需求时使用",
|
||||
"避免在短时间内重复问候同一用户"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行智能问候"""
|
||||
# 获取参数
|
||||
username = self.action_data.get("username", "")
|
||||
greeting_style = self.action_data.get("greeting_style", "casual")
|
||||
|
||||
# 根据风格生成问候消息
|
||||
if greeting_style == "formal":
|
||||
message = f"您好{username}!很荣幸为您服务!"
|
||||
emoji = "🙏"
|
||||
elif greeting_style == "friendly":
|
||||
message = f"你好{username}!欢迎来到这里,希望我们能成为好朋友!"
|
||||
emoji = "😊"
|
||||
else: # casual
|
||||
message = f"嗨{username}!很开心见到你~"
|
||||
emoji = "👋"
|
||||
|
||||
# 发送消息
|
||||
await self.send_text(message)
|
||||
await self.send_type("emoji", emoji)
|
||||
|
||||
return True, f"向{username or '用户'}发送了{greeting_style}风格的问候"
|
||||
```
|
||||
|
||||
### 智能禁言Action
|
||||
|
||||
以下是一个真实的群管理禁言Action示例,展示了LLM判断、参数验证、配置管理等高级功能:
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
import random
|
||||
from src.plugin_system.base.base_action import BaseAction
|
||||
from src.plugin_system.base.component_types import ActionActivationType, ChatMode
|
||||
|
||||
class MuteAction(BaseAction):
|
||||
"""智能禁言Action - 基于LLM智能判断是否需要禁言"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE # Focus模式使用LLM判定
|
||||
normal_activation_type = ActionActivationType.KEYWORD # Normal模式使用关键词
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "mute"
|
||||
action_description = "智能禁言系统,基于LLM判断是否需要禁言"
|
||||
|
||||
# ===== 激活配置 =====
|
||||
# 关键词设置(用于Normal模式)
|
||||
activation_keywords = ["禁言", "mute", "ban", "silence"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# LLM判定提示词(用于Focus模式)
|
||||
llm_judge_prompt = """
|
||||
判定是否需要使用禁言动作的严格条件:
|
||||
|
||||
使用禁言的情况:
|
||||
1. 用户发送明显违规内容(色情、暴力、政治敏感等)
|
||||
2. 恶意刷屏或垃圾信息轰炸
|
||||
3. 用户主动明确要求被禁言("禁言我"等)
|
||||
4. 严重违反群规的行为
|
||||
5. 恶意攻击他人或群组管理
|
||||
|
||||
绝对不要使用的情况:
|
||||
1. 正常聊天和交流
|
||||
2. 情绪化表达但无恶意
|
||||
3. 开玩笑或调侃,除非过分
|
||||
4. 单纯的意见分歧或争论
|
||||
"""
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"target": "禁言对象,必填,输入你要禁言的对象的名字,请仔细思考不要弄错禁言对象",
|
||||
"duration": "禁言时长,必填,输入你要禁言的时长(秒),单位为秒,必须为数字",
|
||||
"reason": "禁言理由,可选",
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"当有人违反了公序良俗的内容",
|
||||
"当有人刷屏时使用",
|
||||
"当有人发了擦边,或者色情内容时使用",
|
||||
"当有人要求禁言自己时使用",
|
||||
"如果某人已经被禁言了,就不要再次禁言了,除非你想追加时间!!",
|
||||
]
|
||||
|
||||
associated_types = ["text", "command"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
"""执行智能禁言判定"""
|
||||
# 获取参数
|
||||
target = self.action_data.get("target")
|
||||
duration = self.action_data.get("duration")
|
||||
reason = self.action_data.get("reason", "违反群规")
|
||||
|
||||
# 参数验证
|
||||
if not target:
|
||||
await self.send_text("没有指定禁言对象呢~")
|
||||
return False, "禁言目标不能为空"
|
||||
|
||||
if not duration:
|
||||
await self.send_text("没有指定禁言时长呢~")
|
||||
return False, "禁言时长不能为空"
|
||||
|
||||
# 获取时长限制配置
|
||||
min_duration = self.api.get_config("mute.min_duration", 60)
|
||||
max_duration = self.api.get_config("mute.max_duration", 2592000)
|
||||
|
||||
# 验证时长格式并转换
|
||||
try:
|
||||
duration_int = int(duration)
|
||||
if duration_int <= 0:
|
||||
await self.send_text("禁言时长必须是正数哦~")
|
||||
return False, "禁言时长必须大于0"
|
||||
|
||||
# 限制禁言时长范围
|
||||
if duration_int < min_duration:
|
||||
duration_int = min_duration
|
||||
elif duration_int > max_duration:
|
||||
duration_int = max_duration
|
||||
|
||||
except (ValueError, TypeError):
|
||||
await self.send_text("禁言时长必须是数字哦~")
|
||||
return False, f"禁言时长格式无效: {duration}"
|
||||
|
||||
# 获取用户ID
|
||||
try:
|
||||
platform, user_id = await self.api.get_user_id_by_person_name(target)
|
||||
except Exception as e:
|
||||
await self.send_text("查找用户信息时出现问题~")
|
||||
return False, f"查找用户ID时出错: {e}"
|
||||
|
||||
if not user_id:
|
||||
await self.send_text(f"找不到 {target} 这个人呢~")
|
||||
return False, f"未找到用户 {target} 的ID"
|
||||
|
||||
# 格式化时长显示
|
||||
time_str = self._format_duration(duration_int)
|
||||
|
||||
# 获取模板化消息
|
||||
message = self._get_template_message(target, time_str, reason)
|
||||
await self.send_message_by_expressor(message)
|
||||
|
||||
# 发送群聊禁言命令
|
||||
success = await self.send_command(
|
||||
command_name="GROUP_BAN",
|
||||
args={"qq_id": str(user_id), "duration": str(duration_int)},
|
||||
display_message=f"禁言了 {target} {time_str}",
|
||||
)
|
||||
|
||||
if success:
|
||||
return True, f"成功禁言 {target},时长 {time_str}"
|
||||
else:
|
||||
await self.send_text("执行禁言动作失败")
|
||||
return False, "发送禁言命令失败"
|
||||
|
||||
def _get_template_message(self, target: str, duration_str: str, reason: str) -> str:
|
||||
"""获取模板化的禁言消息"""
|
||||
templates = self.api.get_config(
|
||||
"mute.templates",
|
||||
[
|
||||
"好的,禁言 {target} {duration},理由:{reason}",
|
||||
"收到,对 {target} 执行禁言 {duration},因为{reason}",
|
||||
"明白了,禁言 {target} {duration},原因是{reason}",
|
||||
"哇哈哈哈哈哈,已禁言 {target} {duration},理由:{reason}",
|
||||
],
|
||||
)
|
||||
template = random.choice(templates)
|
||||
return template.format(target=target, duration=duration_str, reason=reason)
|
||||
|
||||
def _format_duration(self, seconds: int) -> str:
|
||||
"""将秒数格式化为可读的时间字符串"""
|
||||
if seconds < 60:
|
||||
return f"{seconds}秒"
|
||||
elif seconds < 3600:
|
||||
minutes = seconds // 60
|
||||
remaining_seconds = seconds % 60
|
||||
if remaining_seconds > 0:
|
||||
return f"{minutes}分{remaining_seconds}秒"
|
||||
else:
|
||||
return f"{minutes}分钟"
|
||||
else:
|
||||
hours = seconds // 3600
|
||||
remaining_minutes = (seconds % 3600) // 60
|
||||
if remaining_minutes > 0:
|
||||
return f"{hours}小时{remaining_minutes}分钟"
|
||||
else:
|
||||
return f"{hours}小时"
|
||||
```
|
||||
|
||||
**关键特性说明**:
|
||||
|
||||
1. **🎯 双模式激活**:Focus模式使用LLM_JUDGE更谨慎,Normal模式使用KEYWORD快速响应
|
||||
2. **🧠 严格的LLM判定**:详细提示词指导LLM何时应该/不应该使用禁言,避免误判
|
||||
3. **✅ 完善的参数验证**:验证必需参数、数值转换、用户ID查找等多重验证
|
||||
4. **⚙️ 配置驱动**:时长限制、消息模板等都可通过配置文件自定义
|
||||
5. **😊 友好的用户反馈**:错误提示清晰、随机化消息模板、时长格式化显示
|
||||
6. **🛡️ 安全措施**:严格权限控制、防误操作验证、完整错误处理
|
||||
|
||||
### 智能助手Action
|
||||
|
||||
```python
|
||||
class IntelligentHelpAction(BaseAction):
|
||||
"""智能助手Action - 展示LLM判断激活的完整示例"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.RANDOM
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = True
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "intelligent_help"
|
||||
action_description = "智能助手,主动提供帮助和建议"
|
||||
|
||||
# LLM判断提示词
|
||||
llm_judge_prompt = """
|
||||
判定是否需要提供智能帮助的条件:
|
||||
1. 用户表达了困惑或需要帮助
|
||||
2. 对话中出现了技术问题
|
||||
3. 用户寻求解决方案或建议
|
||||
4. 适合提供额外信息的场合
|
||||
|
||||
不要使用的情况:
|
||||
1. 用户明确表示不需要帮助
|
||||
2. 对话进行得很顺利
|
||||
3. 刚刚已经提供过帮助
|
||||
|
||||
请回答"是"或"否"。
|
||||
"""
|
||||
|
||||
# 随机激活概率
|
||||
random_activation_probability = 0.15
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"help_type": "帮助类型:explanation(解释)、suggestion(建议)、guidance(指导)",
|
||||
"topic": "帮助主题或用户关心的问题",
|
||||
"urgency": "紧急程度:low(低)、medium(中)、high(高)"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户表达困惑或寻求帮助时使用",
|
||||
"检测到用户遇到技术问题时使用",
|
||||
"对话中出现知识盲点时主动提供帮助",
|
||||
"避免过度频繁地提供帮助,要恰到好处"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行智能帮助"""
|
||||
# 获取参数
|
||||
help_type = self.action_data.get("help_type", "suggestion")
|
||||
topic = self.action_data.get("topic", "")
|
||||
urgency = self.action_data.get("urgency", "medium")
|
||||
|
||||
# 根据帮助类型和紧急程度生成消息
|
||||
if help_type == "explanation":
|
||||
message = f"关于{topic},让我来为你解释一下..."
|
||||
elif help_type == "guidance":
|
||||
message = f"在{topic}方面,我可以为你提供一些指导..."
|
||||
else: # suggestion
|
||||
message = f"针对{topic},我建议你可以尝试以下方法..."
|
||||
|
||||
# 根据紧急程度调整表情
|
||||
if urgency == "high":
|
||||
emoji = "🚨"
|
||||
elif urgency == "low":
|
||||
emoji = "💡"
|
||||
else:
|
||||
emoji = "🤔"
|
||||
|
||||
# 发送帮助消息
|
||||
await self.send_text(message)
|
||||
await self.send_type("emoji", emoji)
|
||||
|
||||
return True, f"提供了{help_type}类型的帮助,主题:{topic}"
|
||||
```
|
||||
|
||||
## 📊 性能优化建议
|
||||
|
||||
### 1. 合理使用激活类型
|
||||
|
||||
- **ALWAYS**: 仅用于核心功能
|
||||
- **LLM_JUDGE**: 适度使用,避免过多LLM调用
|
||||
- **KEYWORD**: 优选,性能最好
|
||||
- **RANDOM**: 控制概率,避免过于频繁
|
||||
|
||||
### 2. 优化execute方法
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
try:
|
||||
# 快速参数验证
|
||||
if not self._validate_parameters():
|
||||
return False, "参数验证失败"
|
||||
|
||||
# 核心逻辑
|
||||
result = await self._core_logic()
|
||||
|
||||
# 成功返回
|
||||
return True, "执行成功"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 执行失败: {e}")
|
||||
return False, f"执行失败: {str(e)}"
|
||||
```
|
||||
|
||||
### 3. 合理设置并行执行
|
||||
|
||||
```python
|
||||
# 轻量级Action可以并行
|
||||
parallel_action = True # 如:发送表情、记录日志
|
||||
|
||||
# 重要Action应该独占
|
||||
parallel_action = False # 如:回复消息、状态切换
|
||||
```
|
||||
|
||||
## 🐛 调试技巧
|
||||
|
||||
### 1. 日志记录
|
||||
|
||||
```python
|
||||
from src.common.logger import get_logger
|
||||
|
||||
logger = get_logger("my_action")
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
logger.info(f"{self.log_prefix} 开始执行: {self.reasoning}")
|
||||
logger.debug(f"{self.log_prefix} 参数: {self.action_data}")
|
||||
|
||||
# 执行逻辑...
|
||||
|
||||
logger.info(f"{self.log_prefix} 执行完成")
|
||||
```
|
||||
|
||||
### 2. 激活状态检查
|
||||
|
||||
```python
|
||||
# 在execute方法中检查激活原因
|
||||
def _debug_activation(self):
|
||||
logger.debug(f"激活类型: Focus={self.focus_activation_type}, Normal={self.normal_activation_type}")
|
||||
logger.debug(f"当前模式: {self.api.get_chat_mode()}")
|
||||
logger.debug(f"激活原因: {self.reasoning}")
|
||||
```
|
||||
|
||||
### 3. 参数验证
|
||||
|
||||
```python
|
||||
def _validate_parameters(self) -> bool:
|
||||
required_params = ["param1", "param2"]
|
||||
for param in required_params:
|
||||
if param not in self.action_data:
|
||||
logger.warning(f"{self.log_prefix} 缺少必需参数: {param}")
|
||||
return False
|
||||
return True
|
||||
```
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
### 1. 清晰的Action命名
|
||||
|
||||
- 使用描述性的类名:`SmartGreetingAction` 而不是 `Action1`
|
||||
- action_name要简洁明确:`"smart_greeting"` 而不是 `"action_1"`
|
||||
|
||||
### 2. 完整的文档字符串
|
||||
|
||||
```python
|
||||
class MyAction(BaseAction):
|
||||
"""
|
||||
我的Action - 一句话描述功能
|
||||
|
||||
详细描述Action的用途、激活条件、执行逻辑等。
|
||||
|
||||
激活条件:
|
||||
- Focus模式:关键词激活
|
||||
- Normal模式:LLM判断激活
|
||||
|
||||
执行逻辑:
|
||||
1. 验证参数
|
||||
2. 生成响应
|
||||
3. 发送消息
|
||||
"""
|
||||
```
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
try:
|
||||
# 主要逻辑
|
||||
pass
|
||||
except ValueError as e:
|
||||
await self.send_text("参数错误,请检查输入")
|
||||
return False, f"参数错误: {e}"
|
||||
except Exception as e:
|
||||
await self.send_text("操作失败,请稍后重试")
|
||||
return False, f"执行失败: {e}"
|
||||
```
|
||||
|
||||
### 4. 配置驱动
|
||||
|
||||
```python
|
||||
# 从配置文件读取设置
|
||||
enable_feature = self.api.get_config("my_action.enable_feature", True)
|
||||
max_retries = self.api.get_config("my_action.max_retries", 3)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
🎉 **现在你已经掌握了Action组件开发的完整知识!继续学习 [Command组件详解](command-components.md) 来了解命令开发。**
|
||||
411
docs/plugins/api/message-api.md
Normal file
411
docs/plugins/api/message-api.md
Normal file
@@ -0,0 +1,411 @@
|
||||
# 📡 消息API
|
||||
|
||||
## 📖 概述
|
||||
|
||||
消息API提供了发送各种类型消息的接口,支持文本、表情、图片等多种消息类型,以及向不同目标发送消息的功能。
|
||||
|
||||
## 🔄 基础消息发送
|
||||
|
||||
### 发送文本消息
|
||||
|
||||
```python
|
||||
# 发送普通文本消息
|
||||
await self.send_text("这是一条文本消息")
|
||||
|
||||
# 发送多行文本
|
||||
message = """
|
||||
这是第一行
|
||||
这是第二行
|
||||
这是第三行
|
||||
"""
|
||||
await self.send_text(message.strip())
|
||||
```
|
||||
|
||||
### 发送特定类型消息
|
||||
|
||||
```python
|
||||
# 发送表情
|
||||
await self.send_type("emoji", "😊")
|
||||
|
||||
# 发送图片
|
||||
await self.send_type("image", "https://example.com/image.jpg")
|
||||
|
||||
# 发送音频
|
||||
await self.send_type("audio", "audio_file_path")
|
||||
```
|
||||
|
||||
### 发送命令消息
|
||||
|
||||
```python
|
||||
# 发送命令类型的消息
|
||||
await self.send_command("system_command", {"param": "value"})
|
||||
```
|
||||
|
||||
## 🎯 目标消息发送
|
||||
|
||||
### 向指定群聊发送消息
|
||||
|
||||
```python
|
||||
# 向指定群聊发送文本消息
|
||||
success = await self.api.send_text_to_group(
|
||||
text="这是发送到群聊的消息",
|
||||
group_id="123456789",
|
||||
platform="qq"
|
||||
)
|
||||
|
||||
if success:
|
||||
print("消息发送成功")
|
||||
else:
|
||||
print("消息发送失败")
|
||||
```
|
||||
|
||||
### 向指定用户发送私聊消息
|
||||
|
||||
```python
|
||||
# 向指定用户发送私聊消息
|
||||
success = await self.api.send_text_to_user(
|
||||
text="这是私聊消息",
|
||||
user_id="987654321",
|
||||
platform="qq"
|
||||
)
|
||||
```
|
||||
|
||||
### 通用目标消息发送
|
||||
|
||||
```python
|
||||
# 向任意目标发送任意类型消息
|
||||
success = await self.api.send_message_to_target(
|
||||
message_type="text", # 消息类型
|
||||
content="消息内容", # 消息内容
|
||||
platform="qq", # 平台
|
||||
target_id="123456789", # 目标ID
|
||||
is_group=True, # 是否为群聊
|
||||
display_message="显示消息" # 可选:显示消息
|
||||
)
|
||||
```
|
||||
|
||||
## 📨 消息类型支持
|
||||
|
||||
### 支持的消息类型
|
||||
|
||||
| 类型 | 说明 | 示例 |
|
||||
|-----|------|------|
|
||||
| `text` | 普通文本消息 | "Hello World" |
|
||||
| `emoji` | 表情消息 | "😊" |
|
||||
| `image` | 图片消息 | 图片URL或路径 |
|
||||
| `audio` | 音频消息 | 音频文件路径 |
|
||||
| `video` | 视频消息 | 视频文件路径 |
|
||||
| `file` | 文件消息 | 文件路径 |
|
||||
|
||||
### 消息类型示例
|
||||
|
||||
```python
|
||||
# 文本消息
|
||||
await self.send_type("text", "普通文本")
|
||||
|
||||
# 表情消息
|
||||
await self.send_type("emoji", "🎉")
|
||||
|
||||
# 图片消息
|
||||
await self.send_type("image", "/path/to/image.jpg")
|
||||
|
||||
# 音频消息
|
||||
await self.send_type("audio", "/path/to/audio.mp3")
|
||||
|
||||
# 文件消息
|
||||
await self.send_type("file", "/path/to/document.pdf")
|
||||
```
|
||||
|
||||
## 🔍 消息查询
|
||||
|
||||
### 获取聊天类型
|
||||
|
||||
```python
|
||||
# 获取当前聊天类型
|
||||
chat_type = self.api.get_chat_type()
|
||||
|
||||
if chat_type == "group":
|
||||
print("当前是群聊")
|
||||
elif chat_type == "private":
|
||||
print("当前是私聊")
|
||||
```
|
||||
|
||||
### 获取最近消息
|
||||
|
||||
```python
|
||||
# 获取最近的5条消息
|
||||
recent_messages = self.api.get_recent_messages(count=5)
|
||||
|
||||
for message in recent_messages:
|
||||
print(f"用户: {message.user_nickname}")
|
||||
print(f"内容: {message.processed_plain_text}")
|
||||
print(f"时间: {message.timestamp}")
|
||||
```
|
||||
|
||||
### 获取当前消息信息
|
||||
|
||||
```python
|
||||
# 在Action或Command中获取当前处理的消息
|
||||
current_message = self.message
|
||||
|
||||
# 消息基本信息
|
||||
user_id = current_message.message_info.user_info.user_id
|
||||
user_nickname = current_message.message_info.user_info.user_nickname
|
||||
message_content = current_message.processed_plain_text
|
||||
timestamp = current_message.timestamp
|
||||
|
||||
# 群聊信息(如果是群聊)
|
||||
if current_message.message_info.group_info:
|
||||
group_id = current_message.message_info.group_info.group_id
|
||||
group_name = current_message.message_info.group_info.group_name
|
||||
```
|
||||
|
||||
## 🌐 平台支持
|
||||
|
||||
### 支持的平台
|
||||
|
||||
| 平台 | 标识 | 说明 |
|
||||
|-----|------|------|
|
||||
| QQ | `qq` | QQ聊天平台 |
|
||||
| 微信 | `wechat` | 微信聊天平台 |
|
||||
| Discord | `discord` | Discord聊天平台 |
|
||||
|
||||
### 平台特定功能
|
||||
|
||||
```python
|
||||
# 获取当前平台
|
||||
current_platform = self.api.get_current_platform()
|
||||
|
||||
# 根据平台调整消息格式
|
||||
if current_platform == "qq":
|
||||
# QQ平台特定处理
|
||||
await self.send_text("[QQ] 消息内容")
|
||||
elif current_platform == "wechat":
|
||||
# 微信平台特定处理
|
||||
await self.send_text("【微信】消息内容")
|
||||
```
|
||||
|
||||
## 🎨 消息格式化
|
||||
|
||||
### Markdown支持
|
||||
|
||||
```python
|
||||
# 发送Markdown格式的消息(如果平台支持)
|
||||
markdown_message = """
|
||||
**粗体文本**
|
||||
*斜体文本*
|
||||
`代码块`
|
||||
[链接](https://example.com)
|
||||
"""
|
||||
|
||||
await self.send_text(markdown_message)
|
||||
```
|
||||
|
||||
### 消息模板
|
||||
|
||||
```python
|
||||
# 使用模板生成消息
|
||||
def format_user_info(username: str, level: int, points: int) -> str:
|
||||
return f"""
|
||||
👤 用户信息
|
||||
━━━━━━━━━━━━━━━━━━
|
||||
📛 用户名: {username}
|
||||
⭐ 等级: Lv.{level}
|
||||
💰 积分: {points:,}
|
||||
━━━━━━━━━━━━━━━━━━
|
||||
""".strip()
|
||||
|
||||
# 使用模板
|
||||
user_info = format_user_info("张三", 15, 12580)
|
||||
await self.send_text(user_info)
|
||||
```
|
||||
|
||||
### 表情和Unicode
|
||||
|
||||
```python
|
||||
# 发送Unicode表情
|
||||
await self.send_text("消息发送成功 ✅")
|
||||
|
||||
# 发送表情包
|
||||
await self.send_type("emoji", "🎉")
|
||||
|
||||
# 组合文本和表情
|
||||
await self.send_text("恭喜你完成任务!🎊🎉")
|
||||
```
|
||||
|
||||
## 🔄 流式消息
|
||||
|
||||
### 获取聊天流信息
|
||||
|
||||
```python
|
||||
# 获取当前聊天流
|
||||
chat_stream = self.api.get_service("chat_stream")
|
||||
|
||||
if chat_stream:
|
||||
# 流基本信息
|
||||
stream_id = chat_stream.stream_id
|
||||
platform = chat_stream.platform
|
||||
|
||||
# 群聊信息
|
||||
if chat_stream.group_info:
|
||||
group_id = chat_stream.group_info.group_id
|
||||
group_name = chat_stream.group_info.group_name
|
||||
print(f"当前群聊: {group_name} ({group_id})")
|
||||
|
||||
# 用户信息
|
||||
user_id = chat_stream.user_info.user_id
|
||||
user_name = chat_stream.user_info.user_nickname
|
||||
print(f"当前用户: {user_name} ({user_id})")
|
||||
```
|
||||
|
||||
## 🚨 错误处理
|
||||
|
||||
### 消息发送错误处理
|
||||
|
||||
```python
|
||||
async def safe_send_message(self, content: str) -> bool:
|
||||
"""安全发送消息,包含错误处理"""
|
||||
try:
|
||||
await self.send_text(content)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"消息发送失败: {e}")
|
||||
# 发送错误提示
|
||||
try:
|
||||
await self.send_text("❌ 消息发送失败,请稍后重试")
|
||||
except:
|
||||
pass # 避免循环错误
|
||||
return False
|
||||
```
|
||||
|
||||
### 目标消息发送错误处理
|
||||
|
||||
```python
|
||||
async def send_to_group_safely(self, text: str, group_id: str) -> bool:
|
||||
"""安全向群聊发送消息"""
|
||||
try:
|
||||
success = await self.api.send_text_to_group(
|
||||
text=text,
|
||||
group_id=group_id,
|
||||
platform="qq"
|
||||
)
|
||||
|
||||
if not success:
|
||||
logger.warning(f"向群聊 {group_id} 发送消息失败")
|
||||
|
||||
return success
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"向群聊发送消息异常: {e}")
|
||||
return False
|
||||
```
|
||||
|
||||
## 📊 最佳实践
|
||||
|
||||
### 1. 消息长度控制
|
||||
|
||||
```python
|
||||
async def send_long_message(self, content: str, max_length: int = 500):
|
||||
"""发送长消息,自动分段"""
|
||||
if len(content) <= max_length:
|
||||
await self.send_text(content)
|
||||
else:
|
||||
# 分段发送
|
||||
parts = [content[i:i+max_length] for i in range(0, len(content), max_length)]
|
||||
for i, part in enumerate(parts):
|
||||
prefix = f"[{i+1}/{len(parts)}] " if len(parts) > 1 else ""
|
||||
await self.send_text(f"{prefix}{part}")
|
||||
|
||||
# 避免发送过快
|
||||
if i < len(parts) - 1:
|
||||
await asyncio.sleep(0.5)
|
||||
```
|
||||
|
||||
### 2. 消息格式规范
|
||||
|
||||
```python
|
||||
class MessageFormatter:
|
||||
"""消息格式化工具类"""
|
||||
|
||||
@staticmethod
|
||||
def success(message: str) -> str:
|
||||
return f"✅ {message}"
|
||||
|
||||
@staticmethod
|
||||
def error(message: str) -> str:
|
||||
return f"❌ {message}"
|
||||
|
||||
@staticmethod
|
||||
def warning(message: str) -> str:
|
||||
return f"⚠️ {message}"
|
||||
|
||||
@staticmethod
|
||||
def info(message: str) -> str:
|
||||
return f"ℹ️ {message}"
|
||||
|
||||
# 使用示例
|
||||
await self.send_text(MessageFormatter.success("操作成功完成"))
|
||||
await self.send_text(MessageFormatter.error("操作失败,请重试"))
|
||||
```
|
||||
|
||||
### 3. 异步消息处理
|
||||
|
||||
```python
|
||||
async def batch_send_messages(self, messages: List[str]):
|
||||
"""批量发送消息"""
|
||||
tasks = []
|
||||
|
||||
for message in messages:
|
||||
task = self.send_text(message)
|
||||
tasks.append(task)
|
||||
|
||||
# 并发发送,但控制并发数
|
||||
semaphore = asyncio.Semaphore(3) # 最多3个并发
|
||||
|
||||
async def send_with_limit(message):
|
||||
async with semaphore:
|
||||
await self.send_text(message)
|
||||
|
||||
await asyncio.gather(*[send_with_limit(msg) for msg in messages])
|
||||
```
|
||||
|
||||
### 4. 消息缓存
|
||||
|
||||
```python
|
||||
class MessageCache:
|
||||
"""消息缓存管理"""
|
||||
|
||||
def __init__(self):
|
||||
self._cache = {}
|
||||
self._max_size = 100
|
||||
|
||||
def get_cached_message(self, key: str) -> Optional[str]:
|
||||
return self._cache.get(key)
|
||||
|
||||
def cache_message(self, key: str, message: str):
|
||||
if len(self._cache) >= self._max_size:
|
||||
# 删除最旧的缓存
|
||||
oldest_key = next(iter(self._cache))
|
||||
del self._cache[oldest_key]
|
||||
|
||||
self._cache[key] = message
|
||||
|
||||
# 使用缓存避免重复生成消息
|
||||
cache = MessageCache()
|
||||
|
||||
async def send_user_info(self, user_id: str):
|
||||
cache_key = f"user_info_{user_id}"
|
||||
cached_message = cache.get_cached_message(cache_key)
|
||||
|
||||
if cached_message:
|
||||
await self.send_text(cached_message)
|
||||
else:
|
||||
# 生成新消息
|
||||
message = await self._generate_user_info(user_id)
|
||||
cache.cache_message(cache_key, message)
|
||||
await self.send_text(message)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
🎉 **现在你已经掌握了消息API的完整用法!继续学习其他API接口。**
|
||||
560
docs/plugins/command-components.md
Normal file
560
docs/plugins/command-components.md
Normal file
@@ -0,0 +1,560 @@
|
||||
# 💻 Command组件详解
|
||||
|
||||
## 📖 什么是Command
|
||||
|
||||
Command是直接响应用户明确指令的组件,与Action不同,Command是**被动触发**的,当用户输入特定格式的命令时立即执行。Command通过正则表达式匹配用户输入,提供确定性的功能服务。
|
||||
|
||||
### 🎯 Command的特点
|
||||
|
||||
- 🎯 **确定性执行**:匹配到命令立即执行,无随机性
|
||||
- ⚡ **即时响应**:用户主动触发,快速响应
|
||||
- 🔍 **正则匹配**:通过正则表达式精确匹配用户输入
|
||||
- 🛑 **拦截控制**:可以控制是否阻止消息继续处理
|
||||
- 📝 **参数解析**:支持从用户输入中提取参数
|
||||
|
||||
## 🆚 Action vs Command 核心区别
|
||||
|
||||
| 特征 | Action | Command |
|
||||
|-----|-------|---------|
|
||||
| **触发方式** | 麦麦主动决策使用 | 用户主动触发 |
|
||||
| **决策机制** | 两层决策(激活+使用) | 直接匹配执行 |
|
||||
| **随机性** | 有随机性和智能性 | 确定性执行 |
|
||||
| **用途** | 增强麦麦行为拟人化 | 提供具体功能服务 |
|
||||
| **性能影响** | 需要LLM决策 | 正则匹配,性能好 |
|
||||
|
||||
## 🏗️ Command基本结构
|
||||
|
||||
### 必须属性
|
||||
|
||||
```python
|
||||
from src.plugin_system import BaseCommand
|
||||
|
||||
class MyCommand(BaseCommand):
|
||||
# 正则表达式匹配模式
|
||||
command_pattern = r"^/help\s+(?P<topic>\w+)$"
|
||||
|
||||
# 命令帮助说明
|
||||
command_help = "显示指定主题的帮助信息"
|
||||
|
||||
# 使用示例
|
||||
command_examples = ["/help action", "/help command"]
|
||||
|
||||
# 是否拦截后续处理
|
||||
intercept_message = True
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
"""执行命令逻辑"""
|
||||
# 命令执行逻辑
|
||||
return True, "执行成功"
|
||||
```
|
||||
|
||||
### 属性说明
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|-----|------|------|
|
||||
| `command_pattern` | str | 正则表达式匹配模式 |
|
||||
| `command_help` | str | 命令帮助说明 |
|
||||
| `command_examples` | List[str] | 使用示例列表 |
|
||||
| `intercept_message` | bool | 是否拦截消息继续处理 |
|
||||
|
||||
## 🔍 正则表达式匹配
|
||||
|
||||
### 基础匹配
|
||||
|
||||
```python
|
||||
class SimpleCommand(BaseCommand):
|
||||
# 匹配 /ping
|
||||
command_pattern = r"^/ping$"
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
await self.send_text("Pong!")
|
||||
return True, "发送了Pong回复"
|
||||
```
|
||||
|
||||
### 参数捕获
|
||||
|
||||
使用命名组 `(?P<name>pattern)` 捕获参数:
|
||||
|
||||
```python
|
||||
class UserCommand(BaseCommand):
|
||||
# 匹配 /user add 张三 或 /user del 李四
|
||||
command_pattern = r"^/user\s+(?P<action>add|del|info)\s+(?P<username>\w+)$"
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
# 通过 self.matched_groups 获取捕获的参数
|
||||
action = self.matched_groups.get("action")
|
||||
username = self.matched_groups.get("username")
|
||||
|
||||
if action == "add":
|
||||
await self.send_text(f"添加用户:{username}")
|
||||
elif action == "del":
|
||||
await self.send_text(f"删除用户:{username}")
|
||||
elif action == "info":
|
||||
await self.send_text(f"用户信息:{username}")
|
||||
|
||||
return True, f"执行了{action}操作"
|
||||
```
|
||||
|
||||
### 可选参数
|
||||
|
||||
```python
|
||||
class HelpCommand(BaseCommand):
|
||||
# 匹配 /help 或 /help topic
|
||||
command_pattern = r"^/help(?:\s+(?P<topic>\w+))?$"
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
topic = self.matched_groups.get("topic")
|
||||
|
||||
if topic:
|
||||
await self.send_text(f"显示{topic}的帮助")
|
||||
else:
|
||||
await self.send_text("显示总体帮助")
|
||||
|
||||
return True, "显示了帮助信息"
|
||||
```
|
||||
|
||||
## 🛑 拦截控制详解
|
||||
|
||||
### 拦截消息 (intercept_message = True)
|
||||
|
||||
```python
|
||||
class AdminCommand(BaseCommand):
|
||||
command_pattern = r"^/admin\s+.+"
|
||||
command_help = "管理员命令"
|
||||
intercept_message = True # 拦截,不继续处理
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
# 执行管理操作
|
||||
await self.send_text("执行管理命令")
|
||||
# 消息不会继续传递给其他组件
|
||||
return True, "管理命令执行完成"
|
||||
```
|
||||
|
||||
### 不拦截消息 (intercept_message = False)
|
||||
|
||||
```python
|
||||
class LogCommand(BaseCommand):
|
||||
command_pattern = r"^/log\s+.+"
|
||||
command_help = "记录日志"
|
||||
intercept_message = False # 不拦截,继续处理
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
# 记录日志但不阻止后续处理
|
||||
await self.send_text("已记录到日志")
|
||||
# 消息会继续传递,可能触发Action等其他组件
|
||||
return True, "日志记录完成"
|
||||
```
|
||||
|
||||
### 拦截控制的用途
|
||||
|
||||
| 场景 | intercept_message | 说明 |
|
||||
|-----|------------------|------|
|
||||
| 系统命令 | True | 防止命令被当作普通消息处理 |
|
||||
| 查询命令 | True | 直接返回结果,无需后续处理 |
|
||||
| 日志命令 | False | 记录但允许消息继续流转 |
|
||||
| 监控命令 | False | 监控但不影响正常聊天 |
|
||||
|
||||
## 🎨 完整Command示例
|
||||
|
||||
### 用户管理Command
|
||||
|
||||
```python
|
||||
from src.plugin_system import BaseCommand
|
||||
from typing import Tuple, Optional
|
||||
|
||||
class UserManagementCommand(BaseCommand):
|
||||
"""用户管理Command - 展示复杂参数处理"""
|
||||
|
||||
command_pattern = r"^/user\s+(?P<action>add|del|list|info)\s*(?P<username>\w+)?(?:\s+--(?P<options>.+))?$"
|
||||
command_help = "用户管理命令,支持添加、删除、列表、信息查询"
|
||||
command_examples = [
|
||||
"/user add 张三",
|
||||
"/user del 李四",
|
||||
"/user list",
|
||||
"/user info 王五",
|
||||
"/user add 赵六 --role=admin"
|
||||
]
|
||||
intercept_message = True
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
"""执行用户管理命令"""
|
||||
try:
|
||||
action = self.matched_groups.get("action")
|
||||
username = self.matched_groups.get("username")
|
||||
options = self.matched_groups.get("options")
|
||||
|
||||
# 解析选项
|
||||
parsed_options = self._parse_options(options) if options else {}
|
||||
|
||||
if action == "add":
|
||||
return await self._add_user(username, parsed_options)
|
||||
elif action == "del":
|
||||
return await self._delete_user(username)
|
||||
elif action == "list":
|
||||
return await self._list_users()
|
||||
elif action == "info":
|
||||
return await self._show_user_info(username)
|
||||
else:
|
||||
await self.send_text("❌ 不支持的操作")
|
||||
return False, f"不支持的操作: {action}"
|
||||
|
||||
except Exception as e:
|
||||
await self.send_text(f"❌ 命令执行失败: {str(e)}")
|
||||
return False, f"执行失败: {e}"
|
||||
|
||||
def _parse_options(self, options_str: str) -> dict:
|
||||
"""解析命令选项"""
|
||||
options = {}
|
||||
if options_str:
|
||||
for opt in options_str.split():
|
||||
if "=" in opt:
|
||||
key, value = opt.split("=", 1)
|
||||
options[key] = value
|
||||
return options
|
||||
|
||||
async def _add_user(self, username: str, options: dict) -> Tuple[bool, str]:
|
||||
"""添加用户"""
|
||||
if not username:
|
||||
await self.send_text("❌ 请指定用户名")
|
||||
return False, "缺少用户名参数"
|
||||
|
||||
# 检查用户是否已存在
|
||||
existing_users = await self._get_user_list()
|
||||
if username in existing_users:
|
||||
await self.send_text(f"❌ 用户 {username} 已存在")
|
||||
return False, f"用户已存在: {username}"
|
||||
|
||||
# 添加用户逻辑
|
||||
role = options.get("role", "user")
|
||||
await self.send_text(f"✅ 成功添加用户 {username},角色: {role}")
|
||||
return True, f"添加用户成功: {username}"
|
||||
|
||||
async def _delete_user(self, username: str) -> Tuple[bool, str]:
|
||||
"""删除用户"""
|
||||
if not username:
|
||||
await self.send_text("❌ 请指定用户名")
|
||||
return False, "缺少用户名参数"
|
||||
|
||||
await self.send_text(f"✅ 用户 {username} 已删除")
|
||||
return True, f"删除用户成功: {username}"
|
||||
|
||||
async def _list_users(self) -> Tuple[bool, str]:
|
||||
"""列出所有用户"""
|
||||
users = await self._get_user_list()
|
||||
if users:
|
||||
user_list = "\n".join([f"• {user}" for user in users])
|
||||
await self.send_text(f"📋 用户列表:\n{user_list}")
|
||||
else:
|
||||
await self.send_text("📋 暂无用户")
|
||||
return True, "显示用户列表"
|
||||
|
||||
async def _show_user_info(self, username: str) -> Tuple[bool, str]:
|
||||
"""显示用户信息"""
|
||||
if not username:
|
||||
await self.send_text("❌ 请指定用户名")
|
||||
return False, "缺少用户名参数"
|
||||
|
||||
# 模拟用户信息
|
||||
user_info = f"""
|
||||
👤 用户信息: {username}
|
||||
📧 邮箱: {username}@example.com
|
||||
🕒 注册时间: 2024-01-01
|
||||
🎯 角色: 普通用户
|
||||
""".strip()
|
||||
|
||||
await self.send_text(user_info)
|
||||
return True, f"显示用户信息: {username}"
|
||||
|
||||
async def _get_user_list(self) -> list:
|
||||
"""获取用户列表(示例)"""
|
||||
return ["张三", "李四", "王五"]
|
||||
```
|
||||
|
||||
### 系统信息Command
|
||||
|
||||
```python
|
||||
class SystemInfoCommand(BaseCommand):
|
||||
"""系统信息Command - 展示系统查询功能"""
|
||||
|
||||
command_pattern = r"^/(?:status|info)(?:\s+(?P<type>system|memory|plugins|all))?$"
|
||||
command_help = "查询系统状态信息"
|
||||
command_examples = [
|
||||
"/status",
|
||||
"/info system",
|
||||
"/status memory",
|
||||
"/info plugins"
|
||||
]
|
||||
intercept_message = True
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
"""执行系统信息查询"""
|
||||
info_type = self.matched_groups.get("type", "all")
|
||||
|
||||
try:
|
||||
if info_type in ["system", "all"]:
|
||||
await self._show_system_info()
|
||||
|
||||
if info_type in ["memory", "all"]:
|
||||
await self._show_memory_info()
|
||||
|
||||
if info_type in ["plugins", "all"]:
|
||||
await self._show_plugin_info()
|
||||
|
||||
return True, f"显示了{info_type}类型的系统信息"
|
||||
|
||||
except Exception as e:
|
||||
await self.send_text(f"❌ 获取系统信息失败: {str(e)}")
|
||||
return False, f"查询失败: {e}"
|
||||
|
||||
async def _show_system_info(self):
|
||||
"""显示系统信息"""
|
||||
import platform
|
||||
import datetime
|
||||
|
||||
system_info = f"""
|
||||
🖥️ **系统信息**
|
||||
📱 平台: {platform.system()} {platform.release()}
|
||||
🐍 Python: {platform.python_version()}
|
||||
⏰ 运行时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
|
||||
""".strip()
|
||||
|
||||
await self.send_text(system_info)
|
||||
|
||||
async def _show_memory_info(self):
|
||||
"""显示内存信息"""
|
||||
import psutil
|
||||
|
||||
memory = psutil.virtual_memory()
|
||||
memory_info = f"""
|
||||
💾 **内存信息**
|
||||
📊 总内存: {memory.total // (1024**3)} GB
|
||||
🟢 可用内存: {memory.available // (1024**3)} GB
|
||||
📈 使用率: {memory.percent}%
|
||||
""".strip()
|
||||
|
||||
await self.send_text(memory_info)
|
||||
|
||||
async def _show_plugin_info(self):
|
||||
"""显示插件信息"""
|
||||
# 通过API获取插件信息
|
||||
plugins = await self._get_loaded_plugins()
|
||||
|
||||
plugin_info = f"""
|
||||
🔌 **插件信息**
|
||||
📦 已加载插件: {len(plugins)}
|
||||
🔧 活跃插件: {len([p for p in plugins if p.get('active', False)])}
|
||||
""".strip()
|
||||
|
||||
await self.send_text(plugin_info)
|
||||
|
||||
async def _get_loaded_plugins(self) -> list:
|
||||
"""获取已加载的插件列表"""
|
||||
# 这里可以通过self.api获取实际的插件信息
|
||||
return [
|
||||
{"name": "core_actions", "active": True},
|
||||
{"name": "example_plugin", "active": True},
|
||||
]
|
||||
```
|
||||
|
||||
### 自定义前缀Command
|
||||
|
||||
```python
|
||||
class CustomPrefixCommand(BaseCommand):
|
||||
"""自定义前缀Command - 展示非/前缀的命令"""
|
||||
|
||||
# 使用!前缀而不是/前缀
|
||||
command_pattern = r"^[!!](?P<command>roll|dice)\s*(?P<count>\d+)?$"
|
||||
command_help = "骰子命令,使用!前缀"
|
||||
command_examples = ["!roll", "!dice 6", "!roll 20"]
|
||||
intercept_message = True
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
"""执行骰子命令"""
|
||||
import random
|
||||
|
||||
command = self.matched_groups.get("command")
|
||||
count = int(self.matched_groups.get("count", "6"))
|
||||
|
||||
# 限制骰子面数
|
||||
if count > 100:
|
||||
await self.send_text("❌ 骰子面数不能超过100")
|
||||
return False, "骰子面数超限"
|
||||
|
||||
result = random.randint(1, count)
|
||||
await self.send_text(f"🎲 投掷{count}面骰子,结果: {result}")
|
||||
|
||||
return True, f"投掷了{count}面骰子,结果{result}"
|
||||
```
|
||||
|
||||
## 📊 性能优化建议
|
||||
|
||||
### 1. 正则表达式优化
|
||||
|
||||
```python
|
||||
# ✅ 好的做法 - 简单直接
|
||||
command_pattern = r"^/ping$"
|
||||
|
||||
# ❌ 避免 - 过于复杂
|
||||
command_pattern = r"^/(?:ping|pong|test|check|status|info|help|...)"
|
||||
|
||||
# ✅ 好的做法 - 分离复杂逻辑
|
||||
class PingCommand(BaseCommand):
|
||||
command_pattern = r"^/ping$"
|
||||
|
||||
class StatusCommand(BaseCommand):
|
||||
command_pattern = r"^/status$"
|
||||
```
|
||||
|
||||
### 2. 参数验证
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
# 快速参数验证
|
||||
username = self.matched_groups.get("username")
|
||||
if not username or len(username) < 2:
|
||||
await self.send_text("❌ 用户名不合法")
|
||||
return False, "参数验证失败"
|
||||
|
||||
# 主要逻辑
|
||||
...
|
||||
```
|
||||
|
||||
### 3. 异常处理
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
try:
|
||||
# 命令逻辑
|
||||
result = await self._do_command()
|
||||
return True, "执行成功"
|
||||
except ValueError as e:
|
||||
await self.send_text(f"❌ 参数错误: {e}")
|
||||
return False, f"参数错误: {e}"
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 命令执行失败: {e}")
|
||||
await self.send_text("❌ 命令执行失败")
|
||||
return False, f"执行失败: {e}"
|
||||
```
|
||||
|
||||
## 🐛 调试技巧
|
||||
|
||||
### 1. 正则测试
|
||||
|
||||
```python
|
||||
import re
|
||||
|
||||
pattern = r"^/user\s+(?P<action>add|del)\s+(?P<username>\w+)$"
|
||||
test_inputs = [
|
||||
"/user add 张三",
|
||||
"/user del 李四",
|
||||
"/user info 王五", # 不匹配
|
||||
]
|
||||
|
||||
for input_text in test_inputs:
|
||||
match = re.match(pattern, input_text)
|
||||
print(f"'{input_text}' -> {match.groupdict() if match else 'No match'}")
|
||||
```
|
||||
|
||||
### 2. 参数调试
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
# 调试输出
|
||||
logger.debug(f"匹配组: {self.matched_groups}")
|
||||
logger.debug(f"原始消息: {self.message.processed_plain_text}")
|
||||
|
||||
# 命令逻辑...
|
||||
```
|
||||
|
||||
### 3. 拦截测试
|
||||
|
||||
```python
|
||||
# 测试不同的拦截设置
|
||||
intercept_message = True # 测试拦截
|
||||
intercept_message = False # 测试不拦截
|
||||
|
||||
# 观察后续Action是否被触发
|
||||
```
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
### 1. 命令设计原则
|
||||
|
||||
```python
|
||||
# ✅ 好的命令设计
|
||||
"/user add 张三" # 动作 + 对象 + 参数
|
||||
"/config set key=value" # 动作 + 子动作 + 参数
|
||||
"/help command" # 动作 + 可选参数
|
||||
|
||||
# ❌ 避免的设计
|
||||
"/add_user_with_name_张三" # 过于冗长
|
||||
"/u a 张三" # 过于简写
|
||||
```
|
||||
|
||||
### 2. 帮助信息
|
||||
|
||||
```python
|
||||
class WellDocumentedCommand(BaseCommand):
|
||||
command_pattern = r"^/example\s+(?P<param>\w+)$"
|
||||
command_help = "示例命令:处理指定参数并返回结果"
|
||||
command_examples = [
|
||||
"/example test",
|
||||
"/example debug",
|
||||
"/example production"
|
||||
]
|
||||
```
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
param = self.matched_groups.get("param")
|
||||
|
||||
# 参数验证
|
||||
if param not in ["test", "debug", "production"]:
|
||||
await self.send_text("❌ 无效的参数,支持: test, debug, production")
|
||||
return False, "无效参数"
|
||||
|
||||
# 执行逻辑
|
||||
try:
|
||||
result = await self._process_param(param)
|
||||
await self.send_text(f"✅ 处理完成: {result}")
|
||||
return True, f"处理{param}成功"
|
||||
except Exception as e:
|
||||
await self.send_text("❌ 处理失败,请稍后重试")
|
||||
return False, f"处理失败: {e}"
|
||||
```
|
||||
|
||||
### 4. 配置集成
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
# 从配置读取设置
|
||||
max_items = self.api.get_config("command.max_items", 10)
|
||||
timeout = self.api.get_config("command.timeout", 30)
|
||||
|
||||
# 使用配置进行处理
|
||||
...
|
||||
```
|
||||
|
||||
## 📝 Command vs Action 选择指南
|
||||
|
||||
### 使用Command的场景
|
||||
|
||||
- ✅ 用户需要明确调用特定功能
|
||||
- ✅ 需要精确的参数控制
|
||||
- ✅ 管理和配置操作
|
||||
- ✅ 查询和信息显示
|
||||
- ✅ 系统维护命令
|
||||
|
||||
### 使用Action的场景
|
||||
|
||||
- ✅ 增强麦麦的智能行为
|
||||
- ✅ 根据上下文自动触发
|
||||
- ✅ 情绪和表情表达
|
||||
- ✅ 智能建议和帮助
|
||||
- ✅ 随机化的互动
|
||||
|
||||
---
|
||||
|
||||
🎉 **现在你已经掌握了Command组件开发的完整知识!继续学习 [API参考](api/) 来了解所有可用的接口。**
|
||||
412
docs/plugins/development-standards.md
Normal file
412
docs/plugins/development-standards.md
Normal file
@@ -0,0 +1,412 @@
|
||||
# 📋 开发标准规范
|
||||
|
||||
## 🎯 概述
|
||||
|
||||
本文档定义了MaiBot插件开发的标准规范,包括Action组件、Command组件和Tool组件的开发规范,确保代码质量、可维护性和性能。
|
||||
|
||||
## 🧩 组件开发规范
|
||||
|
||||
### Tool组件开发
|
||||
|
||||
**工具基本要求**:
|
||||
- 继承 `BaseTool` 基类
|
||||
- 定义唯一的工具名称
|
||||
- 提供清晰的功能描述
|
||||
- 使用JSONSchema定义参数
|
||||
- 实现 `execute` 异步方法
|
||||
- 使用 `register_tool()` 注册
|
||||
|
||||
**工具开发模板**:
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
|
||||
class MyTool(BaseTool):
|
||||
"""工具类文档字符串"""
|
||||
|
||||
name = "my_tool"
|
||||
description = "详细的工具功能描述,告诉LLM这个工具的用途"
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"param": {
|
||||
"type": "string",
|
||||
"description": "参数详细描述"
|
||||
}
|
||||
},
|
||||
"required": ["param"]
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
"""执行工具逻辑
|
||||
|
||||
Args:
|
||||
function_args: 工具调用参数
|
||||
message_txt: 原始消息文本
|
||||
|
||||
Returns:
|
||||
dict: 包含name和content字段的结果
|
||||
"""
|
||||
# 实现工具功能逻辑
|
||||
result = "处理结果"
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
|
||||
# 注册工具
|
||||
register_tool(MyTool)
|
||||
```
|
||||
|
||||
**工具命名规范**:
|
||||
- 使用描述性的英文名称
|
||||
- 采用下划线命名法(snake_case)
|
||||
- 体现工具的核心功能
|
||||
- 避免过于简短或复杂的名称
|
||||
|
||||
**示例**:
|
||||
```python
|
||||
# ✅ 好的命名
|
||||
name = "weather_query" # 天气查询
|
||||
name = "knowledge_search" # 知识搜索
|
||||
name = "stock_price_check" # 股价检查
|
||||
|
||||
# ❌ 避免的命名
|
||||
name = "tool1" # 无意义
|
||||
name = "wq" # 过于简短
|
||||
name = "weather_and_news" # 功能复杂
|
||||
```
|
||||
|
||||
### Action组件开发
|
||||
|
||||
**Action必需字段检查表**:
|
||||
|
||||
**激活控制字段**:
|
||||
- ✅ `activation_type`:激活类型(KEYWORD/LLM_JUDGE/RANDOM/ALWAYS/NEVER)
|
||||
- ✅ `activation_config`:激活配置参数
|
||||
|
||||
**基本信息字段**:
|
||||
- ✅ `name`:Action唯一标识名称
|
||||
- ✅ `description`:功能描述
|
||||
- ✅ `usage_tip`:使用提示
|
||||
|
||||
**功能定义字段**:
|
||||
- ✅ `func`:执行函数
|
||||
- ✅ `llm_function_tips`:LLM调用提示
|
||||
|
||||
**Action开发模板**:
|
||||
```python
|
||||
from src.plugin_system.base_actions import BaseAction
|
||||
|
||||
class MyAction(BaseAction):
|
||||
"""Action类文档字符串"""
|
||||
|
||||
# 激活控制
|
||||
activation_type = "KEYWORD" # 或 LLM_JUDGE/RANDOM/ALWAYS/NEVER
|
||||
activation_config = {
|
||||
"keywords": ["关键词1", "关键词2"],
|
||||
"priority": 1
|
||||
}
|
||||
|
||||
# 基本信息
|
||||
name = "my_action"
|
||||
description = "Action功能描述"
|
||||
usage_tip = "使用场景和方法提示"
|
||||
|
||||
# 功能定义
|
||||
func = "执行函数名"
|
||||
llm_function_tips = "告诉LLM何时以及如何使用这个Action"
|
||||
|
||||
async def 执行函数名(self, message_txt, sender_name, chat_stream):
|
||||
"""Action执行逻辑"""
|
||||
# 实现Action功能
|
||||
await chat_stream.send_message("执行结果")
|
||||
```
|
||||
|
||||
**激活类型使用规范**:
|
||||
- `KEYWORD`:适用于有明确关键词的功能,性能最优
|
||||
- `LLM_JUDGE`:适用于需要智能判断的复杂场景
|
||||
- `RANDOM`:适用于随机触发的功能
|
||||
- `ALWAYS`:适用于总是可用的基础功能
|
||||
- `NEVER`:适用于临时禁用的功能
|
||||
|
||||
### Command组件开发
|
||||
|
||||
**Command开发模板**:
|
||||
```python
|
||||
from src.plugin_system.base_commands import BaseCommand
|
||||
|
||||
class MyCommand(BaseCommand):
|
||||
"""Command类文档字符串"""
|
||||
|
||||
# 命令基本信息
|
||||
command_name = "my_command"
|
||||
description = "命令功能描述"
|
||||
usage = "/my_command <参数> - 命令使用说明"
|
||||
|
||||
# 匹配模式
|
||||
pattern = r"^/my_command\s+(.*)"
|
||||
|
||||
async def execute(self, match, message_txt, sender_name, chat_stream):
|
||||
"""Command执行逻辑"""
|
||||
params = match.group(1) if match.group(1) else ""
|
||||
|
||||
# 实现命令功能
|
||||
await chat_stream.send_message(f"命令执行结果: {params}")
|
||||
```
|
||||
|
||||
## 📝 代码结构标准
|
||||
|
||||
### 文件组织结构
|
||||
|
||||
```
|
||||
plugins/my_plugin/
|
||||
├── __init__.py # 插件入口
|
||||
├── plugin.py # 插件主文件
|
||||
├── config.toml # 插件配置
|
||||
├── actions/ # Action组件目录
|
||||
│ ├── __init__.py
|
||||
│ └── my_action.py
|
||||
├── commands/ # Command组件目录
|
||||
│ ├── __init__.py
|
||||
│ └── my_command.py
|
||||
├── utils/ # 工具函数目录
|
||||
│ ├── __init__.py
|
||||
│ └── helpers.py
|
||||
└── README.md # 插件说明文档
|
||||
```
|
||||
|
||||
### 插件主文件模板
|
||||
|
||||
```python
|
||||
"""
|
||||
插件名称:My Plugin
|
||||
插件描述:插件功能描述
|
||||
作者:作者名称
|
||||
版本:1.0.0
|
||||
"""
|
||||
|
||||
from src.plugin_system.plugin_interface import PluginInterface
|
||||
from .actions.my_action import MyAction
|
||||
from .commands.my_command import MyCommand
|
||||
|
||||
class MyPlugin(PluginInterface):
|
||||
"""插件主类"""
|
||||
|
||||
def get_action_info(self):
|
||||
"""获取Action信息"""
|
||||
return [MyAction()]
|
||||
|
||||
def get_command_info(self):
|
||||
"""获取Command信息"""
|
||||
return [MyCommand()]
|
||||
|
||||
# 插件实例
|
||||
plugin_instance = MyPlugin()
|
||||
```
|
||||
|
||||
## 🔧 命名规范
|
||||
|
||||
### 类命名
|
||||
- **Action类**:使用 `Action` 后缀,如 `GreetingAction`
|
||||
- **Command类**:使用 `Command` 后缀,如 `HelpCommand`
|
||||
- **Tool类**:使用 `Tool` 后缀,如 `WeatherTool`
|
||||
- **插件类**:使用 `Plugin` 后缀,如 `ExamplePlugin`
|
||||
|
||||
### 变量命名
|
||||
- 使用小写字母和下划线(snake_case)
|
||||
- 布尔变量使用 `is_`、`has_`、`can_` 前缀
|
||||
- 常量使用全大写字母
|
||||
|
||||
### 函数命名
|
||||
- 使用小写字母和下划线(snake_case)
|
||||
- 异步函数不需要特殊前缀
|
||||
- 私有方法使用单下划线前缀
|
||||
|
||||
## 📊 性能优化规范
|
||||
|
||||
### Action激活类型选择
|
||||
1. **首选KEYWORD**:明确知道触发关键词时
|
||||
2. **谨慎使用LLM_JUDGE**:仅在必须智能判断时使用
|
||||
3. **合理设置优先级**:避免过多高优先级Action
|
||||
|
||||
### 异步编程规范
|
||||
- 所有I/O操作必须使用异步
|
||||
- 避免在异步函数中使用阻塞操作
|
||||
- 合理使用 `asyncio.gather()` 并发执行
|
||||
|
||||
### 资源管理
|
||||
- 及时关闭文件、网络连接等资源
|
||||
- 使用上下文管理器(`async with`)
|
||||
- 避免内存泄漏
|
||||
|
||||
## 🚨 错误处理规范
|
||||
|
||||
### 异常处理模板
|
||||
|
||||
```python
|
||||
async def my_function(self, message_txt, sender_name, chat_stream):
|
||||
"""函数文档字符串"""
|
||||
try:
|
||||
# 核心逻辑
|
||||
result = await some_operation()
|
||||
|
||||
# 成功处理
|
||||
await chat_stream.send_message(f"操作成功: {result}")
|
||||
|
||||
except ValueError as e:
|
||||
# 具体异常处理
|
||||
await chat_stream.send_message(f"参数错误: {str(e)}")
|
||||
|
||||
except Exception as e:
|
||||
# 通用异常处理
|
||||
await chat_stream.send_message(f"操作失败: {str(e)}")
|
||||
# 记录错误日志
|
||||
logger.error(f"Function my_function failed: {str(e)}")
|
||||
```
|
||||
|
||||
### 错误信息规范
|
||||
- 使用用户友好的错误提示
|
||||
- 避免暴露系统内部信息
|
||||
- 提供解决建议或替代方案
|
||||
- 记录详细的错误日志
|
||||
|
||||
## 🧪 测试标准
|
||||
|
||||
### 单元测试模板
|
||||
|
||||
```python
|
||||
import unittest
|
||||
import asyncio
|
||||
from unittest.mock import Mock, AsyncMock
|
||||
from plugins.my_plugin.actions.my_action import MyAction
|
||||
|
||||
class TestMyAction(unittest.TestCase):
|
||||
"""MyAction测试类"""
|
||||
|
||||
def setUp(self):
|
||||
"""测试前准备"""
|
||||
self.action = MyAction()
|
||||
self.mock_chat_stream = AsyncMock()
|
||||
|
||||
def test_action_properties(self):
|
||||
"""测试Action属性"""
|
||||
self.assertEqual(self.action.name, "my_action")
|
||||
self.assertIsNotNone(self.action.description)
|
||||
self.assertIsNotNone(self.action.activation_type)
|
||||
|
||||
async def test_action_execution(self):
|
||||
"""测试Action执行"""
|
||||
await self.action.执行函数名("测试消息", "测试用户", self.mock_chat_stream)
|
||||
|
||||
# 验证消息发送
|
||||
self.mock_chat_stream.send_message.assert_called()
|
||||
|
||||
def test_action_execution_sync(self):
|
||||
"""同步测试包装器"""
|
||||
asyncio.run(self.test_action_execution())
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
```
|
||||
|
||||
### 测试覆盖率要求
|
||||
- 核心功能必须有测试覆盖
|
||||
- 异常处理路径需要测试
|
||||
- 边界条件需要验证
|
||||
|
||||
## 📚 文档规范
|
||||
|
||||
### 代码文档
|
||||
- 所有类和函数必须有文档字符串
|
||||
- 使用Google风格的docstring
|
||||
- 包含参数说明和返回值说明
|
||||
|
||||
### README文档模板
|
||||
|
||||
```markdown
|
||||
# 插件名称
|
||||
|
||||
## 📖 插件描述
|
||||
简要描述插件的功能和用途
|
||||
|
||||
## ✨ 功能特性
|
||||
- 功能1:功能描述
|
||||
- 功能2:功能描述
|
||||
|
||||
## 🚀 快速开始
|
||||
### 安装配置
|
||||
1. 步骤1
|
||||
2. 步骤2
|
||||
|
||||
### 使用方法
|
||||
具体的使用说明和示例
|
||||
|
||||
## 📝 配置说明
|
||||
配置文件的详细说明
|
||||
|
||||
## 🔧 开发信息
|
||||
- 作者:作者名称
|
||||
- 版本:版本号
|
||||
- 许可证:许可证类型
|
||||
```
|
||||
|
||||
## 🔍 代码审查清单
|
||||
|
||||
### 基础检查
|
||||
- [ ] 代码符合命名规范
|
||||
- [ ] 类和函数有完整文档字符串
|
||||
- [ ] 异常处理覆盖完整
|
||||
- [ ] 没有硬编码的配置信息
|
||||
|
||||
### Action组件检查
|
||||
- [ ] 包含所有必需字段
|
||||
- [ ] 激活类型选择合理
|
||||
- [ ] LLM函数提示清晰
|
||||
- [ ] 执行函数实现正确
|
||||
|
||||
### Command组件检查
|
||||
- [ ] 正则表达式模式正确
|
||||
- [ ] 参数提取和验证完整
|
||||
- [ ] 使用说明准确
|
||||
|
||||
### Tool组件检查
|
||||
- [ ] 继承BaseTool基类
|
||||
- [ ] 参数定义遵循JSONSchema
|
||||
- [ ] 返回值格式正确
|
||||
- [ ] 工具已正确注册
|
||||
|
||||
### 性能检查
|
||||
- [ ] 避免不必要的LLM_JUDGE激活
|
||||
- [ ] 异步操作使用正确
|
||||
- [ ] 资源管理合理
|
||||
|
||||
### 安全检查
|
||||
- [ ] 输入参数验证
|
||||
- [ ] SQL注入防护
|
||||
- [ ] 敏感信息保护
|
||||
|
||||
## 🎯 最佳实践总结
|
||||
|
||||
### 设计原则
|
||||
1. **单一职责**:每个组件专注单一功能
|
||||
2. **松耦合**:减少组件间依赖
|
||||
3. **高内聚**:相关功能聚合在一起
|
||||
4. **可扩展**:易于添加新功能
|
||||
|
||||
### 性能优化
|
||||
1. **合理选择激活类型**:优先使用KEYWORD
|
||||
2. **避免阻塞操作**:使用异步编程
|
||||
3. **缓存重复计算**:提高响应速度
|
||||
4. **资源池化**:复用连接和对象
|
||||
|
||||
### 用户体验
|
||||
1. **友好的错误提示**:帮助用户理解问题
|
||||
2. **清晰的使用说明**:降低学习成本
|
||||
3. **一致的交互方式**:统一的命令格式
|
||||
4. **及时的反馈**:让用户知道操作状态
|
||||
|
||||
---
|
||||
|
||||
🎉 **遵循这些标准可以确保插件的质量、性能和用户体验!**
|
||||
414
docs/plugins/examples/complete-examples.md
Normal file
414
docs/plugins/examples/complete-examples.md
Normal file
@@ -0,0 +1,414 @@
|
||||
# 📚 完整示例
|
||||
|
||||
## 📖 概述
|
||||
|
||||
这里收集了各种类型的完整插件示例,展示了MaiBot插件系统的最佳实践和高级用法。每个示例都包含完整的代码、配置和说明。
|
||||
|
||||
## 🎯 示例列表
|
||||
|
||||
### 🌟 基础示例
|
||||
- [Hello World插件](#hello-world插件) - 快速入门示例
|
||||
- [简单计算器](#简单计算器) - Command基础用法
|
||||
- [智能问答](#智能问答) - Action基础用法
|
||||
|
||||
### 🔧 实用示例
|
||||
- [用户管理系统](#用户管理系统) - 数据库操作示例
|
||||
- [定时提醒插件](#定时提醒插件) - 定时任务示例
|
||||
- [天气查询插件](#天气查询插件) - 外部API调用示例
|
||||
|
||||
### 🛠️ 工具系统示例
|
||||
- [天气查询工具](#天气查询工具) - Focus模式信息获取工具
|
||||
- [知识搜索工具](#知识搜索工具) - 百科知识查询工具
|
||||
|
||||
### 🚀 高级示例
|
||||
- [多功能聊天助手](#多功能聊天助手) - 综合功能插件
|
||||
- [游戏管理插件](#游戏管理插件) - 复杂状态管理
|
||||
- [数据分析插件](#数据分析插件) - 数据处理和可视化
|
||||
|
||||
---
|
||||
|
||||
## Hello World插件
|
||||
|
||||
最基础的入门插件,展示Action和Command的基本用法。
|
||||
|
||||
### 功能说明
|
||||
- **HelloAction**: 响应问候语,展示关键词激活
|
||||
- **TimeCommand**: 查询当前时间,展示命令处理
|
||||
|
||||
### 完整代码
|
||||
|
||||
`plugins/hello_world_plugin/plugin.py`:
|
||||
|
||||
```python
|
||||
from typing import List, Tuple, Type
|
||||
from src.plugin_system import (
|
||||
BasePlugin, register_plugin, BaseAction, BaseCommand,
|
||||
ComponentInfo, ActionActivationType, ChatMode
|
||||
)
|
||||
|
||||
class HelloAction(BaseAction):
|
||||
"""问候Action"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "hello_greeting"
|
||||
action_description = "向用户发送友好的问候消息"
|
||||
|
||||
# 关键词配置
|
||||
activation_keywords = ["你好", "hello", "hi"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"greeting_style": "问候风格:casual(随意) 或 formal(正式)"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户发送问候语时使用",
|
||||
"营造友好的聊天氛围"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
style = self.action_data.get("greeting_style", "casual")
|
||||
|
||||
if style == "formal":
|
||||
message = "您好!很高兴为您服务!"
|
||||
emoji = "🙏"
|
||||
else:
|
||||
message = "嗨!很开心见到你!"
|
||||
emoji = "😊"
|
||||
|
||||
await self.send_text(message)
|
||||
await self.send_type("emoji", emoji)
|
||||
|
||||
return True, f"发送了{style}风格的问候"
|
||||
|
||||
class TimeCommand(BaseCommand):
|
||||
"""时间查询Command"""
|
||||
|
||||
command_pattern = r"^/time$"
|
||||
command_help = "查询当前时间"
|
||||
command_examples = ["/time"]
|
||||
intercept_message = True
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
import datetime
|
||||
|
||||
now = datetime.datetime.now()
|
||||
time_str = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
await self.send_text(f"⏰ 当前时间:{time_str}")
|
||||
|
||||
return True, f"显示了当前时间: {time_str}"
|
||||
|
||||
@register_plugin
|
||||
class HelloWorldPlugin(BasePlugin):
|
||||
"""Hello World插件"""
|
||||
|
||||
plugin_name = "hello_world_plugin"
|
||||
plugin_description = "Hello World演示插件"
|
||||
plugin_version = "1.0.0"
|
||||
plugin_author = "MaiBot Team"
|
||||
enable_plugin = True
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
return [
|
||||
(HelloAction.get_action_info(), HelloAction),
|
||||
(TimeCommand.get_command_info(
|
||||
name="time_query",
|
||||
description="查询当前系统时间"
|
||||
), TimeCommand),
|
||||
]
|
||||
```
|
||||
|
||||
### 配置文件
|
||||
|
||||
`plugins/hello_world_plugin/config.toml`:
|
||||
|
||||
```toml
|
||||
[plugin]
|
||||
name = "hello_world_plugin"
|
||||
version = "1.0.0"
|
||||
enabled = true
|
||||
|
||||
[greeting]
|
||||
default_style = "casual"
|
||||
enable_emoji = true
|
||||
|
||||
[time]
|
||||
timezone = "Asia/Shanghai"
|
||||
format = "%Y-%m-%d %H:%M:%S"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 天气查询工具
|
||||
|
||||
展示如何创建Focus模式下的信息获取工具,专门用于扩展麦麦的信息获取能力。
|
||||
|
||||
### 功能说明
|
||||
- **Focus模式专用**:仅在专注聊天模式下工作
|
||||
- **自动调用**:LLM根据用户查询自动判断是否使用
|
||||
- **信息增强**:为麦麦提供实时天气数据
|
||||
- **必须启用工具处理器**
|
||||
|
||||
### 完整代码
|
||||
|
||||
`src/tools/tool_can_use/weather_tool.py`:
|
||||
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
import aiohttp
|
||||
import json
|
||||
|
||||
class WeatherTool(BaseTool):
|
||||
"""天气查询工具 - 获取指定城市的实时天气信息"""
|
||||
|
||||
# 工具名称,必须唯一
|
||||
name = "weather_query"
|
||||
|
||||
# 工具描述,告诉LLM这个工具的用途
|
||||
description = "查询指定城市的实时天气信息,包括温度、湿度、天气状况等"
|
||||
|
||||
# 参数定义,遵循JSONSchema格式
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "要查询天气的城市名称,如:北京、上海、纽约"
|
||||
},
|
||||
"country": {
|
||||
"type": "string",
|
||||
"description": "国家代码,如:CN、US,可选参数"
|
||||
}
|
||||
},
|
||||
"required": ["city"]
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
"""执行天气查询"""
|
||||
try:
|
||||
city = function_args.get("city")
|
||||
country = function_args.get("country", "")
|
||||
|
||||
# 构建查询参数
|
||||
location = f"{city},{country}" if country else city
|
||||
|
||||
# 调用天气API
|
||||
weather_data = await self._fetch_weather(location)
|
||||
|
||||
# 格式化结果
|
||||
result = self._format_weather_data(weather_data)
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"天气查询失败: {str(e)}"
|
||||
}
|
||||
|
||||
async def _fetch_weather(self, location: str) -> dict:
|
||||
"""获取天气数据"""
|
||||
# 这里是示例,实际需要接入真实的天气API
|
||||
# 例如:OpenWeatherMap、和风天气等
|
||||
api_url = f"http://api.weather.com/v1/current?q={location}"
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(api_url) as response:
|
||||
return await response.json()
|
||||
|
||||
def _format_weather_data(self, data: dict) -> str:
|
||||
"""格式化天气数据"""
|
||||
if not data:
|
||||
return "暂无天气数据"
|
||||
|
||||
# 提取关键信息
|
||||
city = data.get("location", {}).get("name", "未知城市")
|
||||
temp = data.get("current", {}).get("temp_c", "未知")
|
||||
condition = data.get("current", {}).get("condition", {}).get("text", "未知")
|
||||
humidity = data.get("current", {}).get("humidity", "未知")
|
||||
|
||||
# 格式化输出
|
||||
return f"""
|
||||
🌤️ {city} 实时天气
|
||||
━━━━━━━━━━━━━━━━━━
|
||||
🌡️ 温度: {temp}°C
|
||||
☁️ 天气: {condition}
|
||||
💧 湿度: {humidity}%
|
||||
━━━━━━━━━━━━━━━━━━
|
||||
""".strip()
|
||||
|
||||
# 注册工具(重要!必须调用)
|
||||
register_tool(WeatherTool)
|
||||
```
|
||||
|
||||
### 使用说明
|
||||
|
||||
1. **部署位置**:将文件放在 `src/tools/tool_can_use/` 目录下
|
||||
2. **模式要求**:仅在Focus模式下可用
|
||||
3. **配置要求**:必须开启工具处理器 `enable_tool_processor = True`
|
||||
4. **自动调用**:用户发送"今天北京天气怎么样?"时,麦麦会自动调用此工具
|
||||
|
||||
---
|
||||
|
||||
## 知识搜索工具
|
||||
|
||||
展示如何创建知识查询工具,为麦麦提供百科知识和专业信息。
|
||||
|
||||
### 功能说明
|
||||
- **知识增强**:扩展麦麦的知识获取能力
|
||||
- **分类搜索**:支持科学、历史、技术等分类
|
||||
- **多语言支持**:支持中英文结果
|
||||
- **智能调用**:LLM自动判断何时需要知识查询
|
||||
|
||||
### 完整代码
|
||||
|
||||
`src/tools/tool_can_use/knowledge_search_tool.py`:
|
||||
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
import aiohttp
|
||||
import json
|
||||
|
||||
class KnowledgeSearchTool(BaseTool):
|
||||
"""知识搜索工具 - 查询百科知识和专业信息"""
|
||||
|
||||
name = "knowledge_search"
|
||||
description = "搜索百科知识、专业术语解释、历史事件等信息"
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "要搜索的知识关键词或问题"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": "知识分类:science(科学)、history(历史)、technology(技术)、general(通用)等",
|
||||
"enum": ["science", "history", "technology", "general"]
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"description": "结果语言:zh(中文)、en(英文)",
|
||||
"enum": ["zh", "en"]
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
"""执行知识搜索"""
|
||||
try:
|
||||
query = function_args.get("query")
|
||||
category = function_args.get("category", "general")
|
||||
language = function_args.get("language", "zh")
|
||||
|
||||
# 执行搜索逻辑
|
||||
search_results = await self._search_knowledge(query, category, language)
|
||||
|
||||
# 格式化结果
|
||||
result = self._format_search_results(query, search_results)
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"知识搜索失败: {str(e)}"
|
||||
}
|
||||
|
||||
async def _search_knowledge(self, query: str, category: str, language: str) -> list:
|
||||
"""执行知识搜索"""
|
||||
# 这里实现实际的搜索逻辑
|
||||
# 可以对接维基百科API、百度百科API等
|
||||
|
||||
# 示例API调用
|
||||
if language == "zh":
|
||||
api_url = f"https://zh.wikipedia.org/api/rest_v1/page/summary/{query}"
|
||||
else:
|
||||
api_url = f"https://en.wikipedia.org/api/rest_v1/page/summary/{query}"
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(api_url) as response:
|
||||
if response.status == 200:
|
||||
data = await response.json()
|
||||
return [
|
||||
{
|
||||
"title": data.get("title", "无标题"),
|
||||
"summary": data.get("extract", "无摘要"),
|
||||
"source": "Wikipedia"
|
||||
}
|
||||
]
|
||||
else:
|
||||
return []
|
||||
|
||||
def _format_search_results(self, query: str, results: list) -> str:
|
||||
"""格式化搜索结果"""
|
||||
if not results:
|
||||
return f"未找到关于 '{query}' 的相关信息"
|
||||
|
||||
formatted_text = f"📚 关于 '{query}' 的搜索结果:\n\n"
|
||||
|
||||
for i, result in enumerate(results[:3], 1): # 限制显示前3条
|
||||
title = result.get("title", "无标题")
|
||||
summary = result.get("summary", "无摘要")
|
||||
source = result.get("source", "未知来源")
|
||||
|
||||
formatted_text += f"{i}. **{title}**\n"
|
||||
formatted_text += f" {summary}\n"
|
||||
formatted_text += f" 📖 来源: {source}\n\n"
|
||||
|
||||
return formatted_text.strip()
|
||||
|
||||
# 注册工具
|
||||
register_tool(KnowledgeSearchTool)
|
||||
```
|
||||
|
||||
### 配置示例
|
||||
|
||||
Focus模式配置文件示例:
|
||||
|
||||
```python
|
||||
# 在Focus模式配置中
|
||||
focus_config = {
|
||||
"enable_tool_processor": True, # 必须启用工具处理器
|
||||
"tool_timeout": 30, # 工具执行超时时间(秒)
|
||||
"max_tools_per_message": 3 # 单次消息最大工具调用数
|
||||
}
|
||||
```
|
||||
|
||||
### 使用流程
|
||||
|
||||
1. **用户查询**:用户在Focus模式下发送"什么是量子计算?"
|
||||
2. **LLM判断**:麦麦识别这是知识查询需求
|
||||
3. **工具调用**:自动调用 `knowledge_search` 工具
|
||||
4. **信息获取**:工具查询相关知识信息
|
||||
5. **整合回复**:麦麦将获取的信息整合到回复中
|
||||
|
||||
### 工具系统特点
|
||||
|
||||
- **🎯 专用性**:仅在Focus模式下工作,专注信息获取
|
||||
- **🔍 智能性**:LLM自动判断何时需要使用工具
|
||||
- **📊 丰富性**:为麦麦提供外部数据和实时信息
|
||||
- **⚡ 高效性**:系统自动发现和注册工具
|
||||
- **🔧 独立性**:目前需要单独编写,未来将更好融入插件系统
|
||||
|
||||
---
|
||||
|
||||
🎉 **这些示例展示了MaiBot插件系统的强大功能!根据你的需求选择合适的示例作为起点。**
|
||||
279
docs/plugins/quick-start.md
Normal file
279
docs/plugins/quick-start.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# 🚀 快速开始指南
|
||||
|
||||
## 📖 概述
|
||||
|
||||
这个指南将带你在5分钟内创建你的第一个MaiBot插件。我们将创建一个简单的问候插件,展示插件系统的基本概念。
|
||||
|
||||
## 🎯 学习目标
|
||||
|
||||
- 理解插件的基本结构
|
||||
- 创建你的第一个Action组件
|
||||
- 创建你的第一个Command组件
|
||||
- 学会配置插件
|
||||
|
||||
## 📂 准备工作
|
||||
|
||||
确保你已经:
|
||||
1. 克隆了MaiBot项目
|
||||
2. 安装了Python依赖
|
||||
3. 了解基本的Python语法
|
||||
|
||||
## 🏗️ 创建插件
|
||||
|
||||
### 1. 创建插件目录
|
||||
|
||||
在项目根目录的 `plugins/` 文件夹下创建你的插件目录:
|
||||
|
||||
```bash
|
||||
mkdir plugins/hello_world_plugin
|
||||
cd plugins/hello_world_plugin
|
||||
```
|
||||
|
||||
### 2. 创建插件主文件
|
||||
|
||||
创建 `plugin.py` 文件:
|
||||
|
||||
```python
|
||||
from typing import List, Tuple, Type
|
||||
from src.plugin_system import (
|
||||
BasePlugin, register_plugin, BaseAction, BaseCommand,
|
||||
ComponentInfo, ActionActivationType, ChatMode
|
||||
)
|
||||
|
||||
# ===== Action组件 =====
|
||||
|
||||
class HelloAction(BaseAction):
|
||||
"""问候Action - 展示智能动作的基本用法"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "hello_greeting"
|
||||
action_description = "向用户发送友好的问候消息"
|
||||
|
||||
# 关键词配置
|
||||
activation_keywords = ["你好", "hello", "hi"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"greeting_style": "问候风格:casual(随意) 或 formal(正式)"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户发送问候语时使用",
|
||||
"营造友好的聊天氛围"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行问候动作"""
|
||||
# 获取参数
|
||||
style = self.action_data.get("greeting_style", "casual")
|
||||
|
||||
# 根据风格生成问候语
|
||||
if style == "formal":
|
||||
message = "您好!很高兴为您服务!"
|
||||
emoji = "🙏"
|
||||
else:
|
||||
message = "嗨!很开心见到你!"
|
||||
emoji = "😊"
|
||||
|
||||
# 发送消息
|
||||
await self.send_text(message)
|
||||
await self.send_type("emoji", emoji)
|
||||
|
||||
return True, f"发送了{style}风格的问候"
|
||||
|
||||
# ===== Command组件 =====
|
||||
|
||||
class TimeCommand(BaseCommand):
|
||||
"""时间查询Command - 展示命令的基本用法"""
|
||||
|
||||
command_pattern = r"^/time$"
|
||||
command_help = "查询当前时间"
|
||||
command_examples = ["/time"]
|
||||
intercept_message = True # 拦截消息处理
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行时间查询"""
|
||||
import datetime
|
||||
|
||||
now = datetime.datetime.now()
|
||||
time_str = now.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
await self.send_text(f"⏰ 当前时间:{time_str}")
|
||||
|
||||
return True, f"显示了当前时间: {time_str}"
|
||||
|
||||
# ===== 插件注册 =====
|
||||
|
||||
@register_plugin
|
||||
class HelloWorldPlugin(BasePlugin):
|
||||
"""Hello World插件 - 你的第一个MaiBot插件"""
|
||||
|
||||
# 插件基本信息
|
||||
plugin_name = "hello_world_plugin"
|
||||
plugin_description = "Hello World演示插件,展示基本的Action和Command用法"
|
||||
plugin_version = "1.0.0"
|
||||
plugin_author = "你的名字"
|
||||
enable_plugin = True
|
||||
config_file_name = "config.toml"
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
"""返回插件包含的组件列表"""
|
||||
return [
|
||||
# Action组件 - 使用类中定义的所有属性
|
||||
(HelloAction.get_action_info(), HelloAction),
|
||||
|
||||
# Command组件 - 需要指定name和description
|
||||
(TimeCommand.get_command_info(
|
||||
name="time_query",
|
||||
description="查询当前系统时间"
|
||||
), TimeCommand),
|
||||
]
|
||||
```
|
||||
|
||||
### 3. 创建配置文件
|
||||
|
||||
创建 `config.toml` 文件:
|
||||
|
||||
```toml
|
||||
[plugin]
|
||||
name = "hello_world_plugin"
|
||||
version = "1.0.0"
|
||||
enabled = true
|
||||
description = "Hello World演示插件"
|
||||
|
||||
[greeting]
|
||||
default_style = "casual"
|
||||
enable_emoji = true
|
||||
|
||||
[time]
|
||||
timezone = "Asia/Shanghai"
|
||||
format = "%Y-%m-%d %H:%M:%S"
|
||||
|
||||
[logging]
|
||||
level = "INFO"
|
||||
```
|
||||
|
||||
### 4. 创建说明文档
|
||||
|
||||
创建 `README.md` 文件:
|
||||
|
||||
```markdown
|
||||
# Hello World 插件
|
||||
|
||||
## 概述
|
||||
|
||||
这是一个简单的Hello World插件,演示了MaiBot插件系统的基本用法。
|
||||
|
||||
## 功能
|
||||
|
||||
- **HelloAction**: 智能问候动作,响应用户的问候语
|
||||
- **TimeCommand**: 时间查询命令,显示当前时间
|
||||
|
||||
## 使用方法
|
||||
|
||||
### Action使用
|
||||
当用户发送包含"你好"、"hello"或"hi"的消息时,插件会自动触发问候动作。
|
||||
|
||||
### Command使用
|
||||
发送 `/time` 查询当前时间。
|
||||
|
||||
## 配置
|
||||
|
||||
可以通过 `config.toml` 调整插件行为。
|
||||
```
|
||||
|
||||
## 🎮 测试插件
|
||||
|
||||
### 1. 启动MaiBot
|
||||
|
||||
将插件放入 `plugins/` 目录后,启动MaiBot:
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
### 2. 测试Action
|
||||
|
||||
发送消息:
|
||||
```
|
||||
你好
|
||||
```
|
||||
|
||||
期望输出:
|
||||
```
|
||||
嗨!很开心见到你!😊
|
||||
```
|
||||
|
||||
### 3. 测试Command
|
||||
|
||||
发送命令:
|
||||
```
|
||||
/time
|
||||
```
|
||||
|
||||
期望输出:
|
||||
```
|
||||
⏰ 当前时间:2024-01-01 12:00:00
|
||||
```
|
||||
|
||||
## 🔍 解析代码
|
||||
|
||||
### Action组件重点
|
||||
|
||||
1. **激活控制**: 使用 `KEYWORD` 激活类型,当检测到指定关键词时触发
|
||||
2. **必须项完整**: 包含所有必须的类属性
|
||||
3. **智能决策**: 麦麦会根据情境决定是否使用这个Action
|
||||
|
||||
### Command组件重点
|
||||
|
||||
1. **正则匹配**: 使用 `^/time$` 精确匹配 `/time` 命令
|
||||
2. **消息拦截**: 设置 `intercept_message = True` 防止命令继续处理
|
||||
3. **即时响应**: 匹配到命令立即执行
|
||||
|
||||
### 插件注册重点
|
||||
|
||||
1. **@register_plugin**: 装饰器自动注册插件
|
||||
2. **组件列表**: `get_plugin_components()` 返回所有组件
|
||||
3. **配置加载**: 自动加载 `config.toml` 文件
|
||||
|
||||
## 🎯 下一步
|
||||
|
||||
恭喜!你已经创建了第一个MaiBot插件。接下来可以:
|
||||
|
||||
1. 学习 [Action组件详解](action-components.md) 掌握更复杂的Action开发
|
||||
2. 学习 [Command组件详解](command-components.md) 创建更强大的命令
|
||||
3. 查看 [API参考](api/) 了解所有可用的接口
|
||||
4. 参考 [完整示例](examples/complete-examples.md) 学习最佳实践
|
||||
|
||||
## 🐛 常见问题
|
||||
|
||||
### Q: 插件没有加载怎么办?
|
||||
A: 检查:
|
||||
1. 插件是否放在 `plugins/` 目录下
|
||||
2. `plugin.py` 文件语法是否正确
|
||||
3. 查看启动日志中的错误信息
|
||||
|
||||
### Q: Action没有触发怎么办?
|
||||
A: 检查:
|
||||
1. 关键词是否正确配置
|
||||
2. 消息是否包含激活关键词
|
||||
3. 聊天模式是否匹配
|
||||
|
||||
### Q: Command无响应怎么办?
|
||||
A: 检查:
|
||||
1. 正则表达式是否正确
|
||||
2. 命令格式是否精确匹配
|
||||
3. 是否有其他插件拦截了消息
|
||||
|
||||
---
|
||||
|
||||
🎉 **成功!你已经掌握了MaiBot插件开发的基础!**
|
||||
495
docs/plugins/tool-system.md
Normal file
495
docs/plugins/tool-system.md
Normal file
@@ -0,0 +1,495 @@
|
||||
# 🔧 工具系统详解
|
||||
|
||||
## 📖 什么是工具系统
|
||||
|
||||
工具系统是MaiBot的信息获取能力扩展组件,**专门用于在Focus模式下扩宽麦麦能够获得的信息量**。如果说Action组件功能五花八门,可以拓展麦麦能做的事情,那么Tool就是在某个过程中拓宽了麦麦能够获得的信息量。
|
||||
|
||||
### 🎯 工具系统的特点
|
||||
|
||||
- 🔍 **信息获取增强**:扩展麦麦获取外部信息的能力
|
||||
- 🎯 **Focus模式专用**:仅在专注聊天模式下工作,必须开启工具处理器
|
||||
- 📊 **数据丰富**:帮助麦麦获得更多背景信息和实时数据
|
||||
- 🔌 **插件式架构**:支持独立开发和注册新工具
|
||||
- ⚡ **自动发现**:工具会被系统自动识别和注册
|
||||
|
||||
### 🆚 Tool vs Action vs Command 区别
|
||||
|
||||
| 特征 | Action | Command | Tool |
|
||||
|-----|-------|---------|------|
|
||||
| **主要用途** | 扩展麦麦行为能力 | 响应用户指令 | 扩展麦麦信息获取 |
|
||||
| **适用模式** | 所有模式 | 所有模式 | 仅Focus模式 |
|
||||
| **触发方式** | 麦麦智能决策 | 用户主动触发 | LLM根据需要调用 |
|
||||
| **目标** | 让麦麦做更多事情 | 提供具体功能 | 让麦麦知道更多信息 |
|
||||
| **使用场景** | 增强交互体验 | 功能服务 | 信息查询和分析 |
|
||||
|
||||
## 🏗️ 工具基本结构
|
||||
|
||||
### 必要组件
|
||||
|
||||
每个工具必须继承 `BaseTool` 基类并实现以下属性和方法:
|
||||
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
|
||||
class MyTool(BaseTool):
|
||||
# 工具名称,必须唯一
|
||||
name = "my_tool"
|
||||
|
||||
# 工具描述,告诉LLM这个工具的用途
|
||||
description = "这个工具用于获取特定类型的信息"
|
||||
|
||||
# 参数定义,遵循JSONSchema格式
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "查询参数"
|
||||
},
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"description": "结果数量限制"
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
"""执行工具逻辑"""
|
||||
# 实现工具功能
|
||||
result = f"查询结果: {function_args.get('query')}"
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
|
||||
# 注册工具
|
||||
register_tool(MyTool)
|
||||
```
|
||||
|
||||
### 属性说明
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|-----|------|------|
|
||||
| `name` | str | 工具的唯一标识名称 |
|
||||
| `description` | str | 工具功能描述,帮助LLM理解用途 |
|
||||
| `parameters` | dict | JSONSchema格式的参数定义 |
|
||||
|
||||
### 方法说明
|
||||
|
||||
| 方法 | 参数 | 返回值 | 说明 |
|
||||
|-----|------|--------|------|
|
||||
| `execute` | `function_args`, `message_txt` | `dict` | 执行工具核心逻辑 |
|
||||
|
||||
## 🔄 自动注册机制
|
||||
|
||||
工具系统采用自动发现和注册机制:
|
||||
|
||||
1. **文件扫描**:系统自动遍历 `tool_can_use` 目录中的所有Python文件
|
||||
2. **类识别**:寻找继承自 `BaseTool` 的工具类
|
||||
3. **自动注册**:调用 `register_tool()` 的工具会被注册到系统中
|
||||
4. **即用即加载**:工具在需要时被实例化和调用
|
||||
|
||||
### 注册流程
|
||||
|
||||
```python
|
||||
# 1. 创建工具类
|
||||
class WeatherTool(BaseTool):
|
||||
name = "weather_query"
|
||||
description = "查询指定城市的天气信息"
|
||||
# ...
|
||||
|
||||
# 2. 注册工具(在文件末尾)
|
||||
register_tool(WeatherTool)
|
||||
|
||||
# 3. 系统自动发现(无需手动操作)
|
||||
# discover_tools() 函数会自动完成注册
|
||||
```
|
||||
|
||||
## 🎨 完整工具示例
|
||||
|
||||
### 天气查询工具
|
||||
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
import aiohttp
|
||||
import json
|
||||
|
||||
class WeatherTool(BaseTool):
|
||||
"""天气查询工具 - 获取指定城市的实时天气信息"""
|
||||
|
||||
name = "weather_query"
|
||||
description = "查询指定城市的实时天气信息,包括温度、湿度、天气状况等"
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "要查询天气的城市名称,如:北京、上海、纽约"
|
||||
},
|
||||
"country": {
|
||||
"type": "string",
|
||||
"description": "国家代码,如:CN、US,可选参数"
|
||||
}
|
||||
},
|
||||
"required": ["city"]
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
"""执行天气查询"""
|
||||
try:
|
||||
city = function_args.get("city")
|
||||
country = function_args.get("country", "")
|
||||
|
||||
# 构建查询参数
|
||||
location = f"{city},{country}" if country else city
|
||||
|
||||
# 调用天气API(示例)
|
||||
weather_data = await self._fetch_weather(location)
|
||||
|
||||
# 格式化结果
|
||||
result = self._format_weather_data(weather_data)
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"天气查询失败: {str(e)}"
|
||||
}
|
||||
|
||||
async def _fetch_weather(self, location: str) -> dict:
|
||||
"""获取天气数据"""
|
||||
# 这里是示例,实际需要接入真实的天气API
|
||||
api_url = f"http://api.weather.com/v1/current?q={location}"
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(api_url) as response:
|
||||
return await response.json()
|
||||
|
||||
def _format_weather_data(self, data: dict) -> str:
|
||||
"""格式化天气数据"""
|
||||
if not data:
|
||||
return "暂无天气数据"
|
||||
|
||||
# 提取关键信息
|
||||
city = data.get("location", {}).get("name", "未知城市")
|
||||
temp = data.get("current", {}).get("temp_c", "未知")
|
||||
condition = data.get("current", {}).get("condition", {}).get("text", "未知")
|
||||
humidity = data.get("current", {}).get("humidity", "未知")
|
||||
|
||||
# 格式化输出
|
||||
return f"""
|
||||
🌤️ {city} 实时天气
|
||||
━━━━━━━━━━━━━━━━━━
|
||||
🌡️ 温度: {temp}°C
|
||||
☁️ 天气: {condition}
|
||||
💧 湿度: {humidity}%
|
||||
━━━━━━━━━━━━━━━━━━
|
||||
""".strip()
|
||||
|
||||
# 注册工具
|
||||
register_tool(WeatherTool)
|
||||
```
|
||||
|
||||
### 知识查询工具
|
||||
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
|
||||
class KnowledgeSearchTool(BaseTool):
|
||||
"""知识搜索工具 - 查询百科知识和专业信息"""
|
||||
|
||||
name = "knowledge_search"
|
||||
description = "搜索百科知识、专业术语解释、历史事件等信息"
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "要搜索的知识关键词或问题"
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"description": "知识分类:science(科学)、history(历史)、technology(技术)、general(通用)等",
|
||||
"enum": ["science", "history", "technology", "general"]
|
||||
},
|
||||
"language": {
|
||||
"type": "string",
|
||||
"description": "结果语言:zh(中文)、en(英文)",
|
||||
"enum": ["zh", "en"]
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
"""执行知识搜索"""
|
||||
try:
|
||||
query = function_args.get("query")
|
||||
category = function_args.get("category", "general")
|
||||
language = function_args.get("language", "zh")
|
||||
|
||||
# 执行搜索逻辑
|
||||
search_results = await self._search_knowledge(query, category, language)
|
||||
|
||||
# 格式化结果
|
||||
result = self._format_search_results(query, search_results)
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": f"知识搜索失败: {str(e)}"
|
||||
}
|
||||
|
||||
async def _search_knowledge(self, query: str, category: str, language: str) -> list:
|
||||
"""执行知识搜索"""
|
||||
# 这里实现实际的搜索逻辑
|
||||
# 可以对接维基百科API、百度百科API等
|
||||
|
||||
# 示例返回数据
|
||||
return [
|
||||
{
|
||||
"title": f"{query}的定义",
|
||||
"summary": f"关于{query}的详细解释...",
|
||||
"source": "Wikipedia"
|
||||
}
|
||||
]
|
||||
|
||||
def _format_search_results(self, query: str, results: list) -> str:
|
||||
"""格式化搜索结果"""
|
||||
if not results:
|
||||
return f"未找到关于 '{query}' 的相关信息"
|
||||
|
||||
formatted_text = f"📚 关于 '{query}' 的搜索结果:\n\n"
|
||||
|
||||
for i, result in enumerate(results[:3], 1): # 限制显示前3条
|
||||
title = result.get("title", "无标题")
|
||||
summary = result.get("summary", "无摘要")
|
||||
source = result.get("source", "未知来源")
|
||||
|
||||
formatted_text += f"{i}. **{title}**\n"
|
||||
formatted_text += f" {summary}\n"
|
||||
formatted_text += f" 📖 来源: {source}\n\n"
|
||||
|
||||
return formatted_text.strip()
|
||||
|
||||
# 注册工具
|
||||
register_tool(KnowledgeSearchTool)
|
||||
```
|
||||
|
||||
## 📊 工具开发步骤
|
||||
|
||||
### 1. 创建工具文件
|
||||
|
||||
在 `src/tools/tool_can_use/` 目录下创建新的Python文件:
|
||||
|
||||
```bash
|
||||
# 例如创建 my_new_tool.py
|
||||
touch src/tools/tool_can_use/my_new_tool.py
|
||||
```
|
||||
|
||||
### 2. 实现工具类
|
||||
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
|
||||
class MyNewTool(BaseTool):
|
||||
name = "my_new_tool"
|
||||
description = "新工具的功能描述"
|
||||
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
# 定义参数
|
||||
},
|
||||
"required": []
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
# 实现工具逻辑
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": "执行结果"
|
||||
}
|
||||
|
||||
register_tool(MyNewTool)
|
||||
```
|
||||
|
||||
### 3. 测试工具
|
||||
|
||||
创建测试文件验证工具功能:
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from my_new_tool import MyNewTool
|
||||
|
||||
async def test_tool():
|
||||
tool = MyNewTool()
|
||||
result = await tool.execute({"param": "value"})
|
||||
print(result)
|
||||
|
||||
asyncio.run(test_tool())
|
||||
```
|
||||
|
||||
### 4. 系统集成
|
||||
|
||||
工具创建完成后,系统会自动发现和注册,无需额外配置。
|
||||
|
||||
## ⚙️ 工具处理器配置
|
||||
|
||||
### 启用工具处理器
|
||||
|
||||
工具系统仅在Focus模式下工作,需要确保工具处理器已启用:
|
||||
|
||||
```python
|
||||
# 在Focus模式配置中
|
||||
focus_config = {
|
||||
"enable_tool_processor": True, # 必须启用
|
||||
"tool_timeout": 30, # 工具执行超时时间(秒)
|
||||
"max_tools_per_message": 3 # 单次消息最大工具调用数
|
||||
}
|
||||
```
|
||||
|
||||
### 工具使用流程
|
||||
|
||||
1. **用户发送消息**:在Focus模式下发送需要信息查询的消息
|
||||
2. **LLM判断需求**:麦麦分析消息,判断是否需要使用工具获取信息
|
||||
3. **选择工具**:根据需求选择合适的工具
|
||||
4. **调用工具**:执行工具获取信息
|
||||
5. **整合回复**:将工具获取的信息整合到回复中
|
||||
|
||||
### 使用示例
|
||||
|
||||
```python
|
||||
# 用户消息示例
|
||||
"今天北京的天气怎么样?"
|
||||
|
||||
# 系统处理流程:
|
||||
# 1. 麦麦识别这是天气查询需求
|
||||
# 2. 调用 weather_query 工具
|
||||
# 3. 获取北京天气信息
|
||||
# 4. 整合信息生成回复
|
||||
|
||||
# 最终回复:
|
||||
"根据最新天气数据,北京今天晴天,温度22°C,湿度45%,适合外出活动。"
|
||||
```
|
||||
|
||||
## 🚨 注意事项和限制
|
||||
|
||||
### 当前限制
|
||||
|
||||
1. **模式限制**:仅在Focus模式下可用
|
||||
2. **独立开发**:需要单独编写,暂未完全融入插件系统
|
||||
3. **适用范围**:主要适用于信息获取场景
|
||||
4. **配置要求**:必须开启工具处理器
|
||||
|
||||
### 未来改进
|
||||
|
||||
工具系统在之后可能会面临以下修改:
|
||||
|
||||
1. **插件系统融合**:更好地集成到插件系统中
|
||||
2. **模式扩展**:可能扩展到其他聊天模式
|
||||
3. **配置简化**:简化配置和部署流程
|
||||
4. **性能优化**:提升工具调用效率
|
||||
|
||||
### 开发建议
|
||||
|
||||
1. **功能专一**:每个工具专注单一功能
|
||||
2. **参数明确**:清晰定义工具参数和用途
|
||||
3. **错误处理**:完善的异常处理和错误反馈
|
||||
4. **性能考虑**:避免长时间阻塞操作
|
||||
5. **信息准确**:确保获取信息的准确性和时效性
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
### 1. 工具命名规范
|
||||
|
||||
```python
|
||||
# ✅ 好的命名
|
||||
name = "weather_query" # 清晰表达功能
|
||||
name = "knowledge_search" # 描述性强
|
||||
name = "stock_price_check" # 功能明确
|
||||
|
||||
# ❌ 避免的命名
|
||||
name = "tool1" # 无意义
|
||||
name = "wq" # 过于简短
|
||||
name = "weather_and_news" # 功能过于复杂
|
||||
```
|
||||
|
||||
### 2. 描述规范
|
||||
|
||||
```python
|
||||
# ✅ 好的描述
|
||||
description = "查询指定城市的实时天气信息,包括温度、湿度、天气状况"
|
||||
|
||||
# ❌ 避免的描述
|
||||
description = "天气" # 过于简单
|
||||
description = "获取信息" # 不够具体
|
||||
```
|
||||
|
||||
### 3. 参数设计
|
||||
|
||||
```python
|
||||
# ✅ 合理的参数设计
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"city": {
|
||||
"type": "string",
|
||||
"description": "城市名称,如:北京、上海"
|
||||
},
|
||||
"unit": {
|
||||
"type": "string",
|
||||
"description": "温度单位:celsius(摄氏度) 或 fahrenheit(华氏度)",
|
||||
"enum": ["celsius", "fahrenheit"]
|
||||
}
|
||||
},
|
||||
"required": ["city"]
|
||||
}
|
||||
|
||||
# ❌ 避免的参数设计
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "string",
|
||||
"description": "数据" # 描述不清晰
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 结果格式化
|
||||
|
||||
```python
|
||||
# ✅ 良好的结果格式
|
||||
def _format_result(self, data):
|
||||
return f"""
|
||||
🔍 查询结果
|
||||
━━━━━━━━━━━━
|
||||
📊 数据: {data['value']}
|
||||
📅 时间: {data['timestamp']}
|
||||
📝 说明: {data['description']}
|
||||
━━━━━━━━━━━━
|
||||
""".strip()
|
||||
|
||||
# ❌ 避免的结果格式
|
||||
def _format_result(self, data):
|
||||
return str(data) # 直接返回原始数据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
🎉 **工具系统为麦麦提供了强大的信息获取能力!合理使用工具可以让麦麦变得更加智能和博学。**
|
||||
102
docs/use_tool.md
102
docs/use_tool.md
@@ -1,102 +0,0 @@
|
||||
# 工具系统使用指南
|
||||
|
||||
## 概述
|
||||
|
||||
`tool_can_use` 是一个插件式工具系统,允许轻松扩展和注册新工具。每个工具作为独立的文件存在于该目录下,系统会自动发现和注册这些工具。
|
||||
|
||||
## 工具结构
|
||||
|
||||
每个工具应该继承 `BaseTool` 基类并实现必要的属性和方法:
|
||||
|
||||
```python
|
||||
from src.tools.tool_can_use.base_tool import BaseTool, register_tool
|
||||
|
||||
class MyNewTool(BaseTool):
|
||||
# 工具名称,必须唯一
|
||||
name = "my_new_tool"
|
||||
|
||||
# 工具描述,告诉LLM这个工具的用途
|
||||
description = "这是一个新工具,用于..."
|
||||
|
||||
# 工具参数定义,遵循JSONSchema格式
|
||||
parameters = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"param1": {
|
||||
"type": "string",
|
||||
"description": "参数1的描述"
|
||||
},
|
||||
"param2": {
|
||||
"type": "integer",
|
||||
"description": "参数2的描述"
|
||||
}
|
||||
},
|
||||
"required": ["param1"] # 必需的参数列表
|
||||
}
|
||||
|
||||
async def execute(self, function_args, message_txt=""):
|
||||
"""执行工具逻辑
|
||||
|
||||
Args:
|
||||
function_args: 工具调用参数
|
||||
message_txt: 原始消息文本
|
||||
|
||||
Returns:
|
||||
dict: 包含执行结果的字典,必须包含name和content字段
|
||||
"""
|
||||
# 实现工具逻辑
|
||||
result = f"工具执行结果: {function_args.get('param1')}"
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
|
||||
# 注册工具
|
||||
register_tool(MyNewTool)
|
||||
```
|
||||
|
||||
## 自动注册机制
|
||||
|
||||
工具系统通过以下步骤自动注册工具:
|
||||
|
||||
1. 在`__init__.py`中,`discover_tools()`函数会自动遍历当前目录中的所有Python文件
|
||||
2. 对于每个文件,系统会寻找继承自`BaseTool`的类
|
||||
3. 这些类会被自动注册到工具注册表中
|
||||
|
||||
只要确保在每个工具文件的末尾调用`register_tool(YourToolClass)`,工具就会被自动注册。
|
||||
|
||||
## 添加新工具步骤
|
||||
|
||||
1. 在`tool_can_use`目录下创建新的Python文件(如`my_new_tool.py`)
|
||||
2. 导入`BaseTool`和`register_tool`
|
||||
3. 创建继承自`BaseTool`的工具类
|
||||
4. 实现必要的属性(`name`, `description`, `parameters`)
|
||||
5. 实现`execute`方法
|
||||
6. 使用`register_tool`注册工具
|
||||
|
||||
## 与ToolUser整合
|
||||
|
||||
`ToolUser`类已经更新为使用这个新的工具系统,它会:
|
||||
|
||||
1. 自动获取所有已注册工具的定义
|
||||
2. 基于工具名称找到对应的工具实例
|
||||
3. 调用工具的`execute`方法
|
||||
|
||||
## 使用示例
|
||||
|
||||
```python
|
||||
from src.tools.tool_use import ToolUser
|
||||
|
||||
# 创建工具用户
|
||||
tool_user = ToolUser()
|
||||
|
||||
# 使用工具
|
||||
result = await tool_user.use_tool(message_txt="查询关于Python的知识", sender_name="用户", chat_stream=chat_stream)
|
||||
|
||||
# 处理结果
|
||||
if result["used_tools"]:
|
||||
print("工具使用结果:", result["collected_info"])
|
||||
else:
|
||||
print("未使用工具")
|
||||
```
|
||||
@@ -9,11 +9,29 @@
|
||||
### 🎯 Action组件
|
||||
|
||||
#### SmartGreetingAction - 智能问候
|
||||
- **触发方式**: 关键词触发 (你好、hello、hi、嗨等)
|
||||
- **激活类型**:
|
||||
- Focus模式: KEYWORD (关键词激活)
|
||||
- Normal模式: KEYWORD (关键词激活)
|
||||
- **触发关键词**: 你好、hello、hi、嗨、问候、早上好、晚上好
|
||||
- **支持模式**: 所有聊天模式
|
||||
- **功能**: 智能问候,支持LLM个性化生成
|
||||
- **并行执行**: 否
|
||||
- **功能**: 智能问候,支持多种风格和LLM个性化生成
|
||||
- **参数**: username(用户名), greeting_style(问候风格)
|
||||
- **配置**: 可自定义问候模板、启用表情、LLM生成
|
||||
|
||||
#### HelpfulAction - 智能助手
|
||||
- **激活类型**:
|
||||
- Focus模式: LLM_JUDGE (LLM智能判断)
|
||||
- Normal模式: RANDOM (随机激活,概率15%)
|
||||
- **支持模式**: 所有聊天模式
|
||||
- **并行执行**: 是
|
||||
- **功能**: 主动提供帮助和建议,展示LLM判断激活机制
|
||||
- **参数**: help_type(帮助类型), topic(主题), complexity(复杂度)
|
||||
- **特点**:
|
||||
- 通过LLM智能判断是否需要提供帮助
|
||||
- 展示两层决策机制的实际应用
|
||||
- 支持多种帮助类型(解释、建议、指导、提示)
|
||||
|
||||
### 📝 Command组件
|
||||
|
||||
#### 1. ComprehensiveHelpCommand - 综合帮助系统
|
||||
@@ -94,36 +112,69 @@
|
||||
### 组件控制
|
||||
```toml
|
||||
[components]
|
||||
enable_greeting = true # 启用智能问候
|
||||
enable_help = true # 启用帮助系统
|
||||
enable_send = true # 启用消息发送
|
||||
# ... 其他组件开关
|
||||
enable_greeting = true # 启用智能问候Action
|
||||
enable_helpful = true # 启用智能助手Action
|
||||
enable_help = true # 启用帮助系统Command
|
||||
enable_send = true # 启用消息发送Command
|
||||
enable_echo = true # 启用回声Command
|
||||
enable_info = true # 启用消息信息Command
|
||||
enable_dice = true # 启用骰子Command
|
||||
```
|
||||
|
||||
### 功能配置
|
||||
### Action配置
|
||||
```toml
|
||||
[greeting]
|
||||
template = "你好,{username}!" # 问候模板
|
||||
enable_emoji = true # 启用表情
|
||||
enable_llm = false # 启用LLM生成
|
||||
|
||||
[helpful]
|
||||
enable_llm = false # 启用LLM生成帮助
|
||||
enable_emoji = true # 启用鼓励表情
|
||||
random_activation_probability = 0.15 # 随机激活概率
|
||||
```
|
||||
|
||||
### Command配置
|
||||
```toml
|
||||
[send]
|
||||
max_message_length = 500 # 最大消息长度
|
||||
|
||||
[echo]
|
||||
max_length = 200 # 回声最大长度
|
||||
enable_formatting = true # 启用格式化
|
||||
|
||||
[help]
|
||||
enable_llm = false # 启用LLM生成帮助内容
|
||||
enable_emoji = true # 启用帮助表情
|
||||
```
|
||||
|
||||
## 🚀 使用示例
|
||||
|
||||
### 智能问候
|
||||
### Action组件示例
|
||||
|
||||
#### 智能问候Action (关键词激活)
|
||||
```
|
||||
用户: 你好
|
||||
机器人: 你好,朋友!欢迎使用MaiBot综合插件系统!😊
|
||||
机器人: 嗨!很开心见到你~ 😊
|
||||
|
||||
用户: 早上好
|
||||
机器人: 早上好!今天也要元气满满哦! ✨
|
||||
```
|
||||
|
||||
### 帮助查询
|
||||
#### 智能助手Action (LLM判断激活)
|
||||
```
|
||||
用户: 我不太懂怎么使用这个功能
|
||||
机器人: 关于功能使用,我来为你解释一下:这是一个simple级别的概念...
|
||||
这个概念其实很简单,让我用通俗的话来说明。 💡
|
||||
|
||||
用户: Python装饰器是什么?
|
||||
机器人: 关于Python装饰器,我来为你解释一下:这是一个medium级别的概念...
|
||||
装饰器是一种设计模式,用于在不修改原函数的情况下扩展功能。 🎯
|
||||
```
|
||||
|
||||
### Command组件示例
|
||||
|
||||
#### 帮助查询
|
||||
```
|
||||
用户: /help
|
||||
机器人: [显示完整命令帮助列表]
|
||||
@@ -132,27 +183,53 @@ enable_formatting = true # 启用格式化
|
||||
机器人: [显示send命令的详细帮助]
|
||||
```
|
||||
|
||||
### 消息发送
|
||||
#### 消息发送
|
||||
```
|
||||
用户: /send group 123456 大家好!
|
||||
机器人: ✅ 消息已成功发送到 群聊 123456
|
||||
```
|
||||
|
||||
### 日志监控(不拦截)
|
||||
#### 骰子命令
|
||||
```
|
||||
用户: /log info 这是一条测试消息
|
||||
[日志记录但消息继续处理,可能触发智能问候等其他功能]
|
||||
用户: !dice
|
||||
机器人: 🎲 你投出了: 4
|
||||
|
||||
用户: !骰子 3
|
||||
机器人: 🎲 你投出了3个骰子: 2, 5, 1 (总计: 8)
|
||||
```
|
||||
|
||||
### 两层决策机制展示
|
||||
|
||||
#### 第一层:激活控制
|
||||
```
|
||||
# SmartGreetingAction - 关键词激活
|
||||
用户消息包含"你好" → Action被激活 → 进入候选池
|
||||
|
||||
# HelpfulAction - LLM判断激活
|
||||
用户表达困惑 → LLM判断"是" → Action被激活 → 进入候选池
|
||||
用户正常聊天 → LLM判断"否" → Action不激活 → 不进入候选池
|
||||
```
|
||||
|
||||
#### 第二层:使用决策
|
||||
```
|
||||
# 即使Action被激活,LLM还会根据action_require判断是否真正使用
|
||||
# 比如HelpfulAction的条件:"避免过度频繁地提供帮助,要恰到好处"
|
||||
# 如果刚刚已经提供了帮助,可能不会再次选择使用
|
||||
```
|
||||
|
||||
## 📁 文件结构
|
||||
|
||||
```
|
||||
src/plugins/built_in/example_comprehensive/
|
||||
plugins/example_plugin/ # 用户插件目录
|
||||
├── plugin.py # 主插件文件
|
||||
├── config.toml # 配置文件
|
||||
└── README.md # 说明文档
|
||||
```
|
||||
|
||||
> 💡 **目录说明**:
|
||||
> - `plugins/` - 用户自定义插件目录(推荐放置位置)
|
||||
> - `src/plugins/builtin/` - 系统内置插件目录
|
||||
|
||||
## 🔄 架构升级
|
||||
|
||||
此插件展示了从旧插件系统到新插件系统的完整升级:
|
||||
@@ -169,13 +246,48 @@ src/plugins/built_in/example_comprehensive/
|
||||
|
||||
此插件可作为开发新插件的完整参考:
|
||||
|
||||
1. **Action开发**: 参考 `SmartGreetingAction`
|
||||
2. **Command开发**: 参考各种Command实现
|
||||
3. **拦截控制**: 根据需要设置 `intercept_message`
|
||||
4. **配置使用**: 通过 `self.api.get_config()` 读取配置
|
||||
5. **错误处理**: 完整的异常捕获和用户反馈
|
||||
6. **日志记录**: 结构化的日志输出
|
||||
### Action开发规范
|
||||
1. **必须项检查清单**:
|
||||
- ✅ 激活控制必须项:`focus_activation_type`, `normal_activation_type`, `mode_enable`, `parallel_action`
|
||||
- ✅ 基本信息必须项:`action_name`, `action_description`
|
||||
- ✅ 功能定义必须项:`action_parameters`, `action_require`, `associated_types`
|
||||
|
||||
2. **激活类型选择**:
|
||||
- `KEYWORD`: 适合明确触发词的功能(如问候)
|
||||
- `LLM_JUDGE`: 适合需要智能判断的功能(如帮助)
|
||||
- `RANDOM`: 适合增加随机性的功能
|
||||
- `ALWAYS`: 适合总是考虑的功能
|
||||
- `NEVER`: 用于临时禁用
|
||||
|
||||
3. **两层决策设计**:
|
||||
- 第一层(激活控制):控制Action是否进入候选池
|
||||
- 第二层(使用决策):LLM根据场景智能选择
|
||||
|
||||
### Command开发规范
|
||||
1. **拦截控制**: 根据需要设置 `intercept_message`
|
||||
2. **正则表达式**: 使用命名组捕获参数
|
||||
3. **错误处理**: 完整的异常捕获和用户反馈
|
||||
|
||||
### 通用开发规范
|
||||
1. **配置使用**: 通过 `self.api.get_config()` 读取配置
|
||||
2. **日志记录**: 结构化的日志输出
|
||||
3. **API调用**: 使用新的统一API接口
|
||||
4. **注册简化**: Action使用 `get_action_info()` 无参数调用
|
||||
|
||||
## 🎉 总结
|
||||
|
||||
这个综合示例插件完美展示了新插件系统的强大功能,特别是**拦截控制机制**,让开发者可以精确控制消息处理流程,实现更灵活的插件交互模式。
|
||||
这个综合示例插件完美展示了新插件系统的强大功能:
|
||||
|
||||
### 🚀 核心特性
|
||||
- **两层决策机制**:优化LLM决策压力,提升性能
|
||||
- **完整的Action规范**:所有必须项都在类中统一定义
|
||||
- **灵活的激活控制**:支持多种激活类型和条件
|
||||
- **精确的拦截控制**:Command可以精确控制消息处理流程
|
||||
|
||||
### 📚 学习价值
|
||||
- **Action vs Command**: 清晰展示两种组件的不同设计理念
|
||||
- **激活机制**: 实际演示关键词、LLM判断、随机等激活方式
|
||||
- **配置驱动**: 展示如何通过配置文件控制插件行为
|
||||
- **错误处理**: 完整的异常处理和用户反馈机制
|
||||
|
||||
这个插件是理解和掌握MaiBot插件系统的最佳起点!🌟
|
||||
@@ -8,11 +8,13 @@ description = "展示新插件系统完整功能的示例插件"
|
||||
|
||||
# 组件启用控制
|
||||
[components]
|
||||
enable_greeting = false
|
||||
enable_help = false
|
||||
enable_send = false
|
||||
enable_echo = false
|
||||
enable_info = false
|
||||
enable_greeting = true
|
||||
enable_helpful = true
|
||||
enable_help = true
|
||||
enable_send = true
|
||||
enable_echo = true
|
||||
enable_info = true
|
||||
enable_dice = true
|
||||
|
||||
# 智能问候配置
|
||||
[greeting]
|
||||
@@ -37,11 +39,19 @@ show_detailed_info = true
|
||||
include_stream_info = true
|
||||
max_content_preview = 100
|
||||
|
||||
# 智能帮助配置
|
||||
[helpful]
|
||||
enable_llm = false
|
||||
enable_emoji = true
|
||||
random_activation_probability = 0.15
|
||||
|
||||
# 帮助系统配置
|
||||
[help]
|
||||
show_extended_help = true
|
||||
include_action_info = true
|
||||
include_config_info = true
|
||||
enable_llm = false
|
||||
enable_emoji = true
|
||||
|
||||
# 骰子命令配置
|
||||
[dice]
|
||||
|
||||
@@ -42,19 +42,270 @@ logger = get_logger("example_comprehensive")
|
||||
class SmartGreetingAction(BaseAction):
|
||||
"""智能问候Action - 基于关键词触发的问候系统"""
|
||||
|
||||
# 激活设置
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
activation_keywords = ["你好", "hello", "hi", "嗨", "问候", "早上好", "晚上好"]
|
||||
keyword_case_sensitive = False
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# Action参数定义
|
||||
action_parameters = {"username": "要问候的用户名(可选)"}
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "smart_greeting"
|
||||
action_description = "智能问候系统,基于关键词触发,支持个性化问候消息"
|
||||
|
||||
# Action使用场景
|
||||
action_require = ["用户发送包含问候词汇的消息", "检测到新用户加入时", "响应友好交流需求"]
|
||||
# 关键词配置
|
||||
activation_keywords = ["你好", "hello", "hi", "嗨", "问候", "早上好", "晚上好"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"username": "要问候的用户名(可选)",
|
||||
"greeting_style": "问候风格:casual(随意)、formal(正式)、friendly(友好),默认casual"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户发送包含问候词汇的消息时使用",
|
||||
"检测到新用户加入时使用",
|
||||
"响应友好交流需求时使用",
|
||||
"避免在短时间内重复问候同一用户"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行智能问候"""
|
||||
logger.info(f"{self.log_prefix} 执行智能问候动作: {self.reasoning}")
|
||||
|
||||
try:
|
||||
# 获取参数
|
||||
username = self.action_data.get("username", "")
|
||||
greeting_style = self.action_data.get("greeting_style", "casual")
|
||||
|
||||
# 获取配置
|
||||
template = self.api.get_config("greeting.template", "你好,{username}!欢迎使用MaiBot综合插件系统!")
|
||||
enable_emoji = self.api.get_config("greeting.enable_emoji", True)
|
||||
enable_llm = self.api.get_config("greeting.enable_llm", False)
|
||||
|
||||
# 构建问候消息
|
||||
if enable_llm:
|
||||
# 使用LLM生成个性化问候
|
||||
greeting_message = await self._generate_llm_greeting(username, greeting_style)
|
||||
else:
|
||||
# 使用模板生成问候
|
||||
greeting_message = await self._generate_template_greeting(template, username, greeting_style)
|
||||
|
||||
# 发送问候消息
|
||||
await self.send_text(greeting_message)
|
||||
|
||||
# 可选发送表情
|
||||
if enable_emoji:
|
||||
emojis = ["😊", "👋", "🎉", "✨", "🌟"]
|
||||
selected_emoji = random.choice(emojis)
|
||||
await self.send_type("emoji", selected_emoji)
|
||||
|
||||
logger.info(f"{self.log_prefix} 智能问候执行成功")
|
||||
return True, f"向{username or '用户'}发送了{greeting_style}风格的问候"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 智能问候执行失败: {e}")
|
||||
return False, f"问候失败: {str(e)}"
|
||||
|
||||
async def _generate_template_greeting(self, template: str, username: str, style: str) -> str:
|
||||
"""使用模板生成问候消息"""
|
||||
# 根据风格调整问候语
|
||||
style_templates = {
|
||||
"casual": "嗨{username}!很开心见到你~",
|
||||
"formal": "您好{username},很荣幸为您服务!",
|
||||
"friendly": "你好{username}!欢迎来到这里,希望我们能成为好朋友!😊"
|
||||
}
|
||||
|
||||
selected_template = style_templates.get(style, template)
|
||||
username_display = f" {username}" if username else ""
|
||||
|
||||
return selected_template.format(username=username_display)
|
||||
|
||||
async def _generate_llm_greeting(self, username: str, style: str) -> str:
|
||||
"""使用LLM生成个性化问候"""
|
||||
try:
|
||||
# 获取可用模型
|
||||
models = self.api.get_available_models()
|
||||
if not models:
|
||||
logger.warning(f"{self.log_prefix} 无可用LLM模型,使用默认问候")
|
||||
return await self._generate_template_greeting("你好{username}!", username, style)
|
||||
|
||||
# 构建提示词
|
||||
prompt = f"""
|
||||
请生成一个{style}风格的问候消息。
|
||||
用户名: {username or "用户"}
|
||||
要求:
|
||||
- 风格: {style}
|
||||
- 简洁友好
|
||||
- 不超过50字
|
||||
- 符合中文表达习惯
|
||||
"""
|
||||
|
||||
# 调用LLM
|
||||
model_config = next(iter(models.values()))
|
||||
success, response, reasoning, model_name = await self.api.generate_with_model(
|
||||
prompt=prompt,
|
||||
model_config=model_config,
|
||||
request_type="plugin.greeting",
|
||||
temperature=0.7,
|
||||
max_tokens=100
|
||||
)
|
||||
|
||||
if success and response:
|
||||
return response.strip()
|
||||
else:
|
||||
logger.warning(f"{self.log_prefix} LLM生成失败,使用默认问候")
|
||||
return await self._generate_template_greeting("你好{username}!", username, style)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} LLM问候生成异常: {e}")
|
||||
return await self._generate_template_greeting("你好{username}!", username, style)
|
||||
|
||||
|
||||
class HelpfulAction(BaseAction):
|
||||
"""智能帮助Action - 展示LLM_JUDGE激活类型和随机激活的综合示例"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.RANDOM
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = True
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "helpful_assistant"
|
||||
action_description = "智能助手Action,主动提供帮助和建议,展示LLM判断激活"
|
||||
|
||||
# LLM判断提示词
|
||||
llm_judge_prompt = """
|
||||
判定是否需要使用智能帮助动作的条件:
|
||||
1. 用户表达了困惑或需要帮助
|
||||
2. 用户提出了问题但没有得到满意答案
|
||||
3. 对话中出现了技术术语或复杂概念
|
||||
4. 用户似乎在寻找解决方案
|
||||
5. 适合提供额外信息或建议的场合
|
||||
|
||||
不要使用的情况:
|
||||
1. 用户明确表示不需要帮助
|
||||
2. 对话进行得很顺利,无需干预
|
||||
3. 用户只是在闲聊,没有实际需求
|
||||
|
||||
请回答"是"或"否"。
|
||||
"""
|
||||
|
||||
# 随机激活概率
|
||||
random_activation_probability = 0.15
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"help_type": "帮助类型:explanation(解释)、suggestion(建议)、guidance(指导)、tips(提示)",
|
||||
"topic": "帮助主题或用户关心的问题",
|
||||
"complexity": "复杂度:simple(简单)、medium(中等)、advanced(高级)"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户表达困惑或寻求帮助时使用",
|
||||
"检测到用户遇到技术问题时使用",
|
||||
"对话中出现知识盲点时主动提供帮助",
|
||||
"避免过度频繁地提供帮助,要恰到好处"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行智能帮助"""
|
||||
logger.info(f"{self.log_prefix} 执行智能帮助动作: {self.reasoning}")
|
||||
|
||||
try:
|
||||
# 获取参数
|
||||
help_type = self.action_data.get("help_type", "suggestion")
|
||||
topic = self.action_data.get("topic", "")
|
||||
complexity = self.action_data.get("complexity", "simple")
|
||||
|
||||
# 根据帮助类型生成响应
|
||||
help_message = await self._generate_help_message(help_type, topic, complexity)
|
||||
|
||||
# 发送帮助消息
|
||||
await self.send_text(help_message)
|
||||
|
||||
# 可选发送鼓励表情
|
||||
if self.api.get_config("help.enable_emoji", True):
|
||||
emojis = ["💡", "🤔", "💪", "🎯", "✨"]
|
||||
selected_emoji = random.choice(emojis)
|
||||
await self.send_type("emoji", selected_emoji)
|
||||
|
||||
logger.info(f"{self.log_prefix} 智能帮助执行成功")
|
||||
return True, f"提供了{help_type}类型的帮助,主题:{topic}"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 智能帮助执行失败: {e}")
|
||||
return False, f"帮助失败: {str(e)}"
|
||||
|
||||
async def _generate_help_message(self, help_type: str, topic: str, complexity: str) -> str:
|
||||
"""生成帮助消息"""
|
||||
# 获取配置
|
||||
enable_llm = self.api.get_config("help.enable_llm", False)
|
||||
|
||||
if enable_llm:
|
||||
return await self._generate_llm_help(help_type, topic, complexity)
|
||||
else:
|
||||
return await self._generate_template_help(help_type, topic, complexity)
|
||||
|
||||
async def _generate_template_help(self, help_type: str, topic: str, complexity: str) -> str:
|
||||
"""使用模板生成帮助消息"""
|
||||
help_templates = {
|
||||
"explanation": f"关于{topic},我来为你解释一下:这是一个{complexity}级别的概念...",
|
||||
"suggestion": f"针对{topic},我建议你可以尝试以下方法...",
|
||||
"guidance": f"在{topic}方面,我可以为你提供一些指导...",
|
||||
"tips": f"关于{topic},这里有一些实用的小贴士..."
|
||||
}
|
||||
|
||||
base_message = help_templates.get(help_type, f"关于{topic},我很乐意为你提供帮助!")
|
||||
|
||||
# 根据复杂度调整消息
|
||||
if complexity == "advanced":
|
||||
base_message += "\n\n这个话题比较深入,需要一些基础知识。"
|
||||
elif complexity == "simple":
|
||||
base_message += "\n\n这个概念其实很简单,让我用通俗的话来说明。"
|
||||
|
||||
return base_message
|
||||
|
||||
async def _generate_llm_help(self, help_type: str, topic: str, complexity: str) -> str:
|
||||
"""使用LLM生成个性化帮助"""
|
||||
try:
|
||||
models = self.api.get_available_models()
|
||||
if not models:
|
||||
return await self._generate_template_help(help_type, topic, complexity)
|
||||
|
||||
prompt = f"""
|
||||
请生成一个{help_type}类型的帮助消息。
|
||||
主题: {topic}
|
||||
复杂度: {complexity}
|
||||
要求:
|
||||
- 风格友好、耐心
|
||||
- 内容准确、有用
|
||||
- 长度适中(100-200字)
|
||||
- 根据复杂度调整语言难度
|
||||
"""
|
||||
|
||||
model_config = next(iter(models.values()))
|
||||
success, response, reasoning, model_name = await self.api.generate_with_model(
|
||||
prompt=prompt,
|
||||
model_config=model_config,
|
||||
request_type="plugin.help",
|
||||
temperature=0.7,
|
||||
max_tokens=300
|
||||
)
|
||||
|
||||
if success and response:
|
||||
return response.strip()
|
||||
else:
|
||||
return await self._generate_template_help(help_type, topic, complexity)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} LLM帮助生成异常: {e}")
|
||||
return await self._generate_template_help(help_type, topic, complexity)
|
||||
|
||||
|
||||
# ===== Command组件 =====
|
||||
@@ -405,6 +656,7 @@ class ExampleComprehensivePlugin(BasePlugin):
|
||||
|
||||
# 从配置获取组件启用状态
|
||||
enable_greeting = self.get_config("components.enable_greeting", True)
|
||||
enable_helpful = self.get_config("components.enable_helpful", True)
|
||||
enable_help = self.get_config("components.enable_help", True)
|
||||
enable_send = self.get_config("components.enable_send", True)
|
||||
enable_echo = self.get_config("components.enable_echo", True)
|
||||
@@ -412,16 +664,12 @@ class ExampleComprehensivePlugin(BasePlugin):
|
||||
enable_dice = self.get_config("components.enable_dice", True)
|
||||
components = []
|
||||
|
||||
# 添加Action组件
|
||||
# 添加Action组件 - 使用类中定义的所有属性
|
||||
if enable_greeting:
|
||||
components.append(
|
||||
(
|
||||
SmartGreetingAction.get_action_info(
|
||||
name="smart_greeting", description="智能问候系统,基于关键词触发"
|
||||
),
|
||||
SmartGreetingAction,
|
||||
)
|
||||
)
|
||||
components.append((SmartGreetingAction.get_action_info(), SmartGreetingAction))
|
||||
|
||||
if enable_helpful:
|
||||
components.append((HelpfulAction.get_action_info(), HelpfulAction))
|
||||
|
||||
# 添加Command组件
|
||||
if enable_help:
|
||||
|
||||
@@ -32,7 +32,7 @@ class PluginManager:
|
||||
|
||||
def _ensure_plugin_directories(self):
|
||||
"""确保所有插件目录存在,如果不存在则创建"""
|
||||
default_directories = ["src/plugins/built_in", "src/plugins/examples", "plugins"]
|
||||
default_directories = ["src/plugins/built_in", "plugins"]
|
||||
|
||||
for directory in default_directories:
|
||||
if not os.path.exists(directory):
|
||||
|
||||
Reference in New Issue
Block a user