引入新的 Action 激活机制,允许通过重写 go_activate() 方法来自定义激活逻辑。提供了三个工具函数: - _random_activation(): 随机概率激活 - _keyword_match(): 关键词匹配激活 - _llm_judge_activation(): LLM 智能判断激活 主要变更: - 在 BaseAction 中添加 go_activate() 抽象方法和相关工具函数 - 更新 ActionModifier 使用新的激活判断逻辑 - 在 hello_world_plugin 中添加新的激活方式示例 - 更新文档说明新的激活机制 - 保持向后兼容,旧的激活类型配置仍然可用 BREAKING CHANGE: Action 激活判断现在通过 go_activate() 方法进行,旧的激活类型字段已标记为废弃但仍然兼容
414 lines
12 KiB
Markdown
414 lines
12 KiB
Markdown
# Action 激活机制重构指南
|
||
|
||
## 📋 概述
|
||
|
||
本文档介绍 MoFox-Bot Action 组件的新激活机制。新机制通过 `go_activate()` 方法提供更灵活、更强大的激活判断能力。
|
||
|
||
## 🎯 为什么要重构?
|
||
|
||
### 旧的激活机制的问题
|
||
|
||
1. **不够灵活**:只能使用预定义的激活类型(`ALWAYS`、`NEVER`、`RANDOM`、`KEYWORD`、`LLM_JUDGE`)
|
||
2. **难以组合**:无法轻松组合多种激活条件
|
||
3. **配置复杂**:需要在类属性中配置多个字段
|
||
4. **扩展困难**:添加新的激活逻辑需要修改核心代码
|
||
|
||
### 新的激活机制的优势
|
||
|
||
1. **完全自定义**:通过重写 `go_activate()` 方法实现任意激活逻辑
|
||
2. **灵活组合**:可以轻松组合多种激活条件
|
||
3. **简洁明了**:激活逻辑集中在一个方法中
|
||
4. **易于扩展**:可以实现任何复杂的激活判断
|
||
|
||
## 🚀 快速开始
|
||
|
||
### 基本结构
|
||
|
||
```python
|
||
from src.plugin_system import BaseAction
|
||
|
||
class MyAction(BaseAction):
|
||
"""我的自定义 Action"""
|
||
|
||
action_name = "my_action"
|
||
action_description = "这是一个示例 Action"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""判断此 Action 是否应该被激活
|
||
|
||
Args:
|
||
chat_content: 聊天内容
|
||
llm_judge_model: LLM 判断模型(可选)
|
||
|
||
Returns:
|
||
bool: True 表示激活,False 表示不激活
|
||
"""
|
||
# 在这里实现你的激活逻辑
|
||
return True
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
"""执行 Action 的具体逻辑"""
|
||
await self.send_text("Hello, World!")
|
||
return True, "发送成功"
|
||
```
|
||
|
||
## 🛠️ 工具函数
|
||
|
||
BaseAction 提供了三个便捷的工具函数来简化常见的激活判断:
|
||
|
||
### 1. `_random_activation(probability)` - 随机激活
|
||
|
||
```python
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""30% 概率激活"""
|
||
return await self._random_activation(0.3)
|
||
```
|
||
|
||
**参数:**
|
||
- `probability`: 激活概率,范围 0.0 到 1.0
|
||
|
||
### 2. `_keyword_match(keywords, case_sensitive)` - 关键词匹配
|
||
|
||
```python
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""当消息包含特定关键词时激活"""
|
||
return await self._keyword_match(
|
||
keywords=["你好", "hello", "hi"],
|
||
case_sensitive=False # 不区分大小写
|
||
)
|
||
```
|
||
|
||
**参数:**
|
||
- `keywords`: 关键词列表
|
||
- `case_sensitive`: 是否区分大小写(默认 False)
|
||
|
||
### 3. `_llm_judge_activation(...)` - LLM 智能判断
|
||
|
||
```python
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""使用 LLM 判断是否激活"""
|
||
return await self._llm_judge_activation(
|
||
judge_prompt="当用户询问天气信息时激活",
|
||
llm_judge_model=llm_judge_model
|
||
)
|
||
```
|
||
|
||
**参数:**
|
||
- `judge_prompt`: 判断提示词(核心判断逻辑)
|
||
- `llm_judge_model`: LLM 模型实例(可选,会自动创建)
|
||
- `action_description`: Action 描述(可选,默认使用类属性)
|
||
- `action_require`: 使用场景列表(可选,默认使用类属性)
|
||
|
||
## 📚 示例
|
||
|
||
### 示例 1:简单的关键词激活
|
||
|
||
```python
|
||
class GreetingAction(BaseAction):
|
||
"""问候 Action - 当检测到问候语时激活"""
|
||
|
||
action_name = "greeting"
|
||
action_description = "回应用户的问候"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""检测到问候语时激活"""
|
||
return await self._keyword_match(
|
||
keywords=["你好", "hello", "hi", "嗨"],
|
||
case_sensitive=False
|
||
)
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
await self.send_text("你好!很高兴见到你!👋")
|
||
return True, "发送了问候"
|
||
```
|
||
|
||
### 示例 2:LLM 智能判断激活
|
||
|
||
```python
|
||
class ComfortAction(BaseAction):
|
||
"""安慰 Action - 当用户情绪低落时激活"""
|
||
|
||
action_name = "comfort"
|
||
action_description = "提供情感支持和安慰"
|
||
action_require = ["用户情绪低落", "需要安慰"]
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""使用 LLM 判断用户是否需要安慰"""
|
||
return await self._llm_judge_activation(
|
||
judge_prompt="""
|
||
判断用户是否表达了以下情绪或需求:
|
||
1. 感到难过、沮丧或失落
|
||
2. 表达了负面情绪
|
||
3. 需要安慰或鼓励
|
||
|
||
如果满足上述条件,回答"是",否则回答"否"。
|
||
""",
|
||
llm_judge_model=llm_judge_model
|
||
)
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
await self.send_text("看起来你心情不太好,希望能让你开心一点!🤗💕")
|
||
return True, "发送了安慰"
|
||
```
|
||
|
||
### 示例 3:随机激活
|
||
|
||
```python
|
||
class RandomEmojiAction(BaseAction):
|
||
"""随机表情 Action - 10% 概率激活"""
|
||
|
||
action_name = "random_emoji"
|
||
action_description = "随机发送表情增加趣味性"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""10% 概率激活"""
|
||
return await self._random_activation(0.1)
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
import random
|
||
emojis = ["😊", "😂", "👍", "🎉", "🤔", "🤖"]
|
||
await self.send_text(random.choice(emojis))
|
||
return True, "发送了表情"
|
||
```
|
||
|
||
### 示例 4:组合多种激活条件
|
||
|
||
```python
|
||
class FlexibleAction(BaseAction):
|
||
"""灵活的 Action - 组合多种激活条件"""
|
||
|
||
action_name = "flexible"
|
||
action_description = "展示灵活的激活逻辑"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""组合激活:随机 20% 概率,或者匹配关键词"""
|
||
|
||
# 策略 1: 随机激活
|
||
if await self._random_activation(0.2):
|
||
return True
|
||
|
||
# 策略 2: 关键词匹配
|
||
if await self._keyword_match(["表情", "emoji"], case_sensitive=False):
|
||
return True
|
||
|
||
# 策略 3: 所有条件都不满足
|
||
return False
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
await self.send_text("这是一个灵活的激活示例!✨")
|
||
return True, "执行成功"
|
||
```
|
||
|
||
### 示例 5:复杂的自定义逻辑
|
||
|
||
```python
|
||
class AdvancedAction(BaseAction):
|
||
"""高级 Action - 实现复杂的激活逻辑"""
|
||
|
||
action_name = "advanced"
|
||
action_description = "高级激活逻辑示例"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""实现复杂的激活逻辑"""
|
||
|
||
# 1. 检查时间:只在工作时间激活
|
||
from datetime import datetime
|
||
now = datetime.now()
|
||
if now.hour < 9 or now.hour > 18:
|
||
return False
|
||
|
||
# 2. 检查消息长度:消息太短不激活
|
||
if len(chat_content) < 10:
|
||
return False
|
||
|
||
# 3. 组合关键词和 LLM 判断
|
||
has_keyword = await self._keyword_match(
|
||
["帮助", "help", "求助"],
|
||
case_sensitive=False
|
||
)
|
||
|
||
if has_keyword:
|
||
# 如果匹配到关键词,用 LLM 进一步判断
|
||
return await self._llm_judge_activation(
|
||
judge_prompt="用户是否真的需要帮助?",
|
||
llm_judge_model=llm_judge_model
|
||
)
|
||
|
||
return False
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
await self.send_text("我来帮助你!")
|
||
return True, "提供了帮助"
|
||
```
|
||
|
||
### 示例 6:始终激活或从不激活
|
||
|
||
```python
|
||
class AlwaysActiveAction(BaseAction):
|
||
"""始终激活的 Action"""
|
||
|
||
action_name = "always_active"
|
||
action_description = "这个 Action 总是激活"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""始终返回 True"""
|
||
return True
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
await self.send_text("我总是可用!")
|
||
return True, "执行成功"
|
||
|
||
|
||
class NeverActiveAction(BaseAction):
|
||
"""从不激活的 Action(可用于测试或临时禁用)"""
|
||
|
||
action_name = "never_active"
|
||
action_description = "这个 Action 从不激活"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""始终返回 False"""
|
||
return False
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
# 这个方法不会被调用
|
||
return False, "未执行"
|
||
```
|
||
|
||
## 🔄 从旧的激活机制迁移
|
||
|
||
### 旧写法(已废弃但仍然兼容)
|
||
|
||
```python
|
||
class OldStyleAction(BaseAction):
|
||
action_name = "old_style"
|
||
action_description = "旧风格的 Action"
|
||
|
||
# 旧的激活配置
|
||
activation_type = ActionActivationType.KEYWORD
|
||
activation_keywords = ["你好", "hello"]
|
||
keyword_case_sensitive = False
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
return True, "执行成功"
|
||
```
|
||
|
||
### 新写法(推荐)
|
||
|
||
```python
|
||
class NewStyleAction(BaseAction):
|
||
action_name = "new_style"
|
||
action_description = "新风格的 Action"
|
||
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
"""使用新的激活方式"""
|
||
return await self._keyword_match(
|
||
chat_content,
|
||
keywords=["你好", "hello"],
|
||
case_sensitive=False
|
||
)
|
||
|
||
async def execute(self) -> tuple[bool, str]:
|
||
return True, "执行成功"
|
||
```
|
||
|
||
### 迁移对照表
|
||
|
||
| 旧的激活类型 | 新的实现方式 |
|
||
|-------------|-------------|
|
||
| `ActionActivationType.ALWAYS` | `return True` |
|
||
| `ActionActivationType.NEVER` | `return False` |
|
||
| `ActionActivationType.RANDOM` | `return await self._random_activation(probability)` |
|
||
| `ActionActivationType.KEYWORD` | `return await self._keyword_match( keywords)` |
|
||
| `ActionActivationType.LLM_JUDGE` | `return await self._llm_judge_activation(judge_prompt, llm_judge_model)` |
|
||
|
||
## ⚠️ 注意事项
|
||
|
||
### 1. 向后兼容性
|
||
|
||
旧的激活类型配置仍然有效!如果你的 Action 没有重写 `go_activate()` 方法,BaseAction 的默认实现会自动使用旧的配置字段。
|
||
|
||
### 2. 性能考虑
|
||
|
||
- `_random_activation()` 和 `_keyword_match()` 非常快速
|
||
- `_llm_judge_activation()` 需要调用 LLM,会有延迟
|
||
- ActionModifier 会并行执行所有 Action 的 `go_activate()` 方法以提高性能
|
||
|
||
### 3. 日志记录
|
||
|
||
工具函数会自动记录调试日志,便于追踪激活决策过程:
|
||
|
||
```
|
||
[DEBUG] 随机激活判断: 概率=0.3, 结果=激活
|
||
[DEBUG] 匹配到关键词: ['你好', 'hello']
|
||
[DEBUG] LLM 判断结果: 响应='是', 结果=激活
|
||
```
|
||
|
||
### 4. 错误处理
|
||
|
||
- 如果 `go_activate()` 抛出异常,Action 会被标记为不激活
|
||
- `_llm_judge_activation()` 在出错时默认返回 False(不激活)
|
||
|
||
## 🎨 最佳实践
|
||
|
||
### 1. 保持 `go_activate()` 方法简洁
|
||
|
||
```python
|
||
# ✅ 好的做法:简洁明了
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
return await self._keyword_match(["帮助", "help"])
|
||
|
||
# ❌ 不好的做法:过于复杂
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
# 大量复杂的逻辑...
|
||
# 应该拆分成辅助方法
|
||
```
|
||
|
||
### 2. 合理使用 LLM 判断
|
||
|
||
```python
|
||
# ✅ 好的做法:需要语义理解时使用 LLM
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
# 判断用户情绪需要 LLM
|
||
return await self._llm_judge_activation(
|
||
"用户是否情绪低落?",
|
||
llm_judge_model
|
||
)
|
||
|
||
# ❌ 不好的做法:简单匹配也用 LLM(浪费资源)
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
# 简单的关键词匹配不需要 LLM
|
||
return await self._llm_judge_activation(
|
||
"消息是否包含'你好'?",
|
||
llm_judge_model
|
||
)
|
||
```
|
||
|
||
### 3. 组合条件时使用清晰的逻辑结构
|
||
|
||
```python
|
||
# ✅ 好的做法:清晰的条件组合
|
||
async def go_activate(self, llm_judge_model=None) -> bool:
|
||
# 策略 1: 快速路径 - 关键词匹配
|
||
if await self._keyword_match(["紧急", "urgent"]):
|
||
return True
|
||
|
||
# 策略 2: 随机激活
|
||
if await self._random_activation(0.1):
|
||
return True
|
||
|
||
# 策略 3: LLM 判断(最耗时,放最后)
|
||
return await self._llm_judge_activation(
|
||
"是否需要特别关注?",
|
||
llm_judge_model
|
||
)
|
||
```
|
||
|
||
## 📖 完整示例项目
|
||
|
||
查看 `plugins/hello_world_plugin/plugin.py` 获取更多实际示例。
|
||
|
||
## 🤝 贡献
|
||
|
||
如果你有更好的激活逻辑实现,欢迎分享!
|
||
|