diff --git a/src/chat/planner_actions/action_modifier.py b/src/chat/planner_actions/action_modifier.py index df7ecdccb..e9cc1d106 100644 --- a/src/chat/planner_actions/action_modifier.py +++ b/src/chat/planner_actions/action_modifier.py @@ -205,9 +205,8 @@ class ActionModifier: elif activation_type == ActionActivationType.RANDOM: probability = action_info.random_activation_probability - if probability >= 1.0: - continue # 概率为100%或更高,直接激活 - if random.random() > probability: + probability = action_info.random_activation_probability + if random.random() >= probability: reason = f"RANDOM类型未触发(概率{probability})" deactivated_actions.append((action_name, reason)) logger.debug(f"{self.log_prefix}未激活动作: {action_name},原因: {reason}") diff --git a/src/chat/planner_actions/planner.py b/src/chat/planner_actions/planner.py index 526873b43..0ddbfcb73 100644 --- a/src/chat/planner_actions/planner.py +++ b/src/chat/planner_actions/planner.py @@ -57,30 +57,64 @@ def init_prompt(): {moderation_prompt} -现在请你根据聊天内容和用户的最新消息选择合适的action和触发action的消息: +**任务: 构建一个完整的响应** +你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成: +1. **主要动作**: 这是响应的核心,通常是 `reply`(文本回复)。 +2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。 + +**决策流程:** +1. 首先,决定是否要进行 `reply`。 +2. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格。 +3. 如果需要,选择一个最合适的辅助动作与 `reply` 组合。 +4. 如果用户明确要求了某个动作,请务必优先满足。 + +**可用动作:** {actions_before_now_block} {no_action_block} 动作:reply 动作描述:参与聊天回复,发送文本进行表达 -- 你想要闲聊或者随便附 +- 你想要闲聊或者随便附和 - {mentioned_bonus} - 如果你刚刚进行了回复,不要对同一个话题重复回应 - 不要回复自己发送的消息 {{ "action": "reply", - "target_message_id":"触发action的消息id", - "reason":"回复的原因" + "target_message_id": "触发action的消息id", + "reason": "回复的原因" }} {action_options_text} -- 如果用户明确要求使用某个动作,请优先选择该动作。 -- 当一个动作可以作为另一个动作的补充时,你应该同时选择它们。例如,在回复的同时可以发送表情包(emoji)。 -你必须从上面列出的可用action中选择一个或多个,并说明触发action的消息id(不是消息原文)和选择该action的原因。消息id格式:m+数字 -请根据动作示例,以严格的 JSON 格式输出,返回一个包含所有选定动作的JSON列表。如果只选择一个动作,也请将其包含在列表中。如果没有任何合适的动作,返回一个空列表[]。不要输出markdown格式```json等内容,直接输出且仅包含 JSON 列表内容: +**输出格式:** +你必须以严格的 JSON 格式输出,返回一个包含所有选定动作的JSON列表。如果没有任何合适的动作,返回一个空列表[]。 + +**单动作示例 (仅回复):** +[ + {{ + "action": "reply", + "target_message_id": "m123", + "reason": "回答用户的问题" + }} +] + +**组合动作示例 (回复 + 表情包):** +[ + {{ + "action": "reply", + "target_message_id": "m123", + "reason": "回答用户的问题" + }}, + {{ + "action": "emoji", + "target_message_id": "m123", + "reason": "用一个可爱的表情来缓和气氛" + }} +] + +不要输出markdown格式```json等内容,直接输出且仅包含 JSON 列表内容: """, "planner_prompt", ) @@ -148,9 +182,9 @@ def init_prompt(): 动作描述:{action_description} {action_require} {{ - "action": "{action_name}",{action_parameters}, - "target_message_id":"触发action的消息id", - "reason":"触发action的原因" + "action": "{action_name}", + "target_message_id": "触发action的消息id", + "reason": "触发action的原因"{action_parameters} }} """, "action_prompt", @@ -409,18 +443,18 @@ class ActionPlanner: # --- 3. 后处理 --- final_actions = self._filter_no_actions(final_actions) - # === 强制后处理:确保100%概率的动作在回复时被附带 === - has_reply_action = any(a.get("action_type") == "reply" for a in final_actions) - if has_reply_action: - for action_name, action_info in available_actions.items(): - if action_info.activation_type == ActionActivationType.RANDOM and action_info.random_activation_probability >= 1.0: - # 检查此动作是否已被选择 - is_already_chosen = any(a.get("action_type") == action_name for a in final_actions) - if not is_already_chosen: - logger.info(f"{self.log_prefix}强制添加100%概率动作: {action_name}") + # === 概率模式后处理:根据配置决定是否强制添加 emoji 动作 === + if global_config.emoji.emoji_activate_type == 'random': + has_reply_action = any(a.get("action_type") == "reply" for a in final_actions) + if has_reply_action: + # 检查此动作是否已被选择 + is_already_chosen = any(a.get("action_type") == 'emoji' for a in final_actions) + if not is_already_chosen: + if random.random() < global_config.emoji.emoji_chance: + logger.info(f"{self.log_prefix}根据概率 '{global_config.emoji.emoji_chance}' 添加 emoji 动作") final_actions.append({ - "action_type": action_name, - "reasoning": "根据100%概率设置强制添加", + "action_type": 'emoji', + "reasoning": f"根据概率 {global_config.emoji.emoji_chance} 自动添加", "action_data": {}, "action_message": self.get_latest_message(used_message_id_list), "available_actions": available_actions, diff --git a/src/plugins/built_in/core_actions/emoji.py b/src/plugins/built_in/core_actions/emoji.py index 0944591be..e040d9c37 100644 --- a/src/plugins/built_in/core_actions/emoji.py +++ b/src/plugins/built_in/core_actions/emoji.py @@ -148,9 +148,12 @@ class EmojiAction(BaseAction): chosen_emotion = chosen_emotion.strip().replace('"', "").replace("'", "") logger.info(f"{self.log_prefix} LLM选择的情感: {chosen_emotion}") - if chosen_emotion in emotion_map: - emoji_base64, emoji_description = random.choice(emotion_map[chosen_emotion]) - logger.info(f"{self.log_prefix} 找到匹配情感 '{chosen_emotion}' 的表情包: {emoji_description}") + # 使用模糊匹配来查找最相关的情感标签 + matched_key = next((key for key in emotion_map if chosen_emotion in key), None) + + if matched_key: + emoji_base64, emoji_description = random.choice(emotion_map[matched_key]) + logger.info(f"{self.log_prefix} 找到匹配情感 '{chosen_emotion}' (匹配到: '{matched_key}') 的表情包: {emoji_description}") else: logger.warning( f"{self.log_prefix} LLM选择的情感 '{chosen_emotion}' 不在可用列表中, 将随机选择一个表情包"