初始化
This commit is contained in:
297
docs/plugins/action-components.md
Normal file
297
docs/plugins/action-components.md
Normal file
@@ -0,0 +1,297 @@
|
||||
# ⚡ Action组件详解
|
||||
|
||||
## 📖 什么是Action
|
||||
|
||||
Action是给麦麦在回复之外提供额外功能的智能组件,**由麦麦的决策系统自主选择是否使用**,具有随机性和拟人化的调用特点。Action不是直接响应用户命令,而是让麦麦根据聊天情境智能地选择合适的动作,使其行为更加自然和真实。
|
||||
|
||||
### Action的特点
|
||||
|
||||
- 🧠 **智能激活**:麦麦根据多种条件智能判断是否使用
|
||||
- 🎲 **可随机性**:可以使用随机数激活,增加行为的不可预测性,更接近真人交流
|
||||
- 🤖 **拟人化**:让麦麦的回应更自然、更有个性
|
||||
- 🔄 **情境感知**:基于聊天上下文做出合适的反应
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Action组件的基本结构
|
||||
首先,所有的Action都应该继承`BaseAction`类。
|
||||
|
||||
其次,每个Action组件都应该实现以下基本信息:
|
||||
```python
|
||||
class ExampleAction(BaseAction):
|
||||
action_name = "example_action" # 动作的唯一标识符
|
||||
action_description = "这是一个示例动作" # 动作描述
|
||||
activation_type = ActionActivationType.ALWAYS # 这里以 ALWAYS 为例
|
||||
mode_enable = ChatMode.ALL # 一般取ALL,表示在所有聊天模式下都可用
|
||||
associated_types = ["text", "emoji", ...] # 关联类型
|
||||
parallel_action = False # 是否允许与其他Action并行执行
|
||||
action_parameters = {"param1": "参数1的说明", "param2": "参数2的说明", ...}
|
||||
# Action使用场景描述 - 帮助LLM判断何时"选择"使用
|
||||
action_require = ["使用场景描述1", "使用场景描述2", ...]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""
|
||||
执行Action的主要逻辑
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str]: (是否成功, 执行结果描述)
|
||||
"""
|
||||
# ---- 执行动作的逻辑 ----
|
||||
return True, "执行成功"
|
||||
```
|
||||
#### associated_types: 该Action会发送的消息类型,例如文本、表情等。
|
||||
|
||||
这部分由Adapter传递给处理器。
|
||||
|
||||
以 MaiBot-Napcat-Adapter 为例,可选项目如下:
|
||||
| 类型 | 说明 | 格式 |
|
||||
| --- | --- | --- |
|
||||
| text | 文本消息 | str |
|
||||
| emoji | 表情消息 | str: 表情包的无头base64|
|
||||
| image | 图片消息 | str: 图片的无头base64 |
|
||||
| reply | 回复消息 | str: 回复的消息ID |
|
||||
| voice | 语音消息 | str: wav格式语音的无头base64 |
|
||||
| command | 命令消息 | 参见Adapter文档 |
|
||||
| voiceurl | 语音URL消息 | str: wav格式语音的URL |
|
||||
| music | 音乐消息 | str: 这首歌在网易云音乐的音乐id |
|
||||
| videourl | 视频URL消息 | str: 视频的URL |
|
||||
| file | 文件消息 | str: 文件的路径 |
|
||||
|
||||
**请知悉,对于不同的处理器,其支持的消息类型可能会有所不同。在开发时请注意。**
|
||||
|
||||
#### action_parameters: 该Action的参数说明。
|
||||
这是一个字典,键为参数名,值为参数说明。这个字段可以帮助LLM理解如何使用这个Action,并由LLM返回对应的参数,最后传递到 Action 的 **`action_data`** 属性中。其格式与你定义的格式完全相同 **(除非LLM哈气了,返回了错误的内容)**。
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Action 调用的决策机制
|
||||
|
||||
Action采用**两层决策机制**来优化性能和决策质量:
|
||||
|
||||
> 设计目的:在加载许多插件的时候降低LLM决策压力,避免让麦麦在过多的选项中纠结。
|
||||
|
||||
**第一层:激活控制(Activation Control)**
|
||||
|
||||
激活决定麦麦是否 **“知道”** 这个Action的存在,即这个Action是否进入决策候选池。不被激活的Action麦麦永远不会选择。
|
||||
|
||||
**第二层:使用决策(Usage Decision)**
|
||||
|
||||
在Action被激活后,使用条件决定麦麦什么时候会 **“选择”** 使用这个Action。
|
||||
|
||||
### 决策参数详解 🔧
|
||||
|
||||
#### 第一层:ActivationType 激活类型说明
|
||||
|
||||
| 激活类型 | 说明 | 使用场景 |
|
||||
| ----------- | ---------------------------------------- | ---------------------- |
|
||||
| [`NEVER`](#never-激活) | 从不激活,Action对麦麦不可见 | 临时禁用某个Action |
|
||||
| [`ALWAYS`](#always-激活) | 永远激活,Action总是在麦麦的候选池中 | 核心功能,如回复、不回复 |
|
||||
| [`LLM_JUDGE`](#llm_judge-激活) | 通过LLM智能判断当前情境是否需要激活此Action | 需要智能判断的复杂场景 |
|
||||
| `RANDOM` | 基于随机概率决定是否激活 | 增加行为随机性的功能 |
|
||||
| `KEYWORD` | 当检测到特定关键词时激活 | 明确触发条件的功能 |
|
||||
|
||||
#### `NEVER` 激活
|
||||
|
||||
`ActionActivationType.NEVER` 会使得 Action 永远不会被激活
|
||||
|
||||
```python
|
||||
class DisabledAction(BaseAction):
|
||||
activation_type = ActionActivationType.NEVER # 永远不激活
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 这个Action永远不会被执行
|
||||
return False, "这个Action被禁用"
|
||||
```
|
||||
|
||||
#### `ALWAYS` 激活
|
||||
|
||||
`ActionActivationType.ALWAYS` 会使得 Action 永远会被激活,即一直在 Action 候选池中
|
||||
|
||||
这种激活方式常用于核心功能,如回复或不回复。
|
||||
|
||||
```python
|
||||
class AlwaysActivatedAction(BaseAction):
|
||||
activation_type = ActionActivationType.ALWAYS # 永远激活
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 执行核心功能
|
||||
return True, "执行了核心功能"
|
||||
```
|
||||
|
||||
#### `LLM_JUDGE` 激活
|
||||
|
||||
`ActionActivationType.LLM_JUDGE`会使得这个 Action 根据 LLM 的判断来决定是否加入候选池。
|
||||
|
||||
而 LLM 的判断是基于代码中预设的`llm_judge_prompt`和自动提供的聊天上下文进行的。
|
||||
|
||||
因此使用此种方法需要实现`llm_judge_prompt`属性。
|
||||
|
||||
```python
|
||||
class LLMJudgedAction(BaseAction):
|
||||
activation_type = ActionActivationType.LLM_JUDGE # 通过LLM判断激活
|
||||
# LLM判断提示词
|
||||
llm_judge_prompt = (
|
||||
"判定是否需要使用这个动作的条件:\n"
|
||||
"1. 用户希望调用XXX这个动作\n"
|
||||
"...\n"
|
||||
"请回答\"是\"或\"否\"。\n"
|
||||
)
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 根据LLM判断是否执行
|
||||
return True, "执行了LLM判断功能"
|
||||
```
|
||||
|
||||
#### `RANDOM` 激活
|
||||
|
||||
`ActionActivationType.RANDOM`会使得这个 Action 根据随机概率决定是否加入候选池。
|
||||
|
||||
概率则由代码中的`random_activation_probability`控制。在内部实现中我们使用了`random.random()`来生成一个0到1之间的随机数,并与这个概率进行比较。
|
||||
|
||||
因此使用这个方法需要实现`random_activation_probability`属性。
|
||||
|
||||
```python
|
||||
class SurpriseAction(BaseAction):
|
||||
activation_type = ActionActivationType.RANDOM # 基于随机概率激活
|
||||
# 随机激活概率
|
||||
random_activation_probability = 0.1 # 10%概率激活
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 执行惊喜动作
|
||||
return True, "发送了惊喜内容"
|
||||
```
|
||||
|
||||
#### `KEYWORD` 激活
|
||||
|
||||
`ActionActivationType.KEYWORD`会使得这个 Action 在检测到特定关键词时激活。
|
||||
|
||||
关键词由代码中的`activation_keywords`定义,而`keyword_case_sensitive`则控制关键词匹配时是否区分大小写。在内部实现中,我们使用了`in`操作符来检查消息内容是否包含这些关键词。
|
||||
|
||||
因此,使用此种方法需要实现`activation_keywords`和`keyword_case_sensitive`属性。
|
||||
|
||||
```python
|
||||
class GreetingAction(BaseAction):
|
||||
activation_type = ActionActivationType.KEYWORD # 关键词激活
|
||||
activation_keywords = ["你好", "hello", "hi", "嗨"] # 关键词配置
|
||||
keyword_case_sensitive = False # 不区分大小写
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 执行问候逻辑
|
||||
return True, "发送了问候"
|
||||
```
|
||||
|
||||
一个完整的使用`ActionActivationType.KEYWORD`的例子请参考`plugins/hello_world_plugin`中的`ByeAction`。
|
||||
|
||||
#### 第二层:使用决策
|
||||
|
||||
**在Action被激活后,使用条件决定麦麦什么时候会"选择"使用这个Action**。
|
||||
|
||||
这一层由以下因素综合决定:
|
||||
|
||||
- `action_require`:使用场景描述,帮助LLM判断何时选择
|
||||
- `action_parameters`:所需参数,影响Action的可执行性
|
||||
- 当前聊天上下文和麦麦的决策逻辑
|
||||
|
||||
---
|
||||
|
||||
### 决策流程示例
|
||||
|
||||
```python
|
||||
class EmojiAction(BaseAction):
|
||||
# 第一层:激活控制
|
||||
activation_type = ActionActivationType.RANDOM # 随机激活
|
||||
random_activation_probability = 0.1 # 10%概率激活
|
||||
|
||||
# 第二层:使用决策
|
||||
action_require = [
|
||||
"表达情绪时可以选择使用",
|
||||
"增加聊天趣味性",
|
||||
"不要连续发送多个表情"
|
||||
]
|
||||
```
|
||||
|
||||
**决策流程**:
|
||||
|
||||
1. **第一层激活判断**:
|
||||
|
||||
- 使用随机数进行决策,当`random.random() < self.random_activation_probability`时,麦麦才"知道"可以使用这个Action
|
||||
2. **第二层使用决策**:
|
||||
|
||||
- 即使Action被激活,麦麦还会根据 `action_require` 中的条件判断是否真正选择使用
|
||||
- 例如:如果刚刚已经发过表情,根据"不要连续发送多个表情"的要求,麦麦可能不会选择这个Action
|
||||
|
||||
---
|
||||
|
||||
## Action 内置属性说明
|
||||
```python
|
||||
class BaseAction:
|
||||
def __init__(self):
|
||||
# 消息相关属性
|
||||
self.log_prefix: str # 日志前缀
|
||||
self.group_id: str # 群组ID
|
||||
self.group_name: str # 群组名称
|
||||
self.user_id: str # 用户ID
|
||||
self.user_nickname: str # 用户昵称
|
||||
self.platform: str # 平台类型 (qq, telegram等)
|
||||
self.chat_id: str # 聊天ID
|
||||
self.chat_stream: ChatStream # 聊天流对象
|
||||
self.is_group: bool # 是否群聊
|
||||
|
||||
# 消息体
|
||||
self.action_message: dict # 消息数据
|
||||
|
||||
# Action相关属性
|
||||
self.action_data: dict # Action执行时的数据
|
||||
self.thinking_id: str # 思考ID
|
||||
```
|
||||
action_message为一个字典,包含的键值对如下(省略了不必要的键值对)
|
||||
|
||||
```python
|
||||
{
|
||||
"message_id": "1234567890", # 消息id,str
|
||||
"time": 1627545600.0, # 时间戳,float
|
||||
"chat_id": "abcdef123456", # 聊天ID,str
|
||||
"reply_to": None, # 回复消息id,str或None
|
||||
"interest_value": 0.85, # 兴趣值,float
|
||||
"is_mentioned": True, # 是否被提及,bool
|
||||
"chat_info_last_active_time": 1627548600.0, # 最后活跃时间,float
|
||||
"processed_plain_text": None, # 处理后的文本,str或None
|
||||
"additional_config": None, # Adapter传来的additional_config,dict或None
|
||||
"is_emoji": False, # 是否为表情,bool
|
||||
"is_picid": False, # 是否为图片ID,bool
|
||||
"is_command": False # 是否为命令,bool
|
||||
}
|
||||
```
|
||||
|
||||
部分值的格式请自行查询数据库。
|
||||
|
||||
---
|
||||
|
||||
## Action 内置方法说明
|
||||
```python
|
||||
class BaseAction:
|
||||
def get_config(self, key: str, default=None):
|
||||
"""获取插件配置值,使用嵌套键访问"""
|
||||
|
||||
async def wait_for_new_message(self, timeout: int = 1200) -> Tuple[bool, str]:
|
||||
"""等待新消息或超时"""
|
||||
|
||||
async def send_text(self, content: str, reply_to: str = "", reply_to_platform_id: str = "", typing: bool = False) -> bool:
|
||||
"""发送文本消息"""
|
||||
|
||||
async def send_emoji(self, emoji_base64: str) -> bool:
|
||||
"""发送表情包"""
|
||||
|
||||
async def send_image(self, image_base64: str) -> bool:
|
||||
"""发送图片"""
|
||||
|
||||
async def send_custom(self, message_type: str, content: str, typing: bool = False, reply_to: str = "") -> bool:
|
||||
"""发送自定义类型消息"""
|
||||
|
||||
async def store_action_info(self, action_build_into_prompt: bool = False, action_prompt_display: str = "", action_done: bool = True) -> None:
|
||||
"""存储动作信息到数据库"""
|
||||
|
||||
async def send_command(self, command_name: str, args: Optional[dict] = None, display_message: str = "", storage_message: bool = True) -> bool:
|
||||
"""发送命令消息"""
|
||||
```
|
||||
具体参数与用法参见`BaseAction`基类的定义。
|
||||
130
docs/plugins/api/chat-api.md
Normal file
130
docs/plugins/api/chat-api.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# 聊天API
|
||||
|
||||
聊天API模块专门负责聊天信息的查询和管理,帮助插件获取和管理不同的聊天流。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system import chat_api
|
||||
# 或者
|
||||
from src.plugin_system.apis import chat_api
|
||||
```
|
||||
|
||||
一种**Deprecated**方式:
|
||||
```python
|
||||
from src.plugin_system.apis.chat_api import ChatManager
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 获取所有的聊天流
|
||||
|
||||
```python
|
||||
def get_all_streams(platform: Optional[str] | SpecialTypes = "qq") -> List[ChatStream]:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的聊天流。
|
||||
|
||||
**Returns**:
|
||||
- `List[ChatStream]`:聊天流列表
|
||||
|
||||
### 2. 获取群聊聊天流
|
||||
|
||||
```python
|
||||
def get_group_streams(platform: Optional[str] | SpecialTypes = "qq") -> List[ChatStream]:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的群聊流。
|
||||
|
||||
**Returns**:
|
||||
- `List[ChatStream]`:群聊聊天流列表
|
||||
|
||||
### 3. 获取私聊聊天流
|
||||
|
||||
```python
|
||||
def get_private_streams(platform: Optional[str] | SpecialTypes = "qq") -> List[ChatStream]:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的私聊流。
|
||||
|
||||
**Returns**:
|
||||
- `List[ChatStream]`:私聊聊天流列表
|
||||
|
||||
### 4. 根据群ID获取聊天流
|
||||
|
||||
```python
|
||||
def get_stream_by_group_id(group_id: str, platform: Optional[str] | SpecialTypes = "qq") -> Optional[ChatStream]:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `group_id`:群聊ID
|
||||
- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的群聊流。
|
||||
|
||||
**Returns**:
|
||||
- `Optional[ChatStream]`:聊天流对象,如果未找到返回None
|
||||
|
||||
### 5. 根据用户ID获取私聊流
|
||||
|
||||
```python
|
||||
def get_stream_by_user_id(user_id: str, platform: Optional[str] | SpecialTypes = "qq") -> Optional[ChatStream]:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `user_id`:用户ID
|
||||
- `platform`:平台筛选,默认为"qq",可以使用`SpecialTypes`枚举类中的`SpecialTypes.ALL_PLATFORMS`来获取所有平台的私聊流。
|
||||
|
||||
**Returns**:
|
||||
- `Optional[ChatStream]`:聊天流对象,如果未找到返回None
|
||||
|
||||
### 6. 获取聊天流类型
|
||||
|
||||
```python
|
||||
def get_stream_type(chat_stream: ChatStream) -> str:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `chat_stream`:聊天流对象
|
||||
|
||||
**Returns**:
|
||||
- `str`:聊天流类型,可能的值包括`private`(私聊流),`group`(群聊流)以及`unknown`(未知类型)。
|
||||
|
||||
### 7. 获取聊天流信息
|
||||
|
||||
```python
|
||||
def get_stream_info(chat_stream: ChatStream) -> Dict[str, Any]:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `chat_stream`:聊天流对象
|
||||
|
||||
**Returns**:
|
||||
- `Dict[str, Any]`:聊天流的详细信息,包括但不限于:
|
||||
- `stream_id`:聊天流ID
|
||||
- `platform`:平台名称
|
||||
- `type`:聊天流类型
|
||||
- `group_id`:群聊ID
|
||||
- `group_name`:群聊名称
|
||||
- `user_id`:用户ID
|
||||
- `user_name`:用户名称
|
||||
|
||||
### 8. 获取聊天流统计摘要
|
||||
|
||||
```python
|
||||
def get_streams_summary() -> Dict[str, int]:
|
||||
```
|
||||
|
||||
**Returns**:
|
||||
- `Dict[str, int]`:聊天流统计信息摘要,包含以下键:
|
||||
- `total_streams`:总聊天流数量
|
||||
- `group_streams`:群聊流数量
|
||||
- `private_streams`:私聊流数量
|
||||
- `qq_streams`:QQ平台流数量
|
||||
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 大部分函数在参数不合法时候会抛出异常,请确保你的程序进行了捕获。
|
||||
2. `ChatStream`对象包含了聊天的完整信息,包括用户信息、群信息等。
|
||||
194
docs/plugins/api/component-manage-api.md
Normal file
194
docs/plugins/api/component-manage-api.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# 组件管理API
|
||||
|
||||
组件管理API模块提供了对插件组件的查询和管理功能,使得插件能够获取和使用组件相关的信息。
|
||||
|
||||
## 导入方式
|
||||
```python
|
||||
from src.plugin_system.apis import component_manage_api
|
||||
# 或者
|
||||
from src.plugin_system import component_manage_api
|
||||
```
|
||||
|
||||
## 功能概述
|
||||
|
||||
组件管理API主要提供以下功能:
|
||||
- **插件信息查询** - 获取所有插件或指定插件的信息。
|
||||
- **组件查询** - 按名称或类型查询组件信息。
|
||||
- **组件管理** - 启用或禁用组件,支持全局和局部操作。
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 获取所有插件信息
|
||||
```python
|
||||
def get_all_plugin_info() -> Dict[str, PluginInfo]:
|
||||
```
|
||||
获取所有插件的信息。
|
||||
|
||||
**Returns:**
|
||||
- `Dict[str, PluginInfo]` - 包含所有插件信息的字典,键为插件名称,值为 `PluginInfo` 对象。
|
||||
|
||||
### 2. 获取指定插件信息
|
||||
```python
|
||||
def get_plugin_info(plugin_name: str) -> Optional[PluginInfo]:
|
||||
```
|
||||
获取指定插件的信息。
|
||||
|
||||
**Args:**
|
||||
- `plugin_name` (str): 插件名称。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[PluginInfo]`: 插件信息对象,如果插件不存在则返回 `None`。
|
||||
|
||||
### 3. 获取指定组件信息
|
||||
```python
|
||||
def get_component_info(component_name: str, component_type: ComponentType) -> Optional[Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||
```
|
||||
获取指定组件的信息。
|
||||
|
||||
**Args:**
|
||||
- `component_name` (str): 组件名称。
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[Union[CommandInfo, ActionInfo, EventHandlerInfo]]`: 组件信息对象,如果组件不存在则返回 `None`。
|
||||
|
||||
### 4. 获取指定类型的所有组件信息
|
||||
```python
|
||||
def get_components_info_by_type(component_type: ComponentType) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||
```
|
||||
获取指定类型的所有组件信息。
|
||||
|
||||
**Args:**
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
|
||||
**Returns:**
|
||||
- `Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]`: 包含指定类型组件信息的字典,键为组件名称,值为对应的组件信息对象。
|
||||
|
||||
### 5. 获取指定类型的所有启用的组件信息
|
||||
```python
|
||||
def get_enabled_components_info_by_type(component_type: ComponentType) -> Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]:
|
||||
```
|
||||
获取指定类型的所有启用的组件信息。
|
||||
|
||||
**Args:**
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
|
||||
**Returns:**
|
||||
- `Dict[str, Union[CommandInfo, ActionInfo, EventHandlerInfo]]`: 包含指定类型启用组件信息的字典,键为组件名称,值为对应的组件信息对象。
|
||||
|
||||
### 6. 获取指定 Action 的注册信息
|
||||
```python
|
||||
def get_registered_action_info(action_name: str) -> Optional[ActionInfo]:
|
||||
```
|
||||
获取指定 Action 的注册信息。
|
||||
|
||||
**Args:**
|
||||
- `action_name` (str): Action 名称。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[ActionInfo]` - Action 信息对象,如果 Action 不存在则返回 `None`。
|
||||
|
||||
### 7. 获取指定 Command 的注册信息
|
||||
```python
|
||||
def get_registered_command_info(command_name: str) -> Optional[CommandInfo]:
|
||||
```
|
||||
获取指定 Command 的注册信息。
|
||||
|
||||
**Args:**
|
||||
- `command_name` (str): Command 名称。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[CommandInfo]` - Command 信息对象,如果 Command 不存在则返回 `None`。
|
||||
|
||||
### 8. 获取指定 Tool 的注册信息
|
||||
```python
|
||||
def get_registered_tool_info(tool_name: str) -> Optional[ToolInfo]:
|
||||
```
|
||||
获取指定 Tool 的注册信息。
|
||||
|
||||
**Args:**
|
||||
- `tool_name` (str): Tool 名称。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[ToolInfo]` - Tool 信息对象,如果 Tool 不存在则返回 `None`。
|
||||
|
||||
### 9. 获取指定 EventHandler 的注册信息
|
||||
```python
|
||||
def get_registered_event_handler_info(event_handler_name: str) -> Optional[EventHandlerInfo]:
|
||||
```
|
||||
获取指定 EventHandler 的注册信息。
|
||||
|
||||
**Args:**
|
||||
- `event_handler_name` (str): EventHandler 名称。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[EventHandlerInfo]` - EventHandler 信息对象,如果 EventHandler 不存在则返回 `None`。
|
||||
|
||||
### 10. 全局启用指定组件
|
||||
```python
|
||||
def globally_enable_component(component_name: str, component_type: ComponentType) -> bool:
|
||||
```
|
||||
全局启用指定组件。
|
||||
|
||||
**Args:**
|
||||
- `component_name` (str): 组件名称。
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 启用成功返回 `True`,否则返回 `False`。
|
||||
|
||||
### 11. 全局禁用指定组件
|
||||
```python
|
||||
async def globally_disable_component(component_name: str, component_type: ComponentType) -> bool:
|
||||
```
|
||||
全局禁用指定组件。
|
||||
|
||||
**此函数是异步的,确保在异步环境中调用。**
|
||||
|
||||
**Args:**
|
||||
- `component_name` (str): 组件名称。
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 禁用成功返回 `True`,否则返回 `False`。
|
||||
|
||||
### 12. 局部启用指定组件
|
||||
```python
|
||||
def locally_enable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
|
||||
```
|
||||
局部启用指定组件。
|
||||
|
||||
**Args:**
|
||||
- `component_name` (str): 组件名称。
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
- `stream_id` (str): 消息流 ID。
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 启用成功返回 `True`,否则返回 `False`。
|
||||
|
||||
### 13. 局部禁用指定组件
|
||||
```python
|
||||
def locally_disable_component(component_name: str, component_type: ComponentType, stream_id: str) -> bool:
|
||||
```
|
||||
局部禁用指定组件。
|
||||
|
||||
**Args:**
|
||||
- `component_name` (str): 组件名称。
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
- `stream_id` (str): 消息流 ID。
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 禁用成功返回 `True`,否则返回 `False`。
|
||||
|
||||
### 14. 获取指定消息流中禁用的组件列表
|
||||
```python
|
||||
def get_locally_disabled_components(stream_id: str, component_type: ComponentType) -> list[str]:
|
||||
```
|
||||
获取指定消息流中禁用的组件列表。
|
||||
|
||||
**Args:**
|
||||
- `stream_id` (str): 消息流 ID。
|
||||
- `component_type` (ComponentType): 组件类型。
|
||||
|
||||
**Returns:**
|
||||
- `list[str]` - 禁用的组件名称列表。
|
||||
52
docs/plugins/api/config-api.md
Normal file
52
docs/plugins/api/config-api.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# 配置API
|
||||
|
||||
配置API模块提供了配置读取功能,让插件能够安全地访问全局配置和插件配置。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import config_api
|
||||
# 或者
|
||||
from src.plugin_system import config_api
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 访问全局配置
|
||||
|
||||
```python
|
||||
def get_global_config(key: str, default: Any = None) -> Any:
|
||||
```
|
||||
|
||||
**Args**:
|
||||
- `key`: 命名空间式配置键名,使用嵌套访问,如 "section.subsection.key",大小写敏感
|
||||
- `default`: 如果配置不存在时返回的默认值
|
||||
|
||||
**Returns**:
|
||||
- `Any`: 配置值或默认值
|
||||
|
||||
#### 示例:
|
||||
获取机器人昵称
|
||||
```python
|
||||
bot_name = config_api.get_global_config("bot.nickname", "MaiBot")
|
||||
```
|
||||
|
||||
### 2. 获取插件配置
|
||||
|
||||
```python
|
||||
def get_plugin_config(plugin_config: dict, key: str, default: Any = None) -> Any:
|
||||
```
|
||||
**Args**:
|
||||
- `plugin_config`: 插件配置字典
|
||||
- `key`: 配置键名,支持嵌套访问如 "section.subsection.key",大小写敏感
|
||||
- `default`: 如果配置不存在时返回的默认值
|
||||
|
||||
**Returns**:
|
||||
- `Any`: 配置值或默认值
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **只读访问**:配置API只提供读取功能,插件不能修改全局配置
|
||||
2. **错误处理**:所有函数都有错误处理,失败时会记录日志并返回默认值
|
||||
3. **安全性**:插件通过此API访问配置是安全和隔离的
|
||||
4. **性能**:频繁访问的配置建议在插件初始化时获取并缓存
|
||||
216
docs/plugins/api/database-api.md
Normal file
216
docs/plugins/api/database-api.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# 数据库API
|
||||
|
||||
数据库API模块提供通用的数据库操作功能,支持查询、创建、更新和删除记录,采用Peewee ORM模型。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import database_api
|
||||
# 或者
|
||||
from src.plugin_system import database_api
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 通用数据库操作
|
||||
|
||||
```python
|
||||
async def db_query(
|
||||
model_class: Type[Model],
|
||||
data: Optional[Dict[str, Any]] = None,
|
||||
query_type: Optional[str] = "get",
|
||||
filters: Optional[Dict[str, Any]] = None,
|
||||
limit: Optional[int] = None,
|
||||
order_by: Optional[List[str]] = None,
|
||||
single_result: Optional[bool] = False,
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, Any], None]:
|
||||
```
|
||||
执行数据库查询操作的通用接口。
|
||||
|
||||
**Args:**
|
||||
- `model_class`: Peewee模型类。
|
||||
- Peewee模型类可以在`src.common.database.database_model`模块中找到,如`ActionRecords`、`Messages`等。
|
||||
- `data`: 用于创建或更新的数据
|
||||
- `query_type`: 查询类型
|
||||
- 可选值: `get`, `create`, `update`, `delete`, `count`。
|
||||
- `filters`: 过滤条件字典,键为字段名,值为要匹配的值。
|
||||
- `limit`: 限制结果数量。
|
||||
- `order_by`: 排序字段列表,使用字段名,前缀'-'表示降序。
|
||||
- 排序字段,前缀`-`表示降序,例如`-time`表示按时间字段(即`time`字段)降序
|
||||
- `single_result`: 是否只返回单个结果。
|
||||
|
||||
**Returns:**
|
||||
- 根据查询类型返回不同的结果:
|
||||
- `get`: 返回查询结果列表或单个结果。(如果 `single_result=True`)
|
||||
- `create`: 返回创建的记录。
|
||||
- `update`: 返回受影响的行数。
|
||||
- `delete`: 返回受影响的行数。
|
||||
- `count`: 返回记录数量。
|
||||
|
||||
#### 示例
|
||||
|
||||
1. 查询最近10条消息
|
||||
```python
|
||||
messages = await database_api.db_query(
|
||||
Messages,
|
||||
query_type="get",
|
||||
filters={"chat_id": chat_stream.stream_id},
|
||||
limit=10,
|
||||
order_by=["-time"]
|
||||
)
|
||||
```
|
||||
2. 创建一条记录
|
||||
```python
|
||||
new_record = await database_api.db_query(
|
||||
ActionRecords,
|
||||
data={"action_id": "123", "time": time.time(), "action_name": "TestAction"},
|
||||
query_type="create",
|
||||
)
|
||||
```
|
||||
3. 更新记录
|
||||
```python
|
||||
updated_count = await database_api.db_query(
|
||||
ActionRecords,
|
||||
data={"action_done": True},
|
||||
query_type="update",
|
||||
filters={"action_id": "123"},
|
||||
)
|
||||
```
|
||||
4. 删除记录
|
||||
```python
|
||||
deleted_count = await database_api.db_query(
|
||||
ActionRecords,
|
||||
query_type="delete",
|
||||
filters={"action_id": "123"}
|
||||
)
|
||||
```
|
||||
5. 计数
|
||||
```python
|
||||
count = await database_api.db_query(
|
||||
Messages,
|
||||
query_type="count",
|
||||
filters={"chat_id": chat_stream.stream_id}
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 数据库保存
|
||||
```python
|
||||
async def db_save(
|
||||
model_class: Type[Model], data: Dict[str, Any], key_field: Optional[str] = None, key_value: Optional[Any] = None
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
```
|
||||
保存数据到数据库(创建或更新)
|
||||
|
||||
如果提供了key_field和key_value,会先尝试查找匹配的记录进行更新;
|
||||
|
||||
如果没有找到匹配记录,或未提供key_field和key_value,则创建新记录。
|
||||
|
||||
**Args:**
|
||||
- `model_class`: Peewee模型类。
|
||||
- `data`: 要保存的数据字典。
|
||||
- `key_field`: 用于查找现有记录的字段名,例如"action_id"。
|
||||
- `key_value`: 用于查找现有记录的字段值。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[Dict[str, Any]]`: 保存后的记录数据,失败时返回None。
|
||||
|
||||
#### 示例
|
||||
创建或更新一条记录
|
||||
```python
|
||||
record = await database_api.db_save(
|
||||
ActionRecords,
|
||||
{
|
||||
"action_id": "123",
|
||||
"time": time.time(),
|
||||
"action_name": "TestAction",
|
||||
"action_done": True
|
||||
},
|
||||
key_field="action_id",
|
||||
key_value="123"
|
||||
)
|
||||
```
|
||||
|
||||
### 3. 数据库获取
|
||||
```python
|
||||
async def db_get(
|
||||
model_class: Type[Model],
|
||||
filters: Optional[Dict[str, Any]] = None,
|
||||
limit: Optional[int] = None,
|
||||
order_by: Optional[str] = None,
|
||||
single_result: Optional[bool] = False,
|
||||
) -> Union[List[Dict[str, Any]], Dict[str, Any], None]:
|
||||
```
|
||||
|
||||
从数据库获取记录
|
||||
|
||||
这是db_query方法的简化版本,专注于数据检索操作。
|
||||
|
||||
**Args:**
|
||||
- `model_class`: Peewee模型类。
|
||||
- `filters`: 过滤条件字典,键为字段名,值为要匹配的值。
|
||||
- `limit`: 限制结果数量。
|
||||
- `order_by`: 排序字段,使用字段名,前缀'-'表示降序。
|
||||
- `single_result`: 是否只返回单个结果,如果为True,则返回单个记录字典或None;否则返回记录字典列表或空列表
|
||||
|
||||
**Returns:**
|
||||
- `Union[List[Dict], Dict, None]`: 查询结果列表或单个结果(如果`single_result=True`),失败时返回None。
|
||||
|
||||
#### 示例
|
||||
1. 获取单个记录
|
||||
```python
|
||||
record = await database_api.db_get(
|
||||
ActionRecords,
|
||||
filters={"action_id": "123"},
|
||||
limit=1
|
||||
)
|
||||
```
|
||||
2. 获取最近10条记录
|
||||
```python
|
||||
records = await database_api.db_get(
|
||||
Messages,
|
||||
filters={"chat_id": chat_stream.stream_id},
|
||||
limit=10,
|
||||
order_by="-time",
|
||||
)
|
||||
```
|
||||
|
||||
### 4. 动作信息存储
|
||||
```python
|
||||
async def store_action_info(
|
||||
chat_stream=None,
|
||||
action_build_into_prompt: bool = False,
|
||||
action_prompt_display: str = "",
|
||||
action_done: bool = True,
|
||||
thinking_id: str = "",
|
||||
action_data: Optional[dict] = None,
|
||||
action_name: str = "",
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
```
|
||||
存储动作信息到数据库,是一种针对 Action 的 `db_save()` 的封装函数。
|
||||
|
||||
将Action执行的相关信息保存到ActionRecords表中,用于后续的记忆和上下文构建。
|
||||
|
||||
**Args:**
|
||||
- `chat_stream`: 聊天流对象,包含聊天ID等信息。
|
||||
- `action_build_into_prompt`: 是否将动作信息构建到提示中。
|
||||
- `action_prompt_display`: 动作提示的显示文本。
|
||||
- `action_done`: 动作是否完成。
|
||||
- `thinking_id`: 思考过程的ID。
|
||||
- `action_data`: 动作的数据字典。
|
||||
- `action_name`: 动作的名称。
|
||||
|
||||
**Returns:**
|
||||
- `Optional[Dict[str, Any]]`: 存储后的记录数据,失败时返回None。
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
record = await database_api.store_action_info(
|
||||
chat_stream=chat_stream,
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display="执行了回复动作",
|
||||
action_done=True,
|
||||
thinking_id="thinking_123",
|
||||
action_data={"content": "Hello"},
|
||||
action_name="reply_action"
|
||||
)
|
||||
```
|
||||
141
docs/plugins/api/emoji-api.md
Normal file
141
docs/plugins/api/emoji-api.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# 表情包API
|
||||
|
||||
表情包API模块提供表情包的获取、查询和管理功能,让插件能够智能地选择和使用表情包。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import emoji_api
|
||||
# 或者
|
||||
from src.plugin_system import emoji_api
|
||||
```
|
||||
|
||||
## 二步走识别优化
|
||||
|
||||
从新版本开始,表情包识别系统采用了**二步走识别 + 智能缓存**的优化方案:
|
||||
|
||||
### **收到表情包时的识别流程**
|
||||
1. **第一步**:VLM视觉分析 - 生成详细描述
|
||||
2. **第二步**:LLM情感分析 - 基于详细描述提取核心情感标签
|
||||
3. **缓存机制**:将情感标签缓存到数据库,详细描述保存到Images表
|
||||
|
||||
### **注册表情包时的优化**
|
||||
- **智能复用**:优先从Images表获取已有的详细描述
|
||||
- **避免重复**:如果表情包之前被收到过,跳过VLM调用
|
||||
- **性能提升**:减少不必要的AI调用,降低延时和成本
|
||||
|
||||
### **缓存策略**
|
||||
- **ImageDescriptions表**:缓存最终的情感标签(用于快速显示)
|
||||
- **Images表**:保存详细描述(用于注册时复用)
|
||||
- **双重检查**:防止并发情况下的重复生成
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 表情包获取
|
||||
```python
|
||||
async def get_by_description(description: str) -> Optional[Tuple[str, str, str]]:
|
||||
```
|
||||
根据场景描述选择表情包
|
||||
|
||||
**Args:**
|
||||
- `description`:表情包的描述文本,例如"开心"、"难过"、"愤怒"等
|
||||
|
||||
**Returns:**
|
||||
- `Optional[Tuple[str, str, str]]`:一个元组: (表情包的base64编码, 描述, 情感标签),如果未找到匹配的表情包则返回None
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
emoji_result = await emoji_api.get_by_description("大笑")
|
||||
if emoji_result:
|
||||
emoji_base64, description, matched_scene = emoji_result
|
||||
print(f"获取到表情包: {description}, 场景: {matched_scene}")
|
||||
# 可以将emoji_base64用于发送表情包
|
||||
```
|
||||
|
||||
### 2. 随机获取表情包
|
||||
```python
|
||||
async def get_random(count: Optional[int] = 1) -> List[Tuple[str, str, str]]:
|
||||
```
|
||||
随机获取指定数量的表情包
|
||||
|
||||
**Args:**
|
||||
- `count`:要获取的表情包数量,默认为1
|
||||
|
||||
**Returns:**
|
||||
- `List[Tuple[str, str, str]]`:一个包含多个表情包的列表,每个元素是一个元组: (表情包的base64编码, 描述, 情感标签),如果未找到或出错则返回空列表
|
||||
|
||||
### 3. 根据情感获取表情包
|
||||
```python
|
||||
async def get_by_emotion(emotion: str) -> Optional[Tuple[str, str, str]]:
|
||||
```
|
||||
根据情感标签获取表情包
|
||||
|
||||
**Args:**
|
||||
- `emotion`:情感标签,例如"开心"、"悲伤"、"愤怒"等
|
||||
|
||||
**Returns:**
|
||||
- `Optional[Tuple[str, str, str]]`:一个元组: (表情包的base64编码, 描述, 情感标签),如果未找到则返回None
|
||||
|
||||
### 4. 获取表情包数量
|
||||
```python
|
||||
def get_count() -> int:
|
||||
```
|
||||
获取当前可用表情包的数量
|
||||
|
||||
### 5. 获取表情包系统信息
|
||||
```python
|
||||
def get_info() -> Dict[str, Any]:
|
||||
```
|
||||
获取表情包系统的基本信息
|
||||
|
||||
**Returns:**
|
||||
- `Dict[str, Any]`:包含表情包数量、描述等信息的字典,包含以下键:
|
||||
- `current_count`:当前表情包数量
|
||||
- `max_count`:最大表情包数量
|
||||
- `available_emojis`:当前可用的表情包数量
|
||||
|
||||
### 6. 获取所有可用的情感标签
|
||||
```python
|
||||
def get_emotions() -> List[str]:
|
||||
```
|
||||
获取所有可用的情感标签 **(已经去重)**
|
||||
|
||||
### 7. 获取所有表情包描述
|
||||
```python
|
||||
def get_descriptions() -> List[str]:
|
||||
```
|
||||
获取所有表情包的描述列表
|
||||
|
||||
## 场景描述说明
|
||||
|
||||
### 常用场景描述
|
||||
表情包系统支持多种具体的场景描述,举例如下:
|
||||
|
||||
- **开心类场景**:开心的大笑、满意的微笑、兴奋的手舞足蹈
|
||||
- **无奈类场景**:表示无奈和沮丧、轻微的讽刺、无语的摇头
|
||||
- **愤怒类场景**:愤怒和不满、生气的瞪视、暴躁的抓狂
|
||||
- **惊讶类场景**:震惊的表情、意外的发现、困惑的思考
|
||||
- **可爱类场景**:卖萌的表情、撒娇的动作、害羞的样子
|
||||
|
||||
### 情感关键词示例
|
||||
系统支持的情感关键词举例如下:
|
||||
- 大笑、微笑、兴奋、手舞足蹈
|
||||
- 无奈、沮丧、讽刺、无语、摇头
|
||||
- 愤怒、不满、生气、瞪视、抓狂
|
||||
- 震惊、意外、困惑、思考
|
||||
- 卖萌、撒娇、害羞、可爱
|
||||
|
||||
### 匹配机制
|
||||
- **精确匹配**:优先匹配完整的场景描述,如"开心的大笑"
|
||||
- **关键词匹配**:如果没有精确匹配,则根据关键词进行模糊匹配
|
||||
- **语义匹配**:系统会理解场景的语义含义进行智能匹配
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **异步函数**:部分函数是异步的,需要使用 `await`
|
||||
2. **返回格式**:表情包以base64编码返回,可直接用于发送
|
||||
3. **错误处理**:所有函数都有错误处理,失败时返回None,空列表或默认值
|
||||
4. **使用统计**:系统会记录表情包的使用次数
|
||||
5. **文件依赖**:表情包依赖于本地文件,确保表情包文件存在
|
||||
6. **编码格式**:返回的是base64编码的图片数据,可直接用于网络传输
|
||||
7. **场景理解**:系统能理解具体的场景描述,比简单的情感分类更准确
|
||||
201
docs/plugins/api/generator-api.md
Normal file
201
docs/plugins/api/generator-api.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 回复生成器API
|
||||
|
||||
回复生成器API模块提供智能回复生成功能,让插件能够使用系统的回复生成器来产生自然的聊天回复。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import generator_api
|
||||
# 或者
|
||||
from src.plugin_system import generator_api
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 回复器获取
|
||||
```python
|
||||
def get_replyer(
|
||||
chat_stream: Optional[ChatStream] = None,
|
||||
chat_id: Optional[str] = None,
|
||||
model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
|
||||
request_type: str = "replyer",
|
||||
) -> Optional[DefaultReplyer]:
|
||||
```
|
||||
获取回复器对象
|
||||
|
||||
优先使用chat_stream,如果没有则使用chat_id直接查找。
|
||||
|
||||
使用 ReplyerManager 来管理实例,避免重复创建。
|
||||
|
||||
**Args:**
|
||||
- `chat_stream`: 聊天流对象
|
||||
- `chat_id`: 聊天ID(实际上就是`stream_id`)
|
||||
- `model_set_with_weight`: 模型配置列表,每个元素为 `(TaskConfig, weight)` 元组
|
||||
- `request_type`: 请求类型,用于记录LLM使用情况,可以不写
|
||||
|
||||
**Returns:**
|
||||
- `DefaultReplyer`: 回复器对象,如果获取失败则返回None
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
# 使用聊天流获取回复器
|
||||
replyer = generator_api.get_replyer(chat_stream=chat_stream)
|
||||
|
||||
# 使用平台和ID获取回复器
|
||||
replyer = generator_api.get_replyer(chat_id="123456789")
|
||||
```
|
||||
|
||||
### 2. 回复生成
|
||||
```python
|
||||
async def generate_reply(
|
||||
chat_stream: Optional[ChatStream] = None,
|
||||
chat_id: Optional[str] = None,
|
||||
action_data: Optional[Dict[str, Any]] = None,
|
||||
reply_to: str = "",
|
||||
extra_info: str = "",
|
||||
available_actions: Optional[Dict[str, ActionInfo]] = None,
|
||||
enable_tool: bool = False,
|
||||
enable_splitter: bool = True,
|
||||
enable_chinese_typo: bool = True,
|
||||
return_prompt: bool = False,
|
||||
model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
|
||||
request_type: str = "generator_api",
|
||||
) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
|
||||
```
|
||||
生成回复
|
||||
|
||||
优先使用chat_stream,如果没有则使用chat_id直接查找。
|
||||
|
||||
**Args:**
|
||||
- `chat_stream`: 聊天流对象
|
||||
- `chat_id`: 聊天ID(实际上就是`stream_id`)
|
||||
- `action_data`: 动作数据(向下兼容,包含`reply_to`和`extra_info`)
|
||||
- `reply_to`: 回复目标,格式为 `{发送者的person_name:消息内容}`
|
||||
- `extra_info`: 附加信息
|
||||
- `available_actions`: 可用动作字典,格式为 `{"action_name": ActionInfo}`
|
||||
- `enable_tool`: 是否启用工具
|
||||
- `enable_splitter`: 是否启用分割器
|
||||
- `enable_chinese_typo`: 是否启用中文错别字
|
||||
- `return_prompt`: 是否返回提示词
|
||||
- `model_set_with_weight`: 模型配置列表,每个元素为 `(TaskConfig, weight)` 元组
|
||||
- `request_type`: 请求类型(可选,记录LLM使用)
|
||||
- `request_type`: 请求类型,用于记录LLM使用情况
|
||||
|
||||
**Returns:**
|
||||
- `Tuple[bool, List[Tuple[str, Any]], Optional[str]]`: (是否成功, 回复集合, 提示词)
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
success, reply_set, prompt = await generator_api.generate_reply(
|
||||
chat_stream=chat_stream,
|
||||
action_data=action_data,
|
||||
reply_to="麦麦:你好",
|
||||
available_actions=action_info,
|
||||
enable_tool=True,
|
||||
return_prompt=True
|
||||
)
|
||||
if success:
|
||||
for reply_type, reply_content in reply_set:
|
||||
print(f"回复类型: {reply_type}, 内容: {reply_content}")
|
||||
if prompt:
|
||||
print(f"使用的提示词: {prompt}")
|
||||
```
|
||||
|
||||
### 3. 回复重写
|
||||
```python
|
||||
async def rewrite_reply(
|
||||
chat_stream: Optional[ChatStream] = None,
|
||||
reply_data: Optional[Dict[str, Any]] = None,
|
||||
chat_id: Optional[str] = None,
|
||||
enable_splitter: bool = True,
|
||||
enable_chinese_typo: bool = True,
|
||||
model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
|
||||
raw_reply: str = "",
|
||||
reason: str = "",
|
||||
reply_to: str = "",
|
||||
return_prompt: bool = False,
|
||||
) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
|
||||
```
|
||||
重写回复,使用新的内容替换旧的回复内容。
|
||||
|
||||
优先使用chat_stream,如果没有则使用chat_id直接查找。
|
||||
|
||||
**Args:**
|
||||
- `chat_stream`: 聊天流对象
|
||||
- `reply_data`: 回复数据,包含`raw_reply`, `reason`和`reply_to`,**(向下兼容备用,当其他参数缺失时从此获取)**
|
||||
- `chat_id`: 聊天ID(实际上就是`stream_id`)
|
||||
- `enable_splitter`: 是否启用分割器
|
||||
- `enable_chinese_typo`: 是否启用中文错别字
|
||||
- `model_set_with_weight`: 模型配置列表,每个元素为 (TaskConfig, weight) 元组
|
||||
- `raw_reply`: 原始回复内容
|
||||
- `reason`: 重写原因
|
||||
- `reply_to`: 回复目标,格式为 `{发送者的person_name:消息内容}`
|
||||
|
||||
**Returns:**
|
||||
- `Tuple[bool, List[Tuple[str, Any]], Optional[str]]`: (是否成功, 回复集合, 提示词)
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
success, reply_set, prompt = await generator_api.rewrite_reply(
|
||||
chat_stream=chat_stream,
|
||||
raw_reply="原始回复内容",
|
||||
reason="重写原因",
|
||||
reply_to="麦麦:你好",
|
||||
return_prompt=True
|
||||
)
|
||||
if success:
|
||||
for reply_type, reply_content in reply_set:
|
||||
print(f"回复类型: {reply_type}, 内容: {reply_content}")
|
||||
if prompt:
|
||||
print(f"使用的提示词: {prompt}")
|
||||
```
|
||||
|
||||
## 回复集合`reply_set`格式
|
||||
|
||||
### 回复类型
|
||||
生成的回复集合包含多种类型的回复:
|
||||
|
||||
- `"text"`:纯文本回复
|
||||
- `"emoji"`:表情包回复
|
||||
- `"image"`:图片回复
|
||||
- `"mixed"`:混合类型回复
|
||||
|
||||
### 回复集合结构
|
||||
```python
|
||||
# 示例回复集合
|
||||
reply_set = [
|
||||
("text", "很高兴见到你!"),
|
||||
("emoji", "emoji_base64_data"),
|
||||
("text", "有什么可以帮助你的吗?")
|
||||
]
|
||||
```
|
||||
|
||||
### 4. 自定义提示词回复
|
||||
```python
|
||||
async def generate_response_custom(
|
||||
chat_stream: Optional[ChatStream] = None,
|
||||
chat_id: Optional[str] = None,
|
||||
model_set_with_weight: Optional[List[Tuple[TaskConfig, float]]] = None,
|
||||
prompt: str = "",
|
||||
) -> Optional[str]:
|
||||
```
|
||||
生成自定义提示词回复
|
||||
|
||||
优先使用chat_stream,如果没有则使用chat_id直接查找。
|
||||
|
||||
**Args:**
|
||||
- `chat_stream`: 聊天流对象
|
||||
- `chat_id`: 聊天ID(备用)
|
||||
- `model_set_with_weight`: 模型集合配置列表
|
||||
- `prompt`: 自定义提示词
|
||||
|
||||
**Returns:**
|
||||
- `Optional[str]`: 生成的自定义回复内容,如果生成失败则返回None
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **异步操作**:部分函数是异步的,须使用`await`
|
||||
2. **聊天流依赖**:需要有效的聊天流对象才能正常工作
|
||||
3. **性能考虑**:回复生成可能需要一些时间,特别是使用LLM时
|
||||
4. **回复格式**:返回的回复集合是元组列表,包含类型和内容
|
||||
5. **上下文感知**:生成器会考虑聊天上下文和历史消息,除非你用的是自定义提示词。
|
||||
65
docs/plugins/api/llm-api.md
Normal file
65
docs/plugins/api/llm-api.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# LLM API
|
||||
|
||||
LLM API模块提供与大语言模型交互的功能,让插件能够使用系统配置的LLM模型进行内容生成。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import llm_api
|
||||
# 或者
|
||||
from src.plugin_system import llm_api
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 查询可用模型
|
||||
```python
|
||||
def get_available_models() -> Dict[str, TaskConfig]:
|
||||
```
|
||||
获取所有可用的模型配置。
|
||||
|
||||
**Return:**
|
||||
- `Dict[str, TaskConfig]`:模型配置字典,key为模型名称,value为模型配置对象。
|
||||
|
||||
### 2. 使用模型生成内容
|
||||
```python
|
||||
async def generate_with_model(
|
||||
prompt: str,
|
||||
model_config: TaskConfig,
|
||||
request_type: str = "plugin.generate",
|
||||
temperature: Optional[float] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
) -> Tuple[bool, str, str, str]:
|
||||
```
|
||||
使用指定模型生成内容。
|
||||
|
||||
**Args:**
|
||||
- `prompt`:提示词。
|
||||
- `model_config`:模型配置对象(从 `get_available_models` 获取)。
|
||||
- `request_type`:请求类型标识,默认为 `"plugin.generate"`。
|
||||
- `temperature`:生成内容的温度设置,影响输出的随机性。
|
||||
- `max_tokens`:生成内容的最大token数。
|
||||
|
||||
**Return:**
|
||||
- `Tuple[bool, str, str, str]`:返回一个元组,包含(是否成功, 生成的内容, 推理过程, 模型名称)。
|
||||
|
||||
### 3. 有Tool情况下使用模型生成内容
|
||||
```python
|
||||
async def generate_with_model_with_tools(
|
||||
prompt: str,
|
||||
model_config: TaskConfig,
|
||||
tool_options: List[Dict[str, Any]] | None = None,
|
||||
request_type: str = "plugin.generate",
|
||||
temperature: Optional[float] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
) -> Tuple[bool, str, str, str, List[ToolCall] | None]:
|
||||
```
|
||||
使用指定模型生成内容,并支持工具调用。
|
||||
|
||||
**Args:**
|
||||
- `prompt`:提示词。
|
||||
- `model_config`:模型配置对象(从 `get_available_models` 获取)。
|
||||
- `tool_options`:工具选项列表,包含可用工具的配置,字典为每一个工具的定义,参见[tool-components.md](../tool-components.md#属性说明),可用`tool_api.get_llm_available_tool_definitions()`获取并选择。
|
||||
- `request_type`:请求类型标识,默认为 `"plugin.generate"`。
|
||||
- `temperature`:生成内容的温度设置,影响输出的随机性。
|
||||
- `max_tokens`:生成内容的最大token数。
|
||||
29
docs/plugins/api/logging-api.md
Normal file
29
docs/plugins/api/logging-api.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Logging API
|
||||
|
||||
Logging API模块提供了获取本体logger的功能,允许插件记录日志信息。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import get_logger
|
||||
# 或者
|
||||
from src.plugin_system import get_logger
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
### 1. 获取本体logger
|
||||
```python
|
||||
def get_logger(name: str) -> structlog.stdlib.BoundLogger:
|
||||
```
|
||||
获取本体logger实例。
|
||||
|
||||
**Args:**
|
||||
- `name` (str): 日志记录器的名称。
|
||||
|
||||
**Returns:**
|
||||
- 一个logger实例,有以下方法:
|
||||
- `debug`
|
||||
- `info`
|
||||
- `warning`
|
||||
- `error`
|
||||
- `critical`
|
||||
372
docs/plugins/api/message-api.md
Normal file
372
docs/plugins/api/message-api.md
Normal file
@@ -0,0 +1,372 @@
|
||||
# 消息API
|
||||
|
||||
消息API提供了强大的消息查询、计数和格式化功能,让你轻松处理聊天消息数据。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import message_api
|
||||
# 或者
|
||||
from src.plugin_system import message_api
|
||||
```
|
||||
|
||||
## 功能概述
|
||||
|
||||
消息API主要提供三大类功能:
|
||||
- **消息查询** - 按时间、聊天、用户等条件查询消息
|
||||
- **消息计数** - 统计新消息数量
|
||||
- **消息格式化** - 将消息转换为可读格式
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 按照事件查询消息
|
||||
```python
|
||||
def get_messages_by_time(
|
||||
start_time: float, end_time: float, limit: int = 0, limit_mode: str = "latest", filter_mai: bool = False
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定时间范围内的消息。
|
||||
|
||||
**Args:**
|
||||
- `start_time` (float): 开始时间戳
|
||||
- `end_time` (float): 结束时间戳
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
|
||||
- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
消息列表中包含的键与`Messages`类的属性一致。(位于`src.common.database.database_model`)
|
||||
|
||||
### 2. 获取指定聊天中指定时间范围内的信息
|
||||
```python
|
||||
def get_messages_by_time_in_chat(
|
||||
chat_id: str,
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
filter_mai: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定聊天中指定时间范围内的消息。
|
||||
|
||||
**Args:**
|
||||
- `chat_id` (str): 聊天ID
|
||||
- `start_time` (float): 开始时间戳
|
||||
- `end_time` (float): 结束时间戳
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
|
||||
- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 3. 获取指定聊天中指定时间范围内的信息(包含边界)
|
||||
```python
|
||||
def get_messages_by_time_in_chat_inclusive(
|
||||
chat_id: str,
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
filter_mai: bool = False,
|
||||
filter_command: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定聊天中指定时间范围内的消息(包含边界)。
|
||||
|
||||
**Args:**
|
||||
- `chat_id` (str): 聊天ID
|
||||
- `start_time` (float): 开始时间戳(包含)
|
||||
- `end_time` (float): 结束时间戳(包含)
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
|
||||
- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
|
||||
- `filter_command` (bool): 是否过滤命令消息,默认False
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 4. 获取指定聊天中指定用户在指定时间范围内的消息
|
||||
```python
|
||||
def get_messages_by_time_in_chat_for_users(
|
||||
chat_id: str,
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
person_ids: List[str],
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定聊天中指定用户在指定时间范围内的消息。
|
||||
|
||||
**Args:**
|
||||
- `chat_id` (str): 聊天ID
|
||||
- `start_time` (float): 开始时间戳
|
||||
- `end_time` (float): 结束时间戳
|
||||
- `person_ids` (List[str]): 用户ID列表
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 5. 随机选择一个聊天,返回该聊天在指定时间范围内的消息
|
||||
```python
|
||||
def get_random_chat_messages(
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
filter_mai: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
随机选择一个聊天,返回该聊天在指定时间范围内的消息。
|
||||
|
||||
**Args:**
|
||||
- `start_time` (float): 开始时间戳
|
||||
- `end_time` (float): 结束时间戳
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
|
||||
- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 6. 获取指定用户在所有聊天中指定时间范围内的消息
|
||||
```python
|
||||
def get_messages_by_time_for_users(
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
person_ids: List[str],
|
||||
limit: int = 0,
|
||||
limit_mode: str = "latest",
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定用户在所有聊天中指定时间范围内的消息。
|
||||
|
||||
**Args:**
|
||||
- `start_time` (float): 开始时间戳
|
||||
- `end_time` (float): 结束时间戳
|
||||
- `person_ids` (List[str]): 用户ID列表
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 7. 获取指定时间戳之前的消息
|
||||
```python
|
||||
def get_messages_before_time(
|
||||
timestamp: float,
|
||||
limit: int = 0,
|
||||
filter_mai: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定时间戳之前的消息。
|
||||
|
||||
**Args:**
|
||||
- `timestamp` (float): 时间戳
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 8. 获取指定聊天中指定时间戳之前的消息
|
||||
```python
|
||||
def get_messages_before_time_in_chat(
|
||||
chat_id: str,
|
||||
timestamp: float,
|
||||
limit: int = 0,
|
||||
filter_mai: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定聊天中指定时间戳之前的消息。
|
||||
|
||||
**Args:**
|
||||
- `chat_id` (str): 聊天ID
|
||||
- `timestamp` (float): 时间戳
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 9. 获取指定用户在指定时间戳之前的消息
|
||||
```python
|
||||
def get_messages_before_time_for_users(
|
||||
timestamp: float,
|
||||
person_ids: List[str],
|
||||
limit: int = 0,
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定用户在指定时间戳之前的消息。
|
||||
|
||||
**Args:**
|
||||
- `timestamp` (float): 时间戳
|
||||
- `person_ids` (List[str]): 用户ID列表
|
||||
- `limit` (int): 限制返回消息数量,0为不限制
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 10. 获取指定聊天中最近一段时间的消息
|
||||
```python
|
||||
def get_recent_messages(
|
||||
chat_id: str,
|
||||
hours: float = 24.0,
|
||||
limit: int = 100,
|
||||
limit_mode: str = "latest",
|
||||
filter_mai: bool = False,
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
获取指定聊天中最近一段时间的消息。
|
||||
|
||||
**Args:**
|
||||
- `chat_id` (str): 聊天ID
|
||||
- `hours` (float): 最近多少小时,默认24小时
|
||||
- `limit` (int): 限制返回消息数量,默认100条
|
||||
- `limit_mode` (str): 限制模式,`"earliest"`获取最早记录,`"latest"`获取最新记录
|
||||
- `filter_mai` (bool): 是否过滤掉机器人的消息,默认False
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 消息列表
|
||||
|
||||
|
||||
### 11. 计算指定聊天中从开始时间到结束时间的新消息数量
|
||||
```python
|
||||
def count_new_messages(
|
||||
chat_id: str,
|
||||
start_time: float = 0.0,
|
||||
end_time: Optional[float] = None,
|
||||
) -> int:
|
||||
```
|
||||
计算指定聊天中从开始时间到结束时间的新消息数量。
|
||||
|
||||
**Args:**
|
||||
- `chat_id` (str): 聊天ID
|
||||
- `start_time` (float): 开始时间戳
|
||||
- `end_time` (Optional[float]): 结束时间戳,如果为None则使用当前时间
|
||||
|
||||
**Returns:**
|
||||
- `int` - 新消息数量
|
||||
|
||||
|
||||
### 12. 计算指定聊天中指定用户从开始时间到结束时间的新消息数量
|
||||
```python
|
||||
def count_new_messages_for_users(
|
||||
chat_id: str,
|
||||
start_time: float,
|
||||
end_time: float,
|
||||
person_ids: List[str],
|
||||
) -> int:
|
||||
```
|
||||
计算指定聊天中指定用户从开始时间到结束时间的新消息数量。
|
||||
|
||||
**Args:**
|
||||
- `chat_id` (str): 聊天ID
|
||||
- `start_time` (float): 开始时间戳
|
||||
- `end_time` (float): 结束时间戳
|
||||
- `person_ids` (List[str]): 用户ID列表
|
||||
|
||||
**Returns:**
|
||||
- `int` - 新消息数量
|
||||
|
||||
|
||||
### 13. 将消息列表构建成可读的字符串
|
||||
```python
|
||||
def build_readable_messages_to_str(
|
||||
messages: List[Dict[str, Any]],
|
||||
replace_bot_name: bool = True,
|
||||
merge_messages: bool = False,
|
||||
timestamp_mode: str = "relative",
|
||||
read_mark: float = 0.0,
|
||||
truncate: bool = False,
|
||||
show_actions: bool = False,
|
||||
) -> str:
|
||||
```
|
||||
将消息列表构建成可读的字符串。
|
||||
|
||||
**Args:**
|
||||
- `messages` (List[Dict[str, Any]]): 消息列表
|
||||
- `replace_bot_name` (bool): 是否将机器人的名称替换为"你"
|
||||
- `merge_messages` (bool): 是否合并连续消息
|
||||
- `timestamp_mode` (str): 时间戳显示模式,`"relative"`或`"absolute"`
|
||||
- `read_mark` (float): 已读标记时间戳,用于分割已读和未读消息
|
||||
- `truncate` (bool): 是否截断长消息
|
||||
- `show_actions` (bool): 是否显示动作记录
|
||||
|
||||
**Returns:**
|
||||
- `str` - 格式化后的可读字符串
|
||||
|
||||
|
||||
### 14. 将消息列表构建成可读的字符串,并返回详细信息
|
||||
```python
|
||||
async def build_readable_messages_with_details(
|
||||
messages: List[Dict[str, Any]],
|
||||
replace_bot_name: bool = True,
|
||||
merge_messages: bool = False,
|
||||
timestamp_mode: str = "relative",
|
||||
truncate: bool = False,
|
||||
) -> Tuple[str, List[Tuple[float, str, str]]]:
|
||||
```
|
||||
将消息列表构建成可读的字符串,并返回详细信息。
|
||||
|
||||
**Args:**
|
||||
- `messages` (List[Dict[str, Any]]): 消息列表
|
||||
- `replace_bot_name` (bool): 是否将机器人的名称替换为"你"
|
||||
- `merge_messages` (bool): 是否合并连续消息
|
||||
- `timestamp_mode` (str): 时间戳显示模式,`"relative"`或`"absolute"`
|
||||
- `truncate` (bool): 是否截断长消息
|
||||
|
||||
**Returns:**
|
||||
- `Tuple[str, List[Tuple[float, str, str]]]` - 格式化后的可读字符串和详细信息元组列表(时间戳, 昵称, 内容)
|
||||
|
||||
|
||||
### 15. 从消息列表中提取不重复的用户ID列表
|
||||
```python
|
||||
async def get_person_ids_from_messages(
|
||||
messages: List[Dict[str, Any]],
|
||||
) -> List[str]:
|
||||
```
|
||||
从消息列表中提取不重复的用户ID列表。
|
||||
|
||||
**Args:**
|
||||
- `messages` (List[Dict[str, Any]]): 消息列表
|
||||
|
||||
**Returns:**
|
||||
- `List[str]` - 用户ID列表
|
||||
|
||||
|
||||
### 16. 从消息列表中移除机器人的消息
|
||||
```python
|
||||
def filter_mai_messages(
|
||||
messages: List[Dict[str, Any]],
|
||||
) -> List[Dict[str, Any]]:
|
||||
```
|
||||
从消息列表中移除机器人的消息。
|
||||
|
||||
**Args:**
|
||||
- `messages` (List[Dict[str, Any]]): 消息列表,每个元素是消息字典
|
||||
|
||||
**Returns:**
|
||||
- `List[Dict[str, Any]]` - 过滤后的消息列表
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **时间戳格式**:所有时间参数都使用Unix时间戳(float类型)
|
||||
2. **异步函数**:部分函数是异步函数,需要使用 `await`
|
||||
3. **性能考虑**:查询大量消息时建议设置合理的 `limit` 参数
|
||||
4. **消息格式**:返回的消息是字典格式,包含时间戳、发送者、内容等信息
|
||||
5. **用户ID**:`person_ids` 参数接受字符串列表,用于筛选特定用户的消息
|
||||
119
docs/plugins/api/person-api.md
Normal file
119
docs/plugins/api/person-api.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# 个人信息API
|
||||
|
||||
个人信息API模块提供用户信息查询和管理功能,让插件能够获取和使用用户的相关信息。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import person_api
|
||||
# 或者
|
||||
from src.plugin_system import person_api
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. Person ID 获取
|
||||
```python
|
||||
def get_person_id(platform: str, user_id: int) -> str:
|
||||
```
|
||||
根据平台和用户ID获取person_id
|
||||
|
||||
**Args:**
|
||||
- `platform`:平台名称,如 "qq", "telegram" 等
|
||||
- `user_id`:用户ID
|
||||
|
||||
**Returns:**
|
||||
- `str`:唯一的person_id(MD5哈希值)
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
person_id = person_api.get_person_id("qq", 123456)
|
||||
```
|
||||
|
||||
### 2. 用户信息查询
|
||||
```python
|
||||
async def get_person_value(person_id: str, field_name: str, default: Any = None) -> Any:
|
||||
```
|
||||
查询单个用户信息字段值
|
||||
|
||||
**Args:**
|
||||
- `person_id`:用户的唯一标识ID
|
||||
- `field_name`:要获取的字段名
|
||||
- `default`:字段值不存在时的默认值
|
||||
|
||||
**Returns:**
|
||||
- `Any`:字段值或默认值
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
nickname = await person_api.get_person_value(person_id, "nickname", "未知用户")
|
||||
impression = await person_api.get_person_value(person_id, "impression")
|
||||
```
|
||||
|
||||
### 3. 批量用户信息查询
|
||||
```python
|
||||
async def get_person_values(person_id: str, field_names: list, default_dict: Optional[dict] = None) -> dict:
|
||||
```
|
||||
批量获取用户信息字段值
|
||||
|
||||
**Args:**
|
||||
- `person_id`:用户的唯一标识ID
|
||||
- `field_names`:要获取的字段名列表
|
||||
- `default_dict`:默认值字典,键为字段名,值为默认值
|
||||
|
||||
**Returns:**
|
||||
- `dict`:字段名到值的映射字典
|
||||
|
||||
#### 示例
|
||||
```python
|
||||
values = await person_api.get_person_values(
|
||||
person_id,
|
||||
["nickname", "impression", "know_times"],
|
||||
{"nickname": "未知用户", "know_times": 0}
|
||||
)
|
||||
```
|
||||
|
||||
### 4. 判断用户是否已知
|
||||
```python
|
||||
async def is_person_known(platform: str, user_id: int) -> bool:
|
||||
```
|
||||
判断是否认识某个用户
|
||||
|
||||
**Args:**
|
||||
- `platform`:平台名称
|
||||
- `user_id`:用户ID
|
||||
|
||||
**Returns:**
|
||||
- `bool`:是否认识该用户
|
||||
|
||||
### 5. 根据用户名获取Person ID
|
||||
```python
|
||||
def get_person_id_by_name(person_name: str) -> str:
|
||||
```
|
||||
根据用户名获取person_id
|
||||
|
||||
**Args:**
|
||||
- `person_name`:用户名
|
||||
|
||||
**Returns:**
|
||||
- `str`:person_id,如果未找到返回空字符串
|
||||
|
||||
## 常用字段说明
|
||||
|
||||
### 基础信息字段
|
||||
- `nickname`:用户昵称
|
||||
- `platform`:平台信息
|
||||
- `user_id`:用户ID
|
||||
|
||||
### 关系信息字段
|
||||
- `impression`:对用户的印象
|
||||
- `points`: 用户特征点
|
||||
|
||||
其他字段可以参考`PersonInfo`类的属性(位于`src.common.database.database_model`)
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **异步操作**:部分查询函数都是异步的,需要使用`await`
|
||||
2. **性能考虑**:批量查询优于单个查询
|
||||
3. **隐私保护**:确保用户信息的使用符合隐私政策
|
||||
4. **数据一致性**:person_id是用户的唯一标识,应妥善保存和使用
|
||||
105
docs/plugins/api/plugin-manage-api.md
Normal file
105
docs/plugins/api/plugin-manage-api.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# 插件管理API
|
||||
|
||||
插件管理API模块提供了对插件的加载、卸载、重新加载以及目录管理功能。
|
||||
|
||||
## 导入方式
|
||||
```python
|
||||
from src.plugin_system.apis import plugin_manage_api
|
||||
# 或者
|
||||
from src.plugin_system import plugin_manage_api
|
||||
```
|
||||
|
||||
## 功能概述
|
||||
|
||||
插件管理API主要提供以下功能:
|
||||
- **插件查询** - 列出当前加载的插件或已注册的插件。
|
||||
- **插件管理** - 加载、卸载、重新加载插件。
|
||||
- **插件目录管理** - 添加插件目录并重新扫描。
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 列出当前加载的插件
|
||||
```python
|
||||
def list_loaded_plugins() -> List[str]:
|
||||
```
|
||||
列出所有当前加载的插件。
|
||||
|
||||
**Returns:**
|
||||
- `List[str]` - 当前加载的插件名称列表。
|
||||
|
||||
### 2. 列出所有已注册的插件
|
||||
```python
|
||||
def list_registered_plugins() -> List[str]:
|
||||
```
|
||||
列出所有已注册的插件。
|
||||
|
||||
**Returns:**
|
||||
- `List[str]` - 已注册的插件名称列表。
|
||||
|
||||
### 3. 获取插件路径
|
||||
```python
|
||||
def get_plugin_path(plugin_name: str) -> str:
|
||||
```
|
||||
获取指定插件的路径。
|
||||
|
||||
**Args:**
|
||||
- `plugin_name` (str): 要查询的插件名称。
|
||||
**Returns:**
|
||||
- `str` - 插件的路径,如果插件不存在则 raise ValueError。
|
||||
|
||||
### 4. 卸载指定的插件
|
||||
```python
|
||||
async def remove_plugin(plugin_name: str) -> bool:
|
||||
```
|
||||
卸载指定的插件。
|
||||
|
||||
**Args:**
|
||||
- `plugin_name` (str): 要卸载的插件名称。
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 卸载是否成功。
|
||||
|
||||
### 5. 重新加载指定的插件
|
||||
```python
|
||||
async def reload_plugin(plugin_name: str) -> bool:
|
||||
```
|
||||
重新加载指定的插件。
|
||||
|
||||
**Args:**
|
||||
- `plugin_name` (str): 要重新加载的插件名称。
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 重新加载是否成功。
|
||||
|
||||
### 6. 加载指定的插件
|
||||
```python
|
||||
def load_plugin(plugin_name: str) -> Tuple[bool, int]:
|
||||
```
|
||||
加载指定的插件。
|
||||
|
||||
**Args:**
|
||||
- `plugin_name` (str): 要加载的插件名称。
|
||||
|
||||
**Returns:**
|
||||
- `Tuple[bool, int]` - 加载是否成功,成功或失败的个数。
|
||||
|
||||
### 7. 添加插件目录
|
||||
```python
|
||||
def add_plugin_directory(plugin_directory: str) -> bool:
|
||||
```
|
||||
添加插件目录。
|
||||
|
||||
**Args:**
|
||||
- `plugin_directory` (str): 要添加的插件目录路径。
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 添加是否成功。
|
||||
|
||||
### 8. 重新扫描插件目录
|
||||
```python
|
||||
def rescan_plugin_directory() -> Tuple[int, int]:
|
||||
```
|
||||
重新扫描插件目录,加载新插件。
|
||||
|
||||
**Returns:**
|
||||
- `Tuple[int, int]` - 成功加载的插件数量和失败的插件数量。
|
||||
175
docs/plugins/api/send-api.md
Normal file
175
docs/plugins/api/send-api.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# 消息发送API
|
||||
|
||||
消息发送API模块专门负责发送各种类型的消息,支持文本、表情包、图片等多种消息类型。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import send_api
|
||||
# 或者
|
||||
from src.plugin_system import send_api
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 发送文本消息
|
||||
```python
|
||||
async def text_to_stream(
|
||||
text: str,
|
||||
stream_id: str,
|
||||
typing: bool = False,
|
||||
reply_to: str = "",
|
||||
storage_message: bool = True,
|
||||
) -> bool:
|
||||
```
|
||||
发送文本消息到指定的流
|
||||
|
||||
**Args:**
|
||||
- `text` (str): 要发送的文本内容
|
||||
- `stream_id` (str): 聊天流ID
|
||||
- `typing` (bool): 是否显示正在输入
|
||||
- `reply_to` (str): 回复消息,格式为"发送者:消息内容"
|
||||
- `storage_message` (bool): 是否存储消息到数据库
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 是否发送成功
|
||||
|
||||
### 2. 发送表情包
|
||||
```python
|
||||
async def emoji_to_stream(emoji_base64: str, stream_id: str, storage_message: bool = True) -> bool:
|
||||
```
|
||||
向指定流发送表情包。
|
||||
|
||||
**Args:**
|
||||
- `emoji_base64` (str): 表情包的base64编码
|
||||
- `stream_id` (str): 聊天流ID
|
||||
- `storage_message` (bool): 是否存储消息到数据库
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 是否发送成功
|
||||
|
||||
### 3. 发送图片
|
||||
```python
|
||||
async def image_to_stream(image_base64: str, stream_id: str, storage_message: bool = True) -> bool:
|
||||
```
|
||||
向指定流发送图片。
|
||||
|
||||
**Args:**
|
||||
- `image_base64` (str): 图片的base64编码
|
||||
- `stream_id` (str): 聊天流ID
|
||||
- `storage_message` (bool): 是否存储消息到数据库
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 是否发送成功
|
||||
|
||||
### 4. 发送命令
|
||||
```python
|
||||
async def command_to_stream(command: Union[str, dict], stream_id: str, storage_message: bool = True, display_message: str = "") -> bool:
|
||||
```
|
||||
向指定流发送命令。
|
||||
|
||||
**Args:**
|
||||
- `command` (Union[str, dict]): 命令内容
|
||||
- `stream_id` (str): 聊天流ID
|
||||
- `storage_message` (bool): 是否存储消息到数据库
|
||||
- `display_message` (str): 显示消息
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 是否发送成功
|
||||
|
||||
### 5. 发送自定义类型消息
|
||||
```python
|
||||
async def custom_to_stream(
|
||||
message_type: str,
|
||||
content: str,
|
||||
stream_id: str,
|
||||
display_message: str = "",
|
||||
typing: bool = False,
|
||||
reply_to: str = "",
|
||||
storage_message: bool = True,
|
||||
show_log: bool = True,
|
||||
) -> bool:
|
||||
```
|
||||
向指定流发送自定义类型消息。
|
||||
|
||||
**Args:**
|
||||
- `message_type` (str): 消息类型,如"text"、"image"、"emoji"、"video"、"file"等
|
||||
- `content` (str): 消息内容(通常是base64编码或文本)
|
||||
- `stream_id` (str): 聊天流ID
|
||||
- `display_message` (str): 显示消息
|
||||
- `typing` (bool): 是否显示正在输入
|
||||
- `reply_to` (str): 回复消息,格式为"发送者:消息内容"
|
||||
- `storage_message` (bool): 是否存储消息到数据库
|
||||
- `show_log` (bool): 是否显示日志
|
||||
|
||||
**Returns:**
|
||||
- `bool` - 是否发送成功
|
||||
|
||||
## 使用示例
|
||||
|
||||
### 1. 基础文本发送,并回复消息
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import send_api
|
||||
|
||||
async def send_hello(chat_stream):
|
||||
"""发送问候消息"""
|
||||
|
||||
success = await send_api.text_to_stream(
|
||||
text="Hello, world!",
|
||||
stream_id=chat_stream.stream_id,
|
||||
typing=True,
|
||||
reply_to="User:How are you?",
|
||||
storage_message=True
|
||||
)
|
||||
|
||||
return success
|
||||
```
|
||||
|
||||
### 2. 发送表情包
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import emoji_api
|
||||
async def send_emoji_reaction(chat_stream, emotion):
|
||||
"""根据情感发送表情包"""
|
||||
# 获取表情包
|
||||
emoji_result = await emoji_api.get_by_emotion(emotion)
|
||||
if not emoji_result:
|
||||
return False
|
||||
|
||||
emoji_base64, description, matched_emotion = emoji_result
|
||||
|
||||
# 发送表情包
|
||||
success = await send_api.emoji_to_stream(
|
||||
emoji_base64=emoji_base64,
|
||||
stream_id=chat_stream.stream_id,
|
||||
storage_message=False # 不存储到数据库
|
||||
)
|
||||
|
||||
return success
|
||||
```
|
||||
|
||||
## 消息类型说明
|
||||
|
||||
### 支持的消息类型
|
||||
- `"text"`:纯文本消息
|
||||
- `"emoji"`:表情包消息
|
||||
- `"image"`:图片消息
|
||||
- `"command"`:命令消息
|
||||
- `"video"`:视频消息(如果支持)
|
||||
- `"audio"`:音频消息(如果支持)
|
||||
|
||||
### 回复格式
|
||||
回复消息使用格式:`"发送者:消息内容"` 或 `"发送者:消息内容"`
|
||||
|
||||
系统会自动查找匹配的原始消息并进行回复。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **异步操作**:所有发送函数都是异步的,必须使用`await`
|
||||
2. **错误处理**:发送失败时返回False,成功时返回True
|
||||
3. **发送频率**:注意控制发送频率,避免被平台限制
|
||||
4. **内容限制**:注意平台对消息内容和长度的限制
|
||||
5. **权限检查**:确保机器人有发送消息的权限
|
||||
6. **编码格式**:图片和表情包需要使用base64编码
|
||||
7. **存储选项**:可以选择是否将发送的消息存储到数据库
|
||||
55
docs/plugins/api/tool-api.md
Normal file
55
docs/plugins/api/tool-api.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# 工具API
|
||||
|
||||
工具API模块提供了获取和管理工具实例的功能,让插件能够访问系统中注册的工具。
|
||||
|
||||
## 导入方式
|
||||
|
||||
```python
|
||||
from src.plugin_system.apis import tool_api
|
||||
# 或者
|
||||
from src.plugin_system import tool_api
|
||||
```
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 获取工具实例
|
||||
|
||||
```python
|
||||
def get_tool_instance(tool_name: str) -> Optional[BaseTool]:
|
||||
```
|
||||
|
||||
获取指定名称的工具实例。
|
||||
|
||||
**Args**:
|
||||
- `tool_name`: 工具名称字符串
|
||||
|
||||
**Returns**:
|
||||
- `Optional[BaseTool]`: 工具实例,如果工具不存在则返回 None
|
||||
|
||||
### 2. 获取LLM可用的工具定义
|
||||
|
||||
```python
|
||||
def get_llm_available_tool_definitions():
|
||||
```
|
||||
|
||||
获取所有LLM可用的工具定义列表。
|
||||
|
||||
**Returns**:
|
||||
- `List[Tuple[str, Dict[str, Any]]]`: 工具定义列表,每个元素为 `(工具名称, 工具定义字典)` 的元组
|
||||
- 其具体定义请参照[tool-components.md](../tool-components.md#属性说明)中的工具定义格式。
|
||||
#### 示例:
|
||||
|
||||
```python
|
||||
# 获取所有LLM可用的工具定义
|
||||
tools = tool_api.get_llm_available_tool_definitions()
|
||||
for tool_name, tool_definition in tools:
|
||||
print(f"工具: {tool_name}")
|
||||
print(f"定义: {tool_definition}")
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **工具存在性检查**:使用前请检查工具实例是否为 None
|
||||
2. **权限控制**:某些工具可能有使用权限限制
|
||||
3. **异步调用**:大多数工具方法是异步的,需要使用 await
|
||||
4. **错误处理**:调用工具时请做好异常处理
|
||||
89
docs/plugins/command-components.md
Normal file
89
docs/plugins/command-components.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 💻 Command组件详解
|
||||
|
||||
## 📖 什么是Command
|
||||
|
||||
Command是直接响应用户明确指令的组件,与Action不同,Command是**被动触发**的,当用户输入特定格式的命令时立即执行。
|
||||
|
||||
Command通过正则表达式匹配用户输入,提供确定性的功能服务。
|
||||
|
||||
### 🎯 Command的特点
|
||||
|
||||
- 🎯 **确定性执行**:匹配到命令立即执行,无随机性
|
||||
- ⚡ **即时响应**:用户主动触发,快速响应
|
||||
- 🔍 **正则匹配**:通过正则表达式精确匹配用户输入
|
||||
- 🛑 **拦截控制**:可以控制是否阻止消息继续处理
|
||||
- 📝 **参数解析**:支持从用户输入中提取参数
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Command组件的基本结构
|
||||
|
||||
首先,Command组件需要继承自`BaseCommand`类,并实现必要的方法。
|
||||
|
||||
```python
|
||||
class ExampleCommand(BaseCommand):
|
||||
command_name = "example" # 命令名称,作为唯一标识符
|
||||
command_description = "这是一个示例命令" # 命令描述
|
||||
command_pattern = r"" # 命令匹配的正则表达式
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str], bool]:
|
||||
"""
|
||||
执行Command的主要逻辑
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str, bool]:
|
||||
- 第一个bool表示是否成功执行
|
||||
- 第二个str是执行结果消息
|
||||
- 第三个bool表示是否需要阻止消息继续处理
|
||||
"""
|
||||
# ---- 执行命令的逻辑 ----
|
||||
return True, "执行成功", False
|
||||
```
|
||||
**`command_pattern`**: 该Command匹配的正则表达式,用于精确匹配用户输入。
|
||||
|
||||
请注意:如果希望能获取到命令中的参数,请在正则表达式中使用有命名的捕获组,例如`(?P<param_name>pattern)`。
|
||||
|
||||
这样在匹配时,内部实现可以使用`re.match.groupdict()`方法获取到所有捕获组的参数,并以字典的形式存储在`self.matched_groups`中。
|
||||
|
||||
### 匹配样例
|
||||
假设我们有一个命令`/example param1=value1 param2=value2`,对应的正则表达式可以是:
|
||||
|
||||
```python
|
||||
class ExampleCommand(BaseCommand):
|
||||
command_name = "example"
|
||||
command_description = "这是一个示例命令"
|
||||
command_pattern = r"/example (?P<param1>\w+) (?P<param2>\w+)"
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str], bool]:
|
||||
# 获取匹配的参数
|
||||
param1 = self.matched_groups.get("param1")
|
||||
param2 = self.matched_groups.get("param2")
|
||||
|
||||
# 执行逻辑
|
||||
return True, f"参数1: {param1}, 参数2: {param2}", False
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Command 内置方法说明
|
||||
```python
|
||||
class BaseCommand:
|
||||
def get_config(self, key: str, default=None):
|
||||
"""获取插件配置值,使用嵌套键访问"""
|
||||
|
||||
async def send_text(self, content: str, reply_to: str = "") -> bool:
|
||||
"""发送回复消息"""
|
||||
|
||||
async def send_type(self, message_type: str, content: str, display_message: str = "", typing: bool = False, reply_to: str = "") -> bool:
|
||||
"""发送指定类型的回复消息到当前聊天环境"""
|
||||
|
||||
async def send_command(self, command_name: str, args: Optional[dict] = None, display_message: str = "", storage_message: bool = True) -> bool:
|
||||
"""发送命令消息"""
|
||||
|
||||
async def send_emoji(self, emoji_base64: str) -> bool:
|
||||
"""发送表情包"""
|
||||
|
||||
async def send_image(self, image_base64: str) -> bool:
|
||||
"""发送图片"""
|
||||
```
|
||||
具体参数与用法参见`BaseCommand`基类的定义。
|
||||
347
docs/plugins/configuration-guide.md
Normal file
347
docs/plugins/configuration-guide.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# ⚙️ 插件配置完整指南
|
||||
|
||||
本文档将全面指导你如何为你的插件**定义配置**和在组件中**访问配置**,帮助你构建一个健壮、规范且自带文档的配置系统。
|
||||
|
||||
> **🚨 重要原则:任何时候都不要手动创建 config.toml 文件!**
|
||||
>
|
||||
> 系统会根据你在代码中定义的 `config_schema` 自动生成配置文件。手动创建配置文件会破坏自动化流程,导致配置不一致、缺失注释和文档等问题。
|
||||
|
||||
## 配置版本管理
|
||||
|
||||
### 🎯 版本管理概述
|
||||
|
||||
插件系统提供了强大的**配置版本管理机制**,可以在插件升级时自动处理配置文件的迁移和更新,确保配置结构始终与代码保持同步。
|
||||
|
||||
### 🔄 配置版本管理工作流程
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[插件加载] --> B[检查配置文件]
|
||||
B --> C{配置文件存在?}
|
||||
C -->|不存在| D[生成默认配置]
|
||||
C -->|存在| E[读取当前版本]
|
||||
E --> F{有版本信息?}
|
||||
F -->|无版本| G[跳过版本检查<br/>直接加载配置]
|
||||
F -->|有版本| H{版本匹配?}
|
||||
H -->|匹配| I[直接加载配置]
|
||||
H -->|不匹配| J[配置迁移]
|
||||
J --> K[生成新配置结构]
|
||||
K --> L[迁移旧配置值]
|
||||
L --> M[保存迁移后配置]
|
||||
M --> N[配置加载完成]
|
||||
D --> N
|
||||
G --> N
|
||||
I --> N
|
||||
|
||||
style J fill:#FFB6C1
|
||||
style K fill:#90EE90
|
||||
style G fill:#87CEEB
|
||||
style N fill:#DDA0DD
|
||||
```
|
||||
|
||||
### 📊 版本管理策略
|
||||
|
||||
#### 1. 配置版本定义
|
||||
|
||||
在 `config_schema` 的 `plugin` 节中定义 `config_version`:
|
||||
|
||||
```python
|
||||
config_schema = {
|
||||
"plugin": {
|
||||
"enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
|
||||
"config_version": ConfigField(type=str, default="1.2.0", description="配置文件版本"),
|
||||
},
|
||||
# 其他配置...
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 版本检查行为
|
||||
|
||||
- **无版本信息** (`config_version` 不存在)
|
||||
- 系统会**跳过版本检查**,直接加载现有配置
|
||||
- 适用于旧版本插件的兼容性处理
|
||||
- 日志显示:`配置文件无版本信息,跳过版本检查`
|
||||
|
||||
- **有版本信息** (存在 `config_version` 字段)
|
||||
- 比较当前版本与期望版本
|
||||
- 版本不匹配时自动执行配置迁移
|
||||
- 版本匹配时直接加载配置
|
||||
|
||||
#### 3. 配置迁移过程
|
||||
|
||||
当检测到版本不匹配时,系统会:
|
||||
|
||||
1. **生成新配置结构** - 根据最新的 `config_schema` 生成新的配置结构
|
||||
2. **迁移配置值** - 将旧配置文件中的值迁移到新结构中
|
||||
3. **处理新增字段** - 新增的配置项使用默认值
|
||||
4. **更新版本号** - `config_version` 字段自动更新为最新版本
|
||||
5. **保存配置文件** - 迁移后的配置直接覆盖原文件**(不保留备份)**
|
||||
|
||||
### 🔧 实际使用示例
|
||||
|
||||
#### 版本升级场景
|
||||
|
||||
假设你的插件从 v1.0 升级到 v1.1,新增了权限管理功能:
|
||||
|
||||
**旧版本配置 (v1.0.0):**
|
||||
```toml
|
||||
[plugin]
|
||||
enabled = true
|
||||
config_version = "1.0.0"
|
||||
|
||||
[mute]
|
||||
min_duration = 60
|
||||
max_duration = 3600
|
||||
```
|
||||
|
||||
**新版本Schema (v1.1.0):**
|
||||
```python
|
||||
config_schema = {
|
||||
"plugin": {
|
||||
"enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
|
||||
"config_version": ConfigField(type=str, default="1.1.0", description="配置文件版本"),
|
||||
},
|
||||
"mute": {
|
||||
"min_duration": ConfigField(type=int, default=60, description="最短禁言时长(秒)"),
|
||||
"max_duration": ConfigField(type=int, default=2592000, description="最长禁言时长(秒)"),
|
||||
},
|
||||
"permissions": { # 新增的配置节
|
||||
"allowed_users": ConfigField(type=list, default=[], description="允许的用户列表"),
|
||||
"allowed_groups": ConfigField(type=list, default=[], description="允许的群组列表"),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**迁移后配置 (v1.1.0):**
|
||||
```toml
|
||||
[plugin]
|
||||
enabled = true # 保留原值
|
||||
config_version = "1.1.0" # 自动更新
|
||||
|
||||
[mute]
|
||||
min_duration = 60 # 保留原值
|
||||
max_duration = 3600 # 保留原值
|
||||
|
||||
[permissions] # 新增节,使用默认值
|
||||
allowed_users = []
|
||||
allowed_groups = []
|
||||
```
|
||||
|
||||
#### 无版本配置的兼容性
|
||||
|
||||
对于没有版本信息的旧配置文件:
|
||||
|
||||
**旧配置文件(无版本):**
|
||||
```toml
|
||||
[plugin]
|
||||
enabled = true
|
||||
# 没有 config_version 字段
|
||||
|
||||
[mute]
|
||||
min_duration = 120
|
||||
```
|
||||
|
||||
**系统行为:**
|
||||
- 检测到无版本信息
|
||||
- 跳过版本检查和迁移
|
||||
- 直接加载现有配置
|
||||
- 新增的配置项在代码中使用默认值访问
|
||||
- 系统会详细记录配置迁移过程。
|
||||
|
||||
### ⚠️ 重要注意事项
|
||||
|
||||
#### 1. 版本号管理
|
||||
- 当你修改 `config_schema` 时,**必须同步更新** `config_version`
|
||||
- 请使用语义化版本号 (例如:`1.0.0`, `1.1.0`, `2.0.0`)
|
||||
|
||||
#### 2. 迁移策略
|
||||
- **保留原值优先**: 迁移时优先保留用户的原有配置值
|
||||
- **新增字段默认值**: 新增的配置项使用Schema中定义的默认值
|
||||
- **移除字段警告**: 如果某个配置项在新版本中被移除,会在日志中显示警告
|
||||
|
||||
#### 3. 兼容性考虑
|
||||
- **旧版本兼容**: 无版本信息的配置文件会跳过版本检查
|
||||
- **不保留备份**: 迁移后直接覆盖原配置文件,不保留备份
|
||||
- **失败安全**: 如果迁移过程中出现错误,会回退到原配置
|
||||
|
||||
## 配置定义
|
||||
|
||||
配置的定义在你的插件主类(继承自 `BasePlugin`)中完成,主要通过两个类属性:
|
||||
|
||||
1. `config_section_descriptions`: 一个字典,用于描述配置文件的各个区段(`[section]`)。
|
||||
2. `config_schema`: 核心部分,一个嵌套字典,用于定义每个区段下的具体配置项。
|
||||
|
||||
### `ConfigField`:配置项的基石
|
||||
|
||||
每个配置项都通过一个 `ConfigField` 对象来定义。
|
||||
|
||||
```python
|
||||
from dataclasses import dataclass
|
||||
from src.plugin_system.base.config_types import ConfigField
|
||||
|
||||
@dataclass
|
||||
class ConfigField:
|
||||
"""配置字段定义"""
|
||||
type: type # 字段类型 (例如 str, int, float, bool, list)
|
||||
default: Any # 默认值
|
||||
description: str # 字段描述 (将作为注释生成到配置文件中)
|
||||
example: Optional[str] = None # 示例值 (可选)
|
||||
required: bool = False # 是否必需 (可选, 主要用于文档提示)
|
||||
choices: Optional[List[Any]] = None # 可选值列表 (可选)
|
||||
```
|
||||
|
||||
### 配置示例
|
||||
|
||||
让我们以一个功能丰富的 `MutePlugin` 为例,看看如何定义它的配置。
|
||||
|
||||
```python
|
||||
# src/plugins/built_in/mute_plugin/plugin.py
|
||||
|
||||
from src.plugin_system import BasePlugin, register_plugin, ConfigField
|
||||
from typing import List, Tuple, Type
|
||||
|
||||
@register_plugin
|
||||
class MutePlugin(BasePlugin):
|
||||
"""禁言插件"""
|
||||
|
||||
# 这里是插件基本信息,略去
|
||||
|
||||
# 步骤1: 定义配置节的描述
|
||||
config_section_descriptions = {
|
||||
"plugin": "插件启用配置",
|
||||
"components": "组件启用控制",
|
||||
"mute": "核心禁言功能配置",
|
||||
"smart_mute": "智能禁言Action的专属配置",
|
||||
"logging": "日志记录相关配置"
|
||||
}
|
||||
|
||||
# 步骤2: 使用ConfigField定义详细的配置Schema
|
||||
config_schema = {
|
||||
"plugin": {
|
||||
"enabled": ConfigField(type=bool, default=False, description="是否启用插件")
|
||||
},
|
||||
"components": {
|
||||
"enable_smart_mute": ConfigField(type=bool, default=True, description="是否启用智能禁言Action"),
|
||||
"enable_mute_command": ConfigField(type=bool, default=False, description="是否启用禁言命令Command")
|
||||
},
|
||||
"mute": {
|
||||
"min_duration": ConfigField(type=int, default=60, description="最短禁言时长(秒)"),
|
||||
"max_duration": ConfigField(type=int, default=2592000, description="最长禁言时长(秒),默认30天"),
|
||||
"templates": ConfigField(
|
||||
type=list,
|
||||
default=["好的,禁言 {target} {duration},理由:{reason}", "收到,对 {target} 执行禁言 {duration}"],
|
||||
description="成功禁言后发送的随机消息模板"
|
||||
)
|
||||
},
|
||||
"smart_mute": {
|
||||
"keyword_sensitivity": ConfigField(
|
||||
type=str,
|
||||
default="normal",
|
||||
description="关键词激活的敏感度",
|
||||
choices=["low", "normal", "high"] # 定义可选值
|
||||
),
|
||||
},
|
||||
"logging": {
|
||||
"level": ConfigField(
|
||||
type=str,
|
||||
default="INFO",
|
||||
description="日志记录级别",
|
||||
choices=["DEBUG", "INFO", "WARNING", "ERROR"]
|
||||
),
|
||||
"prefix": ConfigField(type=str, default="[MutePlugin]", description="日志记录前缀", example="[MyMutePlugin]")
|
||||
}
|
||||
}
|
||||
|
||||
# 这里是插件方法,略去
|
||||
```
|
||||
|
||||
当 `mute_plugin` 首次加载且其目录中不存在 `config.toml` 时,系统会自动创建以下文件:
|
||||
|
||||
```toml
|
||||
# mute_plugin - 自动生成的配置文件
|
||||
# 群聊禁言管理插件,提供智能禁言功能
|
||||
|
||||
# 插件启用配置
|
||||
[plugin]
|
||||
|
||||
# 是否启用插件
|
||||
enabled = false
|
||||
|
||||
|
||||
# 组件启用控制
|
||||
[components]
|
||||
|
||||
# 是否启用智能禁言Action
|
||||
enable_smart_mute = true
|
||||
|
||||
# 是否启用禁言命令Command
|
||||
enable_mute_command = false
|
||||
|
||||
|
||||
# 核心禁言功能配置
|
||||
[mute]
|
||||
|
||||
# 最短禁言时长(秒)
|
||||
min_duration = 60
|
||||
|
||||
# 最长禁言时长(秒),默认30天
|
||||
max_duration = 2592000
|
||||
|
||||
# 成功禁言后发送的随机消息模板
|
||||
templates = ["好的,禁言 {target} {duration},理由:{reason}", "收到,对 {target} 执行禁言 {duration}"]
|
||||
|
||||
|
||||
# 智能禁言Action的专属配置
|
||||
[smart_mute]
|
||||
|
||||
# 关键词激活的敏感度
|
||||
# 可选值: low, normal, high
|
||||
keyword_sensitivity = "normal"
|
||||
|
||||
|
||||
# 日志记录相关配置
|
||||
[logging]
|
||||
|
||||
# 日志记录级别
|
||||
# 可选值: DEBUG, INFO, WARNING, ERROR
|
||||
level = "INFO"
|
||||
|
||||
# 日志记录前缀
|
||||
# 示例: [MyMutePlugin]
|
||||
prefix = "[MutePlugin]"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置访问
|
||||
|
||||
如果你想要在你的组件中访问配置,可以通过组件内置的 `get_config()` 方法访问配置。
|
||||
|
||||
其参数为一个命名空间化的字符串。以上面的 `MutePlugin` 为例,你可以这样访问配置:
|
||||
|
||||
```python
|
||||
enable_smart_mute = self.get_config("components.enable_smart_mute", True)
|
||||
```
|
||||
|
||||
如果尝试访问了一个不存在的配置项,系统会自动返回默认值(你传递的)或者 `None`。
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践与注意事项
|
||||
|
||||
|
||||
**🚨 核心原则:永远不要手动创建 config.toml 文件!**
|
||||
|
||||
1. **🔥 绝不手动创建配置文件**: **任何时候都不要手动创建 `config.toml` 文件**!必须通过在 `plugin.py` 中定义 `config_schema` 让系统自动生成。
|
||||
- ❌ **禁止**:`touch config.toml`、手动编写配置文件
|
||||
- ✅ **正确**:定义 `config_schema`,启动插件,让系统自动生成
|
||||
|
||||
2. **Schema优先**: 所有配置项都必须在 `config_schema` 中声明,包括类型、默认值和描述。
|
||||
|
||||
3. **描述清晰**: 为每个 `ConfigField` 和 `config_section_descriptions` 编写清晰、准确的描述。这会直接成为你的插件文档的一部分。
|
||||
|
||||
4. **提供合理默认值**: 确保你的插件在默认配置下就能正常运行(或处于一个安全禁用的状态)。
|
||||
|
||||
5. **gitignore**: 将 `plugins/*/config.toml` 或 `src/plugins/built_in/*/config.toml` 加入 `.gitignore`,以避免提交个人敏感信息。
|
||||
|
||||
6. **配置文件只供修改**: 自动生成的 `config.toml` 文件只应该被用户**修改**,而不是从零创建。
|
||||
40
docs/plugins/dependency-management.md
Normal file
40
docs/plugins/dependency-management.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# 📦 插件依赖管理系统
|
||||
|
||||
现在的Python依赖包管理依然存在问题,请保留你的`python_dependencies`属性,等待后续重构。
|
||||
|
||||
## 📚 详细教程
|
||||
|
||||
### PythonDependency 类详解
|
||||
|
||||
`PythonDependency`是依赖声明的核心类:
|
||||
|
||||
```python
|
||||
PythonDependency(
|
||||
package_name="PIL", # 导入时的包名
|
||||
version=">=11.2.0", # 版本要求
|
||||
optional=False, # 是否为可选依赖
|
||||
description="图像处理库", # 依赖描述
|
||||
install_name="pillow" # pip安装时的包名(可选)
|
||||
)
|
||||
```
|
||||
|
||||
#### 参数说明
|
||||
|
||||
| 参数 | 类型 | 必需 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `package_name` | str | ✅ | Python导入时使用的包名(如`requests`) |
|
||||
| `version` | str | ❌ | 版本要求,使用pip格式(如`>=1.0.0`, `==2.1.3`) |
|
||||
| `optional` | bool | ❌ | 是否为可选依赖,默认`False` |
|
||||
| `description` | str | ❌ | 依赖的用途描述 |
|
||||
| `install_name` | str | ❌ | pip安装时的包名,默认与`package_name`相同,用于处理安装名称和导入名称不一致的情况 |
|
||||
|
||||
#### 版本格式示例
|
||||
|
||||
```python
|
||||
# 常用版本格式
|
||||
PythonDependency("requests", ">=2.25.0") # 最小版本
|
||||
PythonDependency("numpy", ">=1.20.0,<2.0.0") # 版本范围
|
||||
PythonDependency("pillow", "==8.3.2") # 精确版本
|
||||
PythonDependency("scipy", ">=1.7.0,!=1.8.0") # 排除特定版本
|
||||
```
|
||||
|
||||
BIN
docs/plugins/image/quick-start/1750326700269.png
Normal file
BIN
docs/plugins/image/quick-start/1750326700269.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
docs/plugins/image/quick-start/1750332508760.png
Normal file
BIN
docs/plugins/image/quick-start/1750332508760.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
81
docs/plugins/index.md
Normal file
81
docs/plugins/index.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# MaiBot插件开发文档
|
||||
|
||||
> 欢迎来到MaiBot插件系统开发文档!这里是你开始插件开发旅程的最佳起点。
|
||||
|
||||
## 新手入门
|
||||
|
||||
- [📖 快速开始指南](quick-start.md) - 快速创建你的第一个插件
|
||||
|
||||
## 组件功能详解
|
||||
|
||||
- [🧱 Action组件详解](action-components.md) - 掌握最核心的Action组件
|
||||
- [💻 Command组件详解](command-components.md) - 学习直接响应命令的组件
|
||||
- [🔧 Tool组件详解](tool-components.md) - 了解如何扩展信息获取能力
|
||||
- [⚙️ 配置文件系统指南](configuration-guide.md) - 学会使用自动生成的插件配置文件
|
||||
- [📄 Manifest系统指南](manifest-guide.md) - 了解插件元数据管理和配置架构
|
||||
|
||||
Command vs Action 选择指南
|
||||
|
||||
1. 使用Command的场景
|
||||
|
||||
- ✅ 用户需要明确调用特定功能
|
||||
- ✅ 需要精确的参数控制
|
||||
- ✅ 管理和配置操作
|
||||
- ✅ 查询和信息显示
|
||||
- ✅ 系统维护命令
|
||||
|
||||
2. 使用Action的场景
|
||||
|
||||
- ✅ 增强麦麦的智能行为
|
||||
- ✅ 根据上下文自动触发
|
||||
- ✅ 情绪和表情表达
|
||||
- ✅ 智能建议和帮助
|
||||
- ✅ 随机化的互动
|
||||
|
||||
|
||||
## API浏览
|
||||
|
||||
### 消息发送与处理API
|
||||
- [📤 发送API](api/send-api.md) - 各种类型消息发送接口
|
||||
- [消息API](api/message-api.md) - 消息获取,消息构建,消息查询接口
|
||||
- [聊天流API](api/chat-api.md) - 聊天流管理和查询接口
|
||||
|
||||
### AI与生成API
|
||||
- [LLM API](api/llm-api.md) - 大语言模型交互接口,可以使用内置LLM生成内容
|
||||
- [✨ 回复生成器API](api/generator-api.md) - 智能回复生成接口,可以使用内置风格化生成器
|
||||
|
||||
### 表情包API
|
||||
- [😊 表情包API](api/emoji-api.md) - 表情包选择和管理接口
|
||||
|
||||
### 关系系统API
|
||||
- [人物信息API](api/person-api.md) - 用户信息,处理麦麦认识的人和关系的接口
|
||||
|
||||
### 数据与配置API
|
||||
- [🗄️ 数据库API](api/database-api.md) - 数据库操作接口
|
||||
- [⚙️ 配置API](api/config-api.md) - 配置读取和用户信息接口
|
||||
|
||||
### 插件和组件管理API
|
||||
- [🔌 插件API](api/plugin-manage-api.md) - 插件加载和管理接口
|
||||
- [🧩 组件API](api/component-manage-api.md) - 组件注册和管理接口
|
||||
|
||||
### 日志API
|
||||
- [📜 日志API](api/logging-api.md) - logger实例获取接口
|
||||
### 工具API
|
||||
- [🔧 工具API](api/tool-api.md) - tool获取接口
|
||||
|
||||
|
||||
|
||||
## 支持
|
||||
|
||||
> 如果你在文档中发现错误或需要补充,请:
|
||||
|
||||
1. 检查最新的文档版本
|
||||
2. 查看相关示例代码
|
||||
3. 参考其他类似插件
|
||||
4. 提交文档仓库issue
|
||||
|
||||
## 一个方便的小设计
|
||||
|
||||
我们在`__init__.py`中定义了一个`__all__`变量,包含了所有需要导出的类和函数。
|
||||
这样在其他地方导入时,可以直接使用 `from src.plugin_system import *` 来导入所有插件相关的类和函数。
|
||||
或者你可以直接使用 `from src.plugin_system import BasePlugin, register_plugin, ComponentInfo` 之类的方式来导入你需要的部分。
|
||||
205
docs/plugins/manifest-guide.md
Normal file
205
docs/plugins/manifest-guide.md
Normal file
@@ -0,0 +1,205 @@
|
||||
# 📄 插件Manifest系统指南
|
||||
|
||||
## 概述
|
||||
|
||||
MaiBot插件系统现在强制要求每个插件都必须包含一个 `_manifest.json` 文件。这个文件描述了插件的基本信息、依赖关系、组件等重要元数据。
|
||||
|
||||
### 🔄 配置架构:Manifest与Config的职责分离
|
||||
|
||||
为了避免信息重复和提高维护性,我们采用了**双文件架构**:
|
||||
|
||||
- **`_manifest.json`** - 插件的**静态元数据**
|
||||
- 插件身份信息(名称、版本、描述)
|
||||
- 开发者信息(作者、许可证、仓库)
|
||||
- 系统信息(兼容性、组件列表、分类)
|
||||
|
||||
- **`config.toml`** - 插件的**运行时配置**
|
||||
- 启用状态 (`enabled`)
|
||||
- 功能参数配置
|
||||
- 用户可调整的行为设置
|
||||
|
||||
这种分离确保了:
|
||||
- ✅ 元数据信息统一管理
|
||||
- ✅ 运行时配置灵活调整
|
||||
- ✅ 避免重复维护
|
||||
- ✅ 更清晰的职责划分
|
||||
|
||||
## 🔧 Manifest文件结构
|
||||
|
||||
### 必需字段
|
||||
|
||||
以下字段是必需的,不能为空:
|
||||
|
||||
```json
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "插件显示名称",
|
||||
"version": "1.0.0",
|
||||
"description": "插件功能描述",
|
||||
"author": {
|
||||
"name": "作者名称"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 可选字段
|
||||
|
||||
以下字段都是可选的,可以根据需要添加:
|
||||
|
||||
```json
|
||||
{
|
||||
"license": "MIT",
|
||||
"host_application": {
|
||||
"min_version": "1.0.0",
|
||||
"max_version": "4.0.0"
|
||||
},
|
||||
"homepage_url": "https://github.com/your-repo",
|
||||
"repository_url": "https://github.com/your-repo",
|
||||
"keywords": ["关键词1", "关键词2"],
|
||||
"categories": ["分类1", "分类2"],
|
||||
"default_locale": "zh-CN",
|
||||
"locales_path": "_locales",
|
||||
"plugin_info": {
|
||||
"is_built_in": false,
|
||||
"plugin_type": "general",
|
||||
"components": [
|
||||
{
|
||||
"type": "action",
|
||||
"name": "组件名称",
|
||||
"description": "组件描述"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ 管理工具
|
||||
|
||||
### 使用manifest_tool.py
|
||||
|
||||
我们提供了一个命令行工具来帮助管理manifest文件:
|
||||
|
||||
```bash
|
||||
# 扫描缺少manifest的插件
|
||||
python scripts/manifest_tool.py scan src/plugins
|
||||
|
||||
# 为插件创建最小化manifest文件
|
||||
python scripts/manifest_tool.py create-minimal src/plugins/my_plugin --name "我的插件" --author "作者"
|
||||
|
||||
# 为插件创建完整manifest模板
|
||||
python scripts/manifest_tool.py create-complete src/plugins/my_plugin --name "我的插件"
|
||||
|
||||
# 验证manifest文件
|
||||
python scripts/manifest_tool.py validate src/plugins/my_plugin
|
||||
```
|
||||
|
||||
### 验证示例
|
||||
|
||||
验证通过的示例:
|
||||
```
|
||||
✅ Manifest文件验证通过
|
||||
```
|
||||
|
||||
验证失败的示例:
|
||||
```
|
||||
❌ 验证错误:
|
||||
- 缺少必需字段: name
|
||||
- 作者信息缺少name字段或为空
|
||||
⚠️ 验证警告:
|
||||
- 建议填写字段: license
|
||||
- 建议填写字段: keywords
|
||||
```
|
||||
|
||||
## 🔄 迁移指南
|
||||
|
||||
### 对于现有插件
|
||||
|
||||
1. **检查缺少manifest的插件**:
|
||||
```bash
|
||||
python scripts/manifest_tool.py scan src/plugins
|
||||
```
|
||||
|
||||
2. **为每个插件创建manifest**:
|
||||
```bash
|
||||
python scripts/manifest_tool.py create-minimal src/plugins/your_plugin
|
||||
```
|
||||
|
||||
3. **编辑manifest文件**,填写正确的信息。
|
||||
|
||||
4. **验证manifest**:
|
||||
```bash
|
||||
python scripts/manifest_tool.py validate src/plugins/your_plugin
|
||||
```
|
||||
|
||||
### 对于新插件
|
||||
|
||||
创建新插件时,建议的步骤:
|
||||
|
||||
1. **创建插件目录和基本文件**
|
||||
2. **创建完整manifest模板**:
|
||||
```bash
|
||||
python scripts/manifest_tool.py create-complete src/plugins/new_plugin
|
||||
```
|
||||
3. **根据实际情况修改manifest文件**
|
||||
4. **编写插件代码**
|
||||
5. **验证manifest文件**
|
||||
|
||||
## 📋 字段说明
|
||||
|
||||
### 基本信息
|
||||
- `manifest_version`: manifest格式版本,当前为1
|
||||
- `name`: 插件显示名称(必需)
|
||||
- `version`: 插件版本号(必需)
|
||||
- `description`: 插件功能描述(必需)
|
||||
- `author`: 作者信息(必需)
|
||||
- `name`: 作者名称(必需)
|
||||
- `url`: 作者主页(可选)
|
||||
|
||||
### 许可和URL
|
||||
- `license`: 插件许可证(可选,建议填写)
|
||||
- `homepage_url`: 插件主页(可选)
|
||||
- `repository_url`: 源码仓库地址(可选)
|
||||
|
||||
### 分类和标签
|
||||
- `keywords`: 关键词数组(可选,建议填写)
|
||||
- `categories`: 分类数组(可选,建议填写)
|
||||
|
||||
### 兼容性
|
||||
- `host_application`: 主机应用兼容性(可选,建议填写)
|
||||
- `min_version`: 最低兼容版本
|
||||
- `max_version`: 最高兼容版本
|
||||
|
||||
⚠️ 在不填写的情况下,插件将默认支持所有版本。**(由于我们在不同版本对插件系统进行了大量的重构,这种情况几乎不可能。)**
|
||||
|
||||
### 国际化
|
||||
- `default_locale`: 默认语言(可选)
|
||||
- `locales_path`: 语言文件目录(可选)
|
||||
|
||||
### 插件特定信息
|
||||
- `plugin_info`: 插件详细信息(可选)
|
||||
- `is_built_in`: 是否为内置插件
|
||||
- `plugin_type`: 插件类型
|
||||
- `components`: 组件列表
|
||||
|
||||
## ⚠️ 注意事项
|
||||
|
||||
1. **强制要求**:所有插件必须包含`_manifest.json`文件,否则无法加载
|
||||
2. **编码格式**:manifest文件必须使用UTF-8编码
|
||||
3. **JSON格式**:文件必须是有效的JSON格式
|
||||
4. **必需字段**:`manifest_version`、`name`、`version`、`description`、`author.name`是必需的
|
||||
5. **版本兼容**:当前只支持`manifest_version = 1`
|
||||
|
||||
## 🔍 常见问题
|
||||
|
||||
### Q: 可以不填写可选字段吗?
|
||||
A: 可以。所有标记为"可选"的字段都可以不填写,但建议至少填写`license`和`keywords`。
|
||||
|
||||
### Q: manifest验证失败怎么办?
|
||||
A: 根据验证器的错误提示修复相应问题。错误会导致插件加载失败,警告不会。
|
||||
|
||||
## 📚 参考示例
|
||||
|
||||
查看内置插件的manifest文件作为参考:
|
||||
- `src/plugins/built_in/core_actions/_manifest.json`
|
||||
- `src/plugins/built_in/tts_plugin/_manifest.json`
|
||||
- `src/plugins/hello_world_plugin/_manifest.json`
|
||||
428
docs/plugins/quick-start.md
Normal file
428
docs/plugins/quick-start.md
Normal file
@@ -0,0 +1,428 @@
|
||||
# 🚀 快速开始指南
|
||||
|
||||
本指南将带你从零开始创建一个功能完整的MaiCore插件。
|
||||
|
||||
## 📖 概述
|
||||
|
||||
这个指南将带你快速创建你的第一个MaiCore插件。我们将创建一个简单的问候插件,展示插件系统的基本概念。
|
||||
|
||||
以下代码都在我们的`plugins/hello_world_plugin/`目录下。
|
||||
|
||||
### 一个方便的小设计
|
||||
|
||||
在开发中,我们在`__init__.py`中定义了一个`__all__`变量,包含了所有需要导出的类和函数。
|
||||
这样在其他地方导入时,可以直接使用 `from src.plugin_system import *` 来导入所有插件相关的类和函数。
|
||||
或者你可以直接使用 `from src.plugin_system import BasePlugin, register_plugin, ComponentInfo` 之类的方式来导入你需要的部分。
|
||||
|
||||
### 📂 准备工作
|
||||
|
||||
确保你已经:
|
||||
|
||||
1. 克隆了MaiCore项目
|
||||
2. 安装了Python依赖
|
||||
3. 了解基本的Python语法
|
||||
|
||||
## 🏗️ 创建插件
|
||||
|
||||
### 1. 创建插件目录
|
||||
|
||||
在项目根目录的 `plugins/` 文件夹下创建你的插件目录
|
||||
|
||||
这里我们创建一个名为 `hello_world_plugin` 的目录
|
||||
|
||||
### 2. 创建`_manifest.json`文件
|
||||
|
||||
在插件目录下面创建一个 `_manifest.json` 文件,内容如下:
|
||||
|
||||
```json
|
||||
{
|
||||
"manifest_version": 1,
|
||||
"name": "Hello World 插件",
|
||||
"version": "1.0.0",
|
||||
"description": "一个简单的 Hello World 插件",
|
||||
"author": {
|
||||
"name": "你的名字"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
有关 `_manifest.json` 的详细说明,请参考 [Manifest文件指南](./manifest-guide.md)。
|
||||
|
||||
### 3. 创建最简单的插件
|
||||
|
||||
让我们从最基础的开始!创建 `plugin.py` 文件:
|
||||
|
||||
```python
|
||||
from typing import List, Tuple, Type
|
||||
from src.plugin_system import BasePlugin, register_plugin, ComponentInfo
|
||||
|
||||
@register_plugin # 注册插件
|
||||
class HelloWorldPlugin(BasePlugin):
|
||||
"""Hello World插件 - 你的第一个MaiCore插件"""
|
||||
|
||||
# 以下是插件基本信息和方法(必须填写)
|
||||
plugin_name = "hello_world_plugin"
|
||||
enable_plugin = True # 启用插件
|
||||
dependencies = [] # 插件依赖列表(目前为空)
|
||||
python_dependencies = [] # Python依赖列表(目前为空)
|
||||
config_file_name = "config.toml" # 配置文件名
|
||||
config_schema = {} # 配置文件模式(目前为空)
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: # 获取插件组件
|
||||
"""返回插件包含的组件列表(目前是空的)"""
|
||||
return []
|
||||
```
|
||||
|
||||
🎉 恭喜!你刚刚创建了一个最简单但完整的MaiCore插件!
|
||||
|
||||
**解释一下这些代码:**
|
||||
|
||||
- 首先,我们在`plugin.py`中定义了一个HelloWorldPlugin插件类,继承自 `BasePlugin` ,提供基本功能。
|
||||
- 通过给类加上,`@register_plugin` 装饰器,我们告诉系统"这是一个插件"
|
||||
- `plugin_name` 等是插件的基本信息,必须填写
|
||||
- `get_plugin_components()` 返回插件的功能组件,现在我们没有定义任何 Action, Command 或者 EventHandler,所以返回空列表。
|
||||
|
||||
### 4. 测试基础插件
|
||||
|
||||
现在就可以测试这个插件了!启动MaiCore:
|
||||
|
||||
直接通过启动器运行MaiCore或者 `python bot.py`
|
||||
|
||||
在日志中你应该能看到插件被加载的信息。虽然插件还没有任何功能,但它已经成功运行了!
|
||||
|
||||

|
||||
|
||||
### 5. 添加第一个功能:问候Action
|
||||
|
||||
现在我们要给插件加入一个有用的功能,我们从最好玩的Action做起
|
||||
|
||||
Action是一类可以让MaiCore根据自身意愿选择使用的“动作”,在MaiCore中,不论是“回复”还是“不回复”,或者“发送表情”以及“禁言”等等,都是通过Action实现的。
|
||||
|
||||
你可以通过编写动作,来拓展MaiCore的能力,包括发送语音,截图,甚至操作文件,编写代码......
|
||||
|
||||
现在让我们给插件添加第一个简单的功能。这个Action可以对用户发送一句问候语。
|
||||
|
||||
在 `plugin.py` 文件中添加Action组件,完整代码如下:
|
||||
|
||||
```python
|
||||
from typing import List, Tuple, Type
|
||||
from src.plugin_system import (
|
||||
BasePlugin, register_plugin, BaseAction,
|
||||
ComponentInfo, ActionActivationType, ChatMode
|
||||
)
|
||||
|
||||
# ===== Action组件 =====
|
||||
|
||||
class HelloAction(BaseAction):
|
||||
"""问候Action - 简单的问候动作"""
|
||||
|
||||
# === 基本信息(必须填写)===
|
||||
action_name = "hello_greeting"
|
||||
action_description = "向用户发送问候消息"
|
||||
activation_type = ActionActivationType.ALWAYS # 始终激活
|
||||
|
||||
# === 功能描述(必须填写)===
|
||||
action_parameters = {"greeting_message": "要发送的问候消息"}
|
||||
action_require = ["需要发送友好问候时使用", "当有人向你问好时使用", "当你遇见没有见过的人时使用"]
|
||||
associated_types = ["text"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行问候动作 - 这是核心功能"""
|
||||
# 发送问候消息
|
||||
greeting_message = self.action_data.get("greeting_message", "")
|
||||
base_message = self.get_config("greeting.message", "嗨!很开心见到你!😊")
|
||||
message = base_message + greeting_message
|
||||
await self.send_text(message)
|
||||
|
||||
return True, "发送了问候消息"
|
||||
|
||||
@register_plugin
|
||||
class HelloWorldPlugin(BasePlugin):
|
||||
"""Hello World插件 - 你的第一个MaiCore插件"""
|
||||
|
||||
# 插件基本信息
|
||||
plugin_name = "hello_world_plugin"
|
||||
enable_plugin = True
|
||||
dependencies = []
|
||||
python_dependencies = []
|
||||
config_file_name = "config.toml"
|
||||
config_schema = {}
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
"""返回插件包含的组件列表"""
|
||||
return [
|
||||
# 添加我们的问候Action
|
||||
(HelloAction.get_action_info(), HelloAction),
|
||||
]
|
||||
```
|
||||
|
||||
**解释一下这些代码:**
|
||||
|
||||
- `HelloAction` 是我们定义的问候动作类,继承自 `BaseAction`,并实现了核心功能。
|
||||
- 在 `HelloWorldPlugin` 中,我们通过 `get_plugin_components()` 方法,通过调用`get_action_info()`这个内置方法将 `HelloAction` 注册为插件的一个组件。
|
||||
- 这样一来,当插件被加载时,问候动作也会被一并加载,并可以在MaiCore中使用。
|
||||
- `execute()` 函数是Action的核心,定义了当Action被MaiCore选择后,具体要做什么
|
||||
- `self.send_text()` 是发送文本消息的便捷方法
|
||||
|
||||
Action 组件中有关`activation_type`、`action_parameters`、`action_require`、`associated_types` 等的详细说明请参考 [Action组件指南](./action-components.md)。
|
||||
|
||||
### 6. 测试问候Action
|
||||
|
||||
重启MaiCore,然后在聊天中发送任意消息,比如:
|
||||
|
||||
```
|
||||
你好
|
||||
```
|
||||
|
||||
MaiCore可能会选择使用你的问候Action,发送回复:
|
||||
|
||||
```
|
||||
嗨!很开心见到你!😊
|
||||
```
|
||||
|
||||

|
||||
|
||||
> **💡 小提示**:MaiCore会智能地决定什么时候使用它。如果没有立即看到效果,多试几次不同的消息。
|
||||
|
||||
🎉 太棒了!你的插件已经有实际功能了!
|
||||
|
||||
### 7. 添加第二个功能:时间查询Command
|
||||
|
||||
现在让我们添加一个Command组件。Command和Action不同,它是直接响应用户命令的:
|
||||
|
||||
Command是最简单,最直接的响应,不由LLM判断选择使用
|
||||
|
||||
```python
|
||||
# 在现有代码基础上,添加Command组件
|
||||
import datetime
|
||||
from src.plugin_system import BaseCommand
|
||||
#导入Command基类
|
||||
|
||||
class TimeCommand(BaseCommand):
|
||||
"""时间查询Command - 响应/time命令"""
|
||||
|
||||
command_name = "time"
|
||||
command_description = "查询当前时间"
|
||||
|
||||
# === 命令设置(必须填写)===
|
||||
command_pattern = r"^/time$" # 精确匹配 "/time" 命令
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str], bool]:
|
||||
"""执行时间查询"""
|
||||
# 获取当前时间
|
||||
time_format: str = "%Y-%m-%d %H:%M:%S"
|
||||
now = datetime.datetime.now()
|
||||
time_str = now.strftime(time_format)
|
||||
|
||||
# 发送时间信息
|
||||
message = f"⏰ 当前时间:{time_str}"
|
||||
await self.send_text(message)
|
||||
|
||||
return True, f"显示了当前时间: {time_str}", True
|
||||
|
||||
@register_plugin
|
||||
class HelloWorldPlugin(BasePlugin):
|
||||
"""Hello World插件 - 你的第一个MaiCore插件"""
|
||||
|
||||
# 插件基本信息
|
||||
plugin_name = "hello_world_plugin"
|
||||
enable_plugin = True
|
||||
dependencies = []
|
||||
python_dependencies = []
|
||||
config_file_name = "config.toml"
|
||||
config_schema = {}
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
return [
|
||||
(HelloAction.get_action_info(), HelloAction),
|
||||
(TimeCommand.get_command_info(), TimeCommand),
|
||||
]
|
||||
```
|
||||
|
||||
同样的,我们通过 `get_plugin_components()` 方法,通过调用`get_action_info()`这个内置方法将 `TimeCommand` 注册为插件的一个组件。
|
||||
|
||||
**Command组件解释:**
|
||||
|
||||
- `command_pattern` 使用正则表达式匹配用户输入
|
||||
- `^/time$` 表示精确匹配 "/time"
|
||||
|
||||
有关 Command 组件的更多信息,请参考 [Command组件指南](./command-components.md)。
|
||||
|
||||
### 8. 测试时间查询Command
|
||||
|
||||
重启MaiCore,发送命令:
|
||||
|
||||
```
|
||||
/time
|
||||
```
|
||||
|
||||
你应该会收到回复:
|
||||
|
||||
```
|
||||
⏰ 当前时间:2024-01-01 12:00:00
|
||||
```
|
||||
|
||||
🎉 太棒了!现在你已经了解了基本的 Action 和 Command 组件的使用方法。你可以根据自己的需求,继续扩展插件的功能,添加更多的 Action 和 Command 组件,让你的插件更加丰富和强大!
|
||||
|
||||
---
|
||||
|
||||
## 进阶教程
|
||||
|
||||
如果你想让插件更加灵活和强大,可以参考接下来的进阶教程。
|
||||
|
||||
### 1. 添加配置文件
|
||||
|
||||
想要为插件添加配置文件吗?让我们一起来配置`config_schema`属性!
|
||||
|
||||
> **🚨 重要:不要手动创建config.toml文件!**
|
||||
>
|
||||
> 我们需要在插件代码中定义配置Schema,让系统自动生成配置文件。
|
||||
|
||||
首先,在插件类中定义配置Schema:
|
||||
|
||||
```python
|
||||
from src.plugin_system import ConfigField
|
||||
|
||||
@register_plugin
|
||||
class HelloWorldPlugin(BasePlugin):
|
||||
"""Hello World插件 - 你的第一个MaiCore插件"""
|
||||
|
||||
# 插件基本信息
|
||||
plugin_name: str = "hello_world_plugin" # 内部标识符
|
||||
enable_plugin: bool = True
|
||||
dependencies: List[str] = [] # 插件依赖列表
|
||||
python_dependencies: List[str] = [] # Python包依赖列表
|
||||
config_file_name: str = "config.toml" # 配置文件名
|
||||
|
||||
# 配置Schema定义
|
||||
config_schema: dict = {
|
||||
"plugin": {
|
||||
"name": ConfigField(type=str, default="hello_world_plugin", description="插件名称"),
|
||||
"version": ConfigField(type=str, default="1.0.0", description="插件版本"),
|
||||
"enabled": ConfigField(type=bool, default=False, description="是否启用插件"),
|
||||
},
|
||||
"greeting": {
|
||||
"message": ConfigField(type=str, default="嗨!很开心见到你!😊", description="默认问候消息"),
|
||||
"enable_emoji": ConfigField(type=bool, default=True, description="是否启用表情符号"),
|
||||
},
|
||||
"time": {"format": ConfigField(type=str, default="%Y-%m-%d %H:%M:%S", description="时间显示格式")},
|
||||
}
|
||||
|
||||
def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]:
|
||||
return [
|
||||
(HelloAction.get_action_info(), HelloAction),
|
||||
(TimeCommand.get_command_info(), TimeCommand),
|
||||
]
|
||||
```
|
||||
|
||||
这会生成一个如下的 `config.toml` 文件:
|
||||
|
||||
```toml
|
||||
# hello_world_plugin - 自动生成的配置文件
|
||||
# 我的第一个MaiCore插件,包含问候功能和时间查询等基础示例
|
||||
|
||||
# 插件基本信息
|
||||
[plugin]
|
||||
|
||||
# 插件名称
|
||||
name = "hello_world_plugin"
|
||||
|
||||
# 插件版本
|
||||
version = "1.0.0"
|
||||
|
||||
# 是否启用插件
|
||||
enabled = false
|
||||
|
||||
|
||||
# 问候功能配置
|
||||
[greeting]
|
||||
|
||||
# 默认问候消息
|
||||
message = "嗨!很开心见到你!😊"
|
||||
|
||||
# 是否启用表情符号
|
||||
enable_emoji = true
|
||||
|
||||
|
||||
# 时间查询配置
|
||||
[time]
|
||||
|
||||
# 时间显示格式
|
||||
format = "%Y-%m-%d %H:%M:%S"
|
||||
```
|
||||
|
||||
然后修改Action和Command代码,通过 `get_config()` 方法让它们读取配置(配置的键是命名空间式的):
|
||||
|
||||
```python
|
||||
class HelloAction(BaseAction):
|
||||
"""问候Action - 简单的问候动作"""
|
||||
|
||||
# === 基本信息(必须填写)===
|
||||
action_name = "hello_greeting"
|
||||
action_description = "向用户发送问候消息"
|
||||
activation_type = ActionActivationType.ALWAYS # 始终激活
|
||||
|
||||
# === 功能描述(必须填写)===
|
||||
action_parameters = {"greeting_message": "要发送的问候消息"}
|
||||
action_require = ["需要发送友好问候时使用", "当有人向你问好时使用", "当你遇见没有见过的人时使用"]
|
||||
associated_types = ["text"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行问候动作 - 这是核心功能"""
|
||||
# 发送问候消息
|
||||
greeting_message = self.action_data.get("greeting_message", "")
|
||||
base_message = self.get_config("greeting.message", "嗨!很开心见到你!😊")
|
||||
message = base_message + greeting_message
|
||||
await self.send_text(message)
|
||||
|
||||
return True, "发送了问候消息"
|
||||
|
||||
class TimeCommand(BaseCommand):
|
||||
"""时间查询Command - 响应/time命令"""
|
||||
|
||||
command_name = "time"
|
||||
command_description = "查询当前时间"
|
||||
|
||||
# === 命令设置(必须填写)===
|
||||
command_pattern = r"^/time$" # 精确匹配 "/time" 命令
|
||||
|
||||
async def execute(self) -> Tuple[bool, str, bool]:
|
||||
"""执行时间查询"""
|
||||
import datetime
|
||||
|
||||
# 获取当前时间
|
||||
time_format: str = self.get_config("time.format", "%Y-%m-%d %H:%M:%S") # type: ignore
|
||||
now = datetime.datetime.now()
|
||||
time_str = now.strftime(time_format)
|
||||
|
||||
# 发送时间信息
|
||||
message = f"⏰ 当前时间:{time_str}"
|
||||
await self.send_text(message)
|
||||
|
||||
return True, f"显示了当前时间: {time_str}", True
|
||||
```
|
||||
|
||||
**配置系统工作流程:**
|
||||
|
||||
1. **定义Schema**: 在插件代码中定义配置结构
|
||||
2. **自动生成**: 启动插件时,系统会自动生成 `config.toml` 文件
|
||||
3. **用户修改**: 用户可以修改生成的配置文件
|
||||
4. **代码读取**: 使用 `self.get_config()` 读取配置值
|
||||
|
||||
**绝对不要手动创建 `config.toml` 文件!**
|
||||
|
||||
更详细的配置系统介绍请参考 [配置指南](./configuration-guide.md)。
|
||||
|
||||
### 2. 创建说明文档
|
||||
|
||||
你可以创建一个 `README.md` 文件,描述插件的功能和使用方法。
|
||||
|
||||
### 3. 发布到插件市场
|
||||
|
||||
如果你想让更多人使用你的插件,可以将它发布到MaiCore的插件市场。
|
||||
|
||||
这部分请参考 [plugin-repo](https://github.com/Maim-with-u/plugin-repo) 的文档。
|
||||
|
||||
---
|
||||
|
||||
🎉 恭喜你!你已经成功的创建了自己的插件了!
|
||||
246
docs/plugins/tool-components.md
Normal file
246
docs/plugins/tool-components.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# 🔧 工具组件详解
|
||||
|
||||
## 📖 什么是工具
|
||||
|
||||
工具是MaiBot的信息获取能力扩展组件。如果说Action组件功能五花八门,可以拓展麦麦能做的事情,那么Tool就是在某个过程中拓宽了麦麦能够获得的信息量。
|
||||
|
||||
### 🎯 工具的特点
|
||||
|
||||
- 🔍 **信息获取增强**:扩展麦麦获取外部信息的能力
|
||||
- 📊 **数据丰富**:帮助麦麦获得更多背景信息和实时数据
|
||||
- 🔌 **插件式架构**:支持独立开发和注册新工具
|
||||
- ⚡ **自动发现**:工具会被系统自动识别和注册
|
||||
|
||||
### 🆚 Tool vs Action vs Command 区别
|
||||
|
||||
| 特征 | Action | Command | Tool |
|
||||
|-----|-------|---------|------|
|
||||
| **主要用途** | 扩展麦麦行为能力 | 响应用户指令 | 扩展麦麦信息获取 |
|
||||
| **触发方式** | 麦麦智能决策 | 用户主动触发 | LLM根据需要调用 |
|
||||
| **目标** | 让麦麦做更多事情 | 提供具体功能 | 让麦麦知道更多信息 |
|
||||
| **使用场景** | 增强交互体验 | 功能服务 | 信息查询和分析 |
|
||||
|
||||
## 🏗️ Tool组件的基本结构
|
||||
|
||||
每个工具必须继承 `BaseTool` 基类并实现以下属性和方法:
|
||||
```python
|
||||
from src.plugin_system import BaseTool, ToolParamType
|
||||
|
||||
class MyTool(BaseTool):
|
||||
# 工具名称,必须唯一
|
||||
name = "my_tool"
|
||||
|
||||
# 工具描述,告诉LLM这个工具的用途
|
||||
description = "这个工具用于获取特定类型的信息"
|
||||
|
||||
# 参数定义,仅定义参数
|
||||
# 比如想要定义一个类似下面的openai格式的参数表,则可以这么定义:
|
||||
# {
|
||||
# "type": "object",
|
||||
# "properties": {
|
||||
# "query": {
|
||||
# "type": "string",
|
||||
# "description": "查询参数"
|
||||
# },
|
||||
# "limit": {
|
||||
# "type": "integer",
|
||||
# "description": "结果数量限制"
|
||||
# "enum": [10, 20, 50] # 可选值
|
||||
# }
|
||||
# },
|
||||
# "required": ["query"]
|
||||
# }
|
||||
parameters = [
|
||||
("query", ToolParamType.STRING, "查询参数", True, None), # 必填参数
|
||||
("limit", ToolParamType.INTEGER, "结果数量限制", False, ["10", "20", "50"]) # 可选参数
|
||||
]
|
||||
|
||||
available_for_llm = True # 是否对LLM可用
|
||||
|
||||
async def execute(self, function_args: Dict[str, Any]):
|
||||
"""执行工具逻辑"""
|
||||
# 实现工具功能
|
||||
result = f"查询结果: {function_args.get('query')}"
|
||||
|
||||
return {
|
||||
"name": self.name,
|
||||
"content": result
|
||||
}
|
||||
```
|
||||
|
||||
### 属性说明
|
||||
|
||||
| 属性 | 类型 | 说明 |
|
||||
|-----|------|------|
|
||||
| `name` | str | 工具的唯一标识名称 |
|
||||
| `description` | str | 工具功能描述,帮助LLM理解用途 |
|
||||
| `parameters` | list[tuple] | 参数定义 |
|
||||
|
||||
其构造而成的工具定义为:
|
||||
```python
|
||||
definition: Dict[str, Any] = {"name": cls.name, "description": cls.description, "parameters": cls.parameters}
|
||||
```
|
||||
|
||||
### 方法说明
|
||||
|
||||
| 方法 | 参数 | 返回值 | 说明 |
|
||||
|-----|------|--------|------|
|
||||
| `execute` | `function_args` | `dict` | 执行工具核心逻辑 |
|
||||
|
||||
---
|
||||
|
||||
## 🎨 完整工具示例
|
||||
|
||||
完成一个天气查询工具
|
||||
|
||||
```python
|
||||
from src.plugin_system import BaseTool
|
||||
import aiohttp
|
||||
import json
|
||||
|
||||
class WeatherTool(BaseTool):
|
||||
"""天气查询工具 - 获取指定城市的实时天气信息"""
|
||||
|
||||
name = "weather_query"
|
||||
description = "查询指定城市的实时天气信息,包括温度、湿度、天气状况等"
|
||||
available_for_llm = True # 允许LLM调用此工具
|
||||
parameters = [
|
||||
("city", ToolParamType.STRING, "要查询天气的城市名称,如:北京、上海、纽约", True, None),
|
||||
("country", ToolParamType.STRING, "国家代码,如:CN、US,可选参数", False, None)
|
||||
]
|
||||
|
||||
async def execute(self, function_args: dict):
|
||||
"""执行天气查询"""
|
||||
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()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 注意事项和限制
|
||||
|
||||
### 当前限制
|
||||
|
||||
1. **适用范围**:主要适用于信息获取场景
|
||||
2. **配置要求**:必须开启工具处理器
|
||||
|
||||
### 开发建议
|
||||
|
||||
1. **功能专一**:每个工具专注单一功能
|
||||
2. **参数明确**:清晰定义工具参数和用途
|
||||
3. **错误处理**:完善的异常处理和错误反馈
|
||||
4. **性能考虑**:避免长时间阻塞操作
|
||||
5. **信息准确**:确保获取信息的准确性和时效性
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
### 1. 工具命名规范
|
||||
#### ✅ 好的命名
|
||||
```python
|
||||
name = "weather_query" # 清晰表达功能
|
||||
name = "knowledge_search" # 描述性强
|
||||
name = "stock_price_check" # 功能明确
|
||||
```
|
||||
#### ❌ 避免的命名
|
||||
```python
|
||||
name = "tool1" # 无意义
|
||||
name = "wq" # 过于简短
|
||||
name = "weather_and_news" # 功能过于复杂
|
||||
```
|
||||
|
||||
### 2. 描述规范
|
||||
#### ✅ 良好的描述
|
||||
```python
|
||||
description = "查询指定城市的实时天气信息,包括温度、湿度、天气状况"
|
||||
```
|
||||
#### ❌ 避免的描述
|
||||
```python
|
||||
description = "天气" # 过于简单
|
||||
description = "获取信息" # 不够具体
|
||||
```
|
||||
|
||||
### 3. 参数设计
|
||||
|
||||
#### ✅ 合理的参数设计
|
||||
```python
|
||||
parameters = [
|
||||
("city", ToolParamType.STRING, "城市名称,如:北京、上海", True, None),
|
||||
("unit", ToolParamType.STRING, "温度单位:celsius 或 fahrenheit", False, ["celsius", "fahrenheit"])
|
||||
]
|
||||
```
|
||||
#### ❌ 避免的参数设计
|
||||
```python
|
||||
parameters = [
|
||||
("data", "string", "数据", True) # 参数过于模糊
|
||||
]
|
||||
```
|
||||
|
||||
### 4. 结果格式化
|
||||
#### ✅ 良好的结果格式
|
||||
```python
|
||||
def _format_result(self, data):
|
||||
return f"""
|
||||
🔍 查询结果
|
||||
━━━━━━━━━━━━
|
||||
📊 数据: {data['value']}
|
||||
📅 时间: {data['timestamp']}
|
||||
📝 说明: {data['description']}
|
||||
━━━━━━━━━━━━
|
||||
""".strip()
|
||||
```
|
||||
#### ❌ 避免的结果格式
|
||||
```python
|
||||
def _format_result(self, data):
|
||||
return str(data) # 直接返回原始数据
|
||||
```
|
||||
Reference in New Issue
Block a user