From 577e45484e838cf0036748c9407c9a5524c5c547 Mon Sep 17 00:00:00 2001 From: SengokuCola <1026294844@qq.com> Date: Sat, 26 Apr 2025 01:51:49 +0800 Subject: [PATCH] =?UTF-8?q?better=EF=BC=9A=E6=9B=B4=E5=A4=9A=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/heart_flow/README.md | 6 +- src/heart_flow/heartFC_chatting_logic.md | 124 +++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/heart_flow/heartFC_chatting_logic.md diff --git a/src/heart_flow/README.md b/src/heart_flow/README.md index db757c568..cf1cd5ac0 100644 --- a/src/heart_flow/README.md +++ b/src/heart_flow/README.md @@ -1,6 +1,10 @@ # 心流系统 (Heart Flow System) -*在此处简要介绍心流系统的目标和作用* +## 通俗易懂的工作流程介绍 + +心流系统就像一个智能聊天管家,它的工作方式可以这样理解: + +心流系统由主控中心(Heartflow)作为大脑协调全局,它通过场景管家(SubHeartflowManager)管理各个聊天场景的"小管家"(SubHeartflow)。当收到消息时,系统会先进行过滤和基础分析(如屏蔽词检查和兴趣度计算),然后将处理好的消息分发给对应场景的小管家。每个小管家会根据当前状态决定回复方式:不参与(ABSENT)时完全不看不回,普通模式(CHAT)进行简单回复,专注模式(FOCUSED)则深入交流。系统会根据聊天活跃度和兴趣度自动调整各场景的参与程度,同时主控中心也能手动调整整体参与度(如在离线、轻度参与和专注聊天之间切换)。整个系统就像一个拥有多个聊天助手的智能管家,能够智能地动态调整参与聊天的深度和范围。 ## 1. 系统架构 (System Architecture) diff --git a/src/heart_flow/heartFC_chatting_logic.md b/src/heart_flow/heartFC_chatting_logic.md new file mode 100644 index 000000000..67a13cc66 --- /dev/null +++ b/src/heart_flow/heartFC_chatting_logic.md @@ -0,0 +1,124 @@ +# 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`) 配置用于执行规划任务的大语言模型请求。 +- **状态变量**: + - `_initialized`: 标记是否完成懒初始化。 + - `_processing_lock`: 异步锁,确保同一时间只有一个完整的"思考-规划-执行"周期在运行。 + - `_loop_active`: 标记主循环是否正在运行。 + - `_loop_task`: 指向主循环的 `asyncio.Task` 对象。 + - `_cycle_history`: 一个双端队列 (`deque`),用于存储最近若干次循环的信息 (`CycleInfo`)。 + - `_current_cycle`: 当前正在执行的循环信息 (`CycleInfo`)。 +- **懒初始化 (`_initialize`)**: + - 在首次需要访问 `ChatStream` 前调用(通常在 `start` 方法中)。 + - 根据 `stream_id` 从 `chat_manager` 获取对应的 `ChatStream` 实例。 + - 更新日志前缀,使用聊天流的名称以提高可读性。 + +## 2. 生命周期管理 (`start`, `shutdown`) + +- **启动 (`start`)**: + - 外部调用此方法来启动 `HeartFChatting` 的工作流程。 + - 内部调用 `_start_loop_if_needed` 来安全地启动主循环任务 (`_hfc_loop`)。 +- **关闭 (`shutdown`)**: + - 外部调用此方法来优雅地停止 `HeartFChatting`。 + - 取消正在运行的主循环任务 (`_loop_task`)。 + - 清理内部状态(如 `_loop_active`, `_loop_task`)。 + - 释放可能被持有的处理锁 (`_processing_lock`)。 + +## 3. 核心循环 (`_hfc_loop`) + +`_hfc_loop` 是 `HeartFChatting` 的心脏,它以异步方式无限期运行(直到被 `shutdown` 取消),不断执行以下步骤: + +1. **创建循环记录**: 初始化一个新的 `CycleInfo` 对象来记录本次循环的详细信息(ID、开始时间、计时器、动作、思考内容等)。 +2. **获取处理锁**: 使用 `_processing_lock` 确保并发安全。 +3. **执行思考-规划-执行**: 调用 `_think_plan_execute_loop` 方法。 +4. **处理循环延迟**: 根据本次循环是否执行了实际动作以及循环耗时,智能地引入短暂的 `asyncio.sleep`,防止 CPU 空转或过于频繁的循环。 +5. **记录循环信息**: 将完成的 `CycleInfo` 存入 `_cycle_history`,并记录详细的日志,包括循环耗时和各阶段计时。 + +## 4. 思考-规划-执行周期 (`_think_plan_execute_loop`) + +这是每个循环内部的核心逻辑,按顺序执行: + +### 4.1. 思考阶段 (`_get_submind_thinking`) + +1. **触发观察**: 调用关联的 `Observation` 实例的 `observe()` 方法,使其更新对环境(如聊天室新消息)的观察。 +2. **触发子思维**: 调用关联的 `SubMind` 实例的 `do_thinking_before_reply()` 方法。**关键**: 会将上一个循环的 `CycleInfo` 传递给 `SubMind`,使其了解上一次行动的决策、理由以及是否发生了重新规划,从而实现更连贯的思考。 +3. **获取思考结果**: `SubMind` 返回其当前的内心想法 (`current_mind`)。 + +### 4.2. 规划阶段 (`_planner`) + +1. **输入**: 获取 `SubMind` 的当前想法 (`current_mind`)、`SubMind` 通过工具调用收集到的结构化信息 (`structured_info`) 以及观察到的最新消息。 +2. **构建提示词**: 调用 `_build_planner_prompt` 方法,将上述信息以及机器人个性、当前可用动作等整合进一个专门为规划器设计的提示词中。 +3. **定义动作工具**: 使用 `ActionManager.get_planner_tool_definition()` 获取当前可用动作(如 `no_reply`, `text_reply`, `emoji_reply`)的 JSON Schema,将其作为 "工具" 提供给 LLM。 +4. **调用 LLM**: 使用 `self.planner_llm` 向大模型发送请求,**强制要求**模型调用 `decide_reply_action` 这个"工具",并根据提示词内容决定使用哪个动作以及相应的参数(如 `reasoning`, `emoji_query`)。 +5. **处理 LLM 响应**: 使用 `process_llm_tool_response` 解析 LLM 返回的工具调用请求,提取出决策的动作 (`action`)、理由 (`reasoning`) 和可能的表情查询 (`emoji_query`)。 +6. **检查新消息与重新规划**: + - 调用 `_check_new_messages` 检查自规划阶段开始以来是否有新消息。 + - 如果检测到新消息,有一定概率(当前为 30%)触发**重新规划**。这会再次调用 `_planner`,但会传入一个特殊的提示词片段(通过 `_build_replan_prompt` 生成),告知 LLM 它之前的决策以及现在需要重新考虑。 +7. **输出**: 返回一个包含最终决策结果(`action`, `reasoning`, `emoji_query` 等)的字典。如果 LLM 调用或解析失败,`action` 会被设为 "error"。 + +### 4.3. 执行阶段 (`_handle_action`) + +根据规划阶段返回的 `action`,分派到不同的处理方法: + +- **`_handle_text_reply` (文本回复)**: + 1. `_get_anchor_message`: 获取一个用于回复的锚点消息。**注意**: 当前实现是创建一个系统触发的占位符消息作为锚点,而不是实际观察到的最后一条消息。 + 2. `_create_thinking_message`: 调用 `HeartFCSender` 的 `register_thinking` 方法,标记机器人开始思考,并获取一个 `thinking_id`。 + 3. `_replier_work`: 调用回复器生成回复内容。 + 4. `_sender`: 调用发送器发送生成的文本和可能的表情。 +- **`_handle_emoji_reply` (仅表情回复)**: + 1. 获取锚点消息。 + 2. `_handle_emoji`: 获取表情图片并调用 `HeartFCSender` 发送。 +- **`_handle_no_reply` (不回复)**: + 1. 记录不回复的理由。 + 2. `_wait_for_new_message`: 进入等待状态,直到关联的 `Observation` 检测到新消息或超时(当前 300 秒)。 + +## 5. 回复器逻辑 (`_replier_work`) + +- **输入**: 规划器给出的回复理由 (`reason`)、锚点消息 (`anchor_message`)、思考ID (`thinking_id`),以及通过 `self.sub_mind` 获取的结构化信息和当前想法。 +- **处理**: 调用 `self.gpt_instance` (`HeartFCGenerator`) 的 `generate_response` 方法。这个方法负责构建最终的生成提示词(结合思考、理由、上下文等),调用 LLM 生成回复文本。 +- **输出**: 返回一个包含多段回复文本的列表 (`List[str]`),如果生成失败则返回 `None`。 + +## 6. 发送器逻辑 (`_sender`, `_create_thinking_message`, `_send_response_messages`, `_handle_emoji`) + +`HeartFChatting` 类本身不直接处理 WebSocket 发送,而是将发送任务委托给 `HeartFCSender` 实例 (`self.heart_fc_sender`)。 + +- **`_create_thinking_message`**: 准备一个 `MessageThinking` 对象,并调用 `sender.register_thinking(thinking_message)`。 +- **`_send_response_messages`**: + - 检查对应的 `thinking_id` 是否仍然有效(通过 `sender.get_thinking_start_time`)。 + - 遍历 `_replier_work` 返回的回复文本列表 (`response_set`)。 + - 为每一段文本创建一个 `MessageSending` 对象。 + - 调用 `sender.type_and_send_message(bot_message)` 来发送消息。`HeartFCSender` 内部会处理模拟打字延迟、实际发送和消息存储。 + - 发送完成后,调用 `sender.complete_thinking(chat_id, thinking_id)` 来清理思考状态。 + - 记录实际发送的消息 ID 到 `CycleInfo` 中。 +- **`_handle_emoji`**: + - 使用 `emoji_manager` 根据 `emoji_query` 获取表情图片路径。 + - 将图片转为 Base64。 + - 创建 `MessageSending` 对象(标记为 `is_emoji=True`)。 + - 调用 `sender.send_and_store(bot_message)` 来发送并存储表情消息(这个方法不涉及思考状态)。 + +## 7. 循环信息记录 (`CycleInfo`) + +- `CycleInfo` 类用于记录每一次思考-规划-执行循环的详细信息,包括: + - 循环 ID (`cycle_id`) + - 开始和结束时间 (`start_time`, `end_time`) + - 是否执行了实际动作 (`action_taken`) + - 决策的动作类型 (`action_type`) 和理由 (`reasoning`) + - 各阶段的耗时计时器 (`timers`) + - 关联的思考消息 ID (`thinking_id`) + - 是否发生了重新规划 (`replanned`) + - 详细的响应信息 (`response_info`),包括生成的文本、表情查询、锚点消息 ID、实际发送的消息 ID 列表以及 `SubMind` 的思考内容。 +- `HeartFChatting` 维护一个 `_cycle_history` 队列来保存最近的循环记录,方便调试和分析。 + +## 8. 总结 + +`HeartFChatting` 通过精密的循环控制、阶段分离(思考、规划、执行)、与 `SubMind` 和 `Observation` 的紧密协作,以及对 `HeartFCSender` 和 `HeartFCGenerator` 等专用组件的依赖,实现了在 FOCUSED 状态下的主动、深入且有状态的对话逻辑。它能够根据上下文和内部思考动态调整回复策略,并通过 `ActionManager` 灵活控制可执行的动作范围。 \ No newline at end of file