refc:重构插件api,补全文档,合并expressor和replyer,分离reply和sender,新log浏览器
This commit is contained in:
@@ -23,27 +23,28 @@ Action采用**两层决策机制**来优化性能和决策质量:
|
||||
|
||||
#### 激活类型说明
|
||||
|
||||
| 激活类型 | 说明 | 使用场景 |
|
||||
|---------|-----|---------|
|
||||
| `NEVER` | 从不激活,Action对麦麦不可见 | 临时禁用某个Action |
|
||||
| `ALWAYS` | 永远激活,Action总是在麦麦的候选池中 | 核心功能,如回复、表情 |
|
||||
| `LLM_JUDGE` | 通过LLM智能判断当前情境是否需要激活此Action | 需要智能判断的复杂场景 |
|
||||
| `RANDOM` | 基于随机概率决定是否激活 | 增加行为随机性的功能 |
|
||||
| `KEYWORD` | 当检测到特定关键词时激活 | 明确触发条件的功能 |
|
||||
| 激活类型 | 说明 | 使用场景 |
|
||||
| ------------- | ------------------------------------------- | ------------------------ |
|
||||
| `NEVER` | 从不激活,Action对麦麦不可见 | 临时禁用某个Action |
|
||||
| `ALWAYS` | 永远激活,Action总是在麦麦的候选池中 | 核心功能,如回复、不回复 |
|
||||
| `LLM_JUDGE` | 通过LLM智能判断当前情境是否需要激活此Action | 需要智能判断的复杂场景 |
|
||||
| `RANDOM` | 基于随机概率决定是否激活 | 增加行为随机性的功能 |
|
||||
| `KEYWORD` | 当检测到特定关键词时激活 | 明确触发条件的功能 |
|
||||
|
||||
#### 聊天模式控制
|
||||
|
||||
| 模式 | 说明 |
|
||||
|-----|-----|
|
||||
| `ChatMode.FOCUS` | 仅在专注聊天模式下可激活 |
|
||||
| 模式 | 说明 |
|
||||
| ------------------- | ------------------------ |
|
||||
| `ChatMode.FOCUS` | 仅在专注聊天模式下可激活 |
|
||||
| `ChatMode.NORMAL` | 仅在普通聊天模式下可激活 |
|
||||
| `ChatMode.ALL` | 所有模式下都可激活 |
|
||||
| `ChatMode.ALL` | 所有模式下都可激活 |
|
||||
|
||||
### 第二层:使用决策(Usage Decision)
|
||||
|
||||
**在Action被激活后,使用条件决定麦麦什么时候会"选择"使用这个Action**。
|
||||
|
||||
这一层由以下因素综合决定:
|
||||
|
||||
- `action_require`:使用场景描述,帮助LLM判断何时选择
|
||||
- `action_parameters`:所需参数,影响Action的可执行性
|
||||
- 当前聊天上下文和麦麦的决策逻辑
|
||||
@@ -58,7 +59,7 @@ class EmojiAction(BaseAction):
|
||||
focus_activation_type = ActionActivationType.RANDOM # 专注模式下随机激活
|
||||
normal_activation_type = ActionActivationType.KEYWORD # 普通模式下关键词激活
|
||||
activation_keywords = ["表情", "emoji", "😊"]
|
||||
|
||||
|
||||
# 第二层:使用决策
|
||||
action_require = [
|
||||
"表达情绪时可以选择使用",
|
||||
@@ -68,12 +69,14 @@ class EmojiAction(BaseAction):
|
||||
```
|
||||
|
||||
**决策流程**:
|
||||
|
||||
1. **第一层激活判断**:
|
||||
|
||||
- 普通模式:只有当用户消息包含"表情"、"emoji"或"😊"时,麦麦才"知道"可以使用这个Action
|
||||
- 专注模式:随机激活,有概率让麦麦"看到"这个Action
|
||||
|
||||
2. **第二层使用决策**:
|
||||
- 即使Action被激活,麦麦还会根据`action_require`中的条件判断是否真正选择使用
|
||||
|
||||
- 即使Action被激活,麦麦还会根据 `action_require`中的条件判断是否真正选择使用
|
||||
- 例如:如果刚刚已经发过表情,根据"不要连续发送多个表情"的要求,麦麦可能不会选择这个Action
|
||||
|
||||
## 📋 Action必须项清单
|
||||
@@ -125,38 +128,147 @@ action_require = [
|
||||
associated_types = ["text", "emoji", "image"]
|
||||
```
|
||||
|
||||
### 4. 动作记录必须项
|
||||
### 4. 新API导入必须项
|
||||
|
||||
每个 Action 在执行完成后,**必须**使用 `store_action_info` 记录动作信息。这是非常重要的,因为:
|
||||
|
||||
1. **记忆连续性**:让麦麦记住自己执行过的动作,避免重复执行
|
||||
2. **上下文理解**:帮助麦麦理解自己的行为历史,做出更合理的决策
|
||||
3. **行为追踪**:便于后续查询和分析麦麦的行为模式
|
||||
使用新插件系统时,必须导入所需的API模块:
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
# 导入新API模块
|
||||
from src.plugin_system.apis import generator_api, send_api, emoji_api
|
||||
|
||||
# 如果需要使用其他API
|
||||
from src.plugin_system.apis import llm_api, database_api, message_api
|
||||
```
|
||||
|
||||
### 5. 动作记录必须项
|
||||
|
||||
每个 Action 在执行完成后,**必须**使用 `store_action_info` 记录动作信息:
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# ... 执行动作的代码 ...
|
||||
|
||||
|
||||
if success:
|
||||
# 存储动作信息
|
||||
await self.api.store_action_info(
|
||||
# 存储动作信息 - 使用新API格式
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True, # 让麦麦知道这个动作
|
||||
action_prompt_display=f"执行了xxx动作,参数:{param}", # 动作描述
|
||||
action_done=True, # 动作是否完成
|
||||
thinking_id=self.thinking_id, # 关联的思考ID
|
||||
action_data={ # 动作的详细数据
|
||||
"param1": value1,
|
||||
"param2": value2
|
||||
}
|
||||
)
|
||||
return True, "动作执行成功"
|
||||
```
|
||||
|
||||
> ⚠️ **重要提示**:如果不记录动作信息,可能会导致以下问题:
|
||||
> - 麦麦不知道自己执行过什么动作,可能会重复执行
|
||||
> - 无法追踪动作历史,影响后续决策
|
||||
> - 在长对话中失去上下文连续性
|
||||
> - 无法进行行为分析和优化
|
||||
> ⚠️ **重要提示**:新API格式中不再需要手动传递 `thinking_id` 等参数,BaseAction会自动处理。
|
||||
|
||||
## 🚀 新API使用指南
|
||||
|
||||
### 📨 消息发送API
|
||||
|
||||
新的消息发送API更加简洁,自动处理群聊/私聊逻辑:
|
||||
|
||||
```python
|
||||
class MessageAction(BaseAction):
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 发送文本消息 - 自动判断群聊/私聊
|
||||
await self.send_text("Hello World!")
|
||||
|
||||
# 发送表情包
|
||||
emoji_base64 = await emoji_api.get_by_description("开心")
|
||||
if emoji_base64:
|
||||
await self.send_emoji(emoji_base64)
|
||||
|
||||
# 发送图片
|
||||
await self.send_image(image_base64)
|
||||
|
||||
# 发送自定义类型消息
|
||||
await self.send_custom("video", video_data, typing=True)
|
||||
|
||||
return True, "消息发送完成"
|
||||
```
|
||||
|
||||
### 🤖 智能生成API (replyer_1)
|
||||
|
||||
使用replyer_1生成个性化内容:
|
||||
|
||||
```python
|
||||
class SmartReplyAction(BaseAction):
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 构建生成参数
|
||||
reply_data = {
|
||||
"text": "请生成一个友好的回复",
|
||||
"style": "casual",
|
||||
"topic": "日常聊天",
|
||||
"replyer_name": "replyer_1" # 指定使用replyer_1
|
||||
}
|
||||
|
||||
# 使用generator_api生成回复
|
||||
success, reply_set = await generator_api.generate_reply(
|
||||
chat_stream=self.chat_stream,
|
||||
action_data=reply_data,
|
||||
platform=self.platform,
|
||||
chat_id=self.chat_id,
|
||||
is_group=self.is_group
|
||||
)
|
||||
|
||||
if success and reply_set:
|
||||
# 提取并发送文本回复
|
||||
for reply_type, reply_content in reply_set:
|
||||
if reply_type == "text":
|
||||
await self.send_text(reply_content)
|
||||
elif reply_type == "emoji":
|
||||
await self.send_emoji(reply_content)
|
||||
|
||||
# 记录动作
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display=f"使用replyer_1生成了智能回复",
|
||||
action_done=True
|
||||
)
|
||||
|
||||
return True, "智能回复生成成功"
|
||||
else:
|
||||
return False, "回复生成失败"
|
||||
```
|
||||
|
||||
### ⚙️ 配置访问API
|
||||
|
||||
使用便捷的配置访问方法:
|
||||
|
||||
```python
|
||||
class ConfigurableAction(BaseAction):
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 获取插件配置 - 支持嵌套键访问
|
||||
enable_feature = self.get_config("features.enable_smart_mode", False)
|
||||
max_length = self.get_config("limits.max_text_length", 200)
|
||||
style = self.get_config("behavior.response_style", "friendly")
|
||||
|
||||
if enable_feature:
|
||||
# 启用高级功能
|
||||
pass
|
||||
|
||||
return True, "配置获取成功"
|
||||
```
|
||||
|
||||
### 📊 数据库API
|
||||
|
||||
使用新的数据库API存储和查询数据:
|
||||
|
||||
```python
|
||||
class DataAction(BaseAction):
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 使用database_api
|
||||
from src.plugin_system.apis import database_api
|
||||
|
||||
# 存储数据
|
||||
await database_api.store_action_info(
|
||||
chat_stream=self.chat_stream,
|
||||
action_name=self.action_name,
|
||||
action_data=self.action_data,
|
||||
# ... 其他参数
|
||||
)
|
||||
|
||||
return True, "数据存储完成"
|
||||
```
|
||||
|
||||
## 🔧 激活类型详解
|
||||
|
||||
@@ -168,10 +280,34 @@ async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
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]:
|
||||
# 可选:使用replyer_1生成个性化问候
|
||||
if self.get_config("greeting.use_smart_reply", False):
|
||||
greeting_data = {
|
||||
"text": "生成一个友好的问候语",
|
||||
"replyer_name": "replyer_1"
|
||||
}
|
||||
|
||||
success, reply_set = await generator_api.generate_reply(
|
||||
chat_stream=self.chat_stream,
|
||||
action_data=greeting_data
|
||||
)
|
||||
|
||||
if success:
|
||||
for reply_type, content in reply_set:
|
||||
if reply_type == "text":
|
||||
await self.send_text(content)
|
||||
break
|
||||
return True, "发送智能问候"
|
||||
|
||||
# 传统问候方式
|
||||
await self.send_text("你好!很高兴见到你!")
|
||||
return True, "发送问候"
|
||||
```
|
||||
|
||||
### LLM_JUDGE激活
|
||||
@@ -182,16 +318,38 @@ class GreetingAction(BaseAction):
|
||||
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]:
|
||||
# 使用replyer_1生成帮助内容
|
||||
help_data = {
|
||||
"text": "用户需要帮助,请提供适当的帮助信息",
|
||||
"help_type": self.action_data.get("help_type", "general"),
|
||||
"replyer_name": "replyer_1"
|
||||
}
|
||||
|
||||
success, reply_set = await generator_api.generate_reply(
|
||||
chat_stream=self.chat_stream,
|
||||
action_data=help_data
|
||||
)
|
||||
|
||||
if success:
|
||||
for reply_type, content in reply_set:
|
||||
if reply_type == "text":
|
||||
await self.send_text(content)
|
||||
return True, "提供了帮助"
|
||||
else:
|
||||
await self.send_text("我来帮助你!有什么问题吗?")
|
||||
return True, "提供了默认帮助"
|
||||
```
|
||||
|
||||
### RANDOM激活
|
||||
@@ -202,466 +360,210 @@ class HelpAction(BaseAction):
|
||||
class SurpriseAction(BaseAction):
|
||||
focus_activation_type = ActionActivationType.RANDOM
|
||||
normal_activation_type = ActionActivationType.RANDOM
|
||||
|
||||
|
||||
# 随机激活概率
|
||||
random_activation_probability = 0.1 # 10%概率激活
|
||||
```
|
||||
|
||||
### ALWAYS/NEVER激活
|
||||
|
||||
```python
|
||||
class CoreAction(BaseAction):
|
||||
focus_activation_type = ActionActivationType.ALWAYS # 总是激活
|
||||
normal_activation_type = ActionActivationType.NEVER # 在普通模式下禁用
|
||||
```
|
||||
|
||||
## 🎨 完整Action示例
|
||||
|
||||
### 智能问候Action
|
||||
|
||||
```python
|
||||
from src.plugin_system import BaseAction, ActionActivationType, ChatMode
|
||||
|
||||
class SmartGreetingAction(BaseAction):
|
||||
"""智能问候Action - 展示关键词激活的完整示例"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "smart_greeting"
|
||||
action_description = "智能问候系统,基于关键词触发,支持个性化问候消息"
|
||||
|
||||
# 关键词配置
|
||||
activation_keywords = ["你好", "hello", "hi", "嗨", "问候", "早上好", "晚上好"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"username": "要问候的用户名(可选)",
|
||||
"greeting_style": "问候风格:casual(随意)、formal(正式)、friendly(友好)"
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"用户发送包含问候词汇的消息时使用",
|
||||
"检测到新用户加入时使用",
|
||||
"响应友好交流需求时使用",
|
||||
"避免在短时间内重复问候同一用户"
|
||||
]
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行智能问候"""
|
||||
# 获取参数
|
||||
username = self.action_data.get("username", "")
|
||||
greeting_style = self.action_data.get("greeting_style", "casual")
|
||||
|
||||
# 根据风格生成问候消息
|
||||
if greeting_style == "formal":
|
||||
message = f"您好{username}!很荣幸为您服务!"
|
||||
emoji = "🙏"
|
||||
elif greeting_style == "friendly":
|
||||
message = f"你好{username}!欢迎来到这里,希望我们能成为好朋友!"
|
||||
emoji = "😊"
|
||||
else: # casual
|
||||
message = f"嗨{username}!很开心见到你~"
|
||||
emoji = "👋"
|
||||
|
||||
# 发送消息
|
||||
await self.send_text(message)
|
||||
await self.send_type("emoji", emoji)
|
||||
|
||||
return True, f"向{username or '用户'}发送了{greeting_style}风格的问候"
|
||||
import random
|
||||
|
||||
surprises = ["🎉", "✨", "🌟", "💝", "🎈"]
|
||||
selected = random.choice(surprises)
|
||||
|
||||
await self.send_emoji(selected)
|
||||
return True, f"发送了惊喜表情: {selected}"
|
||||
```
|
||||
|
||||
### 智能禁言Action
|
||||
## 💡 完整示例
|
||||
|
||||
以下是一个真实的群管理禁言Action示例,展示了LLM判断、参数验证、配置管理等高级功能:
|
||||
### 智能聊天Action
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
import random
|
||||
from src.plugin_system.base.base_action import BaseAction
|
||||
from src.plugin_system.base.component_types import ActionActivationType, ChatMode
|
||||
from src.plugin_system.apis import generator_api, emoji_api
|
||||
|
||||
class MuteAction(BaseAction):
|
||||
"""智能禁言Action - 基于LLM智能判断是否需要禁言"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE # Focus模式使用LLM判定
|
||||
normal_activation_type = ActionActivationType.KEYWORD # Normal模式使用关键词
|
||||
class IntelligentChatAction(BaseAction):
|
||||
"""智能聊天Action - 展示新API的完整用法"""
|
||||
|
||||
# 激活设置
|
||||
focus_activation_type = ActionActivationType.ALWAYS
|
||||
normal_activation_type = ActionActivationType.LLM_JUDGE
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = False
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "mute"
|
||||
action_description = "智能禁言系统,基于LLM判断是否需要禁言"
|
||||
|
||||
# ===== 激活配置 =====
|
||||
# 关键词设置(用于Normal模式)
|
||||
activation_keywords = ["禁言", "mute", "ban", "silence"]
|
||||
keyword_case_sensitive = False
|
||||
|
||||
# LLM判定提示词(用于Focus模式)
|
||||
llm_judge_prompt = """
|
||||
判定是否需要使用禁言动作的严格条件:
|
||||
|
||||
使用禁言的情况:
|
||||
1. 用户发送明显违规内容(色情、暴力、政治敏感等)
|
||||
2. 恶意刷屏或垃圾信息轰炸
|
||||
3. 用户主动明确要求被禁言("禁言我"等)
|
||||
4. 严重违反群规的行为
|
||||
5. 恶意攻击他人或群组管理
|
||||
|
||||
绝对不要使用的情况:
|
||||
1. 正常聊天和交流
|
||||
2. 情绪化表达但无恶意
|
||||
3. 开玩笑或调侃,除非过分
|
||||
4. 单纯的意见分歧或争论
|
||||
"""
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
action_parameters = {
|
||||
"target": "禁言对象,必填,输入你要禁言的对象的名字,请仔细思考不要弄错禁言对象",
|
||||
"duration": "禁言时长,必填,输入你要禁言的时长(秒),单位为秒,必须为数字",
|
||||
"reason": "禁言理由,可选",
|
||||
}
|
||||
|
||||
action_require = [
|
||||
"当有人违反了公序良俗的内容",
|
||||
"当有人刷屏时使用",
|
||||
"当有人发了擦边,或者色情内容时使用",
|
||||
"当有人要求禁言自己时使用",
|
||||
"如果某人已经被禁言了,就不要再次禁言了,除非你想追加时间!!",
|
||||
]
|
||||
|
||||
associated_types = ["text", "command"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, Optional[str]]:
|
||||
"""执行智能禁言判定"""
|
||||
# 获取参数
|
||||
target = self.action_data.get("target")
|
||||
duration = self.action_data.get("duration")
|
||||
reason = self.action_data.get("reason", "违反群规")
|
||||
|
||||
# 参数验证
|
||||
if not target:
|
||||
await self.send_text("没有指定禁言对象呢~")
|
||||
return False, "禁言目标不能为空"
|
||||
|
||||
if not duration:
|
||||
await self.send_text("没有指定禁言时长呢~")
|
||||
return False, "禁言时长不能为空"
|
||||
|
||||
# 获取时长限制配置
|
||||
min_duration = self.api.get_config("mute.min_duration", 60)
|
||||
max_duration = self.api.get_config("mute.max_duration", 2592000)
|
||||
|
||||
# 验证时长格式并转换
|
||||
try:
|
||||
duration_int = int(duration)
|
||||
if duration_int <= 0:
|
||||
await self.send_text("禁言时长必须是正数哦~")
|
||||
return False, "禁言时长必须大于0"
|
||||
|
||||
# 限制禁言时长范围
|
||||
if duration_int < min_duration:
|
||||
duration_int = min_duration
|
||||
elif duration_int > max_duration:
|
||||
duration_int = max_duration
|
||||
|
||||
except (ValueError, TypeError):
|
||||
await self.send_text("禁言时长必须是数字哦~")
|
||||
return False, f"禁言时长格式无效: {duration}"
|
||||
|
||||
# 获取用户ID
|
||||
try:
|
||||
platform, user_id = await self.api.get_user_id_by_person_name(target)
|
||||
except Exception as e:
|
||||
await self.send_text("查找用户信息时出现问题~")
|
||||
return False, f"查找用户ID时出错: {e}"
|
||||
|
||||
if not user_id:
|
||||
await self.send_text(f"找不到 {target} 这个人呢~")
|
||||
return False, f"未找到用户 {target} 的ID"
|
||||
|
||||
# 格式化时长显示
|
||||
time_str = self._format_duration(duration_int)
|
||||
|
||||
# 获取模板化消息
|
||||
message = self._get_template_message(target, time_str, reason)
|
||||
await self.send_message_by_expressor(message)
|
||||
|
||||
# 发送群聊禁言命令
|
||||
success = await self.send_command(
|
||||
command_name="GROUP_BAN",
|
||||
args={"qq_id": str(user_id), "duration": str(duration_int)},
|
||||
display_message=f"禁言了 {target} {time_str}",
|
||||
)
|
||||
|
||||
if success:
|
||||
return True, f"成功禁言 {target},时长 {time_str}"
|
||||
else:
|
||||
await self.send_text("执行禁言动作失败")
|
||||
return False, "发送禁言命令失败"
|
||||
|
||||
def _get_template_message(self, target: str, duration_str: str, reason: str) -> str:
|
||||
"""获取模板化的禁言消息"""
|
||||
templates = self.api.get_config(
|
||||
"mute.templates",
|
||||
[
|
||||
"好的,禁言 {target} {duration},理由:{reason}",
|
||||
"收到,对 {target} 执行禁言 {duration},因为{reason}",
|
||||
"明白了,禁言 {target} {duration},原因是{reason}",
|
||||
"哇哈哈哈哈哈,已禁言 {target} {duration},理由:{reason}",
|
||||
],
|
||||
)
|
||||
template = random.choice(templates)
|
||||
return template.format(target=target, duration=duration_str, reason=reason)
|
||||
|
||||
def _format_duration(self, seconds: int) -> str:
|
||||
"""将秒数格式化为可读的时间字符串"""
|
||||
if seconds < 60:
|
||||
return f"{seconds}秒"
|
||||
elif seconds < 3600:
|
||||
minutes = seconds // 60
|
||||
remaining_seconds = seconds % 60
|
||||
if remaining_seconds > 0:
|
||||
return f"{minutes}分{remaining_seconds}秒"
|
||||
else:
|
||||
return f"{minutes}分钟"
|
||||
else:
|
||||
hours = seconds // 3600
|
||||
remaining_minutes = (seconds % 3600) // 60
|
||||
if remaining_minutes > 0:
|
||||
return f"{hours}小时{remaining_minutes}分钟"
|
||||
else:
|
||||
return f"{hours}小时"
|
||||
```
|
||||
|
||||
**关键特性说明**:
|
||||
|
||||
1. **🎯 双模式激活**:Focus模式使用LLM_JUDGE更谨慎,Normal模式使用KEYWORD快速响应
|
||||
2. **🧠 严格的LLM判定**:详细提示词指导LLM何时应该/不应该使用禁言,避免误判
|
||||
3. **✅ 完善的参数验证**:验证必需参数、数值转换、用户ID查找等多重验证
|
||||
4. **⚙️ 配置驱动**:时长限制、消息模板等都可通过配置文件自定义
|
||||
5. **😊 友好的用户反馈**:错误提示清晰、随机化消息模板、时长格式化显示
|
||||
6. **🛡️ 安全措施**:严格权限控制、防误操作验证、完整错误处理
|
||||
|
||||
### 智能助手Action
|
||||
|
||||
```python
|
||||
class IntelligentHelpAction(BaseAction):
|
||||
"""智能助手Action - 展示LLM判断激活的完整示例"""
|
||||
|
||||
# ===== 激活控制必须项 =====
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.RANDOM
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = True
|
||||
|
||||
# ===== 基本信息必须项 =====
|
||||
action_name = "intelligent_help"
|
||||
action_description = "智能助手,主动提供帮助和建议"
|
||||
|
||||
|
||||
# 基本信息
|
||||
action_name = "intelligent_chat"
|
||||
action_description = "使用replyer_1进行智能聊天回复,支持表情包和个性化回复"
|
||||
|
||||
# LLM判断提示词
|
||||
llm_judge_prompt = """
|
||||
判定是否需要提供智能帮助的条件:
|
||||
1. 用户表达了困惑或需要帮助
|
||||
2. 对话中出现了技术问题
|
||||
3. 用户寻求解决方案或建议
|
||||
4. 适合提供额外信息的场合
|
||||
|
||||
不要使用的情况:
|
||||
1. 用户明确表示不需要帮助
|
||||
2. 对话进行得很顺利
|
||||
3. 刚刚已经提供过帮助
|
||||
|
||||
判断是否需要进行智能聊天回复:
|
||||
1. 用户提出了有趣的话题
|
||||
2. 需要更加个性化的回复
|
||||
3. 适合发送表情包的情况
|
||||
|
||||
请回答"是"或"否"。
|
||||
"""
|
||||
|
||||
# 随机激活概率
|
||||
random_activation_probability = 0.15
|
||||
|
||||
# ===== 功能定义必须项 =====
|
||||
|
||||
# 功能定义
|
||||
action_parameters = {
|
||||
"help_type": "帮助类型:explanation(解释)、suggestion(建议)、guidance(指导)",
|
||||
"topic": "帮助主题或用户关心的问题",
|
||||
"urgency": "紧急程度:low(低)、medium(中)、high(高)"
|
||||
"topic": "聊天话题",
|
||||
"mood": "当前氛围(happy/sad/excited/calm)",
|
||||
"include_emoji": "是否包含表情包(true/false)"
|
||||
}
|
||||
|
||||
|
||||
action_require = [
|
||||
"用户表达困惑或寻求帮助时使用",
|
||||
"检测到用户遇到技术问题时使用",
|
||||
"对话中出现知识盲点时主动提供帮助",
|
||||
"避免过度频繁地提供帮助,要恰到好处"
|
||||
"需要更个性化回复时使用",
|
||||
"聊天氛围适合发送表情时使用",
|
||||
"避免在正式场合使用"
|
||||
]
|
||||
|
||||
|
||||
associated_types = ["text", "emoji"]
|
||||
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
"""执行智能帮助"""
|
||||
# 获取参数
|
||||
help_type = self.action_data.get("help_type", "suggestion")
|
||||
topic = self.action_data.get("topic", "")
|
||||
urgency = self.action_data.get("urgency", "medium")
|
||||
|
||||
# 根据帮助类型和紧急程度生成消息
|
||||
if help_type == "explanation":
|
||||
message = f"关于{topic},让我来为你解释一下..."
|
||||
elif help_type == "guidance":
|
||||
message = f"在{topic}方面,我可以为你提供一些指导..."
|
||||
else: # suggestion
|
||||
message = f"针对{topic},我建议你可以尝试以下方法..."
|
||||
|
||||
# 根据紧急程度调整表情
|
||||
if urgency == "high":
|
||||
emoji = "🚨"
|
||||
elif urgency == "low":
|
||||
emoji = "💡"
|
||||
topic = self.action_data.get("topic", "日常聊天")
|
||||
mood = self.action_data.get("mood", "happy")
|
||||
include_emoji = self.action_data.get("include_emoji", "true") == "true"
|
||||
|
||||
# 构建智能回复数据
|
||||
chat_data = {
|
||||
"text": f"请针对{topic}话题进行回复,当前氛围是{mood}",
|
||||
"topic": topic,
|
||||
"mood": mood,
|
||||
"style": "conversational",
|
||||
"replyer_name": "replyer_1" # 使用replyer_1
|
||||
}
|
||||
|
||||
# 生成智能回复
|
||||
success, reply_set = await generator_api.generate_reply(
|
||||
chat_stream=self.chat_stream,
|
||||
action_data=chat_data,
|
||||
platform=self.platform,
|
||||
chat_id=self.chat_id,
|
||||
is_group=self.is_group
|
||||
)
|
||||
|
||||
reply_sent = False
|
||||
|
||||
if success and reply_set:
|
||||
# 发送生成的回复
|
||||
for reply_type, content in reply_set:
|
||||
if reply_type == "text":
|
||||
await self.send_text(content)
|
||||
reply_sent = True
|
||||
elif reply_type == "emoji":
|
||||
await self.send_emoji(content)
|
||||
|
||||
# 如果配置允许且生成失败,发送表情包
|
||||
if include_emoji and not reply_sent:
|
||||
emoji_result = await emoji_api.get_by_description(mood)
|
||||
if emoji_result:
|
||||
emoji_base64, emoji_desc, matched_emotion = emoji_result
|
||||
await self.send_emoji(emoji_base64)
|
||||
reply_sent = True
|
||||
|
||||
# 记录动作执行
|
||||
if reply_sent:
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display=f"进行了智能聊天回复,话题:{topic},氛围:{mood}",
|
||||
action_done=True
|
||||
)
|
||||
return True, f"完成智能聊天回复:{topic}"
|
||||
else:
|
||||
emoji = "🤔"
|
||||
|
||||
# 发送帮助消息
|
||||
await self.send_text(message)
|
||||
await self.send_type("emoji", emoji)
|
||||
|
||||
return True, f"提供了{help_type}类型的帮助,主题:{topic}"
|
||||
return False, "智能回复生成失败"
|
||||
```
|
||||
|
||||
## 📊 性能优化建议
|
||||
## 🛠️ 调试技巧
|
||||
|
||||
### 1. 合理使用激活类型
|
||||
|
||||
- **ALWAYS**: 仅用于核心功能
|
||||
- **LLM_JUDGE**: 适度使用,避免过多LLM调用
|
||||
- **KEYWORD**: 优选,性能最好
|
||||
- **RANDOM**: 控制概率,避免过于频繁
|
||||
|
||||
### 2. 优化execute方法
|
||||
### 开发调试Action
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
try:
|
||||
# 快速参数验证
|
||||
if not self._validate_parameters():
|
||||
return False, "参数验证失败"
|
||||
|
||||
# 核心逻辑
|
||||
result = await self._core_logic()
|
||||
|
||||
# 成功返回
|
||||
return True, "执行成功"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 执行失败: {e}")
|
||||
return False, f"执行失败: {str(e)}"
|
||||
class DebugAction(BaseAction):
|
||||
"""调试Action - 展示如何调试新API"""
|
||||
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
activation_keywords = ["debug", "调试"]
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = True
|
||||
|
||||
action_name = "debug_helper"
|
||||
action_description = "调试助手,显示当前状态信息"
|
||||
|
||||
action_parameters = {}
|
||||
action_require = ["需要调试信息时使用"]
|
||||
associated_types = ["text"]
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
# 收集调试信息
|
||||
debug_info = {
|
||||
"聊天类型": "群聊" if self.is_group else "私聊",
|
||||
"平台": self.platform,
|
||||
"目标ID": self.target_id,
|
||||
"用户ID": self.user_id,
|
||||
"用户昵称": self.user_nickname,
|
||||
"动作数据": self.action_data,
|
||||
}
|
||||
|
||||
if self.is_group:
|
||||
debug_info.update({
|
||||
"群ID": self.group_id,
|
||||
"群名": self.group_name,
|
||||
})
|
||||
|
||||
# 格式化调试信息
|
||||
info_lines = ["🔍 调试信息:"]
|
||||
for key, value in debug_info.items():
|
||||
info_lines.append(f" • {key}: {value}")
|
||||
|
||||
debug_text = "\n".join(info_lines)
|
||||
|
||||
# 发送调试信息
|
||||
await self.send_text(debug_text)
|
||||
|
||||
# 测试配置获取
|
||||
test_config = self.get_config("debug.verbose", True)
|
||||
if test_config:
|
||||
await self.send_text(f"配置测试: debug.verbose = {test_config}")
|
||||
|
||||
return True, "调试信息已发送"
|
||||
```
|
||||
|
||||
### 3. 合理设置并行执行
|
||||
## 📚 最佳实践
|
||||
|
||||
```python
|
||||
# 轻量级Action可以并行
|
||||
parallel_action = True # 如:发送表情、记录日志
|
||||
1. **总是导入所需的API模块**:
|
||||
|
||||
# 重要Action应该独占
|
||||
parallel_action = False # 如:回复消息、状态切换
|
||||
```
|
||||
```python
|
||||
from src.plugin_system.apis import generator_api, send_api, emoji_api
|
||||
```
|
||||
2. **在生成内容时指定replyer_1**:
|
||||
|
||||
## 🐛 调试技巧
|
||||
```python
|
||||
action_data = {
|
||||
"text": "生成内容的请求",
|
||||
"replyer_name": "replyer_1"
|
||||
}
|
||||
```
|
||||
3. **使用便捷发送方法**:
|
||||
|
||||
### 1. 日志记录
|
||||
```python
|
||||
await self.send_text("文本") # 自动处理群聊/私聊
|
||||
await self.send_emoji(emoji_base64)
|
||||
```
|
||||
4. **合理使用配置**:
|
||||
|
||||
```python
|
||||
from src.common.logger import get_logger
|
||||
```python
|
||||
enable_feature = self.get_config("section.key", default_value)
|
||||
```
|
||||
5. **总是记录动作信息**:
|
||||
|
||||
logger = get_logger("my_action")
|
||||
```python
|
||||
await self.store_action_info(
|
||||
action_build_into_prompt=True,
|
||||
action_prompt_display="动作描述",
|
||||
action_done=True
|
||||
)
|
||||
```
|
||||
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
logger.info(f"{self.log_prefix} 开始执行: {self.reasoning}")
|
||||
logger.debug(f"{self.log_prefix} 参数: {self.action_data}")
|
||||
|
||||
# 执行逻辑...
|
||||
|
||||
logger.info(f"{self.log_prefix} 执行完成")
|
||||
```
|
||||
|
||||
### 2. 激活状态检查
|
||||
|
||||
```python
|
||||
# 在execute方法中检查激活原因
|
||||
def _debug_activation(self):
|
||||
logger.debug(f"激活类型: Focus={self.focus_activation_type}, Normal={self.normal_activation_type}")
|
||||
logger.debug(f"当前模式: {self.api.get_chat_mode()}")
|
||||
logger.debug(f"激活原因: {self.reasoning}")
|
||||
```
|
||||
|
||||
### 3. 参数验证
|
||||
|
||||
```python
|
||||
def _validate_parameters(self) -> bool:
|
||||
required_params = ["param1", "param2"]
|
||||
for param in required_params:
|
||||
if param not in self.action_data:
|
||||
logger.warning(f"{self.log_prefix} 缺少必需参数: {param}")
|
||||
return False
|
||||
return True
|
||||
```
|
||||
|
||||
## 🎯 最佳实践
|
||||
|
||||
### 1. 清晰的Action命名
|
||||
|
||||
- 使用描述性的类名:`SmartGreetingAction` 而不是 `Action1`
|
||||
- action_name要简洁明确:`"smart_greeting"` 而不是 `"action_1"`
|
||||
|
||||
### 2. 完整的文档字符串
|
||||
|
||||
```python
|
||||
class MyAction(BaseAction):
|
||||
"""
|
||||
我的Action - 一句话描述功能
|
||||
|
||||
详细描述Action的用途、激活条件、执行逻辑等。
|
||||
|
||||
激活条件:
|
||||
- Focus模式:关键词激活
|
||||
- Normal模式:LLM判断激活
|
||||
|
||||
执行逻辑:
|
||||
1. 验证参数
|
||||
2. 生成响应
|
||||
3. 发送消息
|
||||
"""
|
||||
```
|
||||
|
||||
### 3. 错误处理
|
||||
|
||||
```python
|
||||
async def execute(self) -> Tuple[bool, str]:
|
||||
try:
|
||||
# 主要逻辑
|
||||
pass
|
||||
except ValueError as e:
|
||||
await self.send_text("参数错误,请检查输入")
|
||||
return False, f"参数错误: {e}"
|
||||
except Exception as e:
|
||||
await self.send_text("操作失败,请稍后重试")
|
||||
return False, f"执行失败: {e}"
|
||||
```
|
||||
|
||||
### 4. 配置驱动
|
||||
|
||||
```python
|
||||
# 从配置文件读取设置
|
||||
enable_feature = self.api.get_config("my_action.enable_feature", True)
|
||||
max_retries = self.api.get_config("my_action.max_retries", 3)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
🎉 **现在你已经掌握了Action组件开发的完整知识!继续学习 [Command组件详解](command-components.md) 来了解命令开发。**
|
||||
通过使用新的API格式,Action的开发变得更加简洁和强大!
|
||||
|
||||
Reference in New Issue
Block a user