From f999ebd2fdf773e4f661c58b769bd5eb9d9c9ee0 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Mon, 16 Jun 2025 13:47:40 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E6=96=B0=E5=A2=9E=E8=A1=A8?= =?UTF-8?q?=E8=BE=BE=E6=96=B9=E5=BC=8F=E9=80=89=E6=8B=A9=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- action_activation_system_usage.md | 773 ------------------ plugins/example_plugin/config.toml | 10 +- src/chat/focus_chat/heartFC_chat.py | 3 + .../info/expression_selection_info.py | 71 ++ .../expression_selector_processor.py | 365 +++++++++ .../focus_chat/planners/planner_simple.py | 9 + .../focus_chat/replyer/default_replyer.py | 43 +- src/chat/normal_chat/normal_chat.py | 2 +- src/config/official_configs.py | 6 + src/person_info/relationship_manager.py | 2 +- template/bot_config_template.toml | 3 +- 11 files changed, 480 insertions(+), 807 deletions(-) delete mode 100644 action_activation_system_usage.md create mode 100644 src/chat/focus_chat/info/expression_selection_info.py create mode 100644 src/chat/focus_chat/info_processors/expression_selector_processor.py diff --git a/action_activation_system_usage.md b/action_activation_system_usage.md deleted file mode 100644 index cbc6e60b7..000000000 --- a/action_activation_system_usage.md +++ /dev/null @@ -1,773 +0,0 @@ -# MaiBot 动作激活系统使用指南 - -## 概述 - -MaiBot 的动作激活系统采用**双激活类型架构**,为Focus模式和Normal模式分别提供最优的激活策略。 - -**系统已集成四大核心特性:** -- 🎯 **双激活类型**:Focus模式智能化,Normal模式高性能 -- 🚀 **并行判定**:多个LLM判定任务并行执行 -- 💾 **智能缓存**:相同上下文的判定结果缓存复用 -- ⚡ **并行动作**:支持与回复同时执行的动作 - -## 双激活类型系统 🆕 - -### 系统设计理念 - -**Focus模式**:智能优先 -- 支持复杂的LLM判定 -- 提供精确的上下文理解 -- 适合需要深度分析的场景 - -**Normal模式**:性能优先 -- 使用快速的关键词匹配 -- 采用简单的随机触发 -- 确保快速响应用户 - -### 核心属性配置 - -```python -from src.chat.focus_chat.planners.actions.base_action import BaseAction, register_action, ActionActivationType -from src.chat.chat_mode import ChatMode - -@register_action -class MyAction(BaseAction): - action_name = "my_action" - action_description = "我的动作描述" - - # 双激活类型配置 - focus_activation_type = ActionActivationType.LLM_JUDGE # Focus模式使用智能判定 - normal_activation_type = ActionActivationType.KEYWORD # Normal模式使用关键词 - activation_keywords = ["关键词1", "关键词2", "keyword"] - keyword_case_sensitive = False - - # 模式启用控制 - mode_enable = ChatMode.ALL # 支持的聊天模式 - - # 并行执行控制 - parallel_action = False # 是否与回复并行执行 - - # 插件系统控制 - enable_plugin = True # 是否启用此插件 -``` - -## 激活类型详解 - -### 1. ALWAYS - 总是激活 -**用途**:基础必需动作,始终可用 -```python -focus_activation_type = ActionActivationType.ALWAYS -normal_activation_type = ActionActivationType.ALWAYS -``` -**示例**:`reply_action`, `no_reply_action` - -### 2. RANDOM - 随机激活 -**用途**:增加不可预测性和趣味性 -```python -focus_activation_type = ActionActivationType.RANDOM -normal_activation_type = ActionActivationType.RANDOM -random_activation_probability = 0.2 # 20%概率激活 -``` -**示例**:`vtb_action` (表情动作) - -### 3. LLM_JUDGE - LLM智能判定 -**用途**:需要上下文理解的复杂判定 -```python -focus_activation_type = ActionActivationType.LLM_JUDGE -# 注意:Normal模式使用LLM_JUDGE会产生性能警告 -normal_activation_type = ActionActivationType.KEYWORD # 推荐在Normal模式使用KEYWORD -``` -**优化特性**: -- ⚡ **直接判定**:直接进行LLM判定,减少复杂度 -- 🚀 **并行执行**:多个LLM判定同时进行 -- 💾 **结果缓存**:相同上下文复用结果(30秒有效期) - -### 4. KEYWORD - 关键词触发 -**用途**:精确命令式触发 -```python -focus_activation_type = ActionActivationType.KEYWORD -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["画", "画图", "生成图片", "draw"] -keyword_case_sensitive = False # 不区分大小写 -``` -**示例**:`pic_action`, `mute_action` - -## 模式启用控制 (ChatMode) - -### 模式类型 -```python -from src.chat.chat_mode import ChatMode - -# 在所有模式下启用 -mode_enable = ChatMode.ALL # 默认值 - -# 仅在Focus模式启用 -mode_enable = ChatMode.FOCUS - -# 仅在Normal模式启用 -mode_enable = ChatMode.NORMAL -``` - -### 使用场景建议 -- **ChatMode.ALL**: 通用功能(如回复、图片生成) -- **ChatMode.FOCUS**: 需要深度理解的智能功能 -- **ChatMode.NORMAL**: 快速响应的基础功能 - -## 并行动作系统 🆕 - -### 概念说明 -```python -# 并行动作:与回复生成同时执行 -parallel_action = True # 不会阻止回复,提升用户体验 - -# 串行动作:替代回复生成(传统行为) -parallel_action = False # 默认值,动作执行时不生成回复 -``` - -### 适用场景 -**并行动作 (parallel_action = True)**: -- 情感表达(表情、动作) -- 状态变更(禁言、设置) -- 辅助功能(TTS播报) - -**串行动作 (parallel_action = False)**: -- 内容生成(图片、文档) -- 搜索查询 -- 需要完整注意力的操作 - -### 实际案例 -```python -@register_action -class MuteAction(PluginAction): - action_name = "mute_action" - focus_activation_type = ActionActivationType.LLM_JUDGE - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["禁言", "mute", "ban", "silence"] - parallel_action = True # 禁言的同时还可以回复确认信息 - -@register_action -class PicAction(PluginAction): - action_name = "pic_action" - focus_activation_type = ActionActivationType.LLM_JUDGE - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["画", "绘制", "生成图片", "画图", "draw", "paint"] - parallel_action = False # 专注于图片生成,不同时回复 -``` - -## 推荐配置模式 - -### 模式1:智能自适应(推荐) -```python -# Focus模式智能判定,Normal模式快速触发 -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["相关", "关键词", "英文keyword"] -mode_enable = ChatMode.ALL -parallel_action = False # 根据具体需求调整 -``` - -### 模式2:统一关键词 -```python -# 两个模式都使用关键词,确保行为一致 -focus_activation_type = ActionActivationType.KEYWORD -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["画", "图片", "生成"] -mode_enable = ChatMode.ALL -parallel_action = False -``` - -### 模式3:Focus专享功能 -```python -# 仅在Focus模式启用的高级功能 -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.ALWAYS # 不会生效 -mode_enable = ChatMode.FOCUS -parallel_action = False -``` - -### 模式4:随机娱乐功能 -```python -# 增加趣味性的随机功能 -focus_activation_type = ActionActivationType.RANDOM -normal_activation_type = ActionActivationType.RANDOM -random_activation_probability = 0.08 # 8%概率 -mode_enable = ChatMode.ALL -parallel_action = True # 通常与回复并行 -``` - -## 性能优化详解 - -### 并行判定机制 -```python -# 自动将多个LLM判定任务并行执行 -async def _process_llm_judge_actions_parallel(self, llm_judge_actions, ...): - tasks = [self._llm_judge_action(name, info, ...) for name, info in llm_judge_actions.items()] - results = await asyncio.gather(*tasks, return_exceptions=True) -``` - -**优势**: -- 多个LLM判定同时进行,显著减少总耗时 -- 异常处理确保单个失败不影响整体 -- 自动负载均衡 - -### 智能缓存系统 -```python -# 基于上下文哈希的缓存机制 -cache_key = f"{action_name}_{context_hash}" -if cache_key in self._llm_judge_cache: - return cached_result # 直接返回缓存结果 -``` - -**特性**: -- 30秒缓存有效期 -- MD5哈希确保上下文一致性 -- 自动清理过期缓存 -- 命中率优化:相同聊天上下文的重复判定 - -### 分层判定架构 - -#### 第一层:智能动态过滤 -```python -def _pre_filter_llm_actions(self, llm_judge_actions, observed_messages_str, ...): - # 动态收集所有KEYWORD类型actions的关键词 - all_keyword_actions = self.action_manager.get_registered_actions() - collected_keywords = {} - - for action_name, action_info in all_keyword_actions.items(): - if action_info.get("activation_type") == "KEYWORD": - keywords = action_info.get("activation_keywords", []) - if keywords: - collected_keywords[action_name] = [kw.lower() for kw in keywords] - - # 基于实际配置进行智能过滤 - for action_name, action_info in llm_judge_actions.items(): - # 策略1: 避免与KEYWORD类型重复 - # 策略2: 基于action描述进行语义相关性检查 - # 策略3: 保留核心actions -``` - -**智能过滤策略**: -- **动态关键词收集**:从各个action的实际配置中收集关键词,无硬编码 -- **重复避免机制**:如果存在对应的KEYWORD触发action,优先使用KEYWORD -- **语义相关性检查**:基于action描述和消息内容进行智能匹配 -- **长度与复杂度匹配**:短消息自动排除复杂operations -- **核心action保护**:确保reply/no_reply等基础action始终可用 - -#### 第二层:LLM精确判定 -通过第一层过滤后的动作才进入LLM判定,大幅减少: -- LLM调用次数 -- 总处理时间 -- API成本 - -## HFC流程级并行化优化 🆕 - -### 三阶段并行架构 - -除了动作激活系统内部的优化,整个HFC(HeartFocus Chat)流程也实现了并行化: - -```python -# 在 heartFC_chat.py 中的优化 -if global_config.focus_chat.parallel_processing: - # 并行执行调整动作、回忆和处理器阶段 - with Timer("并行调整动作、回忆和处理", cycle_timers): - async def modify_actions_task(): - await self.action_modifier.modify_actions(observations=self.observations) - await self.action_observation.observe() - self.observations.append(self.action_observation) - return True - - # 创建三个并行任务 - action_modify_task = asyncio.create_task(modify_actions_task()) - memory_task = asyncio.create_task(self.memory_activator.activate_memory(self.observations)) - processor_task = asyncio.create_task(self._process_processors(self.observations, [])) - - # 等待三个任务完成 - _, running_memorys, (all_plan_info, processor_time_costs) = await asyncio.gather( - action_modify_task, memory_task, processor_task - ) -``` - -### 并行化阶段说明 - -**1. 调整动作阶段(Action Modifier)** -- 执行动作激活系统的智能判定 -- 包含并行LLM判定和缓存 -- 更新可用动作列表 - -**2. 回忆激活阶段(Memory Activator)** -- 根据当前观察激活相关记忆 -- 检索历史对话和上下文信息 -- 为规划器提供背景知识 - -**3. 信息处理器阶段(Processors)** -- 处理观察信息,提取关键特征 -- 生成结构化的计划信息 -- 为规划器提供决策依据 - -### 性能提升效果 - -**理论提升**: -- 原串行执行:500ms + 800ms + 1000ms = 2300ms -- 现并行执行:max(500ms, 800ms, 1000ms) = 1000ms -- **性能提升:2.3x** - -**实际效果**: -- 显著减少每个HFC循环的总耗时 -- 提高机器人响应速度 -- 优化用户体验 - -### 配置控制 - -通过配置文件控制是否启用并行处理: -```yaml -focus_chat: - parallel_processing: true # 启用并行处理 -``` - -**建议设置**: -- **生产环境**:启用(`true`)- 获得最佳性能 -- **调试环境**:可选择禁用(`false`)- 便于问题定位 - -## 使用示例 - -### 定义新的动作类 - -```python -from src.chat.focus_chat.planners.actions.plugin_action import PluginAction, register_action, ActionActivationType -from src.chat.chat_mode import ChatMode - -@register_action -class MyAction(PluginAction): - action_name = "my_action" - action_description = "我的自定义动作" - - # 双激活类型配置 - focus_activation_type = ActionActivationType.LLM_JUDGE - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["自定义", "触发", "custom"] - - # 模式和并行控制 - mode_enable = ChatMode.ALL - parallel_action = False - enable_plugin = True - - async def process(self): - # 动作执行逻辑 - pass -``` - -### 关键词触发动作 -```python -@register_action -class SearchAction(PluginAction): - action_name = "search_action" - focus_activation_type = ActionActivationType.KEYWORD - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["搜索", "查找", "什么是", "search", "find"] - keyword_case_sensitive = False - mode_enable = ChatMode.ALL - parallel_action = False -``` - -### 随机触发动作 -```python -@register_action -class SurpriseAction(PluginAction): - action_name = "surprise_action" - focus_activation_type = ActionActivationType.RANDOM - normal_activation_type = ActionActivationType.RANDOM - random_activation_probability = 0.1 # 10%概率 - mode_enable = ChatMode.ALL - parallel_action = True # 惊喜动作与回复并行 -``` - -### Focus专享智能动作 -```python -@register_action -class AdvancedAnalysisAction(PluginAction): - action_name = "advanced_analysis" - focus_activation_type = ActionActivationType.LLM_JUDGE - normal_activation_type = ActionActivationType.ALWAYS # 不会生效 - mode_enable = ChatMode.FOCUS # 仅Focus模式 - parallel_action = False -``` - -## 现有插件的配置示例 - -### MuteAction (禁言动作) -```python -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["禁言", "mute", "ban", "silence"] -mode_enable = ChatMode.ALL -parallel_action = True # 可以与回复同时进行 -``` - -### PicAction (图片生成) -```python -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.KEYWORD -activation_keywords = ["画", "绘制", "生成图片", "画图", "draw", "paint", "图片生成"] -mode_enable = ChatMode.ALL -parallel_action = False # 专注生成,不同时回复 -``` - -### VTBAction (虚拟主播表情) -```python -focus_activation_type = ActionActivationType.LLM_JUDGE -normal_activation_type = ActionActivationType.RANDOM -random_activation_probability = 0.08 -mode_enable = ChatMode.ALL -parallel_action = False # 替代文字回复 -``` - -## 性能监控 - -### 实时性能指标 -```python -# 自动记录的性能指标 -logger.debug(f"激活判定:{before_count} -> {after_count} actions") -logger.debug(f"并行LLM判定完成,耗时: {duration:.2f}s") -logger.debug(f"使用缓存结果 {action_name}: {'激活' if result else '未激活'}") -logger.debug(f"清理了 {count} 个过期缓存条目") -logger.debug(f"并行调整动作、回忆和处理完成,耗时: {duration:.2f}s") -``` - -### 性能优化建议 -1. **合理配置缓存时间**:根据聊天活跃度调整 `_cache_expiry_time` -2. **优化过滤规则**:根据实际使用情况调整 `_quick_filter_keywords` -3. **监控并行效果**:关注 `asyncio.gather` 的执行时间 -4. **缓存命中率**:监控缓存使用情况,优化策略 -5. **启用流程并行化**:确保 `parallel_processing` 配置为 `true` -6. **激活类型选择**:Normal模式优先使用KEYWORD,避免LLM_JUDGE - -## 迁移指南 ⚠️ - -### 重大变更说明 -**旧的 `action_activation_type` 属性已被移除**,必须更新为新的双激活类型系统。 - -### 快速迁移步骤 - -#### 第一步:更新基本属性 -```python -# 旧的配置(已废弃)❌ -class OldAction(BaseAction): - action_activation_type = ActionActivationType.LLM_JUDGE - -# 新的配置(必须使用)✅ -class NewAction(BaseAction): - focus_activation_type = ActionActivationType.LLM_JUDGE - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["相关", "关键词"] - mode_enable = ChatMode.ALL - parallel_action = False - enable_plugin = True -``` - -#### 第二步:根据原类型选择对应策略 -```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 # 添加关键词 -activation_keywords = ["需要", "添加", "关键词"] - -# 原来是 KEYWORD -focus_activation_type = ActionActivationType.KEYWORD -normal_activation_type = ActionActivationType.KEYWORD -# 保持原有的 activation_keywords - -# 原来是 RANDOM -focus_activation_type = ActionActivationType.RANDOM -normal_activation_type = ActionActivationType.RANDOM -# 保持原有的 random_activation_probability -``` - -#### 第三步:配置新功能 -```python -# 添加模式控制 -mode_enable = ChatMode.ALL # 或 ChatMode.FOCUS / ChatMode.NORMAL - -# 添加并行控制 -parallel_action = False # 根据动作特性选择True/False - -# 添加插件控制 -enable_plugin = True # 是否启用此插件 -``` - -### 批量迁移脚本 -可以创建以下脚本来帮助批量迁移: - -```python -# migrate_actions.py -import os -import re - -def migrate_action_file(filepath): - with open(filepath, 'r', encoding='utf-8') as f: - content = f.read() - - # 替换 action_activation_type - if 'action_activation_type = ActionActivationType.ALWAYS' in content: - content = content.replace( - 'action_activation_type = ActionActivationType.ALWAYS', - 'focus_activation_type = ActionActivationType.ALWAYS\n normal_activation_type = ActionActivationType.ALWAYS' - ) - elif 'action_activation_type = ActionActivationType.LLM_JUDGE' in content: - content = content.replace( - 'action_activation_type = ActionActivationType.LLM_JUDGE', - 'focus_activation_type = ActionActivationType.LLM_JUDGE\n normal_activation_type = ActionActivationType.KEYWORD\n activation_keywords = ["需要", "添加", "关键词"] # TODO: 配置合适的关键词' - ) - # ... 其他替换逻辑 - - # 添加新属性 - if 'mode_enable' not in content: - # 在class定义后添加新属性 - # ... - - with open(filepath, 'w', encoding='utf-8') as f: - f.write(content) - -# 使用示例 -migrate_action_file('src/plugins/your_plugin/actions/your_action.py') -``` - -## 测试验证 - -运行动作激活优化测试: -```bash -python test_action_activation_optimized.py -``` - -运行HFC并行化测试: -```bash -python test_parallel_optimization.py -``` - -测试内容包括: -- ✅ 双激活类型功能验证 -- ✅ 并行处理功能验证 -- ✅ 缓存机制效果测试 -- ✅ 分层判定规则验证 -- ✅ 性能对比分析 -- ✅ HFC流程并行化效果 -- ✅ 多循环平均性能测试 -- ✅ 并行动作系统验证 -- ✅ 迁移兼容性测试 - -## 最佳实践 - -### 1. 激活类型选择 -- **ALWAYS**:reply, no_reply 等基础动作 -- **LLM_JUDGE**:需要智能判断的复杂动作(建议仅用于Focus模式) -- **KEYWORD**:明确的命令式动作(推荐在Normal模式使用) -- **RANDOM**:增趣动作,低概率触发 - -### 2. 双模式配置策略 -- **智能自适应**:Focus用LLM_JUDGE,Normal用KEYWORD -- **性能优先**:两个模式都用KEYWORD或RANDOM -- **功能分离**:某些功能仅在特定模式启用 - -### 3. 并行动作使用建议 -- **parallel_action = True**:辅助性、非内容生成类动作 -- **parallel_action = False**:主要内容生成、需要完整注意力的动作 - -### 4. LLM判定提示词编写 -- 明确描述激活条件和排除条件 -- 避免模糊的描述 -- 考虑边界情况 -- 保持简洁明了 - -### 5. 关键词设置 -- 包含同义词和英文对应词 -- 考虑用户的不同表达习惯 -- 避免过于宽泛的关键词 -- 根据实际使用调整 - -### 6. 性能优化 -- 定期监控处理时间 -- 根据使用模式调整缓存策略 -- 优化激活判定逻辑 -- 平衡准确性和性能 -- **启用并行处理配置** -- **Normal模式避免使用LLM_JUDGE** - -### 7. 并行化最佳实践 -- 在生产环境启用 `parallel_processing` -- 监控并行阶段的执行时间 -- 确保各阶段的独立性 -- 避免共享状态导致的竞争条件 - -## 总结 - -优化后的动作激活系统通过**五层优化策略**,实现了全方位的性能提升: - -### 第一层:双激活类型系统 -- **Focus模式**:智能化优先,支持复杂LLM判定 -- **Normal模式**:性能优先,使用快速关键词匹配 -- **模式自适应**:根据聊天模式选择最优策略 - -### 第二层:动作激活内部优化 -- **并行判定**:多个LLM判定任务并行执行 -- **智能缓存**:相同上下文的判定结果缓存复用 -- **分层判定**:快速过滤 + 精确判定的两层架构 - -### 第三层:并行动作系统 -- **并行执行**:支持动作与回复同时进行 -- **用户体验**:减少等待时间,提升交互流畅性 -- **灵活控制**:每个动作可独立配置并行行为 - -### 第四层:HFC流程级并行化 -- **三阶段并行**:调整动作、回忆、处理器同时执行 -- **性能提升**:2.3x 理论加速比 -- **配置控制**:可根据环境灵活开启/关闭 - -### 第五层:插件系统增强 -- **enable_plugin**:精确控制插件启用状态 -- **mode_enable**:支持模式级别的功能控制 -- **向后兼容**:平滑迁移旧系统配置 - -### 综合效果 -- **响应速度**:显著提升机器人反应速度 -- **成本优化**:减少不必要的LLM调用 -- **智能决策**:双激活类型覆盖所有场景 -- **用户体验**:更快速、更智能的交互 -- **灵活配置**:精细化的功能控制 - -**总性能提升预估:4-6x** -- 双激活类型系统:1.5x (Normal模式优化) -- 动作激活内部优化:1.5-2x -- HFC流程并行化:2.3x -- 并行动作系统:额外30-50%提升 -- 缓存和过滤优化:额外20-30%提升 - -这使得MaiBot能够更快速、更智能地响应用户需求,同时提供灵活的配置选项以适应不同的使用场景,实现了卓越的交互体验。 - -## 如何为Action添加激活类型 - -### 对于普通Action - -```python -from src.chat.focus_chat.planners.actions.base_action import BaseAction, register_action, ActionActivationType -from src.chat.chat_mode import ChatMode - -@register_action -class YourAction(BaseAction): - action_name = "your_action" - action_description = "你的动作描述" - - # 双激活类型配置 - focus_activation_type = ActionActivationType.LLM_JUDGE - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["关键词1", "关键词2", "keyword"] - keyword_case_sensitive = False - - # 新增属性 - mode_enable = ChatMode.ALL - parallel_action = False - enable_plugin = True - - # ... 其他代码 -``` - -### 对于插件Action - -```python -from src.chat.focus_chat.planners.actions.plugin_action import PluginAction, register_action, ActionActivationType -from src.chat.chat_mode import ChatMode - -@register_action -class YourPluginAction(PluginAction): - action_name = "your_plugin_action" - action_description = "你的插件动作描述" - - # 双激活类型配置 - focus_activation_type = ActionActivationType.KEYWORD - normal_activation_type = ActionActivationType.KEYWORD - activation_keywords = ["触发词1", "trigger", "启动"] - keyword_case_sensitive = False - - # 新增属性 - mode_enable = ChatMode.ALL - parallel_action = True # 与回复并行执行 - enable_plugin = True - - # ... 其他代码 -``` - -## 工作流程 - -1. **ActionModifier处理**: 在planner运行前,ActionModifier会遍历所有注册的动作 -2. **模式检查**: 根据当前聊天模式(Focus/Normal)和action的mode_enable进行过滤 -3. **激活类型判断**: 根据当前模式选择对应的激活类型(focus_activation_type或normal_activation_type) -4. **激活决策**: - - ALWAYS: 直接激活 - - RANDOM: 根据概率随机决定 - - LLM_JUDGE: 调用小模型判定(Normal模式会警告) - - KEYWORD: 检测关键词匹配 -5. **并行性检查**: 根据parallel_action决定是否与回复并行 -6. **结果收集**: 收集所有激活的动作供planner使用 - -## 配置建议 - -### 双激活类型策略选择 -- **智能自适应(推荐)**: Focus用LLM_JUDGE,Normal用KEYWORD -- **性能优先**: 两个模式都用KEYWORD或RANDOM -- **功能专享**: 某些高级功能仅在Focus模式启用 - -### LLM判定提示词编写 -- 明确指出激活条件和不激活条件 -- 使用简单清晰的语言 -- 避免过于复杂的逻辑判断 - -### 随机概率设置 -- 核心功能: 不建议使用随机 -- 娱乐功能: 0.1-0.3 (10%-30%) -- 辅助功能: 0.05-0.2 (5%-20%) - -### 关键词设计 -- 包含常用的同义词和变体 -- 考虑中英文兼容 -- 避免过于宽泛的词汇 -- 测试关键词的覆盖率 - -### 性能考虑 -- LLM判定会增加响应时间,适度使用 -- 关键词检测性能最好,推荐优先使用 -- Normal模式避免使用LLM_JUDGE -- 建议优先级:KEYWORD > ALWAYS > RANDOM > LLM_JUDGE - -## 调试和测试 - -使用提供的测试脚本验证激活类型系统: - -```bash -python test_action_activation.py -``` - -该脚本会显示: -- 所有注册动作的双激活类型配置 -- 模拟不同模式下的激活结果 -- 并行动作系统的工作状态 -- 帮助验证配置是否正确 - -## 注意事项 - -1. **重大变更**: `action_activation_type` 已被移除,必须使用双激活类型 -2. **向后兼容**: 系统不再兼容旧的单一激活类型配置 -3. **错误处理**: LLM判定失败时默认不激活该动作 -4. **性能警告**: Normal模式使用LLM_JUDGE会产生警告 -5. **日志记录**: 系统会记录激活决策过程,便于调试 -6. **性能影响**: LLM判定会略微增加响应时间 - -## 未来扩展 - -系统设计支持未来添加更多激活类型和功能,如: -- 基于时间的激活 -- 基于用户权限的激活 -- 基于群组设置的激活 -- 基于对话历史的激活 -- 基于情感状态的激活 \ No newline at end of file diff --git a/plugins/example_plugin/config.toml b/plugins/example_plugin/config.toml index c1e7a8ee6..f400ff76f 100644 --- a/plugins/example_plugin/config.toml +++ b/plugins/example_plugin/config.toml @@ -8,12 +8,12 @@ description = "展示新插件系统完整功能的示例插件" # 组件启用控制 [components] -enable_greeting = true +enable_greeting = false enable_helpful = true -enable_help = true -enable_send = true -enable_echo = true -enable_info = true +enable_help = false +enable_send = false +enable_echo = false +enable_info = false enable_dice = true # 智能问候配置 diff --git a/src/chat/focus_chat/heartFC_chat.py b/src/chat/focus_chat/heartFC_chat.py index 15fbd64b6..d23cda123 100644 --- a/src/chat/focus_chat/heartFC_chat.py +++ b/src/chat/focus_chat/heartFC_chat.py @@ -26,6 +26,7 @@ from src.chat.focus_chat.replyer.default_replyer import DefaultReplyer from src.chat.focus_chat.memory_activator import MemoryActivator from src.chat.focus_chat.info_processors.base_processor import BaseProcessor from src.chat.focus_chat.info_processors.self_processor import SelfProcessor +from src.chat.focus_chat.info_processors.expression_selector_processor import ExpressionSelectorProcessor from src.chat.focus_chat.planners.planner_factory import PlannerFactory from src.chat.focus_chat.planners.modify_actions import ActionModifier from src.chat.focus_chat.planners.action_manager import ActionManager @@ -48,6 +49,7 @@ PROCESSOR_CLASSES = { "WorkingMemoryProcessor": (WorkingMemoryProcessor, "working_memory_processor"), "SelfProcessor": (SelfProcessor, "self_identify_processor"), "RelationshipProcessor": (RelationshipProcessor, "relation_processor"), + "ExpressionSelectorProcessor": (ExpressionSelectorProcessor, "expression_selector_processor"), } logger = get_logger("hfc") # Logger Name Changed @@ -189,6 +191,7 @@ class HeartFChatting: "WorkingMemoryProcessor", "SelfProcessor", "RelationshipProcessor", + "ExpressionSelectorProcessor", ]: self.processors.append(processor_actual_class(subheartflow_id=self.stream_id)) elif name == "ChattingInfoProcessor": diff --git a/src/chat/focus_chat/info/expression_selection_info.py b/src/chat/focus_chat/info/expression_selection_info.py new file mode 100644 index 000000000..9cdd6121d --- /dev/null +++ b/src/chat/focus_chat/info/expression_selection_info.py @@ -0,0 +1,71 @@ +from dataclasses import dataclass +from typing import List, Dict, Any +from .info_base import InfoBase + + +@dataclass +class ExpressionSelectionInfo(InfoBase): + """表达选择信息类 + + 用于存储和管理选中的表达方式信息。 + + Attributes: + type (str): 信息类型标识符,默认为 "expression_selection" + data (Dict[str, Any]): 包含选中表达方式的数据字典 + """ + + type: str = "expression_selection" + + def get_selected_expressions(self) -> List[Dict[str, str]]: + """获取选中的表达方式列表 + + Returns: + List[Dict[str, str]]: 选中的表达方式列表 + """ + return self.get_info("selected_expressions") or [] + + def set_selected_expressions(self, expressions: List[Dict[str, str]]) -> None: + """设置选中的表达方式列表 + + Args: + expressions: 选中的表达方式列表 + """ + self.data["selected_expressions"] = expressions + + def get_expressions_count(self) -> int: + """获取选中表达方式的数量 + + Returns: + int: 表达方式数量 + """ + return len(self.get_selected_expressions()) + + def get_processed_info(self) -> str: + """获取处理后的信息 + + Returns: + str: 处理后的信息字符串 + """ + expressions = self.get_selected_expressions() + if not expressions: + return "" + + # 格式化表达方式为可读文本 + formatted_expressions = [] + for expr in expressions: + situation = expr.get("situation", "") + style = expr.get("style", "") + expr_type = expr.get("type", "") + + if situation and style: + formatted_expressions.append(f"当{situation}时,使用 {style}") + + return "\n".join(formatted_expressions) + + def get_expressions_for_action_data(self) -> List[Dict[str, str]]: + """获取用于action_data的表达方式数据 + + Returns: + List[Dict[str, str]]: 格式化后的表达方式数据 + """ + return self.get_selected_expressions() \ No newline at end of file diff --git a/src/chat/focus_chat/info_processors/expression_selector_processor.py b/src/chat/focus_chat/info_processors/expression_selector_processor.py new file mode 100644 index 000000000..5b6275861 --- /dev/null +++ b/src/chat/focus_chat/info_processors/expression_selector_processor.py @@ -0,0 +1,365 @@ +import time +import random +from typing import List, Dict +from src.chat.heart_flow.observation.chatting_observation import ChattingObservation +from src.chat.heart_flow.observation.observation import Observation +from src.llm_models.utils_model import LLMRequest +from src.config.config import global_config +from src.common.logger import get_logger +from src.chat.utils.prompt_builder import Prompt, global_prompt_manager +from src.chat.message_receive.chat_stream import get_chat_manager +from .base_processor import BaseProcessor +from src.chat.focus_chat.info.info_base import InfoBase +from src.chat.focus_chat.info.expression_selection_info import ExpressionSelectionInfo +from src.chat.focus_chat.expressors.exprssion_learner import get_expression_learner +from json_repair import repair_json +import json + +logger = get_logger("processor") + + +def weighted_sample_no_replacement(items, weights, k) -> list: + """ + 加权随机抽样,不允许重复 + + Args: + items: 待抽样的项目列表 + weights: 对应项目的权重列表 + k: 抽样数量 + + Returns: + 抽样结果列表 + """ + if not items or k <= 0: + return [] + + k = min(k, len(items)) + selected = [] + remaining_items = list(items) + remaining_weights = list(weights) + + for _ in range(k): + if not remaining_items: + break + + # 计算累积权重 + total_weight = sum(remaining_weights) + if total_weight <= 0: + # 如果权重都为0或负数,则随机选择 + selected_index = random.randint(0, len(remaining_items) - 1) + else: + # 加权随机选择 + rand_val = random.uniform(0, total_weight) + cumulative_weight = 0 + selected_index = 0 + for i, weight in enumerate(remaining_weights): + cumulative_weight += weight + if rand_val <= cumulative_weight: + selected_index = i + break + + # 添加选中的项目 + selected.append(remaining_items[selected_index]) + # 移除已选中的项目 + remaining_items.pop(selected_index) + remaining_weights.pop(selected_index) + + return selected + + +def init_prompt(): + expression_evaluation_prompt = """ +你的名字是{bot_name} + +以下是正在进行的聊天内容: +{chat_observe_info} + +以下是可选的表达情境: +{all_situations} + +请你分析聊天内容的语境、情绪、话题类型,从上述情境中选择最适合当前聊天情境的10个情境。 +考虑因素包括: +1. 聊天的情绪氛围(轻松、严肃、幽默等) +2. 话题类型(日常、技术、游戏、情感等) +3. 情境与当前语境的匹配度 + +请以JSON格式输出,只需要输出选中的情境编号: +{{ + "selected_situations": [1, 3, 5, 7, 9, 12, 15, 18, 21, 25] +}} + +请严格按照JSON格式输出,不要包含其他内容: +""" + Prompt(expression_evaluation_prompt, "expression_evaluation_prompt") + + +class ExpressionSelectorProcessor(BaseProcessor): + log_prefix = "表达选择器" + + def __init__(self, subheartflow_id: str): + super().__init__() + + self.subheartflow_id = subheartflow_id + self.last_selection_time = 0 + self.selection_interval = 60 # 1分钟间隔 + self.cached_expressions = [] # 缓存上一次选择的表达方式 + + # 表达方式选择模式 + self.selection_mode = getattr(global_config.expression, "selection_mode", "llm") # "llm" 或 "random" + + self.llm_model = LLMRequest( + model=global_config.model.utils_small, + request_type="focus.processor.expression_selector", + ) + + name = get_chat_manager().get_stream_name(self.subheartflow_id) + self.log_prefix = f"[{name}] 表达选择器" + + async def process_info(self, observations: List[Observation] = None, *infos) -> List[InfoBase]: + """处理信息对象 + + Args: + observations: 观察对象列表 + + Returns: + List[InfoBase]: 处理后的表达选择信息列表 + """ + current_time = time.time() + + # 检查频率限制 + if current_time - self.last_selection_time < self.selection_interval: + logger.debug(f"{self.log_prefix} 距离上次选择不足{self.selection_interval}秒,使用缓存的表达方式") + # 使用缓存的表达方式 + if self.cached_expressions: + # 从缓存的15个中随机选5个 + final_expressions = random.sample(self.cached_expressions, min(5, len(self.cached_expressions))) + + # 创建表达选择信息 + expression_info = ExpressionSelectionInfo() + expression_info.set_selected_expressions(final_expressions) + + logger.info(f"{self.log_prefix} 使用缓存选择了{len(final_expressions)}个表达方式") + return [expression_info] + else: + logger.debug(f"{self.log_prefix} 没有缓存的表达方式,跳过选择") + return [] + + # 获取聊天内容 + chat_info = "" + if observations: + for observation in observations: + if isinstance(observation, ChattingObservation): + chat_info = observation.get_observe_info() + break + + if not chat_info: + logger.debug(f"{self.log_prefix} 没有聊天内容,跳过表达方式选择") + return [] + + try: + # 根据模式选择表达方式 + if self.selection_mode == "llm": + # LLM模式:调用LLM选择15个,然后随机选5个 + selected_expressions = await self._select_suitable_expressions_llm(chat_info) + cache_size = len(selected_expressions) if selected_expressions else 0 + mode_desc = f"LLM模式(已缓存{cache_size}个)" + else: + # 随机模式:直接随机选择5个 + selected_expressions = await self._select_suitable_expressions_random(chat_info) + cache_size = len(selected_expressions) if selected_expressions else 0 + mode_desc = f"随机模式(已缓存{cache_size}个)" + + if selected_expressions: + # 缓存选择的表达方式 + self.cached_expressions = selected_expressions + # 更新最后选择时间 + self.last_selection_time = current_time + + # 从选择的表达方式中随机选5个 + final_expressions = random.sample(selected_expressions, min(4, len(selected_expressions))) + + # 创建表达选择信息 + expression_info = ExpressionSelectionInfo() + expression_info.set_selected_expressions(final_expressions) + + logger.info(f"{self.log_prefix} 为当前聊天选择了{len(final_expressions)}个表达方式({mode_desc})") + return [expression_info] + else: + logger.debug(f"{self.log_prefix} 未选择任何表达方式") + return [] + + except Exception as e: + logger.error(f"{self.log_prefix} 处理表达方式选择时出错: {e}") + return [] + + async def _get_random_expressions(self) -> tuple[List[Dict], List[Dict], List[Dict]]: + """随机获取表达方式:20个style,20个grammar,20个personality""" + expression_learner = get_expression_learner() + + # 获取所有表达方式 + ( + learnt_style_expressions, + learnt_grammar_expressions, + personality_expressions, + ) = await expression_learner.get_expression_by_chat_id(self.subheartflow_id) + + # 随机选择 + selected_style = random.sample(learnt_style_expressions, min(15, len(learnt_style_expressions))) + selected_grammar = random.sample(learnt_grammar_expressions, min(15, len(learnt_grammar_expressions))) + selected_personality = random.sample(personality_expressions, min(5, len(personality_expressions))) + + return selected_style, selected_grammar, selected_personality + + async def _select_suitable_expressions_llm(self, chat_info: str) -> List[Dict[str, str]]: + """使用LLM选择适合的表达方式""" + + # 1. 获取35个随机表达方式 + style_exprs, grammar_exprs, personality_exprs = await self._get_random_expressions() + + # 2. 构建所有表达方式的索引和情境列表 + all_expressions = [] + all_situations = [] + + # 添加style表达方式 + for expr in style_exprs: + if isinstance(expr, dict) and "situation" in expr and "style" in expr: + expr_with_type = expr.copy() + expr_with_type["type"] = "style" + all_expressions.append(expr_with_type) + all_situations.append(f"{len(all_expressions)}. [语言风格] {expr['situation']}") + + # 添加grammar表达方式 + for expr in grammar_exprs: + if isinstance(expr, dict) and "situation" in expr and "style" in expr: + expr_with_type = expr.copy() + expr_with_type["type"] = "grammar" + all_expressions.append(expr_with_type) + all_situations.append(f"{len(all_expressions)}. [句法语法] {expr['situation']}") + + # 添加personality表达方式 + for expr in personality_exprs: + if isinstance(expr, dict) and "situation" in expr and "style" in expr: + expr_with_type = expr.copy() + expr_with_type["type"] = "personality" + all_expressions.append(expr_with_type) + all_situations.append(f"{len(all_expressions)}. [个性表达] {expr['situation']}") + + if not all_expressions: + logger.warning(f"{self.log_prefix} 没有找到可用的表达方式") + return [] + + all_situations_str = "\n".join(all_situations) + + # 3. 构建prompt(只包含情境,不包含完整的表达方式) + prompt = (await global_prompt_manager.get_prompt_async("expression_evaluation_prompt")).format( + bot_name=global_config.bot.nickname, + chat_observe_info=chat_info, + all_situations=all_situations_str, + ) + + # 4. 调用LLM + try: + content, _ = await self.llm_model.generate_response_async(prompt=prompt) + + logger.info(f"{self.log_prefix} LLM返回结果: {content}") + + if not content: + logger.warning(f"{self.log_prefix} LLM返回空结果") + return [] + + # 5. 解析结果 + result = repair_json(content) + if isinstance(result, str): + result = json.loads(result) + + if not isinstance(result, dict) or "selected_situations" not in result: + logger.error(f"{self.log_prefix} LLM返回格式错误") + return [] + + selected_indices = result["selected_situations"] + + # 根据索引获取完整的表达方式 + valid_expressions = [] + for idx in selected_indices: + if isinstance(idx, int) and 1 <= idx <= len(all_expressions): + valid_expressions.append(all_expressions[idx - 1]) # 索引从1开始 + + logger.info(f"{self.log_prefix} LLM从{len(all_expressions)}个情境中选择了{len(valid_expressions)}个") + return valid_expressions + + except Exception as e: + logger.error(f"{self.log_prefix} LLM处理表达方式选择时出错: {e}") + return [] + + async def _select_suitable_expressions_random(self, chat_info: str) -> List[Dict[str, str]]: + """随机选择表达方式(原replyer逻辑)""" + + # 获取所有表达方式 + expression_learner = get_expression_learner() + ( + learnt_style_expressions, + learnt_grammar_expressions, + personality_expressions, + ) = await expression_learner.get_expression_by_chat_id(self.subheartflow_id) + + selected_expressions = [] + + # 1. learnt_style_expressions相似度匹配选择3条 + if learnt_style_expressions: + similar_exprs = self._find_similar_expressions(chat_info, learnt_style_expressions, 3) + for expr in similar_exprs: + if isinstance(expr, dict) and "situation" in expr and "style" in expr: + expr_copy = expr.copy() + expr_copy["type"] = "style" + selected_expressions.append(expr_copy) + + # 2. learnt_grammar_expressions加权随机选2条 + if learnt_grammar_expressions: + weights = [expr.get("count", 1) for expr in learnt_grammar_expressions] + selected_learnt = weighted_sample_no_replacement(learnt_grammar_expressions, weights, 2) + for expr in selected_learnt: + if isinstance(expr, dict) and "situation" in expr and "style" in expr: + expr_copy = expr.copy() + expr_copy["type"] = "grammar" + selected_expressions.append(expr_copy) + + # 3. personality_expressions随机选1条 + if personality_expressions: + expr = random.choice(personality_expressions) + if isinstance(expr, dict) and "situation" in expr and "style" in expr: + expr_copy = expr.copy() + expr_copy["type"] = "personality" + selected_expressions.append(expr_copy) + + logger.info(f"{self.log_prefix} 随机模式选择了{len(selected_expressions)}个表达方式") + return selected_expressions + + def _find_similar_expressions(self, input_text: str, expressions: List[Dict], top_k: int = 3) -> List[Dict]: + """使用简单的文本匹配找出相似的表达方式(简化版,避免依赖sklearn)""" + if not expressions or not input_text: + return random.sample(expressions, min(top_k, len(expressions))) if expressions else [] + + # 简单的关键词匹配 + scored_expressions = [] + input_words = set(input_text.lower().split()) + + for expr in expressions: + situation = expr.get("situation", "").lower() + situation_words = set(situation.split()) + + # 计算交集大小作为相似度 + similarity = len(input_words & situation_words) + scored_expressions.append((similarity, expr)) + + # 按相似度排序 + scored_expressions.sort(key=lambda x: x[0], reverse=True) + + # 如果没有匹配的,随机选择 + if all(score == 0 for score, _ in scored_expressions): + return random.sample(expressions, min(top_k, len(expressions))) + + # 返回top_k个最相似的 + return [expr for _, expr in scored_expressions[:top_k]] + + +init_prompt() \ No newline at end of file diff --git a/src/chat/focus_chat/planners/planner_simple.py b/src/chat/focus_chat/planners/planner_simple.py index c5b4be80e..8fe2dd209 100644 --- a/src/chat/focus_chat/planners/planner_simple.py +++ b/src/chat/focus_chat/planners/planner_simple.py @@ -11,6 +11,7 @@ from src.chat.focus_chat.info.action_info import ActionInfo from src.chat.focus_chat.info.structured_info import StructuredInfo from src.chat.focus_chat.info.self_info import SelfInfo from src.chat.focus_chat.info.relation_info import RelationInfo +from src.chat.focus_chat.info.expression_selection_info import ExpressionSelectionInfo from src.common.logger import get_logger from src.chat.utils.prompt_builder import Prompt, global_prompt_manager from src.individuality.individuality import get_individuality @@ -122,6 +123,7 @@ class ActionPlanner(BasePlanner): chat_type = "group" is_group_chat = True relation_info = "" + selected_expressions = [] for info in all_plan_info: if isinstance(info, ObsInfo): observed_messages = info.get_talking_message() @@ -136,6 +138,8 @@ class ActionPlanner(BasePlanner): relation_info = info.get_processed_info() elif isinstance(info, StructuredInfo): structured_info = info.get_processed_info() + elif isinstance(info, ExpressionSelectionInfo): + selected_expressions = info.get_expressions_for_action_data() else: extra_info.append(info.get_processed_info()) # elif not isinstance(info, ActionInfo): # 跳过已处理的ActionInfo @@ -237,6 +241,11 @@ class ActionPlanner(BasePlanner): if relation_info: action_data["relation_info_block"] = relation_info + + # 将选中的表达方式传递给action_data + if selected_expressions: + action_data["selected_expressions"] = selected_expressions + logger.debug(f"{self.log_prefix} 传递{len(selected_expressions)}个选中的表达方式到action_data") # 对于reply动作不需要额外处理,因为相关字段已经在上面的循环中添加到action_data diff --git a/src/chat/focus_chat/replyer/default_replyer.py b/src/chat/focus_chat/replyer/default_replyer.py index cf3368799..c8d05ec41 100644 --- a/src/chat/focus_chat/replyer/default_replyer.py +++ b/src/chat/focus_chat/replyer/default_replyer.py @@ -268,6 +268,7 @@ class DefaultReplyer: sender_name=sender, # Pass determined name target_message=targer, config_expression_style=global_config.expression.expression_style, + action_data=action_data, # 传递action_data ) # 4. 调用 LLM 生成回复 @@ -324,6 +325,7 @@ class DefaultReplyer: identity, target_message, config_expression_style, + action_data=None, # stuation, ) -> str: is_group_chat = bool(chat_stream.group_info) @@ -343,35 +345,24 @@ class DefaultReplyer: show_actions=True, ) - expression_learner = get_expression_learner() - ( - learnt_style_expressions, - learnt_grammar_expressions, - personality_expressions, - ) = await expression_learner.get_expression_by_chat_id(chat_stream.stream_id) - style_habbits = [] grammar_habbits = [] - # 1. learnt_expressions加权随机选3条 - if learnt_style_expressions: - # 使用相似度匹配选择最相似的表达 - similar_exprs = find_similar_expressions(target_message, learnt_style_expressions, 3) - for expr in similar_exprs: - # print(f"expr: {expr}") + + # 使用从处理器传来的选中表达方式 + selected_expressions = action_data.get("selected_expressions", []) if action_data else [] + + if selected_expressions: + logger.info(f"{self.log_prefix} 使用处理器选中的{len(selected_expressions)}个表达方式") + for expr in selected_expressions: if isinstance(expr, dict) and "situation" in expr and "style" in expr: - style_habbits.append(f"当{expr['situation']}时,使用 {expr['style']}") - # 2. learnt_grammar_expressions加权随机选2条 - if learnt_grammar_expressions: - weights = [expr["count"] for expr in learnt_grammar_expressions] - selected_learnt = weighted_sample_no_replacement(learnt_grammar_expressions, weights, 2) - for expr in selected_learnt: - if isinstance(expr, dict) and "situation" in expr and "style" in expr: - grammar_habbits.append(f"当{expr['situation']}时,使用 {expr['style']}") - # 3. personality_expressions随机选1条 - if personality_expressions: - expr = random.choice(personality_expressions) - if isinstance(expr, dict) and "situation" in expr and "style" in expr: - style_habbits.append(f"当{expr['situation']}时,使用 {expr['style']}") + expr_type = expr.get("type", "style") + if expr_type == "grammar": + grammar_habbits.append(f"当{expr['situation']}时,使用 {expr['style']}") + else: + style_habbits.append(f"当{expr['situation']}时,使用 {expr['style']}") + else: + logger.debug(f"{self.log_prefix} 没有从处理器获得表达方式,将使用空的表达方式") + # 不再在replyer中进行随机选择,全部交给处理器处理 style_habbits_str = "\n".join(style_habbits) grammar_habbits_str = "\n".join(grammar_habbits) diff --git a/src/chat/normal_chat/normal_chat.py b/src/chat/normal_chat/normal_chat.py index 76ee974aa..57cd32039 100644 --- a/src/chat/normal_chat/normal_chat.py +++ b/src/chat/normal_chat/normal_chat.py @@ -807,7 +807,7 @@ class NormalChat: time_elapsed = current_time - stats["first_time"] total_messages = self._get_total_messages_in_timerange(stats["first_time"], stats["last_time"]) - print(f"person_id: {person_id}, total_messages: {total_messages}, time_elapsed: {time_elapsed}") + # print(f"person_id: {person_id}, total_messages: {total_messages}, time_elapsed: {time_elapsed}") # 检查是否满足关系构建条件 should_build_relation = ( diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 56913e2b5..3d751bf37 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -182,6 +182,9 @@ class FocusChatProcessorConfig(ConfigBase): working_memory_processor: bool = True """是否启用工作记忆处理器""" + expression_selector_processor: bool = True + """是否启用表达方式选择处理器""" + @dataclass class ExpressionConfig(ConfigBase): @@ -196,6 +199,9 @@ class ExpressionConfig(ConfigBase): enable_expression_learning: bool = True """是否启用表达学习""" + selection_mode: str = "llm" + """表达方式选择模式:'llm' 使用LLM智能选择,'random' 使用传统随机选择""" + @dataclass class EmojiConfig(ConfigBase): diff --git a/src/person_info/relationship_manager.py b/src/person_info/relationship_manager.py index 5f5628c18..a4e26a4e2 100644 --- a/src/person_info/relationship_manager.py +++ b/src/person_info/relationship_manager.py @@ -546,7 +546,7 @@ class RelationshipManager: days_diff = hours_diff / 24 - 7 return max(0.1, 0.95 - days_diff * (0.85 / 23)) except Exception as e: - self.logger.error(f"计算时间权重失败: {e}") + logger.error(f"计算时间权重失败: {e}") return 0.5 # 发生错误时返回中等权重 def tfidf_similarity(self, s1, s2): diff --git a/template/bot_config_template.toml b/template/bot_config_template.toml index d772a6b9f..5ecd225ec 100644 --- a/template/bot_config_template.toml +++ b/template/bot_config_template.toml @@ -1,5 +1,5 @@ [inner] -version = "2.22.0" +version = "2.23.0" #----以下是给开发人员阅读的,如果你只是部署了麦麦,不需要阅读---- #如果你想要修改配置文件,请在修改后将version的值进行变更 @@ -43,6 +43,7 @@ identity_detail = [ expression_style = "描述麦麦说话的表达风格,表达习惯,例如:(回复尽量简短一些。可以参考贴吧,知乎和微博的回复风格,回复不要浮夸,不要用夸张修辞,平淡一些。不要有额外的符号,尽量简单简短)" enable_expression_learning = false # 是否启用表达学习,麦麦会学习不同群里人类说话风格(群之间不互通) learning_interval = 600 # 学习间隔 单位秒 +selection_mode = "llm" # 专注模式下 表达方式选择模式:'llm' 使用LLM智能选择,'random' 使用传统随机选择 [relationship] enable_relationship = true # 是否启用关系系统