From e93192bbbb054c9344f9a7bc52d3954e54bfc0b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 28 Apr 2025 02:36:06 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20=E8=87=AA=E5=8A=A8=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E4=BB=A3=E7=A0=81=20[skip=20ci]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/PFC/action_planner.py | 25 ++++--- src/plugins/PFC/conversation.py | 104 ++++++++++++++------------- src/plugins/PFC/conversation_info.py | 2 + src/plugins/PFC/reply_generator.py | 17 +++-- 4 files changed, 78 insertions(+), 70 deletions(-) diff --git a/src/plugins/PFC/action_planner.py b/src/plugins/PFC/action_planner.py index 154b9328f..fcf0cff68 100644 --- a/src/plugins/PFC/action_planner.py +++ b/src/plugins/PFC/action_planner.py @@ -1,5 +1,5 @@ import time -from typing import Tuple, Optional # 增加了 Optional +from typing import Tuple, Optional # 增加了 Optional from src.common.logger_manager import get_logger from ..models.utils_model import LLMRequest from ...config.config import global_config @@ -100,7 +100,12 @@ class ActionPlanner: # self.action_planner_info = ActionPlannerInfo() # 移除未使用的变量 # 修改 plan 方法签名,增加 last_successful_reply_action 参数 - async def plan(self, observation_info: ObservationInfo, conversation_info: ConversationInfo, last_successful_reply_action: Optional[str]) -> Tuple[str, str]: + async def plan( + self, + observation_info: ObservationInfo, + conversation_info: ConversationInfo, + last_successful_reply_action: Optional[str], + ) -> Tuple[str, str]: """规划下一步行动 Args: @@ -138,7 +143,6 @@ class ActionPlanner: except Exception as e: logger.warning(f"获取 Bot 上次发言时间时出错: {e}") - # --- 获取超时提示信息 --- # (这部分逻辑不变) timeout_context = "" @@ -240,7 +244,6 @@ class ActionPlanner: identity_addon = f"并且{cleaned_details}" persona_text = f"你的名字是{self.name},{self.personality_info}{identity_addon}。" - # 构建行动历史和上一次行动结果 (action_history_summary, last_action_context) # (这部分逻辑不变) action_history_summary = "你最近执行的行动历史:\n" @@ -278,13 +281,13 @@ class ActionPlanner: if len(action_data) > 0: action_type = action_data[0] if len(action_data) > 1: - plan_reason = action_data[1] # 可能是规划原因或最终原因 + plan_reason = action_data[1] # 可能是规划原因或最终原因 if len(action_data) > 2: status = action_data[2] if status == "recall" and len(action_data) > 3: final_reason = action_data[3] elif status == "done" and action_type in ["direct_reply", "send_new_message"]: - plan_reason = "成功发送" # 简化显示 + plan_reason = "成功发送" # 简化显示 reason_text = f", 失败/取消原因: {final_reason}" if final_reason else "" summary_line = f"- 时间:{action_time}, 尝试行动:'{action_type}', 状态:{status}{reason_text}" @@ -309,7 +312,7 @@ class ActionPlanner: # self.last_successful_action_type = None # 非完成状态,清除记录 # --- 选择 Prompt --- - if last_successful_reply_action in ['direct_reply', 'send_new_message']: + if last_successful_reply_action in ["direct_reply", "send_new_message"]: prompt_template = PROMPT_FOLLOW_UP logger.debug("使用 PROMPT_FOLLOW_UP (追问决策)") else: @@ -324,7 +327,7 @@ class ActionPlanner: last_action_context=last_action_context, time_since_last_bot_message_info=time_since_last_bot_message_info, timeout_context=timeout_context, - chat_history_text=chat_history_text if chat_history_text.strip() else "还没有聊天记录。" + chat_history_text=chat_history_text if chat_history_text.strip() else "还没有聊天记录。", ) logger.debug(f"发送到LLM的最终提示词:\n------\n{prompt}\n------") @@ -346,13 +349,13 @@ class ActionPlanner: # 更新 valid_actions 列表以包含 send_new_message valid_actions = [ "direct_reply", - "send_new_message", # 添加新动作 + "send_new_message", # 添加新动作 "fetch_knowledge", "wait", "listening", "rethink_goal", "end_conversation", - "block_and_ignore" + "block_and_ignore", ] if action not in valid_actions: logger.warning(f"LLM返回了未知的行动类型: '{action}',强制改为 wait") @@ -365,4 +368,4 @@ class ActionPlanner: except Exception as e: logger.error(f"规划行动时调用 LLM 或处理结果出错: {str(e)}") - return "wait", f"行动规划处理中发生错误,暂时等待: {str(e)}" \ No newline at end of file + return "wait", f"行动规划处理中发生错误,暂时等待: {str(e)}" diff --git a/src/plugins/PFC/conversation.py b/src/plugins/PFC/conversation.py index f9c8d40c2..6afc57c31 100644 --- a/src/plugins/PFC/conversation.py +++ b/src/plugins/PFC/conversation.py @@ -13,7 +13,7 @@ from .pfc import ChatObserver, GoalAnalyzer, DirectMessageSender from src.common.logger_manager import get_logger from .action_planner import ActionPlanner from .observation_info import ObservationInfo -from .conversation_info import ConversationInfo # 确保导入 ConversationInfo +from .conversation_info import ConversationInfo # 确保导入 ConversationInfo from .reply_generator import ReplyGenerator from ..chat.chat_stream import ChatStream from maim_message import UserInfo @@ -153,9 +153,7 @@ class Conversation: # --- 调用 Action Planner --- # 传递 self.conversation_info.last_successful_reply_action action, reason = await self.action_planner.plan( - self.observation_info, - self.conversation_info, - self.conversation_info.last_successful_reply_action + self.observation_info, self.conversation_info, self.conversation_info.last_successful_reply_action ) # --- 规划后检查是否有 *更多* 新消息到达 --- @@ -184,7 +182,6 @@ class Conversation: else: logger.error("无法清理未处理消息: ObservationInfo 缺少 clear_unprocessed_messages 方法!") - await self._handle_action(action, reason, self.observation_info, self.conversation_info) # 检查是否需要结束对话 (逻辑不变) @@ -205,7 +202,6 @@ class Conversation: self.should_continue = False logger.info("检测到'结束对话'目标,停止循环。") - except Exception as loop_err: logger.error(f"PFC主循环出错: {loop_err}") logger.error(traceback.format_exc()) @@ -219,14 +215,16 @@ class Conversation: def _check_new_messages_after_planning(self): """检查在规划后是否有新消息""" # 检查 ObservationInfo 是否已初始化并且有 new_messages_count 属性 - if not hasattr(self, 'observation_info') or not hasattr(self.observation_info, 'new_messages_count'): + if not hasattr(self, "observation_info") or not hasattr(self.observation_info, "new_messages_count"): logger.warning("ObservationInfo 未初始化或缺少 'new_messages_count' 属性,无法检查新消息。") - return False # 或者根据需要抛出错误 + return False # 或者根据需要抛出错误 if self.observation_info.new_messages_count > 2: - logger.info(f"生成/执行动作期间收到 {self.observation_info.new_messages_count} 条新消息,取消当前动作并重新规划") + logger.info( + f"生成/执行动作期间收到 {self.observation_info.new_messages_count} 条新消息,取消当前动作并重新规划" + ) # 如果有新消息,也应该重置上次回复状态 - if hasattr(self, 'conversation_info'): # 确保 conversation_info 已初始化 + if hasattr(self, "conversation_info"): # 确保 conversation_info 已初始化 self.conversation_info.last_successful_reply_action = None else: logger.warning("ConversationInfo 未初始化,无法重置 last_successful_reply_action。") @@ -240,9 +238,9 @@ class Conversation: chat_info = msg_dict.get("chat_info") if chat_info and isinstance(chat_info, dict): chat_stream = ChatStream.from_dict(chat_info) - elif self.chat_stream: # 使用实例变量中的 chat_stream + elif self.chat_stream: # 使用实例变量中的 chat_stream chat_stream = self.chat_stream - else: # Fallback: 尝试从 manager 获取 (可能需要 stream_id) + else: # Fallback: 尝试从 manager 获取 (可能需要 stream_id) chat_stream = chat_manager.get_stream(self.stream_id) if not chat_stream: raise ValueError(f"无法确定 ChatStream for stream_id {self.stream_id}") @@ -250,9 +248,9 @@ class Conversation: user_info = UserInfo.from_dict(msg_dict.get("user_info", {})) return Message( - message_id=msg_dict.get("message_id", f"gen_{time.time()}"), # 提供默认 ID - chat_stream=chat_stream, # 使用确定的 chat_stream - time=msg_dict.get("time", time.time()), # 提供默认时间 + message_id=msg_dict.get("message_id", f"gen_{time.time()}"), # 提供默认 ID + chat_stream=chat_stream, # 使用确定的 chat_stream + time=msg_dict.get("time", time.time()), # 提供默认时间 user_info=user_info, processed_plain_text=msg_dict.get("processed_plain_text", ""), detailed_plain_text=msg_dict.get("detailed_plain_text", ""), @@ -278,12 +276,12 @@ class Conversation: "final_reason": None, } # 确保 done_action 列表存在 - if not hasattr(conversation_info, 'done_action'): + if not hasattr(conversation_info, "done_action"): conversation_info.done_action = [] conversation_info.done_action.append(current_action_record) action_index = len(conversation_info.done_action) - 1 - action_successful = False # 用于标记动作是否成功完成 + action_successful = False # 用于标记动作是否成功完成 # --- 根据不同的 action 执行 --- @@ -302,7 +300,9 @@ class Conversation: self.state = ConversationState.GENERATING # 1. 生成回复 (调用 generate 时传入 action_type) - self.generated_reply = await self.reply_generator.generate(observation_info, conversation_info, action_type='send_new_message') + self.generated_reply = await self.reply_generator.generate( + observation_info, conversation_info, action_type="send_new_message" + ) logger.info(f"第 {reply_attempt_count} 次生成的追问回复: {self.generated_reply}") # 2. 检查回复 (逻辑不变) @@ -323,7 +323,9 @@ class Conversation: final_reply_to_send = self.generated_reply break elif need_replan: - logger.warning(f"第 {reply_attempt_count} 次追问检查建议重新规划,停止尝试。原因: {check_reason}") + logger.warning( + f"第 {reply_attempt_count} 次追问检查建议重新规划,停止尝试。原因: {check_reason}" + ) break except Exception as check_err: logger.error(f"第 {reply_attempt_count} 次调用 ReplyChecker (追问) 时出错: {check_err}") @@ -338,16 +340,16 @@ class Conversation: conversation_info.done_action[action_index].update( {"status": "recall", "final_reason": f"有新消息,取消发送追问: {final_reply_to_send}"} ) - return # 直接返回,重新规划 + return # 直接返回,重新规划 # 发送合适的回复 self.generated_reply = final_reply_to_send # --- 在这里调用 _send_reply --- - await self._send_reply() # <--- 调用恢复后的函数 + await self._send_reply() # <--- 调用恢复后的函数 # 更新状态: 标记上次成功是 send_new_message - self.conversation_info.last_successful_reply_action = 'send_new_message' - action_successful = True # 标记动作成功 + self.conversation_info.last_successful_reply_action = "send_new_message" + action_successful = True # 标记动作成功 else: # 追问失败 @@ -371,7 +373,6 @@ class Conversation: } conversation_info.done_action.append(wait_action_record) - elif action == "direct_reply": max_reply_attempts = 3 reply_attempt_count = 0 @@ -386,7 +387,9 @@ class Conversation: self.state = ConversationState.GENERATING # 1. 生成回复 - self.generated_reply = await self.reply_generator.generate(observation_info, conversation_info, action_type='direct_reply') + self.generated_reply = await self.reply_generator.generate( + observation_info, conversation_info, action_type="direct_reply" + ) logger.info(f"第 {reply_attempt_count} 次生成的首次回复: {self.generated_reply}") # 2. 检查回复 @@ -407,7 +410,9 @@ class Conversation: final_reply_to_send = self.generated_reply break elif need_replan: - logger.warning(f"第 {reply_attempt_count} 次首次回复检查建议重新规划,停止尝试。原因: {check_reason}") + logger.warning( + f"第 {reply_attempt_count} 次首次回复检查建议重新规划,停止尝试。原因: {check_reason}" + ) break except Exception as check_err: logger.error(f"第 {reply_attempt_count} 次调用 ReplyChecker (首次回复) 时出错: {check_err}") @@ -422,16 +427,16 @@ class Conversation: conversation_info.done_action[action_index].update( {"status": "recall", "final_reason": f"有新消息,取消发送首次回复: {final_reply_to_send}"} ) - return # 直接返回,重新规划 + return # 直接返回,重新规划 # 发送合适的回复 self.generated_reply = final_reply_to_send # --- 在这里调用 _send_reply --- - await self._send_reply() # <--- 调用恢复后的函数 + await self._send_reply() # <--- 调用恢复后的函数 # 更新状态: 标记上次成功是 direct_reply - self.conversation_info.last_successful_reply_action = 'direct_reply' - action_successful = True # 标记动作成功 + self.conversation_info.last_successful_reply_action = "direct_reply" + action_successful = True # 标记动作成功 else: # 首次回复失败 @@ -460,7 +465,7 @@ class Conversation: knowledge_query = reason try: # 检查 knowledge_fetcher 是否存在 - if not hasattr(self, 'knowledge_fetcher'): + if not hasattr(self, "knowledge_fetcher"): logger.error("KnowledgeFetcher 未初始化,无法获取知识。") raise AttributeError("KnowledgeFetcher not initialized") @@ -468,23 +473,24 @@ class Conversation: logger.info(f"获取到知识: {knowledge[:100]}..., 来源: {source}") if knowledge: # 确保 knowledge_list 存在 - if not hasattr(conversation_info, 'knowledge_list'): + if not hasattr(conversation_info, "knowledge_list"): conversation_info.knowledge_list = [] - conversation_info.knowledge_list.append({"query": knowledge_query, "knowledge": knowledge, "source": source}) + conversation_info.knowledge_list.append( + {"query": knowledge_query, "knowledge": knowledge, "source": source} + ) action_successful = True except Exception as fetch_err: logger.error(f"获取知识时出错: {fetch_err}") conversation_info.done_action[action_index].update( {"status": "recall", "final_reason": f"获取知识失败: {fetch_err}"} ) - self.conversation_info.last_successful_reply_action = None # 重置状态 - + self.conversation_info.last_successful_reply_action = None # 重置状态 elif action == "rethink_goal": self.state = ConversationState.RETHINKING try: # 检查 goal_analyzer 是否存在 - if not hasattr(self, 'goal_analyzer'): + if not hasattr(self, "goal_analyzer"): logger.error("GoalAnalyzer 未初始化,无法重新思考目标。") raise AttributeError("GoalAnalyzer not initialized") await self.goal_analyzer.analyze_goal(conversation_info, observation_info) @@ -494,31 +500,29 @@ class Conversation: conversation_info.done_action[action_index].update( {"status": "recall", "final_reason": f"重新思考目标失败: {rethink_err}"} ) - self.conversation_info.last_successful_reply_action = None # 重置状态 - + self.conversation_info.last_successful_reply_action = None # 重置状态 elif action == "listening": self.state = ConversationState.LISTENING logger.info("倾听对方发言...") try: # 检查 waiter 是否存在 - if not hasattr(self, 'waiter'): + if not hasattr(self, "waiter"): logger.error("Waiter 未初始化,无法倾听。") raise AttributeError("Waiter not initialized") await self.waiter.wait_listening(conversation_info) - action_successful = True # Listening 完成就算成功 + action_successful = True # Listening 完成就算成功 except Exception as listen_err: logger.error(f"倾听时出错: {listen_err}") conversation_info.done_action[action_index].update( {"status": "recall", "final_reason": f"倾听失败: {listen_err}"} ) - self.conversation_info.last_successful_reply_action = None # 重置状态 - + self.conversation_info.last_successful_reply_action = None # 重置状态 elif action == "end_conversation": self.should_continue = False logger.info("决定结束对话...") - action_successful = True # 标记动作成功 + action_successful = True # 标记动作成功 elif action == "block_and_ignore": logger.info("不想再理你了...") @@ -526,24 +530,24 @@ class Conversation: self.ignore_until_timestamp = time.time() + ignore_duration_seconds logger.info(f"将忽略此对话直到: {datetime.datetime.fromtimestamp(self.ignore_until_timestamp)}") self.state = ConversationState.IGNORED - action_successful = True # 标记动作成功 + action_successful = True # 标记动作成功 else: # 对应 'wait' 动作 self.state = ConversationState.WAITING logger.info("等待更多信息...") try: # 检查 waiter 是否存在 - if not hasattr(self, 'waiter'): + if not hasattr(self, "waiter"): logger.error("Waiter 未初始化,无法等待。") raise AttributeError("Waiter not initialized") _timeout_occurred = await self.waiter.wait(self.conversation_info) - action_successful = True # Wait 完成就算成功 + action_successful = True # Wait 完成就算成功 except Exception as wait_err: logger.error(f"等待时出错: {wait_err}") conversation_info.done_action[action_index].update( {"status": "recall", "final_reason": f"等待失败: {wait_err}"} ) - self.conversation_info.last_successful_reply_action = None # 重置状态 + self.conversation_info.last_successful_reply_action = None # 重置状态 # --- 更新 Action History 状态 --- # 只有当动作本身成功时,才更新状态为 done @@ -555,7 +559,7 @@ class Conversation: } ) # 重置状态: 对于非回复类动作的成功,清除上次回复状态 - if action not in ['direct_reply', 'send_new_message']: + if action not in ["direct_reply", "send_new_message"]: self.conversation_info.last_successful_reply_action = None logger.debug(f"动作 {action} 成功完成,重置 last_successful_reply_action") # 如果动作是 recall 状态,在各自的处理逻辑中已经更新了 done_action @@ -571,7 +575,7 @@ class Conversation: reply_content = self.generated_reply # 发送消息 (确保 direct_sender 和 chat_stream 有效) - if not hasattr(self, 'direct_sender') or not self.direct_sender: + if not hasattr(self, "direct_sender") or not self.direct_sender: logger.error("DirectMessageSender 未初始化,无法发送回复。") return if not self.chat_stream: @@ -587,7 +591,7 @@ class Conversation: # if not await self.chat_observer.wait_for_update(): # logger.warning("等待 ChatObserver 更新完成超时") - self.state = ConversationState.ANALYZING # 更新状态 + self.state = ConversationState.ANALYZING # 更新状态 except Exception as e: logger.error(f"发送消息或更新状态时失败: {str(e)}") diff --git a/src/plugins/PFC/conversation_info.py b/src/plugins/PFC/conversation_info.py index c4350ed93..04524b697 100644 --- a/src/plugins/PFC/conversation_info.py +++ b/src/plugins/PFC/conversation_info.py @@ -1,4 +1,6 @@ from typing import Optional + + class ConversationInfo: def __init__(self): self.done_action = [] diff --git a/src/plugins/PFC/reply_generator.py b/src/plugins/PFC/reply_generator.py index 59e261ac5..020d57a49 100644 --- a/src/plugins/PFC/reply_generator.py +++ b/src/plugins/PFC/reply_generator.py @@ -75,7 +75,9 @@ class ReplyGenerator: self.reply_checker = ReplyChecker(stream_id) # 修改 generate 方法签名,增加 action_type 参数 - async def generate(self, observation_info: ObservationInfo, conversation_info: ConversationInfo, action_type: str) -> str: + async def generate( + self, observation_info: ObservationInfo, conversation_info: ConversationInfo, action_type: str + ) -> str: """生成回复 Args: @@ -109,7 +111,7 @@ class ReplyGenerator: reasoning = str(reasoning) if reasoning is not None else "没有明确原因" goals_str += f"- 目标:{goal}\n 原因:{reasoning}\n" else: - goals_str = "- 目前没有明确对话目标\n" # 简化无目标情况 + goals_str = "- 目前没有明确对话目标\n" # 简化无目标情况 # 获取聊天历史记录 (chat_history_text) chat_history_text = observation_info.chat_history_str @@ -126,7 +128,6 @@ class ReplyGenerator: elif not chat_history_text: chat_history_text = "还没有聊天记录。" - # 构建 Persona 文本 (persona_text) identity_details_only = self.identity_detail_info identity_addon = "" @@ -144,18 +145,16 @@ class ReplyGenerator: persona_text = f"你的名字是{self.name},{self.personality_info}{identity_addon}。" # --- 选择 Prompt --- - if action_type == 'send_new_message': + if action_type == "send_new_message": prompt_template = PROMPT_SEND_NEW_MESSAGE logger.info("使用 PROMPT_SEND_NEW_MESSAGE (追问生成)") - else: # 默认使用 direct_reply 的 prompt + else: # 默认使用 direct_reply 的 prompt prompt_template = PROMPT_DIRECT_REPLY logger.info("使用 PROMPT_DIRECT_REPLY (首次/非连续回复生成)") # --- 格式化最终的 Prompt --- prompt = prompt_template.format( - persona_text=persona_text, - goals_str=goals_str, - chat_history_text=chat_history_text + persona_text=persona_text, goals_str=goals_str, chat_history_text=chat_history_text ) # --- 调用 LLM 生成 --- @@ -177,4 +176,4 @@ class ReplyGenerator: """检查回复是否合适 (此方法逻辑保持不变) """ - return await self.reply_checker.check(reply, goal, chat_history, chat_history_str, retry_count) \ No newline at end of file + return await self.reply_checker.check(reply, goal, chat_history, chat_history_str, retry_count)