383 lines
12 KiB
Markdown
383 lines
12 KiB
Markdown
# ⚡ Action组件详解
|
||
|
||
## 📖 什么是Action
|
||
|
||
Action是给麦麦在回复之外提供额外功能的智能组件,**由麦麦的决策系统自主选择是否使用**,具有随机性和拟人化的调用特点。Action不是直接响应用户命令,而是让麦麦根据聊天情境智能地选择合适的动作,使其行为更加自然和真实。
|
||
|
||
### 🎯 Action的特点
|
||
|
||
- 🧠 **智能激活**:麦麦根据多种条件智能判断是否使用
|
||
- 🎲 **随机性**:增加行为的不可预测性,更接近真人交流
|
||
- 🤖 **拟人化**:让麦麦的回应更自然、更有个性
|
||
- 🔄 **情境感知**:基于聊天上下文做出合适的反应
|
||
|
||
## 🎯 两层决策机制
|
||
|
||
Action采用**两层决策机制**来优化性能和决策质量:
|
||
|
||
### 第一层:激活控制(Activation Control)
|
||
|
||
**激活决定麦麦是否"知道"这个Action的存在**,即这个Action是否进入决策候选池。**不被激活的Action麦麦永远不会选择**。
|
||
|
||
> 🎯 **设计目的**:在加载许多插件的时候降低LLM决策压力,避免让麦麦在过多的选项中纠结。
|
||
|
||
#### 激活类型说明
|
||
|
||
| 激活类型 | 说明 | 使用场景 |
|
||
| ------------- | ------------------------------------------- | ------------------------ |
|
||
| `NEVER` | 从不激活,Action对麦麦不可见 | 临时禁用某个Action |
|
||
| `ALWAYS` | 永远激活,Action总是在麦麦的候选池中 | 核心功能,如回复、不回复 |
|
||
| `LLM_JUDGE` | 通过LLM智能判断当前情境是否需要激活此Action | 需要智能判断的复杂场景 |
|
||
| `RANDOM` | 基于随机概率决定是否激活 | 增加行为随机性的功能 |
|
||
| `KEYWORD` | 当检测到特定关键词时激活 | 明确触发条件的功能 |
|
||
|
||
#### 聊天模式控制
|
||
|
||
| 模式 | 说明 |
|
||
| ------------------- | ------------------------ |
|
||
| `ChatMode.FOCUS` | 仅在专注聊天模式下可激活 |
|
||
| `ChatMode.NORMAL` | 仅在普通聊天模式下可激活 |
|
||
| `ChatMode.ALL` | 所有模式下都可激活 |
|
||
|
||
### 第二层:使用决策(Usage Decision)
|
||
|
||
**在Action被激活后,使用条件决定麦麦什么时候会"选择"使用这个Action**。
|
||
|
||
这一层由以下因素综合决定:
|
||
|
||
- `action_require`:使用场景描述,帮助LLM判断何时选择
|
||
- `action_parameters`:所需参数,影响Action的可执行性
|
||
- 当前聊天上下文和麦麦的决策逻辑
|
||
|
||
### 🎬 决策流程示例
|
||
|
||
假设有一个"发送表情"Action:
|
||
|
||
```python
|
||
class EmojiAction(BaseAction):
|
||
# 第一层:激活控制
|
||
focus_activation_type = ActionActivationType.RANDOM # 专注模式下随机激活
|
||
normal_activation_type = ActionActivationType.KEYWORD # 普通模式下关键词激活
|
||
activation_keywords = ["表情", "emoji", "😊"]
|
||
|
||
# 第二层:使用决策
|
||
action_require = [
|
||
"表达情绪时可以选择使用",
|
||
"增加聊天趣味性",
|
||
"不要连续发送多个表情"
|
||
]
|
||
```
|
||
|
||
**决策流程**:
|
||
|
||
1. **第一层激活判断**:
|
||
|
||
- 普通模式:只有当用户消息包含"表情"、"emoji"或"😊"时,麦麦才"知道"可以使用这个Action
|
||
- 专注模式:随机激活,有概率让麦麦"看到"这个Action
|
||
2. **第二层使用决策**:
|
||
|
||
- 即使Action被激活,麦麦还会根据 `action_require`中的条件判断是否真正选择使用
|
||
- 例如:如果刚刚已经发过表情,根据"不要连续发送多个表情"的要求,麦麦可能不会选择这个Action
|
||
|
||
## 📋 Action必须项清单
|
||
|
||
每个Action类都**必须**包含以下属性:
|
||
|
||
### 1. 激活控制必须项
|
||
|
||
```python
|
||
# 专注模式下的激活类型
|
||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||
|
||
# 普通模式下的激活类型
|
||
normal_activation_type = ActionActivationType.KEYWORD
|
||
|
||
# 启用的聊天模式
|
||
mode_enable = ChatMode.ALL
|
||
|
||
# 是否允许与其他Action并行执行
|
||
parallel_action = False
|
||
```
|
||
|
||
### 2. 基本信息必须项
|
||
|
||
```python
|
||
# Action的唯一标识名称
|
||
action_name = "my_action"
|
||
|
||
# Action的功能描述
|
||
action_description = "描述这个Action的具体功能和用途"
|
||
```
|
||
|
||
### 3. 功能定义必须项
|
||
|
||
```python
|
||
# Action参数定义 - 告诉LLM执行时需要什么参数
|
||
action_parameters = {
|
||
"param1": "参数1的说明",
|
||
"param2": "参数2的说明"
|
||
}
|
||
|
||
# Action使用场景描述 - 帮助LLM判断何时"选择"使用
|
||
action_require = [
|
||
"使用场景描述1",
|
||
"使用场景描述2"
|
||
]
|
||
|
||
# 关联的消息类型 - 说明Action能处理什么类型的内容
|
||
associated_types = ["text", "emoji", "image"]
|
||
```
|
||
|
||
### 4. 执行方法必须项
|
||
|
||
```python
|
||
async def execute(self) -> Tuple[bool, str]:
|
||
"""
|
||
执行Action的主要逻辑
|
||
|
||
Returns:
|
||
Tuple[bool, str]: (是否成功, 执行结果描述)
|
||
"""
|
||
# 执行动作的代码
|
||
success = True
|
||
message = "动作执行成功"
|
||
|
||
return success, message
|
||
```
|
||
|
||
## 🔧 激活类型详解
|
||
|
||
### KEYWORD激活
|
||
|
||
当检测到特定关键词时激活Action:
|
||
|
||
```python
|
||
class GreetingAction(BaseAction):
|
||
focus_activation_type = ActionActivationType.KEYWORD
|
||
normal_activation_type = ActionActivationType.KEYWORD
|
||
|
||
# 关键词配置
|
||
activation_keywords = ["你好", "hello", "hi", "嗨"]
|
||
keyword_case_sensitive = False # 不区分大小写
|
||
|
||
async def execute(self) -> Tuple[bool, str]:
|
||
# 执行问候逻辑
|
||
return True, "发送了问候"
|
||
```
|
||
|
||
### LLM_JUDGE激活
|
||
|
||
通过LLM智能判断是否激活:
|
||
|
||
```python
|
||
class HelpAction(BaseAction):
|
||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||
normal_activation_type = ActionActivationType.LLM_JUDGE
|
||
|
||
# LLM判断提示词
|
||
llm_judge_prompt = """
|
||
判定是否需要使用帮助动作的条件:
|
||
1. 用户表达了困惑或需要帮助
|
||
2. 用户提出了问题但没有得到满意答案
|
||
3. 对话中出现了技术术语或复杂概念
|
||
|
||
请回答"是"或"否"。
|
||
"""
|
||
|
||
async def execute(self) -> Tuple[bool, str]:
|
||
# 执行帮助逻辑
|
||
return True, "提供了帮助"
|
||
```
|
||
|
||
### RANDOM激活
|
||
|
||
基于随机概率激活:
|
||
|
||
```python
|
||
class SurpriseAction(BaseAction):
|
||
focus_activation_type = ActionActivationType.RANDOM
|
||
normal_activation_type = ActionActivationType.RANDOM
|
||
|
||
# 随机激活概率
|
||
random_activation_probability = 0.1 # 10%概率激活
|
||
|
||
async def execute(self) -> Tuple[bool, str]:
|
||
# 执行惊喜动作
|
||
return True, "发送了惊喜内容"
|
||
```
|
||
|
||
### ALWAYS激活
|
||
|
||
永远激活,常用于核心功能:
|
||
|
||
```python
|
||
class CoreAction(BaseAction):
|
||
focus_activation_type = ActionActivationType.ALWAYS
|
||
normal_activation_type = ActionActivationType.ALWAYS
|
||
|
||
async def execute(self) -> Tuple[bool, str]:
|
||
# 执行核心功能
|
||
return True, "执行了核心功能"
|
||
```
|
||
|
||
### NEVER激活
|
||
|
||
从不激活,用于临时禁用:
|
||
|
||
```python
|
||
class DisabledAction(BaseAction):
|
||
focus_activation_type = ActionActivationType.NEVER
|
||
normal_activation_type = ActionActivationType.NEVER
|
||
|
||
async def execute(self) -> Tuple[bool, str]:
|
||
# 这个方法不会被调用
|
||
return False, "已禁用"
|
||
```
|
||
|
||
## 📚 BaseAction内置属性和方法
|
||
|
||
### 内置属性
|
||
|
||
```python
|
||
class MyAction(BaseAction):
|
||
def __init__(self):
|
||
# 消息相关属性
|
||
self.message # 当前消息对象
|
||
self.chat_stream # 聊天流对象
|
||
self.user_id # 用户ID
|
||
self.user_nickname # 用户昵称
|
||
self.platform # 平台类型 (qq, telegram等)
|
||
self.chat_id # 聊天ID
|
||
self.is_group # 是否群聊
|
||
|
||
# Action相关属性
|
||
self.action_data # Action执行时的数据
|
||
self.thinking_id # 思考ID
|
||
self.matched_groups # 匹配到的组(如果有正则匹配)
|
||
```
|
||
|
||
### 内置方法
|
||
|
||
```python
|
||
class MyAction(BaseAction):
|
||
# 配置相关
|
||
def get_config(self, key: str, default=None):
|
||
"""获取配置值"""
|
||
pass
|
||
|
||
# 消息发送相关
|
||
async def send_text(self, text: str):
|
||
"""发送文本消息"""
|
||
pass
|
||
|
||
async def send_emoji(self, emoji_base64: str):
|
||
"""发送表情包"""
|
||
pass
|
||
|
||
async def send_image(self, image_base64: str):
|
||
"""发送图片"""
|
||
pass
|
||
|
||
# 动作记录相关
|
||
async def store_action_info(self, **kwargs):
|
||
"""记录动作信息"""
|
||
pass
|
||
```
|
||
|
||
## 🎯 完整Action示例
|
||
|
||
```python
|
||
from src.plugin_system import BaseAction, ActionActivationType, ChatMode
|
||
from typing import Tuple
|
||
|
||
class ExampleAction(BaseAction):
|
||
"""示例Action - 展示完整的Action结构"""
|
||
|
||
# === 激活控制 ===
|
||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||
normal_activation_type = ActionActivationType.KEYWORD
|
||
mode_enable = ChatMode.ALL
|
||
parallel_action = False
|
||
|
||
# 关键词激活配置
|
||
activation_keywords = ["示例", "测试", "example"]
|
||
keyword_case_sensitive = False
|
||
|
||
# LLM判断提示词
|
||
llm_judge_prompt = "当用户需要示例或测试功能时激活"
|
||
|
||
# 随机激活概率(如果使用RANDOM类型)
|
||
random_activation_probability = 0.2
|
||
|
||
# === 基本信息 ===
|
||
action_name = "example_action"
|
||
action_description = "这是一个示例Action,用于演示Action的完整结构"
|
||
|
||
# === 功能定义 ===
|
||
action_parameters = {
|
||
"content": "要处理的内容",
|
||
"type": "处理类型",
|
||
"options": "可选配置"
|
||
}
|
||
|
||
action_require = [
|
||
"用户需要示例功能时使用",
|
||
"适合用于测试和演示",
|
||
"不要在正式对话中频繁使用"
|
||
]
|
||
|
||
associated_types = ["text", "emoji"]
|
||
|
||
async def execute(self) -> Tuple[bool, str]:
|
||
"""执行示例Action"""
|
||
try:
|
||
# 获取Action参数
|
||
content = self.action_data.get("content", "默认内容")
|
||
action_type = self.action_data.get("type", "default")
|
||
|
||
# 获取配置
|
||
enable_feature = self.get_config("example.enable_advanced", False)
|
||
max_length = self.get_config("example.max_length", 100)
|
||
|
||
# 执行具体逻辑
|
||
if action_type == "greeting":
|
||
await self.send_text(f"你好!这是示例内容:{content}")
|
||
elif action_type == "info":
|
||
await self.send_text(f"信息:{content[:max_length]}")
|
||
else:
|
||
await self.send_text("执行了示例Action")
|
||
|
||
# 记录动作信息
|
||
await self.store_action_info(
|
||
action_build_into_prompt=True,
|
||
action_prompt_display=f"执行了示例动作:{action_type}",
|
||
action_done=True
|
||
)
|
||
|
||
return True, f"示例Action执行成功,类型:{action_type}"
|
||
|
||
except Exception as e:
|
||
return False, f"执行失败:{str(e)}"
|
||
```
|
||
|
||
## 🎯 最佳实践
|
||
|
||
### 1. Action设计原则
|
||
|
||
- **单一职责**:每个Action只负责一个明确的功能
|
||
- **智能激活**:合理选择激活类型,避免过度激活
|
||
- **清晰描述**:提供准确的`action_require`帮助LLM决策
|
||
- **错误处理**:妥善处理执行过程中的异常情况
|
||
|
||
### 2. 性能优化
|
||
|
||
- **激活控制**:使用合适的激活类型减少不必要的LLM调用
|
||
- **并行执行**:谨慎设置`parallel_action`,避免冲突
|
||
- **资源管理**:及时释放占用的资源
|
||
|
||
### 3. 调试技巧
|
||
|
||
- **日志记录**:在关键位置添加日志
|
||
- **参数验证**:检查`action_data`的有效性
|
||
- **配置测试**:测试不同配置下的行为
|