diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index be15d53e8..50dd21d0d 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -26,12 +26,13 @@ jobs: - name: Install Ruff and Run Checks uses: astral-sh/ruff-action@v3 with: + args: "--version" version: "latest" - name: Run Ruff Fix - run: ruff check --fix + run: ruff check --fix --unsafe-fixes || true - name: Run Ruff Format - run: ruff format - - name: Commit changes + run: ruff format || true + - name: 提交更改 if: success() run: | git config --local user.email "github-actions[bot]@users.noreply.github.com" diff --git a/.gitignore b/.gitignore index c5cb6f769..700806770 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ MaiBot-Napcat-Adapter /log_debug /src/test nonebot-maibot-adapter/ +MaiMBot-LPMM *.zip run.bat log_debug/ @@ -309,9 +310,4 @@ src/plugins/test_plugin_pic/actions/pic_action_config.toml run_pet.bat # 忽略 /src/plugins 但保留特定目录 -/src/plugins/* -!/src/plugins/doubao_pic/ -!/src/plugins/mute_plugin/ -!/src/plugins/tts_plugin/ -!/src/plugins/vtb_action/ -!/src/plugins/__init__.py +plugins/* diff --git a/CORRECTED_ARCHITECTURE.md b/CORRECTED_ARCHITECTURE.md deleted file mode 100644 index ca522383b..000000000 --- a/CORRECTED_ARCHITECTURE.md +++ /dev/null @@ -1,299 +0,0 @@ -# 修正后的动作激活架构 - -## 架构原则 - -### 正确的职责分工 -- **主循环 (`modify_actions`)**: 负责完整的动作管理,包括传统观察处理和新的激活类型判定 -- **规划器 (`Planner`)**: 专注于从最终确定的动作集中进行决策,不再处理动作筛选 - -### 关注点分离 -- **动作管理** → 主循环处理 -- **决策制定** → 规划器处理 -- **配置解析** → ActionManager处理 - -## 修正后的调用流程 - -### 1. 主循环阶段 (heartFC_chat.py) - -```python -# 在主循环中调用完整的动作管理流程 -async def modify_actions_task(): - # 提取聊天上下文信息 - observed_messages_str = "" - chat_context = "" - - for obs in self.observations: - if hasattr(obs, 'get_talking_message_str_truncate'): - observed_messages_str = obs.get_talking_message_str_truncate() - elif hasattr(obs, 'get_chat_type'): - chat_context = f"聊天类型: {obs.get_chat_type()}" - - # 调用完整的动作修改流程 - await self.action_modifier.modify_actions( - observations=self.observations, - observed_messages_str=observed_messages_str, - chat_context=chat_context, - extra_context=extra_context - ) -``` - -**处理内容:** -- 传统观察处理(循环历史分析、类型匹配等) -- 双激活类型判定(Focus模式和Normal模式分别处理) -- 并行LLM判定 -- 智能缓存 -- 动态关键词收集 - -### 2. 规划器阶段 (planner_simple.py) - -```python -# 规划器直接获取最终的动作集 -current_available_actions_dict = self.action_manager.get_using_actions() - -# 获取完整的动作信息 -all_registered_actions = self.action_manager.get_registered_actions() -current_available_actions = {} -for action_name in current_available_actions_dict.keys(): - if action_name in all_registered_actions: - current_available_actions[action_name] = all_registered_actions[action_name] -``` - -**处理内容:** -- 仅获取经过完整处理的最终动作集 -- 专注于从可用动作中进行决策 -- 不再处理动作筛选逻辑 - -## 核心优化功能 - -### 1. 并行LLM判定 -```python -# 同时判定多个LLM_JUDGE类型的动作 -task_results = await asyncio.gather(*tasks, return_exceptions=True) -``` - -### 2. 智能缓存系统 -```python -# 基于上下文哈希的缓存机制 -cache_key = f"{action_name}_{context_hash}" -if cache_key in self._llm_judge_cache: - return cached_result -``` - -### 3. 直接LLM判定 -```python -# 直接对所有LLM_JUDGE类型的动作进行并行判定 -llm_results = await self._process_llm_judge_actions_parallel(llm_judge_actions, ...) -``` - -### 4. 动态关键词收集 -```python -# 从动作配置中动态收集关键词,避免硬编码 -for action_name, action_info in llm_judge_actions.items(): - keywords = action_info.get("activation_keywords", []) - if keywords: - # 检查消息中的关键词匹配 -``` - -## 双激活类型系统 🆕 - -### 系统设计理念 -**Focus模式** 和 **Normal模式** 采用不同的激活策略: -- **Focus模式**: 智能化优先,支持复杂的LLM判定 -- **Normal模式**: 性能优先,使用快速的关键词和随机触发 - -### 双激活类型配置 -```python -class MyAction(BaseAction): - action_name = "my_action" - action_description = "我的动作" - - # Focus模式激活类型(支持LLM_JUDGE) - focus_activation_type = ActionActivationType.LLM_JUDGE - - # Normal模式激活类型(建议使用KEYWORD/RANDOM/ALWAYS) - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["关键词1", "keyword"] - - # 模式启用控制 - mode_enable = ChatMode.ALL # 在所有模式下启用 - - # 并行执行控制 - parallel_action = False # 是否与回复并行执行 -``` - -### 模式启用类型 (ChatMode) -```python -from src.chat.chat_mode import ChatMode - -# 可选值: -mode_enable = ChatMode.FOCUS # 仅在Focus模式启用 -mode_enable = ChatMode.NORMAL # 仅在Normal模式启用 -mode_enable = ChatMode.ALL # 在所有模式启用(默认) -``` - -### 并行动作系统 🆕 -```python -# 并行动作:可以与回复生成同时进行 -parallel_action = True # 不会阻止回复生成 - -# 串行动作:会替代回复生成 -parallel_action = False # 默认值,传统行为 -``` - -**并行动作的优势:** -- 提升用户体验(同时获得回复和动作执行) -- 减少响应延迟 -- 适用于情感表达、状态变更等辅助性动作 - -## 四种激活类型 - -### 1. ALWAYS - 始终激活 -```python -focus_activation_type = ActionActivationType.ALWAYS -normal_activation_type = ActionActivationType.ALWAYS -# 基础动作,如 reply, no_reply -``` - -### 2. RANDOM - 随机激活 -```python -focus_activation_type = ActionActivationType.RANDOM -normal_activation_type = ActionActivationType.RANDOM -random_probability = 0.3 # 激活概率 -# 用于增加惊喜元素,如随机表情 -``` - -### 3. LLM_JUDGE - 智能判定 -```python -focus_activation_type = ActionActivationType.LLM_JUDGE -# 注意:Normal模式不建议使用LLM_JUDGE,会发出警告 -normal_activation_type = ActionActivationType.KEYWORD -# 需要理解上下文的复杂动作,如情感表达 -``` - -### 4. KEYWORD - 关键词触发 -```python -focus_activation_type = ActionActivationType.KEYWORD -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["画", "图片", "生成"] -# 明确指令触发的动作,如图片生成 -``` - -## 推荐配置模式 - -### 模式1:智能自适应 -```python -# Focus模式使用智能判定,Normal模式使用关键词 -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["相关", "关键词"] -``` - -### 模式2:统一关键词 -```python -# 两个模式都使用关键词,确保一致性 -focus_activation_type = ActionActivationType.KEYWORD -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["画", "图片", "生成"] -``` - -### 模式3:Focus专享 -```python -# 仅在Focus模式启用的智能功能 -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.ALWAYS # 不会生效 -mode_enable = ChatMode.FOCUS -``` - -## 性能提升 - -### 理论性能改进 -- **并行LLM判定**: 1.5-2x 提升 -- **智能缓存**: 20-30% 额外提升 -- **双模式优化**: Normal模式额外1.5x提升 -- **整体预期**: 3-5x 性能提升 - -### 缓存策略 -- **缓存键**: `{action_name}_{context_hash}` -- **过期时间**: 30秒 -- **哈希算法**: MD5 (消息内容+上下文) - -## 向后兼容性 - -### ⚠️ 重大变更说明 -**旧的 `action_activation_type` 属性已被移除**,必须更新为新的双激活类型系统: - -#### 迁移指南 -```python -# 旧的配置(已废弃) -class OldAction(BaseAction): - action_activation_type = ActionActivationType.LLM_JUDGE # ❌ 已移除 - -# 新的配置(必须使用) -class NewAction(BaseAction): - focus_activation_type = ActionActivationType.LLM_JUDGE # ✅ Focus模式 - normal_activation_type = ActionActivationType.KEYWORD # ✅ Normal模式 - activation_keywords = ["相关", "关键词"] - mode_enable = ChatMode.ALL - parallel_action = False -``` - -#### 快速迁移脚本 -对于简单的迁移,可以使用以下模式: -```python -# 如果原来是 ALWAYS -focus_activation_type = ActionActivationType.ALWAYS -normal_activation_type = ActionActivationType.ALWAYS - -# 如果原来是 LLM_JUDGE -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.KEYWORD # 需要添加关键词 - -# 如果原来是 KEYWORD -focus_activation_type = ActionActivationType.KEYWORD -normal_activation_type = ActionActivationType.KEYWORD - -# 如果原来是 RANDOM -focus_activation_type = ActionActivationType.RANDOM -normal_activation_type = ActionActivationType.RANDOM -``` - -## 测试验证 - -### 运行测试 -```bash -python test_corrected_architecture.py -``` - -### 测试内容 -- 双激活类型系统验证 -- 数据一致性检查 -- 职责分离确认 -- 性能测试 -- 向后兼容性验证 -- 并行动作功能验证 - -## 优势总结 - -### 1. 清晰的架构 -- **单一职责**: 每个组件专注于自己的核心功能 -- **关注点分离**: 动作管理与决策制定分离 -- **可维护性**: 逻辑清晰,易于理解和修改 - -### 2. 高性能 -- **并行处理**: 多个LLM判定同时进行 -- **智能缓存**: 避免重复计算 -- **双模式优化**: Focus智能化,Normal快速化 - -### 3. 智能化 -- **动态配置**: 从动作配置中收集关键词 -- **上下文感知**: 基于聊天内容智能激活 -- **冲突避免**: 防止重复激活 -- **模式自适应**: 根据聊天模式选择最优策略 - -### 4. 可扩展性 -- **插件式**: 新的激活类型易于添加 -- **配置驱动**: 通过配置控制行为 -- **模块化**: 各组件独立可测试 -- **双模式支持**: 灵活适应不同使用场景 - -这个修正后的架构实现了正确的职责分工,确保了主循环负责动作管理,规划器专注于决策,同时集成了双激活类型、并行判定和智能缓存等优化功能。 \ No newline at end of file diff --git a/HEARFLOW_API_说明文档.md b/HEARFLOW_API_说明文档.md new file mode 100644 index 000000000..434cd3cfa --- /dev/null +++ b/HEARFLOW_API_说明文档.md @@ -0,0 +1,241 @@ +# HearflowAPI 使用说明 + +## 概述 + +HearflowAPI 是一个新增的插件API模块,提供了与心流和子心流相关的操作接口。通过这个API,插件开发者可以方便地获取和操作sub_hearflow实例。 + +## 主要功能 + +### 1. 获取子心流实例 + +#### `get_sub_hearflow_by_chat_id(chat_id: str) -> Optional[SubHeartflow]` +根据chat_id获取指定的sub_hearflow实例(仅获取已存在的)。 + +**参数:** +- `chat_id`: 聊天ID,与sub_hearflow的subheartflow_id相同 + +**返回值:** +- `SubHeartflow`: sub_hearflow实例,如果不存在则返回None + +**示例:** +```python +# 获取当前聊天的子心流实例 +current_subflow = await self.get_sub_hearflow_by_chat_id(self.observation.chat_id) +if current_subflow: + print(f"找到子心流: {current_subflow.chat_id}") +else: + print("子心流不存在") +``` + +#### `get_or_create_sub_hearflow_by_chat_id(chat_id: str) -> Optional[SubHeartflow]` +根据chat_id获取或创建sub_hearflow实例。 + +**参数:** +- `chat_id`: 聊天ID + +**返回值:** +- `SubHeartflow`: sub_hearflow实例,创建失败时返回None + +**示例:** +```python +# 获取或创建子心流实例 +subflow = await self.get_or_create_sub_hearflow_by_chat_id("some_chat_id") +if subflow: + print("成功获取或创建子心流") +``` + +### 2. 获取子心流列表 + +#### `get_all_sub_hearflow_ids() -> List[str]` +获取所有活跃子心流的ID列表。 + +**返回值:** +- `List[str]`: 所有活跃子心流的ID列表 + +#### `get_all_sub_hearflows() -> List[SubHeartflow]` +获取所有活跃的子心流实例。 + +**返回值:** +- `List[SubHeartflow]`: 所有活跃的子心流实例列表 + +**示例:** +```python +# 获取所有活跃的子心流ID +all_chat_ids = self.get_all_sub_hearflow_ids() +print(f"共有 {len(all_chat_ids)} 个活跃的子心流") + +# 获取所有活跃的子心流实例 +all_subflows = self.get_all_sub_hearflows() +for subflow in all_subflows: + print(f"子心流 {subflow.chat_id} 状态: {subflow.chat_state.chat_status.value}") +``` + +### 3. 心流状态操作 + +#### `get_sub_hearflow_chat_state(chat_id: str) -> Optional[ChatState]` +获取指定子心流的聊天状态。 + +**参数:** +- `chat_id`: 聊天ID + +**返回值:** +- `ChatState`: 聊天状态,如果子心流不存在则返回None + +#### `set_sub_hearflow_chat_state(chat_id: str, target_state: ChatState) -> bool` +设置指定子心流的聊天状态。 + +**参数:** +- `chat_id`: 聊天ID +- `target_state`: 目标状态 + +**返回值:** +- `bool`: 是否设置成功 + +**示例:** +```python +from src.chat.heart_flow.sub_heartflow import ChatState + +# 获取当前状态 +current_state = await self.get_sub_hearflow_chat_state(self.observation.chat_id) +print(f"当前状态: {current_state.value}") + +# 设置状态 +success = await self.set_sub_hearflow_chat_state(self.observation.chat_id, ChatState.FOCUS) +if success: + print("状态设置成功") +``` + +### 4. Replyer和Expressor操作 + +#### `get_sub_hearflow_replyer_and_expressor(chat_id: str) -> Tuple[Optional[Any], Optional[Any]]` +根据chat_id获取指定子心流的replyer和expressor实例。 + +**参数:** +- `chat_id`: 聊天ID + +**返回值:** +- `Tuple[Optional[Any], Optional[Any]]`: (replyer实例, expressor实例),如果子心流不存在或未处于FOCUSED状态,返回(None, None) + +#### `get_sub_hearflow_replyer(chat_id: str) -> Optional[Any]` +根据chat_id获取指定子心流的replyer实例。 + +**参数:** +- `chat_id`: 聊天ID + +**返回值:** +- `Optional[Any]`: replyer实例,如果不存在则返回None + +#### `get_sub_hearflow_expressor(chat_id: str) -> Optional[Any]` +根据chat_id获取指定子心流的expressor实例。 + +**参数:** +- `chat_id`: 聊天ID + +**返回值:** +- `Optional[Any]`: expressor实例,如果不存在则返回None + +**示例:** +```python +# 获取replyer和expressor +replyer, expressor = await self.get_sub_hearflow_replyer_and_expressor(self.observation.chat_id) +if replyer and expressor: + print(f"获取到replyer: {type(replyer).__name__}") + print(f"获取到expressor: {type(expressor).__name__}") + + # 检查属性 + print(f"Replyer聊天ID: {replyer.chat_id}") + print(f"Expressor聊天ID: {expressor.chat_id}") + print(f"是否群聊: {replyer.is_group_chat}") + +# 单独获取replyer +replyer = await self.get_sub_hearflow_replyer(self.observation.chat_id) +if replyer: + print("获取到replyer实例") + +# 单独获取expressor +expressor = await self.get_sub_hearflow_expressor(self.observation.chat_id) +if expressor: + print("获取到expressor实例") +``` + +## 可用的聊天状态 + +```python +from src.chat.heart_flow.sub_heartflow import ChatState + +ChatState.FOCUS # 专注模式 +ChatState.NORMAL # 普通模式 +ChatState.ABSENT # 离开模式 +``` + +## 完整插件示例 + +```python +from typing import Tuple +from src.plugin_system.base.base_action import BaseAction as PluginAction, register_action +from src.chat.heart_flow.sub_heartflow import ChatState + +@register_action +class MyHearflowPlugin(PluginAction): + """我的心流插件""" + + activation_keywords = ["心流信息"] + + async def process(self) -> Tuple[bool, str]: + try: + # 获取当前聊天的chat_id + current_chat_id = self.observation.chat_id + + # 获取子心流实例 + subflow = await self.get_sub_hearflow_by_chat_id(current_chat_id) + if not subflow: + return False, "未找到子心流实例" + + # 获取状态信息 + current_state = await self.get_sub_hearflow_chat_state(current_chat_id) + + # 构建回复 + response = f"心流信息:\n" + response += f"聊天ID: {current_chat_id}\n" + response += f"当前状态: {current_state.value}\n" + response += f"是否群聊: {subflow.is_group_chat}\n" + + return True, response + + except Exception as e: + return False, f"处理出错: {str(e)}" +``` + +## 注意事项 + +1. **线程安全**: API内部已处理锁机制,确保线程安全。 + +2. **错误处理**: 所有API方法都包含异常处理,失败时会记录日志并返回安全的默认值。 + +3. **性能考虑**: `get_sub_hearflow_by_chat_id` 只获取已存在的实例,性能更好;`get_or_create_sub_hearflow_by_chat_id` 会在需要时创建新实例。 + +4. **状态管理**: 修改心流状态时请谨慎,确保不会影响系统的正常运行。 + +5. **日志记录**: 所有操作都会记录适当的日志,便于调试和监控。 + +6. **Replyer和Expressor可用性**: + - 这些实例仅在子心流处于**FOCUSED状态**时可用 + - 如果子心流处于NORMAL或ABSENT状态,将返回None + - 需要确保HeartFC实例存在且正常运行 + +7. **使用Replyer和Expressor时的注意事项**: + - 直接调用这些实例的方法需要谨慎,可能影响系统正常运行 + - 建议主要用于监控、信息获取和状态检查 + - 不建议在插件中直接调用回复生成方法,这可能与系统的正常流程冲突 + +## 相关类型和模块 + +- `SubHeartflow`: 子心流实例类 +- `ChatState`: 聊天状态枚举 +- `DefaultReplyer`: 默认回复器类 +- `DefaultExpressor`: 默认表达器类 +- `HeartFChatting`: 专注聊天主类 +- `src.chat.heart_flow.heartflow`: 主心流模块 +- `src.chat.heart_flow.subheartflow_manager`: 子心流管理器 +- `src.chat.focus_chat.replyer.default_replyer`: 回复器模块 +- `src.chat.focus_chat.expressors.default_expressor`: 表达器模块 \ No newline at end of file diff --git a/MaiMBot-LPMM b/MaiMBot-LPMM deleted file mode 160000 index d5824d2f4..000000000 --- a/MaiMBot-LPMM +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d5824d2f48c9415cf619d2b32608c2db6a1bbc39 diff --git a/bot.py b/bot.py index 3737279d3..8007a1ed8 100644 --- a/bot.py +++ b/bot.py @@ -2,29 +2,38 @@ import asyncio import hashlib import os import sys -from pathlib import Path import time import platform import traceback +from pathlib import Path from dotenv import load_dotenv -from src.common.logger_manager import get_logger - -# from src.common.logger import LogConfig, CONFIRM_STYLE_CONFIG -from src.common.crash_logger import install_crash_handler -from src.main import MainSystem from rich.traceback import install +# 最早期初始化日志系统,确保所有后续模块都使用正确的日志格式 +from src.common.logger import initialize_logging, get_logger +from src.common.crash_logger import install_crash_handler +from src.main import MainSystem from src.manager.async_task_manager import async_task_manager +initialize_logging() + +logger = get_logger("main") + +# 直接加载生产环境变量配置 +if os.path.exists(".env"): + load_dotenv(".env", override=True) + logger.info("成功加载环境变量配置") +else: + logger.warning("未找到.env文件,请确保程序所需的环境变量被正确设置") + install(extra_lines=3) # 设置工作目录为脚本所在目录 script_dir = os.path.dirname(os.path.abspath(__file__)) os.chdir(script_dir) -print(f"已设置工作目录为: {script_dir}") +logger.info(f"已设置工作目录为: {script_dir}") -logger = get_logger("main") confirm_logger = get_logger("confirm") # 获取没有加载env时的环境变量 env_mask = {key: os.getenv(key) for key in os.environ} @@ -34,8 +43,6 @@ driver = None app = None loop = None -# shutdown_requested = False # 新增全局变量 - async def request_shutdown() -> bool: """请求关闭程序""" @@ -65,16 +72,6 @@ def easter_egg(): print(rainbow_text) -def load_env(): - # 直接加载生产环境变量配置 - if os.path.exists(".env"): - load_dotenv(".env", override=True) - logger.success("成功加载环境变量配置") - else: - logger.error("未找到.env文件,请确保文件存在") - raise FileNotFoundError("未找到.env文件,请确保文件存在") - - def scan_provider(env_config: dict): provider = {} @@ -211,8 +208,6 @@ def raw_main(): easter_egg() - load_env() - env_config = {key: os.getenv(key) for key in os.environ} scan_provider(env_config) @@ -235,7 +230,7 @@ if __name__ == "__main__": loop.run_until_complete(main_system.initialize()) loop.run_until_complete(main_system.schedule_tasks()) except KeyboardInterrupt: - # loop.run_until_complete(global_api.stop()) + # loop.run_until_complete(get_global_api().stop()) logger.warning("收到中断信号,正在优雅关闭...") if loop and not loop.is_closed(): try: diff --git a/docs/HeartFC_chatting_logic.md b/docs/HeartFC_chatting_logic.md deleted file mode 100644 index 6d51c978b..000000000 --- a/docs/HeartFC_chatting_logic.md +++ /dev/null @@ -1,92 +0,0 @@ -# HeartFChatting 逻辑详解 - -`HeartFChatting` 类是心流系统(Heart Flow System)中实现**专注聊天**(`ChatState.FOCUSED`)功能的核心。顾名思义,其职责乃是在特定聊天流(`stream_id`)中,模拟更为连贯深入之对话。此非凭空臆造,而是依赖一个持续不断的 **思考(Think)-规划(Plan)-执行(Execute)** 循环。当其所系的 `SubHeartflow` 进入 `FOCUSED` 状态时,便会创建并启动 `HeartFChatting` 实例;若状态转为他途(譬如 `CHAT` 或 `ABSENT`),则会将其关闭。 - -## 1. 初始化简述 (`__init__`, `_initialize`) - -创生之初,`HeartFChatting` 需注入若干关键之物:`chat_id`(亦即 `stream_id`)、关联的 `SubMind` 实例,以及 `Observation` 实例(用以观察环境)。 - -其内部核心组件包括: - -- `ActionManager`: 管理当前循环可选之策(如:不应、言语、表情)。 -- `HeartFCGenerator` (`self.gpt_instance`): 专司生成回复文本之职。 -- `ToolUser` (`self.tool_user`): 虽主要用于获取工具定义,然亦备 `SubMind` 调用之需(实际执行由 `SubMind` 操持)。 -- `HeartFCSender` (`self.heart_fc_sender`): 负责消息发送诸般事宜,含"正在思考"之态。 -- `LLMRequest` (`self.planner_llm`): 配置用于执行"规划"任务的大语言模型。 - -*初始化过程采取懒加载策略,仅在首次需要访问 `ChatStream` 时(通常在 `start` 方法中)进行。* - -## 2. 生命周期 (`start`, `shutdown`) - -- **启动 (`start`)**: 外部调用此法,以启 `HeartFChatting` 之流程。内部会安全地启动主循环任务。 -- **关闭 (`shutdown`)**: 外部调用此法,以止其运行。会取消主循环任务,清理状态,并释放锁。 - -## 3. 核心循环 (`_hfc_loop`) 与 循环记录 (`CycleInfo`) - -`_hfc_loop` 乃 `HeartFChatting` 之脉搏,以异步方式不舍昼夜运行(直至 `shutdown` 被调用)。其核心在于周而复始地执行 **思考-规划-执行** 之周期。 - -每一轮循环,皆会创建一个 `CycleInfo` 对象。此对象犹如史官,详细记载该次循环之点滴: - -- **身份标识**: 循环 ID (`cycle_id`)。 -- **时间轨迹**: 起止时刻 (`start_time`, `end_time`)。 -- **行动细节**: 是否执行动作 (`action_taken`)、动作类型 (`action_type`)、决策理由 (`reasoning`)。 -- **耗时考量**: 各阶段计时 (`timers`)。 -- **关联信息**: 思考消息 ID (`thinking_id`)、是否重新规划 (`replanned`)、详尽响应信息 (`response_info`,含生成文本、表情、锚点、实际发送ID、`SubMind`思考等)。 - -这些 `CycleInfo` 被存入一个队列 (`_cycle_history`),近者得观。此记录不仅便于调试,更关键的是,它会作为**上下文信息**传递给下一次循环的"思考"阶段,使得 `SubMind` 能鉴往知来,做出更连贯的决策。 - -*循环间会根据执行情况智能引入延迟,避免空耗资源。* - -## 4. 思考-规划-执行周期 (`_think_plan_execute_loop`) - -此乃 `HeartFChatting` 最核心的逻辑单元,每一循环皆按序执行以下三步: - -### 4.1. 思考 (`_get_submind_thinking`) - -* **第一步:观察环境**: 调用 `Observation` 的 `observe()` 方法,感知聊天室是否有新动态(如新消息)。 -* **第二步:触发子思维**: 调用关联 `SubMind` 的 `do_thinking_before_reply()` 方法。 - * **关键点**: 会将**上一个循环**的 `CycleInfo` 传入,让 `SubMind` 了解上次行动的决策、理由及是否重新规划,从而实现"承前启后"的思考。 - * `SubMind` 在此阶段不仅进行思考,还可能**调用其配置的工具**来收集信息。 -* **第三步:获取成果**: `SubMind` 返回两部分重要信息: - 1. 当前的内心想法 (`current_mind`)。 - 2. 通过工具调用收集到的结构化信息 (`structured_info`)。 - -### 4.2. 规划 (`_planner`) - -* **输入**: 接收来自"思考"阶段的 `current_mind` 和 `structured_info`,以及"观察"到的最新消息。 -* **目标**: 基于当前想法、已知信息、聊天记录、机器人个性以及可用动作,决定**接下来要做什么**。 -* **决策方式**: - 1. 构建一个精心设计的提示词 (`_build_planner_prompt`)。 - 2. 获取 `ActionManager` 中定义的当前可用动作(如 `no_reply`, `text_reply`, `emoji_reply`)作为"工具"选项。 - 3. 调用大语言模型 (`self.planner_llm`),**强制**其选择一个动作"工具"并提供理由。可选动作包括: - * `no_reply`: 不回复(例如,自己刚说过话或对方未回应)。 - * `text_reply`: 发送文本回复。 - * `emoji_reply`: 仅发送表情。 - * 文本回复亦可附带表情(通过 `emoji_query` 参数指定)。 -* **动态调整(重新规划)**: - * 在做出初步决策后,会检查自规划开始后是否有新消息 (`_check_new_messages`)。 - * 若有新消息,则有一定概率触发**重新规划**。此时会再次调用规划器,但提示词会包含之前决策的信息,要求 LLM 重新考虑。 -* **输出**: 返回一个包含最终决策的字典,主要包括: - * `action`: 选定的动作类型。 - * `reasoning`: 做出此决策的理由。 - * `emoji_query`: (可选) 如果需要发送表情,指定表情的主题。 - -### 4.3. 执行 (`_handle_action`) - -* **输入**: 接收"规划"阶段输出的 `action`、`reasoning` 和 `emoji_query`。 -* **行动**: 根据 `action` 的类型,分派到不同的处理函数: - * **文本回复 (`_handle_text_reply`)**: - 1. 获取锚点消息(当前实现为系统触发的占位符)。 - 2. 调用 `HeartFCSender` 的 `register_thinking` 标记开始思考。 - 3. 调用 `HeartFCGenerator` (`_replier_work`) 生成回复文本。**注意**: 回复器逻辑 (`_replier_work`) 本身并非独立复杂组件,主要是调用 `HeartFCGenerator` 完成文本生成。 - 4. 调用 `HeartFCSender` (`_sender`) 发送生成的文本和可能的表情。**注意**: 发送逻辑 (`_sender`, `_send_response_messages`, `_handle_emoji`) 同样委托给 `HeartFCSender` 实例处理,包含模拟打字、实际发送、存储消息等细节。 - * **仅表情回复 (`_handle_emoji_reply`)**: - 1. 获取锚点消息。 - 2. 调用 `HeartFCSender` 发送表情。 - * **不回复 (`_handle_no_reply`)**: - 1. 记录理由。 - 2. 进入等待状态 (`_wait_for_new_message`),直到检测到新消息或超时(目前300秒),期间会监听关闭信号。 - -## 总结 - -`HeartFChatting` 通过 **观察 -> 思考(含工具)-> 规划 -> 执行** 的闭环,并利用 `CycleInfo` 进行上下文传递,实现了更加智能和连贯的专注聊天行为。其核心在于利用 `SubMind` 进行深度思考和信息收集,再通过 LLM 规划器进行决策,最后由 `HeartFCSender` 可靠地执行消息发送任务。 diff --git a/docs/HeartFC_readme.md b/docs/HeartFC_readme.md deleted file mode 100644 index 790fc5bb7..000000000 --- a/docs/HeartFC_readme.md +++ /dev/null @@ -1,159 +0,0 @@ -# HeartFC_chat 工作原理文档 - -HeartFC_chat 是一个基于心流理论的聊天系统,通过模拟人类的思维过程和情感变化来实现自然的对话交互。系统采用Plan-Replier-Sender循环机制,实现了智能化的对话决策和生成。 - -## 核心工作流程 - -### 1. 消息处理与存储 (HeartFCMessageReceiver) -[代码位置: src/plugins/focus_chat/heartflow_message_receiver.py] - -消息处理器负责接收和预处理消息,主要完成以下工作: -```mermaid -graph TD - A[接收原始消息] --> B[解析为MessageRecv对象] - B --> C[消息缓冲处理] - C --> D[过滤检查] - D --> E[存储到数据库] -``` - -核心实现: -- 消息处理入口:`process_message()` [行号: 38-215] - - 消息解析和缓冲:`message_buffer.start_caching_messages()` [行号: 63] - - 过滤检查:`_check_ban_words()`, `_check_ban_regex()` [行号: 196-215] - - 消息存储:`storage.store_message()` [行号: 108] - -### 2. 对话管理循环 (HeartFChatting) -[代码位置: src/plugins/focus_chat/focus_chat.py] - -HeartFChatting是系统的核心组件,实现了完整的对话管理循环: - -```mermaid -graph TD - A[Plan阶段] -->|决策是否回复| B[Replier阶段] - B -->|生成回复内容| C[Sender阶段] - C -->|发送消息| D[等待新消息] - D --> A -``` - -#### Plan阶段 [行号: 282-386] -- 主要函数:`_planner()` -- 功能实现: - * 获取观察信息:`observation.observe()` [行号: 297] - * 思维处理:`sub_mind.do_thinking_before_reply()` [行号: 301] - * LLM决策:使用`PLANNER_TOOL_DEFINITION`进行动作规划 [行号: 13-42] - -#### Replier阶段 [行号: 388-416] -- 主要函数:`_replier_work()` -- 调用生成器:`gpt_instance.generate_response()` [行号: 394] -- 处理生成结果和错误情况 - -#### Sender阶段 [行号: 418-450] -- 主要函数:`_sender()` -- 发送实现: - * 创建消息:`_create_thinking_message()` [行号: 452-477] - * 发送回复:`_send_response_messages()` [行号: 479-525] - * 处理表情:`_handle_emoji()` [行号: 527-567] - -### 3. 回复生成机制 (HeartFCGenerator) -[代码位置: src/plugins/focus_chat/heartFC_generator.py] - -回复生成器负责产生高质量的回复内容: - -```mermaid -graph TD - A[获取上下文信息] --> B[构建提示词] - B --> C[调用LLM生成] - C --> D[后处理优化] - D --> E[返回回复集] -``` - -核心实现: -- 生成入口:`generate_response()` [行号: 39-67] - * 情感调节:`arousal_multiplier = MoodManager.get_instance().get_arousal_multiplier()` [行号: 47] - * 模型生成:`_generate_response_with_model()` [行号: 69-95] - * 响应处理:`_process_response()` [行号: 97-106] - -### 4. 提示词构建系统 (HeartFlowPromptBuilder) -[代码位置: src/plugins/focus_chat/heartflow_prompt_builder.py] - -提示词构建器支持两种工作模式,HeartFC_chat专门使用Focus模式,而Normal模式是为normal_chat设计的: - -#### 专注模式 (Focus Mode) - HeartFC_chat专用 -- 实现函数:`_build_prompt_focus()` [行号: 116-141] -- 特点: - * 专注于当前对话状态和思维 - * 更强的目标导向性 - * 用于HeartFC_chat的Plan-Replier-Sender循环 - * 简化的上下文处理,专注于决策 - -#### 普通模式 (Normal Mode) - Normal_chat专用 -- 实现函数:`_build_prompt_normal()` [行号: 143-215] -- 特点: - * 用于normal_chat的常规对话 - * 完整的个性化处理 - * 关系系统集成 - * 知识库检索:`get_prompt_info()` [行号: 217-591] - -HeartFC_chat的Focus模式工作流程: -```mermaid -graph TD - A[获取结构化信息] --> B[获取当前思维状态] - B --> C[构建专注模式提示词] - C --> D[用于Plan阶段决策] - D --> E[用于Replier阶段生成] -``` - -## 智能特性 - -### 1. 对话决策机制 -- LLM决策工具定义:`PLANNER_TOOL_DEFINITION` [focus_chat.py 行号: 13-42] -- 决策执行:`_planner()` [focus_chat.py 行号: 282-386] -- 考虑因素: - * 上下文相关性 - * 情感状态 - * 兴趣程度 - * 对话时机 - -### 2. 状态管理 -[代码位置: src/plugins/focus_chat/focus_chat.py] -- 状态机实现:`HeartFChatting`类 [行号: 44-567] -- 核心功能: - * 初始化:`_initialize()` [行号: 89-112] - * 循环控制:`_run_pf_loop()` [行号: 192-281] - * 状态转换:`_handle_loop_completion()` [行号: 166-190] - -### 3. 回复生成策略 -[代码位置: src/plugins/focus_chat/heartFC_generator.py] -- 温度调节:`current_model.temperature = global_config.llm_normal["temp"] * arousal_multiplier` [行号: 48] -- 生成控制:`_generate_response_with_model()` [行号: 69-95] -- 响应处理:`_process_response()` [行号: 97-106] - -## 系统配置 - -### 关键参数 -- LLM配置:`model_normal` [heartFC_generator.py 行号: 32-37] -- 过滤规则:`_check_ban_words()`, `_check_ban_regex()` [heartflow_message_receiver.py 行号: 196-215] -- 状态控制:`INITIAL_DURATION = 60.0` [focus_chat.py 行号: 11] - -### 优化建议 -1. 调整LLM参数:`temperature`和`max_tokens` -2. 优化提示词模板:`init_prompt()` [heartflow_prompt_builder.py 行号: 8-115] -3. 配置状态转换条件 -4. 维护过滤规则 - -## 注意事项 - -1. 系统稳定性 -- 异常处理:各主要函数都包含try-except块 -- 状态检查:`_processing_lock`确保并发安全 -- 循环控制:`_loop_active`和`_loop_task`管理 - -2. 性能优化 -- 缓存使用:`message_buffer`系统 -- LLM调用优化:批量处理和复用 -- 异步处理:使用`asyncio` - -3. 质量控制 -- 日志记录:使用`get_module_logger()` -- 错误追踪:详细的异常记录 -- 响应监控:完整的状态跟踪 diff --git a/docs/HeartFC_system.md b/docs/HeartFC_system.md deleted file mode 100644 index 1c1db6a14..000000000 --- a/docs/HeartFC_system.md +++ /dev/null @@ -1,241 +0,0 @@ -# 心流系统 (Heart Flow System) - -## 一条消息是怎么到最终回复的?简明易懂的介绍 - -1 接受消息,由HeartHC_processor处理消息,存储消息 - - 1.1 process_message()函数,接受消息 - - 1.2 创建消息对应的聊天流(chat_stream)和子心流(sub_heartflow) - - 1.3 进行常规消息处理 - - 1.4 存储消息 store_message() - - 1.5 计算兴趣度Interest - - 1.6 将消息连同兴趣度,存储到内存中的interest_dict(SubHeartflow的属性) - -2 根据 sub_heartflow 的聊天状态,决定后续处理流程 - - 2a ABSENT状态:不做任何处理 - - 2b CHAT状态:送入NormalChat 实例 - - 2c FOCUS状态:送入HeartFChatting 实例 - -b NormalChat工作方式 - - b.1 启动后台任务 _reply_interested_message,持续运行。 - b.2 该任务轮询 InterestChatting 提供的 interest_dict - b.3 对每条消息,结合兴趣度、是否被提及(@)、意愿管理器(WillingManager)计算回复概率。(这部分要改,目前还是用willing计算的,之后要和Interest合并) - b.4 若概率通过: - b.4.1 创建"思考中"消息 (MessageThinking)。 - b.4.2 调用 NormalChatGenerator 生成文本回复。 - b.4.3 通过 message_manager 发送回复 (MessageSending)。 - b.4.4 可能根据配置和文本内容,额外发送一个匹配的表情包。 - b.4.5 更新关系值和全局情绪。 - b.5 处理完成后,从 interest_dict 中移除该消息。 - -c HeartFChatting工作方式 - - c.1 启动主循环 _hfc_loop - c.2 每个循环称为一个周期 (Cycle),执行 think_plan_execute 流程。 - c.3 Think (思考) 阶段: - c.3.1 观察 (Observe): 通过 ChattingObservation,使用 observe() 获取最新的聊天消息。 - c.3.2 思考 (Think): 调用 SubMind 的 do_thinking_before_reply 方法。 - c.3.2.1 SubMind 结合观察到的内容、个性、情绪、上周期动作等信息,生成当前的内心想法 (current_mind)。 - c.3.2.2 在此过程中 SubMind 的LLM可能请求调用工具 (ToolUser) 来获取额外信息或执行操作,结果存储在 structured_info 中。 - c.4 Plan (规划/决策) 阶段: - c.4.1 结合观察到的消息文本、`SubMind` 生成的 `current_mind` 和 `structured_info`、以及 `ActionManager` 提供的可用动作,决定本次周期的行动 (`text_reply`/`emoji_reply`/`no_reply`) 和理由。 - c.4.2 重新规划检查 (Re-plan Check): 如果在 c.3.1 到 c.4.1 期间检测到新消息,可能(有概率)触发重新执行 c.4.1 决策步骤。 - c.5 Execute (执行/回复) 阶段: - c.5.1 如果决策是 text_reply: - c.5.1.1 获取锚点消息。 - c.5.1.2 通过 HeartFCSender 注册"思考中"状态。 - c.5.1.3 调用 HeartFCGenerator (gpt_instance) 生成回复文本。 - c.5.1.4 通过 HeartFCSender 发送回复 - c.5.1.5 如果规划时指定了表情查询 (emoji_query),随后发送表情。 - c.5.2 如果决策是 emoji_reply: - c.5.2.1 获取锚点消息。 - c.5.2.2 通过 HeartFCSender 直接发送匹配查询 (emoji_query) 的表情。 - c.5.3 如果决策是 no_reply: - c.5.3.1 进入等待状态,直到检测到新消息或超时。 - c.5.3.2 同时,增加内部连续不回复计数器。如果该计数器达到预设阈值(例如 5 次),则调用初始化时由 `SubHeartflowManager` 提供的回调函数。此回调函数会通知 `SubHeartflowManager` 请求将对应的 `SubHeartflow` 状态转换为 `ABSENT`。如果执行了其他动作(如 `text_reply` 或 `emoji_reply`),则此计数器会被重置。 - c.6 循环结束后,记录周期信息 (CycleInfo),并根据情况进行短暂休眠,防止CPU空转。 - - - -## 1. 一条消息是怎么到最终回复的?复杂细致的介绍 - -### 1.1. 主心流 (Heartflow) -- **文件**: `heartflow.py` -- **职责**: - - 作为整个系统的主控制器。 - - 持有并管理 `SubHeartflowManager`,用于管理所有子心流。 - - 持有并管理自身状态 `self.current_state: MaiStateInfo`,该状态控制系统的整体行为模式。 - - 统筹管理系统后台任务(如消息存储、资源分配等)。 - - **注意**: 主心流自身不进行周期性的全局思考更新。 - -### 1.2. 子心流 (SubHeartflow) -- **文件**: `sub_heartflow.py` -- **职责**: - - 处理具体的交互场景,例如:群聊、私聊、与虚拟主播(vtb)互动、桌面宠物交互等。 - - 维护特定场景下的思维状态和聊天流状态 (`ChatState`)。 - - 通过关联的 `Observation` 实例接收和处理信息。 - - 拥有独立的思考 (`SubMind`) 和回复判断能力。 -- **观察者**: 每个子心流可以拥有一个或多个 `Observation` 实例(目前每个子心流仅使用一个 `ChattingObservation`)。 -- **内部结构**: - - **聊天流状态 (`ChatState`)**: 标记当前子心流的参与模式 (`ABSENT`, `CHAT`, `FOCUSED`),决定是否观察、回复以及使用何种回复模式。 - - **聊天实例 (`NormalChatInstance` / `HeartFlowChatInstance`)**: 根据 `ChatState` 激活对应的实例来处理聊天逻辑。同一时间只有一个实例处于活动状态。 - -### 1.3. 观察系统 (Observation) -- **文件**: `observation.py` -- **职责**: - - 定义信息输入的来源和格式。 - - 为子心流提供其所处环境的信息。 -- **当前实现**: - - 目前仅有 `ChattingObservation` 一种观察类型。 - - `ChattingObservation` 负责从数据库拉取指定聊天的最新消息,并将其格式化为可读内容,供 `SubHeartflow` 使用。 - -### 1.4. 子心流管理器 (SubHeartflowManager) -- **文件**: `subheartflow_manager.py` -- **职责**: - - 作为 `Heartflow` 的成员变量存在。 - - **在初始化时接收并持有 `Heartflow` 的 `MaiStateInfo` 实例。** - - 负责所有 `SubHeartflow` 实例的生命周期管理,包括: - - 创建和获取 (`get_or_create_subheartflow`)。 - - 停止和清理 (`sleep_subheartflow`, `cleanup_inactive_subheartflows`)。 - - 根据 `Heartflow` 的状态 (`self.mai_state_info`) 和限制条件,激活、停用或调整子心流的状态(例如 `enforce_subheartflow_limits`, `randomly_deactivate_subflows`, `sbhf_absent_into_focus`)。 - - **新增**: 通过调用 `sbhf_absent_into_chat` 方法,使用 LLM (配置与 `Heartflow` 主 LLM 相同) 评估处于 `ABSENT` 或 `CHAT` 状态的子心流,根据观察到的活动摘要和 `Heartflow` 的当前状态,判断是否应在 `ABSENT` 和 `CHAT` 之间进行转换 (同样受限于 `CHAT` 状态的数量上限)。 - - **清理机制**: 通过后台任务 (`BackgroundTaskManager`) 定期调用 `cleanup_inactive_subheartflows` 方法,此方法会识别并**删除**那些处于 `ABSENT` 状态超过一小时 (`INACTIVE_THRESHOLD_SECONDS`) 的子心流实例。 - -### 1.5. 消息处理与回复流程 (Message Processing vs. Replying Flow) -- **关注点分离**: 系统严格区分了接收和处理传入消息的流程与决定和生成回复的流程。 - - **消息处理 (Processing)**: - - 由一个独立的处理器(例如 `HeartFCMessageReceiver`)负责接收原始消息数据。 - - 职责包括:消息解析 (`MessageRecv`)、过滤(屏蔽词、正则表达式)、基于记忆系统的初步兴趣计算 (`HippocampusManager`)、消息存储 (`MessageStorage`) 以及用户关系更新 (`RelationshipManager`)。 - - 处理后的消息信息(如计算出的兴趣度)会传递给对应的 `SubHeartflow`。 - - **回复决策与生成 (Replying)**: - - 由 `SubHeartflow` 及其当前激活的聊天实例 (`NormalChatInstance` 或 `HeartFlowChatInstance`) 负责。 - - 基于其内部状态 (`ChatState`、`SubMind` 的思考结果)、观察到的信息 (`Observation` 提供的内容) 以及 `InterestChatting` 的状态来决定是否回复、何时回复以及如何回复。 -- **消息缓冲 (Message Caching)**: - - `message_buffer` 模块会对某些传入消息进行临时缓存,尤其是在处理连续的多部分消息(如多张图片)时。 - - 这个缓冲机制发生在 `HeartFCMessageReceiver` 处理流程中,确保消息的完整性,然后才进行后续的存储和兴趣计算。 - - 缓存的消息最终仍会流向对应的 `ChatStream`(与 `SubHeartflow` 关联),但核心的消息处理与回复决策仍然是分离的步骤。 - -## 2. 核心控制与状态管理 (Core Control and State Management) - -### 2.1. Heart Flow 整体控制 -- **控制者**: 主心流 (`Heartflow`) -- **核心职责**: - - 通过其成员 `SubHeartflowManager` 创建和管理子心流(**在创建 `SubHeartflowManager` 时会传入自身的 `MaiStateInfo`**)。 - - 通过其成员 `self.current_state: MaiStateInfo` 控制整体行为模式。 - - 管理系统级后台任务。 - - **注意**: 不再提供直接获取所有子心流 ID (`get_all_subheartflows_streams_ids`) 的公共方法。 - -### 2.2. Heart Flow 状态 (`MaiStateInfo`) -- **定义与管理**: `Heartflow` 持有 `MaiStateInfo` 的实例 (`self.current_state`) 来管理其状态。状态的枚举定义在 `my_state_manager.py` 中的 `MaiState`。 -- **状态及含义**: - - `MaiState.OFFLINE` (不在线): 不观察任何群消息,不进行主动交互,仅存储消息。当主状态变为 `OFFLINE` 时,`SubHeartflowManager` 会将所有子心流的状态设置为 `ChatState.ABSENT`。 - - `MaiState.PEEKING` (看一眼手机): 有限度地参与聊天(由 `MaiStateInfo` 定义具体的普通/专注群数量限制)。 - - `MaiState.NORMAL_CHAT` (正常看手机): 正常参与聊天,允许 `SubHeartflow` 进入 `CHAT` 或 `FOCUSED` 状态(数量受限)。 - * `MaiState.FOCUSED_CHAT` (专心看手机): 更积极地参与聊天,通常允许更多或更高优先级的 `FOCUSED` 状态子心流。 -- **当前转换逻辑**: 目前,`MaiState` 之间的转换由 `MaiStateManager` 管理,主要基于状态持续时间和随机概率。这是一种临时的实现方式,未来计划进行改进。 -- **作用**: `Heartflow` 的状态直接影响 `SubHeartflowManager` 如何管理子心流(如激活数量、允许的状态等)。 - -### 2.3. 聊天流状态 (`ChatState`) 与转换 -- **管理对象**: 每个 `SubHeartflow` 实例内部维护其 `ChatStateInfo`,包含当前的 `ChatState`。 -- **状态及含义**: - - `ChatState.ABSENT` (不参与/没在看): 初始或停用状态。子心流不观察新信息,不进行思考,也不回复。 - - `ChatState.NORMAL` (随便看看/水群): 普通聊天模式。激活 `NormalChatInstance`。 - * `ChatState.FOCUSED` (专注/认真聊天): 专注聊天模式。激活 `HeartFlowChatInstance`。 -- **选择**: 子心流可以根据外部指令(来自 `SubHeartflowManager`)或内部逻辑(未来的扩展)选择进入 `ABSENT` 状态(不回复不观察),或进入 `CHAT` / `FOCUSED` 中的一种回复模式。 -- **状态转换机制** (由 `SubHeartflowManager` 驱动,更细致的说明): - - **初始状态**: 新创建的 `SubHeartflow` 默认为 `ABSENT` 状态。 - - **`ABSENT` -> `CHAT` (激活闲聊)**: - - **触发条件**: `Heartflow` 的主状态 (`MaiState`) 允许 `CHAT` 模式,且当前 `CHAT` 状态的子心流数量未达上限。 - - **判定机制**: `SubHeartflowManager` 中的 `sbhf_absent_into_chat` 方法调用大模型(LLM)。LLM 读取该群聊的近期内容和结合自身个性信息,判断是否"想"在该群开始聊天。 - - **执行**: 若 LLM 判断为是,且名额未满,`SubHeartflowManager` 调用 `change_chat_state(ChatState.NORMAL)`。 - - **`CHAT` -> `FOCUSED` (激活专注)**: - - **触发条件**: 子心流处于 `CHAT` 状态,其内部维护的"开屎热聊"概率 (`InterestChatting.start_hfc_probability`) 达到预设阈值(表示对当前聊天兴趣浓厚),同时 `Heartflow` 的主状态允许 `FOCUSED` 模式,且 `FOCUSED` 名额未满。 - - **判定机制**: `SubHeartflowManager` 中的 `sbhf_absent_into_focus` 方法定期检查满足条件的 `CHAT` 子心流。 - - **执行**: 若满足所有条件,`SubHeartflowManager` 调用 `change_chat_state(ChatState.FOCUSED)`。 - - **注意**: 无法从 `ABSENT` 直接跳到 `FOCUSED`,必须先经过 `CHAT`。 - - **`FOCUSED` -> `ABSENT` (退出专注)**: - - **主要途径 (内部驱动)**: 在 `FOCUSED` 状态下运行的 `HeartFlowChatInstance` 连续多次决策为 `no_reply` (例如达到 5 次,次数可配),它会通过回调函数 (`sbhf_focus_into_absent`) 请求 `SubHeartflowManager` 将其状态**直接**设置为 `ABSENT`。 - - **其他途径 (外部驱动)**: - - `Heartflow` 主状态变为 `OFFLINE`,`SubHeartflowManager` 强制所有子心流变为 `ABSENT`。 - - `SubHeartflowManager` 因 `FOCUSED` 名额超限 (`enforce_subheartflow_limits`) 或随机停用 (`randomly_deactivate_subflows`) 而将其设置为 `ABSENT`。 - - **`CHAT` -> `ABSENT` (退出闲聊)**: - - **主要途径 (内部驱动)**: `SubHeartflowManager` 中的 `sbhf_absent_into_chat` 方法调用 LLM。LLM 读取群聊内容和结合自身状态,判断是否"不想"继续在此群闲聊。 - - **执行**: 若 LLM 判断为是,`SubHeartflowManager` 调用 `change_chat_state(ChatState.ABSENT)`。 - - **其他途径 (外部驱动)**: - - `Heartflow` 主状态变为 `OFFLINE`。 - - `SubHeartflowManager` 因 `CHAT` 名额超限或随机停用。 - - **全局强制 `ABSENT`**: 当 `Heartflow` 的 `MaiState` 变为 `OFFLINE` 时,`SubHeartflowManager` 会调用所有子心流的 `change_chat_state(ChatState.ABSENT)`,强制它们全部停止活动。 - - **状态变更执行者**: `change_chat_state` 方法仅负责执行状态的切换和对应聊天实例的启停,不进行名额检查。名额检查的责任由 `SubHeartflowManager` 中的各个决策方法承担。 - - **最终清理**: 进入 `ABSENT` 状态的子心流不会立即被删除,只有在 `ABSENT` 状态持续一小时 (`INACTIVE_THRESHOLD_SECONDS`) 后,才会被后台清理任务 (`cleanup_inactive_subheartflows`) 删除。 - -## 3. 聊天实例详解 (Chat Instances Explained) - -### 3.1. NormalChatInstance -- **激活条件**: 对应 `SubHeartflow` 的 `ChatState` 为 `CHAT`。 -- **工作流程**: - - 当 `SubHeartflow` 进入 `CHAT` 状态时,`NormalChatInstance` 会被激活。 - - 实例启动后,会创建一个后台任务 (`_reply_interested_message`)。 - - 该任务持续监控由 `InterestChatting` 传入的、具有一定兴趣度的消息列表 (`interest_dict`)。 - - 对列表中的每条消息,结合是否被提及 (`@`)、消息本身的兴趣度以及当前的回复意愿 (`WillingManager`),计算出一个回复概率。 - - 根据计算出的概率随机决定是否对该消息进行回复。 - - 如果决定回复,则调用 `NormalChatGenerator` 生成回复内容,并可能附带表情包。 -- **行为特点**: - - 回复相对常规、简单。 - - 不投入过多计算资源。 - - 侧重于维持基本的交流氛围。 - - 示例:对问候语、日常分享等进行简单回应。 - -### 3.2. HeartFlowChatInstance (继承自原 PFC 逻辑) -- **激活条件**: 对应 `SubHeartflow` 的 `ChatState` 为 `FOCUSED`。 -- **工作流程**: - - 基于更复杂的规则(原 PFC 模式)进行深度处理。 - - 对群内话题进行深入分析。 - - 可能主动发起相关话题或引导交流。 -- **行为特点**: - - 回复更积极、深入。 - - 投入更多资源参与聊天。 - - 回复内容可能更详细、有针对性。 - - 对话题参与度高,能带动交流。 - - 示例:对复杂或有争议话题阐述观点,并与人互动。 - -## 4. 工作流程示例 (Example Workflow) - -1. **启动**: `Heartflow` 启动,初始化 `MaiStateInfo` (例如 `OFFLINE`) 和 `SubHeartflowManager`。 -2. **状态变化**: 用户操作或内部逻辑使 `Heartflow` 的 `current_state` 变为 `NORMAL_CHAT`。 -3. **管理器响应**: `SubHeartflowManager` 检测到状态变化,根据 `NORMAL_CHAT` 的限制,调用 `get_or_create_subheartflow` 获取或创建子心流,并通过 `change_chat_state` 将部分子心流状态从 `ABSENT` 激活为 `CHAT`。 -4. **子心流激活**: 被激活的 `SubHeartflow` 启动其 `NormalChatInstance`。 -5. **信息接收**: 该 `SubHeartflow` 的 `ChattingObservation` 开始从数据库拉取新消息。 -6. **普通回复**: `NormalChatInstance` 处理观察到的信息,执行普通回复逻辑。 -7. **兴趣评估**: `SubHeartflowManager` 定期评估该子心流的 `InterestChatting` 状态。 -8. **提升状态**: 若兴趣度达标且 `Heartflow` 状态允许,`SubHeartflowManager` 调用该子心流的 `change_chat_state` 将其状态提升为 `FOCUSED`。 -9. **子心流切换**: `SubHeartflow` 内部停止 `NormalChatInstance`,启动 `HeartFlowChatInstance`。 -10. **专注回复**: `HeartFlowChatInstance` 开始根据其逻辑进行更深入的交互。 -11. **状态回落/停用**: 若 `Heartflow` 状态变为 `OFFLINE`,`SubHeartflowManager` 会调用所有活跃子心流的 `change_chat_state(ChatState.ABSENT)`,使其进入 `ABSENT` 状态(它们不会立即被删除,只有在 `ABSENT` 状态持续1小时后才会被清理)。 - -## 5. 使用与配置 (Usage and Configuration) - -### 5.1. 使用说明 (Code Examples) -- **(内部)创建/获取子心流** (由 `SubHeartflowManager` 调用, 示例): - ```python - # subheartflow_manager.py (get_or_create_subheartflow 内部) - # 注意:mai_states 现在是 self.mai_state_info - new_subflow = SubHeartflow(subheartflow_id, self.mai_state_info) - await new_subflow.initialize() - observation = ChattingObservation(chat_id=subheartflow_id) - new_subflow.add_observation(observation) - ``` -- **(内部)添加观察者** (由 `SubHeartflowManager` 或 `SubHeartflow` 内部调用): - ```python - # sub_heartflow.py - self.observations.append(observation) - ``` - diff --git a/docs/develop/plugin_develop/index.md b/docs/develop/plugin_develop/index.md deleted file mode 100644 index 82e79da35..000000000 --- a/docs/develop/plugin_develop/index.md +++ /dev/null @@ -1,174 +0,0 @@ -# 如何编写MaiBot插件 - -## 前言 - -目前插件系统为v0.1版本,仅试行并实现简单功能,且只能在focus下使用 - -目前插件的形式为给focus模型的决策增加新**动作action** - -原有focus的planner有reply和no_reply两种动作 - -在麦麦plugin文件夹中的示例插件新增了mute_action动作和pic_action动作,你可以参考其中的代码 - -在**之后的更新**中,会兼容normal_chat aciton,更多的自定义组件,tool,和/help式指令 - -## 基本步骤 - -1. 在`src/plugins/你的插件名/actions/`目录下创建插件文件 -2. 继承`PluginAction`基类 -3. 实现`process`方法 -4. 在`src/plugins/你的插件名/__init__.py`中导入你的插件类,确保插件能被正确加载 - -```python -# src/plugins/你的插件名/__init__.py -from .actions.your_action import YourAction - -__all__ = ["YourAction"] -``` - -## 插件结构示例 - -```python -from src.common.logger_manager import get_logger -from src.chat.focus_chat.planners.actions.plugin_action import PluginAction, register_action -from typing import Tuple - -logger = get_logger("your_action_name") - -@register_action -class YourAction(PluginAction): - """你的动作描述""" - - action_name = "your_action_name" # 动作名称,必须唯一 - action_description = "这个动作的详细描述,会展示给用户" - action_parameters = { - "param1": "参数1的说明(可选)", - "param2": "参数2的说明(可选)" - } - action_require = [ - "使用场景1", - "使用场景2" - ] - default = False # 是否默认启用 - - associated_types = ["command", "text"] #该插件会发送的消息类型 - - async def process(self) -> Tuple[bool, str]: - """插件核心逻辑""" - # 你的代码逻辑... - return True, "执行结果" -``` - -## 可用的API方法 - -插件可以使用`PluginAction`基类提供的以下API: - -### 1. 直接发送消息 - -```python -#发送文本 -await self.send_message(type="text", data="你好") - -#发送图片 -await self.send_message(type="image", data=base64_image_string) - -#发送命令(需要adapter支持) -await self.send_message( - type="command", - data={"name": "GROUP_BAN", "args": {"qq_id": str(user_id), "duration": duration_str}}, - display_message=f"我 禁言了 {target} {duration_str}秒", -) -``` -会将消息直接以原始文本发送 -type指定消息类型 -data为发送内容 - -### 2. 使用表达器发送消息 - -```python -await self.send_message_by_expressor("你好") - -await self.send_message_by_expressor(f"禁言{target} {duration}秒,因为{reason}") -``` -将消息通过表达器发送,使用LLM组织成符合bot语言风格的内容并发送 -只能发送文本 - -### 3. 获取聊天类型 - -```python -chat_type = self.get_chat_type() # 返回 "group" 或 "private" 或 "unknown" -``` - -### 4. 获取最近消息 - -```python -messages = self.get_recent_messages(count=5) # 获取最近5条消息 -# 返回格式: [{"sender": "发送者", "content": "内容", "timestamp": 时间戳}, ...] -``` - -### 5. 获取动作参数 - -```python -param_value = self.action_data.get("param_name", "默认值") -``` - -### 6. 获取可用模型 - -```python -models = self.get_available_models() # 返回所有可用的模型配置 -# 返回格式: {"model_name": {"config": "value", ...}, ...} -``` - -### 7. 使用模型生成内容 - -```python -success, response, reasoning, model_name = await self.generate_with_model( - prompt="你的提示词", - model_config=models["model_name"], # 从get_available_models获取的模型配置 - max_tokens=2000, # 可选,最大生成token数 - request_type="plugin.generate", # 可选,请求类型标识 - temperature=0.7, # 可选,温度参数 - # 其他模型特定参数... -) -``` - -### 8. 获取用户ID - -```python -platform, user_id = await self.get_user_id_by_person_name("用户名") -``` - -### 日志记录 - -```python -logger.info(f"{self.log_prefix} 你的日志信息") -logger.warning("警告信息") -logger.error("错误信息") -``` - -## 返回值说明 - -`process`方法必须返回一个元组,包含两个元素: - -- 第一个元素(bool): 表示动作是否执行成功 -- 第二个元素(str): 执行结果的文本描述(可以为空"") - -```python -return True, "执行成功的消息" -# 或 -return False, "执行失败的原因" -``` - -## 最佳实践 - -1. 使用`action_parameters`清晰定义你的动作需要的参数 -2. 使用`action_require`描述何时应该使用你的动作 -3. 使用`action_description`准确描述你的动作功能 -4. 使用`logger`记录重要信息,方便调试 -5. 避免操作底层系统,尽量使用`PluginAction`提供的API - -## 注册与加载 - -插件会在系统启动时自动加载,只要放在正确的目录并添加了`@register_action`装饰器。 - -若设置`default = True`,插件会自动添加到默认动作集并启用,否则默认只加载不启用。 diff --git a/docs/plugin_detailed_guide.md b/docs/plugin_detailed_guide.md new file mode 100644 index 000000000..1af9fee3b --- /dev/null +++ b/docs/plugin_detailed_guide.md @@ -0,0 +1,752 @@ +# MaiBot 插件详细解析指南 + +## 📋 目录 + +1. [插件基类详解](#插件基类详解) +2. [Action组件深入](#action组件深入) +3. [Command组件深入](#command组件深入) +4. [API系统详解](#api系统详解) +5. [配置系统](#配置系统) +6. [注册中心机制](#注册中心机制) +7. [高级功能](#高级功能) +8. [最佳实践](#最佳实践) + +--- + +## 插件基类详解 + +### BasePlugin 核心功能 + +`BasePlugin` 是所有插件的基类,提供插件的生命周期管理和基础功能。 + +```python +@register_plugin +class MyPlugin(BasePlugin): + # 必需的基本信息 + plugin_name = "my_plugin" # 插件唯一标识 + plugin_description = "插件功能描述" # 简短描述 + plugin_version = "1.0.0" # 版本号 + plugin_author = "作者名称" # 作者信息 + enable_plugin = True # 是否启用 + + # 可选配置 + dependencies = ["other_plugin"] # 依赖的其他插件 + config_file_name = "config.toml" # 配置文件名 + + def get_plugin_components(self) -> List[Tuple[ComponentInfo, Type]]: + """返回插件包含的组件列表(必须实现)""" + return [ + (MyAction.get_action_info(), MyAction), + (MyCommand.get_command_info(), MyCommand) + ] +``` + +### 插件生命周期 + +1. **加载阶段** - 插件管理器扫描插件目录 +2. **实例化阶段** - 创建插件实例,传入 `plugin_dir` +3. **配置加载** - 自动加载配置文件(如果指定) +4. **依赖检查** - 验证依赖的插件是否存在 +5. **组件注册** - 注册所有组件到注册中心 +6. **运行阶段** - 组件响应用户交互 + +### 配置访问 + +```python +class MyPlugin(BasePlugin): + config_file_name = "config.toml" + + def some_method(self): + # 获取配置值 + max_retry = self.get_config("network.max_retry", 3) + api_key = self.get_config("api.key", "") + + # 配置支持嵌套结构 + db_config = self.get_config("database", {}) +``` + +--- + +## Action组件深入 + +### Action激活机制 + +Action组件支持多种激活方式,可以组合使用: + +#### 1. 关键词激活 + +```python +class KeywordAction(BaseAction): + focus_activation_type = ActionActivationType.KEYWORD + normal_activation_type = ActionActivationType.KEYWORD + activation_keywords = ["天气", "weather", "温度"] + keyword_case_sensitive = False # 是否区分大小写 + + async def execute(self) -> Tuple[bool, str]: + # 获取触发的关键词 + triggered_keyword = self.action_data.get("triggered_keyword") + return True, f"检测到关键词: {triggered_keyword}" +``` + +#### 2. LLM智能判断 + +```python +class SmartAction(BaseAction): + focus_activation_type = ActionActivationType.LLM_JUDGE + llm_judge_prompt = """ + 判断用户消息是否表达了情感支持的需求。 + 如果用户显得沮丧、焦虑或需要安慰,返回True,否则返回False。 + """ + + async def execute(self) -> Tuple[bool, str]: + # LLM判断为需要情感支持 + user_emotion = self.action_data.get("emotion", "neutral") + return True, "我理解你现在的感受,有什么可以帮助你的吗? 🤗" +``` + +#### 3. 随机激活 + +```python +class RandomAction(BaseAction): + focus_activation_type = ActionActivationType.RANDOM + random_activation_probability = 0.1 # 10%概率触发 + + async def execute(self) -> Tuple[bool, str]: + import random + responses = ["今天天气不错呢!", "你知道吗,刚才想到一个有趣的事...", "随便聊聊吧!"] + return True, random.choice(responses) +``` + +#### 4. 始终激活 + +```python +class AlwaysAction(BaseAction): + focus_activation_type = ActionActivationType.ALWAYS + parallel_action = True # 允许与其他Action并行 + + async def execute(self) -> Tuple[bool, str]: + # 记录所有消息到数据库 + await self.api.store_user_data("last_message", self.action_data.get("message")) + return True, "" # 静默执行,不发送回复 +``` + +### Action数据访问 + +```python +class DataAction(BaseAction): + async def execute(self) -> Tuple[bool, str]: + # 访问消息数据 + message = self.action_data.get("message", "") + username = self.action_data.get("username", "用户") + user_id = self.action_data.get("user_id", "") + platform = self.action_data.get("platform", "") + + # 访问系统数据 + thinking_id = self.thinking_id + reasoning = self.reasoning # 执行该动作的理由 + + # 访问计时器信息 + timers = self.cycle_timers + + return True, f"处理来自 {platform} 的用户 {username} 的消息" +``` + +### 聊天模式支持 + +```python +class ModeAwareAction(BaseAction): + mode_enable = ChatMode.PRIVATE # 只在私聊中启用 + # mode_enable = ChatMode.GROUP # 只在群聊中启用 + # mode_enable = ChatMode.ALL # 在所有模式中启用 + + async def execute(self) -> Tuple[bool, str]: + current_mode = self.action_data.get("chat_mode", ChatMode.PRIVATE) + return True, f"当前聊天模式: {current_mode.name}" +``` + +--- + +## Command组件深入 + +### 高级正则表达式模式 + +Command使用正则表达式进行精确匹配,支持复杂的参数提取: + +#### 1. 基础命令 + +```python +class BasicCommand(BaseCommand): + command_pattern = r"^/hello$" + command_help = "简单的问候命令" + + async def execute(self) -> Tuple[bool, Optional[str]]: + await self.send_reply("Hello!") + return True, "Hello!" +``` + +#### 2. 带参数命令 + +```python +class ParameterCommand(BaseCommand): + command_pattern = r"^/user\s+(?Padd|remove|list)\s+(?P\w+)?$" + command_help = "用户管理命令,用法:/user [用户名]" + command_examples = ["/user add alice", "/user remove bob", "/user list"] + + async def execute(self) -> Tuple[bool, Optional[str]]: + action = self.matched_groups.get("action") + name = self.matched_groups.get("name") + + if action == "add" and name: + # 添加用户逻辑 + await self.api.store_user_data(f"user_{name}", {"name": name, "created": self.api.get_current_time()}) + response = f"用户 {name} 已添加" + elif action == "remove" and name: + # 删除用户逻辑 + await self.api.delete_user_data(f"user_{name}") + response = f"用户 {name} 已删除" + elif action == "list": + # 列出用户逻辑 + users = await self.api.get_user_data_pattern("user_*") + response = f"用户列表: {', '.join(users.keys())}" + else: + response = "参数错误,请查看帮助信息" + + await self.send_reply(response) + return True, response +``` + +#### 3. 复杂参数解析 + +```python +class AdvancedCommand(BaseCommand): + command_pattern = r"^/remind\s+(?P