# 💻 Command组件详解 ## 📖 什么是Command Command是直接响应用户明确指令的组件,与Action不同,Command是**被动触发**的,当用户输入特定格式的命令时立即执行。Command通过正则表达式匹配用户输入,提供确定性的功能服务。 ### 🎯 Command的特点 - 🎯 **确定性执行**:匹配到命令立即执行,无随机性 - ⚡ **即时响应**:用户主动触发,快速响应 - 🔍 **正则匹配**:通过正则表达式精确匹配用户输入 - 🛑 **拦截控制**:可以控制是否阻止消息继续处理 - 📝 **参数解析**:支持从用户输入中提取参数 ## 🆚 Action vs Command 核心区别 | 特征 | Action | Command | |-----|-------|---------| | **触发方式** | 麦麦主动决策使用 | 用户主动触发 | | **决策机制** | 两层决策(激活+使用) | 直接匹配执行 | | **随机性** | 有随机性和智能性 | 确定性执行 | | **用途** | 增强麦麦行为拟人化 | 提供具体功能服务 | | **性能影响** | 需要LLM决策 | 正则匹配,性能好 | ## 🏗️ Command基本结构 ### 必须属性 ```python from src.plugin_system import BaseCommand class MyCommand(BaseCommand): # 正则表达式匹配模式 command_pattern = r"^/help\s+(?P\w+)$" # 命令帮助说明 command_help = "显示指定主题的帮助信息" # 使用示例 command_examples = ["/help action", "/help command"] # 是否拦截后续处理 intercept_message = True async def execute(self) -> Tuple[bool, Optional[str]]: """执行命令逻辑""" # 命令执行逻辑 return True, "执行成功" ``` ### 属性说明 | 属性 | 类型 | 说明 | |-----|------|------| | `command_pattern` | str | 正则表达式匹配模式 | | `command_help` | str | 命令帮助说明 | | `command_examples` | List[str] | 使用示例列表 | | `intercept_message` | bool | 是否拦截消息继续处理 | ## 🔍 正则表达式匹配 ### 基础匹配 ```python class SimpleCommand(BaseCommand): # 匹配 /ping command_pattern = r"^/ping$" async def execute(self) -> Tuple[bool, Optional[str]]: await self.send_text("Pong!") return True, "发送了Pong回复" ``` ### 参数捕获 使用命名组 `(?Ppattern)` 捕获参数: ```python class UserCommand(BaseCommand): # 匹配 /user add 张三 或 /user del 李四 command_pattern = r"^/user\s+(?Padd|del|info)\s+(?P\w+)$" async def execute(self) -> Tuple[bool, Optional[str]]: # 通过 self.matched_groups 获取捕获的参数 action = self.matched_groups.get("action") username = self.matched_groups.get("username") if action == "add": await self.send_text(f"添加用户:{username}") elif action == "del": await self.send_text(f"删除用户:{username}") elif action == "info": await self.send_text(f"用户信息:{username}") return True, f"执行了{action}操作" ``` ### 可选参数 ```python class HelpCommand(BaseCommand): # 匹配 /help 或 /help topic command_pattern = r"^/help(?:\s+(?P\w+))?$" async def execute(self) -> Tuple[bool, Optional[str]]: topic = self.matched_groups.get("topic") if topic: await self.send_text(f"显示{topic}的帮助") else: await self.send_text("显示总体帮助") return True, "显示了帮助信息" ``` ## 🛑 拦截控制详解 ### 拦截消息 (intercept_message = True) ```python class AdminCommand(BaseCommand): command_pattern = r"^/admin\s+.+" command_help = "管理员命令" intercept_message = True # 拦截,不继续处理 async def execute(self) -> Tuple[bool, Optional[str]]: # 执行管理操作 await self.send_text("执行管理命令") # 消息不会继续传递给其他组件 return True, "管理命令执行完成" ``` ### 不拦截消息 (intercept_message = False) ```python class LogCommand(BaseCommand): command_pattern = r"^/log\s+.+" command_help = "记录日志" intercept_message = False # 不拦截,继续处理 async def execute(self) -> Tuple[bool, Optional[str]]: # 记录日志但不阻止后续处理 await self.send_text("已记录到日志") # 消息会继续传递,可能触发Action等其他组件 return True, "日志记录完成" ``` ### 拦截控制的用途 | 场景 | intercept_message | 说明 | |-----|------------------|------| | 系统命令 | True | 防止命令被当作普通消息处理 | | 查询命令 | True | 直接返回结果,无需后续处理 | | 日志命令 | False | 记录但允许消息继续流转 | | 监控命令 | False | 监控但不影响正常聊天 | ## 🎨 完整Command示例 ### 用户管理Command ```python from src.plugin_system import BaseCommand from typing import Tuple, Optional class UserManagementCommand(BaseCommand): """用户管理Command - 展示复杂参数处理""" command_pattern = r"^/user\s+(?Padd|del|list|info)\s*(?P\w+)?(?:\s+--(?P.+))?$" command_help = "用户管理命令,支持添加、删除、列表、信息查询" command_examples = [ "/user add 张三", "/user del 李四", "/user list", "/user info 王五", "/user add 赵六 --role=admin" ] intercept_message = True async def execute(self) -> Tuple[bool, Optional[str]]: """执行用户管理命令""" try: action = self.matched_groups.get("action") username = self.matched_groups.get("username") options = self.matched_groups.get("options") # 解析选项 parsed_options = self._parse_options(options) if options else {} if action == "add": return await self._add_user(username, parsed_options) elif action == "del": return await self._delete_user(username) elif action == "list": return await self._list_users() elif action == "info": return await self._show_user_info(username) else: await self.send_text("❌ 不支持的操作") return False, f"不支持的操作: {action}" except Exception as e: await self.send_text(f"❌ 命令执行失败: {str(e)}") return False, f"执行失败: {e}" def _parse_options(self, options_str: str) -> dict: """解析命令选项""" options = {} if options_str: for opt in options_str.split(): if "=" in opt: key, value = opt.split("=", 1) options[key] = value return options async def _add_user(self, username: str, options: dict) -> Tuple[bool, str]: """添加用户""" if not username: await self.send_text("❌ 请指定用户名") return False, "缺少用户名参数" # 检查用户是否已存在 existing_users = await self._get_user_list() if username in existing_users: await self.send_text(f"❌ 用户 {username} 已存在") return False, f"用户已存在: {username}" # 添加用户逻辑 role = options.get("role", "user") await self.send_text(f"✅ 成功添加用户 {username},角色: {role}") return True, f"添加用户成功: {username}" async def _delete_user(self, username: str) -> Tuple[bool, str]: """删除用户""" if not username: await self.send_text("❌ 请指定用户名") return False, "缺少用户名参数" await self.send_text(f"✅ 用户 {username} 已删除") return True, f"删除用户成功: {username}" async def _list_users(self) -> Tuple[bool, str]: """列出所有用户""" users = await self._get_user_list() if users: user_list = "\n".join([f"• {user}" for user in users]) await self.send_text(f"📋 用户列表:\n{user_list}") else: await self.send_text("📋 暂无用户") return True, "显示用户列表" async def _show_user_info(self, username: str) -> Tuple[bool, str]: """显示用户信息""" if not username: await self.send_text("❌ 请指定用户名") return False, "缺少用户名参数" # 模拟用户信息 user_info = f""" 👤 用户信息: {username} 📧 邮箱: {username}@example.com 🕒 注册时间: 2024-01-01 🎯 角色: 普通用户 """.strip() await self.send_text(user_info) return True, f"显示用户信息: {username}" async def _get_user_list(self) -> list: """获取用户列表(示例)""" return ["张三", "李四", "王五"] ``` ### 系统信息Command ```python class SystemInfoCommand(BaseCommand): """系统信息Command - 展示系统查询功能""" command_pattern = r"^/(?:status|info)(?:\s+(?Psystem|memory|plugins|all))?$" command_help = "查询系统状态信息" command_examples = [ "/status", "/info system", "/status memory", "/info plugins" ] intercept_message = True async def execute(self) -> Tuple[bool, Optional[str]]: """执行系统信息查询""" info_type = self.matched_groups.get("type", "all") try: if info_type in ["system", "all"]: await self._show_system_info() if info_type in ["memory", "all"]: await self._show_memory_info() if info_type in ["plugins", "all"]: await self._show_plugin_info() return True, f"显示了{info_type}类型的系统信息" except Exception as e: await self.send_text(f"❌ 获取系统信息失败: {str(e)}") return False, f"查询失败: {e}" async def _show_system_info(self): """显示系统信息""" import platform import datetime system_info = f""" 🖥️ **系统信息** 📱 平台: {platform.system()} {platform.release()} 🐍 Python: {platform.python_version()} ⏰ 运行时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} """.strip() await self.send_text(system_info) async def _show_memory_info(self): """显示内存信息""" import psutil memory = psutil.virtual_memory() memory_info = f""" 💾 **内存信息** 📊 总内存: {memory.total // (1024**3)} GB 🟢 可用内存: {memory.available // (1024**3)} GB 📈 使用率: {memory.percent}% """.strip() await self.send_text(memory_info) async def _show_plugin_info(self): """显示插件信息""" # 通过配置获取插件信息 plugins = await self._get_loaded_plugins() plugin_info = f""" 🔌 **插件信息** 📦 已加载插件: {len(plugins)} 🔧 活跃插件: {len([p for p in plugins if p.get('active', False)])} """.strip() await self.send_text(plugin_info) async def _get_loaded_plugins(self) -> list: """获取已加载的插件列表""" # 这里可以通过配置或API获取实际的插件信息 return [ {"name": "core_actions", "active": True}, {"name": "example_plugin", "active": True}, ] ``` ### 自定义前缀Command ```python class CustomPrefixCommand(BaseCommand): """自定义前缀Command - 展示非/前缀的命令""" # 使用!前缀而不是/前缀 command_pattern = r"^[!!](?Proll|dice)\s*(?P\d+)?$" command_help = "骰子命令,使用!前缀" command_examples = ["!roll", "!dice 6", "!roll 20"] intercept_message = True async def execute(self) -> Tuple[bool, Optional[str]]: """执行骰子命令""" import random command = self.matched_groups.get("command") count = int(self.matched_groups.get("count", "6")) # 限制骰子面数 if count > 100: await self.send_text("❌ 骰子面数不能超过100") return False, "骰子面数超限" result = random.randint(1, count) await self.send_text(f"🎲 投掷{count}面骰子,结果: {result}") return True, f"投掷了{count}面骰子,结果{result}" ``` ## 🔧 新API格式使用指南 ### 消息发送 ```python # 新API格式 ✅ await self.send_text("消息内容") await self.send_emoji("😊") # 旧API格式 ❌ await self.api.send_text_to_group("消息内容", group_id, "qq") ``` ### 配置访问 ```python # 新API格式 ✅ config_value = self.get_config("section.key", "default_value") # 旧API格式 ❌ config_value = self.api.get_config("section.key", "default_value") ``` ### 用户信息获取 ```python # 新API格式 ✅ user_id = self.user_id user_nickname = self.user_nickname is_group_chat = self.is_group # 旧API格式 ❌ user_id = self.message.message_info.user_info.user_id ``` ### 动作记录 ```python # 新API格式 ✅ (在Action中) await self.store_action_info( action_build_into_prompt=True, action_prompt_display="执行了某操作", action_done=True ) # 旧API格式 ❌ await self.api.store_action_info(...) ``` ## 📊 性能优化建议 ### 1. 正则表达式优化 ```python # ✅ 好的做法 - 简单直接 command_pattern = r"^/ping$" # ❌ 避免 - 过于复杂 command_pattern = r"^/(?:ping|pong|test|check|status|info|help|...)" # ✅ 好的做法 - 分离复杂逻辑 ``` ### 2. 参数验证 ```python # ✅ 好的做法 - 早期验证 async def execute(self) -> Tuple[bool, Optional[str]]: username = self.matched_groups.get("username") if not username: await self.send_text("❌ 请提供用户名") return False, "缺少参数" # 继续处理... ``` ### 3. 错误处理 ```python # ✅ 好的做法 - 完整错误处理 async def execute(self) -> Tuple[bool, Optional[str]]: try: # 主要逻辑 result = await self._process_command() return True, "执行成功" except ValueError as e: await self.send_text(f"❌ 参数错误: {e}") return False, f"参数错误: {e}" except Exception as e: await self.send_text(f"❌ 执行失败: {e}") return False, f"执行失败: {e}" ``` 通过新的API格式,Command开发变得更加简洁和直观! ## 🎯 最佳实践 ### 1. 命令设计原则 ```python # ✅ 好的命令设计 "/user add 张三" # 动作 + 对象 + 参数 "/config set key=value" # 动作 + 子动作 + 参数 "/help command" # 动作 + 可选参数 # ❌ 避免的设计 "/add_user_with_name_张三" # 过于冗长 "/u a 张三" # 过于简写 ``` ### 2. 帮助信息 ```python class WellDocumentedCommand(BaseCommand): command_pattern = r"^/example\s+(?P\w+)$" command_help = "示例命令:处理指定参数并返回结果" command_examples = [ "/example test", "/example debug", "/example production" ] ``` ### 3. 错误处理 ```python async def execute(self) -> Tuple[bool, Optional[str]]: param = self.matched_groups.get("param") # 参数验证 if param not in ["test", "debug", "production"]: await self.send_text("❌ 无效的参数,支持: test, debug, production") return False, "无效参数" # 执行逻辑 try: result = await self._process_param(param) await self.send_text(f"✅ 处理完成: {result}") return True, f"处理{param}成功" except Exception as e: await self.send_text("❌ 处理失败,请稍后重试") return False, f"处理失败: {e}" ``` ### 4. 配置集成 ```python async def execute(self) -> Tuple[bool, Optional[str]]: # 从配置读取设置 max_items = self.api.get_config("command.max_items", 10) timeout = self.api.get_config("command.timeout", 30) # 使用配置进行处理 ... ``` ## 📝 Command vs Action 选择指南 ### 使用Command的场景 - ✅ 用户需要明确调用特定功能 - ✅ 需要精确的参数控制 - ✅ 管理和配置操作 - ✅ 查询和信息显示 - ✅ 系统维护命令 ### 使用Action的场景 - ✅ 增强麦麦的智能行为 - ✅ 根据上下文自动触发 - ✅ 情绪和表情表达 - ✅ 智能建议和帮助 - ✅ 随机化的互动 --- 🎉 **现在你已经掌握了Command组件开发的完整知识!继续学习 [API参考](api/) 来了解所有可用的接口。**