feat:添加获取Chat_stream的api
This commit is contained in:
@@ -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` 可靠地执行消息发送任务。
|
||||
@@ -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()`
|
||||
- 错误追踪:详细的异常记录
|
||||
- 响应监控:完整的状态跟踪
|
||||
@@ -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)
|
||||
```
|
||||
|
||||
@@ -1,524 +0,0 @@
|
||||
# 如何编写MaiBot插件
|
||||
|
||||
## 前言
|
||||
|
||||
插件系统目前为v1.0版本,支持Focus和Normal两种聊天模式下的动作扩展。
|
||||
|
||||
### 🆕 v1.0 新特性
|
||||
- **双激活类型系统**:Focus模式智能化,Normal模式高性能
|
||||
- **并行动作支持**:支持与回复同时执行的动作
|
||||
- **四种激活类型**:ALWAYS、RANDOM、LLM_JUDGE、KEYWORD
|
||||
- **智能缓存机制**:提升LLM判定性能
|
||||
- **模式启用控制**:精确控制插件在不同模式下的行为
|
||||
|
||||
插件以**动作(Action)**的形式扩展MaiBot功能。原有的focus模式包含reply和no_reply两种基础动作,通过插件系统可以添加更多自定义动作如mute_action、pic_action等。
|
||||
|
||||
**⚠️ 重要变更**:旧的`action_activation_type`属性已被移除,必须使用新的双激活类型系统。详见[迁移指南](#迁移指南)。
|
||||
|
||||
## 动作激活系统 🚀
|
||||
|
||||
### 双激活类型架构
|
||||
|
||||
MaiBot采用**双激活类型架构**,为Focus模式和Normal模式分别提供最优的激活策略:
|
||||
|
||||
**Focus模式**:智能优先
|
||||
- 支持复杂的LLM判定
|
||||
- 提供精确的上下文理解
|
||||
- 适合需要深度分析的场景
|
||||
|
||||
**Normal模式**:性能优先
|
||||
- 使用快速的关键词匹配
|
||||
- 采用简单的随机触发
|
||||
- 确保快速响应用户
|
||||
|
||||
### 四种激活类型
|
||||
|
||||
#### 1. ALWAYS - 总是激活
|
||||
```python
|
||||
focus_activation_type = ActionActivationType.ALWAYS
|
||||
normal_activation_type = ActionActivationType.ALWAYS
|
||||
```
|
||||
**用途**:基础必需动作,如`reply_action`、`no_reply_action`
|
||||
|
||||
#### 2. KEYWORD - 关键词触发
|
||||
```python
|
||||
focus_activation_type = ActionActivationType.KEYWORD
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
activation_keywords = ["画", "画图", "生成图片", "draw"]
|
||||
keyword_case_sensitive = False
|
||||
```
|
||||
**用途**:精确命令式触发,如图片生成、搜索等
|
||||
|
||||
#### 3. LLM_JUDGE - 智能判定
|
||||
```python
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.KEYWORD # 推荐Normal模式使用KEYWORD
|
||||
```
|
||||
**用途**:需要上下文理解的复杂判定,如情感分析、意图识别
|
||||
|
||||
**优化特性**:
|
||||
- 🚀 并行执行:多个LLM判定同时进行
|
||||
- 💾 智能缓存:相同上下文复用结果(30秒有效期)
|
||||
- ⚡ 直接判定:减少复杂度,提升性能
|
||||
|
||||
#### 4. RANDOM - 随机激活
|
||||
```python
|
||||
focus_activation_type = ActionActivationType.RANDOM
|
||||
normal_activation_type = ActionActivationType.RANDOM
|
||||
random_activation_probability = 0.1 # 10%概率
|
||||
```
|
||||
**用途**:增加不可预测性和趣味性,如随机表情
|
||||
|
||||
### 并行动作系统 🆕
|
||||
|
||||
支持动作与回复生成同时执行:
|
||||
|
||||
```python
|
||||
# 并行动作:与回复生成同时执行
|
||||
parallel_action = True # 提升用户体验,适用于辅助性动作
|
||||
|
||||
# 串行动作:替代回复生成(传统行为)
|
||||
parallel_action = False # 默认值,适用于主要内容生成
|
||||
```
|
||||
|
||||
**适用场景**:
|
||||
- **并行动作**:情感表达、状态变更、TTS播报
|
||||
- **串行动作**:图片生成、搜索查询、内容创作
|
||||
|
||||
### 模式启用控制
|
||||
|
||||
```python
|
||||
from src.chat.chat_mode import ChatMode
|
||||
|
||||
mode_enable = ChatMode.ALL # 在所有模式下启用(默认)
|
||||
mode_enable = ChatMode.FOCUS # 仅在Focus模式启用
|
||||
mode_enable = ChatMode.NORMAL # 仅在Normal模式启用
|
||||
```
|
||||
|
||||
## 基本步骤
|
||||
|
||||
1. 在`src/plugins/你的插件名/actions/`目录下创建插件文件
|
||||
2. 继承`PluginAction`基类
|
||||
3. 配置双激活类型和相关属性
|
||||
4. 实现`process`方法
|
||||
5. 在`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, ActionActivationType
|
||||
from src.chat.chat_mode import ChatMode
|
||||
from typing import Tuple
|
||||
|
||||
logger = get_logger("your_action_name")
|
||||
|
||||
@register_action
|
||||
class YourAction(PluginAction):
|
||||
"""你的动作描述"""
|
||||
|
||||
action_name = "your_action_name"
|
||||
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 # 是否启用插件
|
||||
|
||||
# 传统配置
|
||||
action_parameters = {
|
||||
"param1": "参数1的说明(可选)",
|
||||
"param2": "参数2的说明(可选)"
|
||||
}
|
||||
action_require = [
|
||||
"使用场景1",
|
||||
"使用场景2"
|
||||
]
|
||||
default = False
|
||||
|
||||
associated_types = ["text", "command"]
|
||||
|
||||
async def process(self) -> Tuple[bool, str]:
|
||||
"""插件核心逻辑"""
|
||||
# 你的代码逻辑...
|
||||
return True, "执行结果"
|
||||
```
|
||||
|
||||
### 关键词触发插件
|
||||
|
||||
```python
|
||||
@register_action
|
||||
class SearchAction(PluginAction):
|
||||
action_name = "search_action"
|
||||
action_description = "智能搜索功能"
|
||||
|
||||
# 两个模式都使用关键词触发
|
||||
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
|
||||
enable_plugin = True
|
||||
|
||||
async def process(self) -> Tuple[bool, str]:
|
||||
# 搜索逻辑
|
||||
return True, "搜索完成"
|
||||
```
|
||||
|
||||
### 并行辅助动作
|
||||
|
||||
```python
|
||||
@register_action
|
||||
class EmotionAction(PluginAction):
|
||||
action_name = "emotion_action"
|
||||
action_description = "情感表达动作"
|
||||
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.RANDOM
|
||||
random_activation_probability = 0.05 # 5%概率
|
||||
|
||||
mode_enable = ChatMode.ALL
|
||||
parallel_action = True # 🆕 与回复并行执行
|
||||
enable_plugin = True
|
||||
|
||||
async def process(self) -> Tuple[bool, str]:
|
||||
# 情感表达逻辑
|
||||
return True, "" # 并行动作通常不返回文本
|
||||
```
|
||||
|
||||
### Focus专享高级功能
|
||||
|
||||
```python
|
||||
@register_action
|
||||
class AdvancedAnalysisAction(PluginAction):
|
||||
action_name = "advanced_analysis"
|
||||
action_description = "高级分析功能"
|
||||
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.ALWAYS # 不会生效
|
||||
|
||||
mode_enable = ChatMode.FOCUS # 🆕 仅在Focus模式启用
|
||||
parallel_action = False
|
||||
enable_plugin = True
|
||||
```
|
||||
|
||||
## 推荐配置模式
|
||||
|
||||
### 模式1:智能自适应(推荐)
|
||||
```python
|
||||
# Focus模式智能判定,Normal模式快速触发
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
normal_activation_type = ActionActivationType.KEYWORD
|
||||
activation_keywords = ["相关", "关键词"]
|
||||
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
|
||||
```
|
||||
|
||||
### 模式3:Focus专享功能
|
||||
```python
|
||||
# 仅在Focus模式启用的高级功能
|
||||
focus_activation_type = ActionActivationType.LLM_JUDGE
|
||||
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 # 通常与回复并行
|
||||
```
|
||||
|
||||
## 可用的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}秒",
|
||||
)
|
||||
```
|
||||
|
||||
### 2. 使用表达器发送消息
|
||||
|
||||
```python
|
||||
await self.send_message_by_expressor("你好")
|
||||
await self.send_message_by_expressor(f"禁言{target} {duration}秒,因为{reason}")
|
||||
```
|
||||
|
||||
### 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. 激活类型选择
|
||||
- **ALWAYS**:仅用于基础必需动作
|
||||
- **KEYWORD**:明确的命令式动作,性能最佳
|
||||
- **LLM_JUDGE**:复杂判断,建议仅在Focus模式使用
|
||||
- **RANDOM**:娱乐功能,低概率触发
|
||||
|
||||
### 2. 双模式配置
|
||||
- **智能自适应**:Focus用LLM_JUDGE,Normal用KEYWORD(推荐)
|
||||
- **性能优先**:两个模式都用KEYWORD或RANDOM
|
||||
- **功能分离**:高级功能仅在Focus模式启用
|
||||
|
||||
### 3. 并行动作使用
|
||||
- **parallel_action = True**:辅助性、非内容生成类动作
|
||||
- **parallel_action = False**:主要内容生成、需要完整注意力的动作
|
||||
|
||||
### 4. LLM判定优化
|
||||
- 编写清晰的激活条件描述
|
||||
- 避免过于复杂的逻辑判断
|
||||
- 利用智能缓存机制(自动)
|
||||
- Normal模式避免使用LLM_JUDGE
|
||||
|
||||
### 5. 关键词设计
|
||||
- 包含同义词和英文对应词
|
||||
- 考虑用户的不同表达习惯
|
||||
- 避免过于宽泛的关键词
|
||||
- 根据实际使用调整覆盖率
|
||||
|
||||
## 迁移指南 ⚠️
|
||||
|
||||
### 重大变更说明
|
||||
**旧的 `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 # 是否启用此插件
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 代码组织
|
||||
- 使用清晰的`action_description`描述功能
|
||||
- 使用`action_parameters`定义所需参数
|
||||
- 使用`action_require`描述使用场景
|
||||
- 使用`logger`记录重要信息,方便调试
|
||||
|
||||
### 2. 性能考虑
|
||||
- 优先使用KEYWORD触发,性能最佳
|
||||
- Normal模式避免使用LLM_JUDGE
|
||||
- 合理设置随机概率(0.05-0.3)
|
||||
- 利用智能缓存机制(自动优化)
|
||||
|
||||
### 3. 用户体验
|
||||
- 并行动作提升响应速度
|
||||
- 关键词覆盖用户常用表达
|
||||
- 错误处理和友好提示
|
||||
- 避免操作底层系统
|
||||
|
||||
### 4. 兼容性
|
||||
- 支持中英文关键词
|
||||
- 考虑不同聊天模式的用户需求
|
||||
- 提供合理的默认配置
|
||||
- 向后兼容旧版本用户习惯
|
||||
|
||||
## 注册与加载
|
||||
|
||||
插件会在系统启动时自动加载,只要:
|
||||
1. 放在正确的目录结构中
|
||||
2. 添加了`@register_action`装饰器
|
||||
3. 在`__init__.py`中正确导入
|
||||
|
||||
若设置`default = True`,插件会自动添加到默认动作集并启用,否则默认只加载不启用。
|
||||
|
||||
## 调试和测试
|
||||
|
||||
### 性能监控
|
||||
系统会自动记录以下性能指标:
|
||||
```python
|
||||
logger.debug(f"激活判定:{before_count} -> {after_count} actions")
|
||||
logger.debug(f"并行LLM判定完成,耗时: {duration:.2f}s")
|
||||
logger.debug(f"使用缓存结果 {action_name}: {'激活' if result else '未激活'}")
|
||||
```
|
||||
|
||||
### 测试验证
|
||||
使用测试脚本验证配置:
|
||||
```bash
|
||||
python test_action_activation.py
|
||||
```
|
||||
|
||||
该脚本会显示:
|
||||
- 所有注册动作的双激活类型配置
|
||||
- 模拟不同模式下的激活结果
|
||||
- 并行动作系统的工作状态
|
||||
- 帮助验证配置是否正确
|
||||
|
||||
## 系统优势
|
||||
|
||||
### 1. 高性能
|
||||
- **并行判定**:多个LLM判定同时进行
|
||||
- **智能缓存**:避免重复计算
|
||||
- **双模式优化**:Focus智能化,Normal快速化
|
||||
- **预期性能提升**:3-5x
|
||||
|
||||
### 2. 智能化
|
||||
- **上下文感知**:基于聊天内容智能激活
|
||||
- **动态配置**:从动作配置中收集关键词
|
||||
- **冲突避免**:防止重复激活
|
||||
- **模式自适应**:根据聊天模式选择最优策略
|
||||
|
||||
### 3. 可扩展性
|
||||
- **插件式**:新的激活类型易于添加
|
||||
- **配置驱动**:通过配置控制行为
|
||||
- **模块化**:各组件独立可测试
|
||||
- **双模式支持**:灵活适应不同使用场景
|
||||
|
||||
### 4. 用户体验
|
||||
- **响应速度**:显著提升机器人反应速度
|
||||
- **智能决策**:精确理解用户意图
|
||||
- **交互流畅**:并行动作减少等待时间
|
||||
- **适应性强**:不同模式满足不同需求
|
||||
|
||||
这个升级后的插件系统为MaiBot提供了强大而灵活的扩展能力,既保证了性能,又提供了智能化的用户体验。
|
||||
@@ -16,6 +16,7 @@ from src.chat.actions.plugin_api.llm_api import LLMAPI
|
||||
from src.chat.actions.plugin_api.database_api import DatabaseAPI
|
||||
from src.chat.actions.plugin_api.config_api import ConfigAPI
|
||||
from src.chat.actions.plugin_api.utils_api import UtilsAPI
|
||||
from src.chat.actions.plugin_api.stream_api import StreamAPI
|
||||
|
||||
# 以下为类型注解需要
|
||||
from src.chat.message_receive.chat_stream import ChatStream # noqa
|
||||
@@ -26,7 +27,7 @@ from src.chat.focus_chat.info.obs_info import ObsInfo # noqa
|
||||
logger = get_logger("plugin_action")
|
||||
|
||||
|
||||
class PluginAction(BaseAction, MessageAPI, LLMAPI, DatabaseAPI, ConfigAPI, UtilsAPI):
|
||||
class PluginAction(BaseAction, MessageAPI, LLMAPI, DatabaseAPI, ConfigAPI, UtilsAPI, StreamAPI):
|
||||
"""插件动作基类
|
||||
|
||||
封装了主程序内部依赖,提供简化的API接口给插件开发者
|
||||
|
||||
@@ -3,6 +3,7 @@ from src.chat.actions.plugin_api.llm_api import LLMAPI
|
||||
from src.chat.actions.plugin_api.database_api import DatabaseAPI
|
||||
from src.chat.actions.plugin_api.config_api import ConfigAPI
|
||||
from src.chat.actions.plugin_api.utils_api import UtilsAPI
|
||||
from src.chat.actions.plugin_api.stream_api import StreamAPI
|
||||
|
||||
__all__ = [
|
||||
'MessageAPI',
|
||||
@@ -10,4 +11,5 @@ __all__ = [
|
||||
'DatabaseAPI',
|
||||
'ConfigAPI',
|
||||
'UtilsAPI',
|
||||
'StreamAPI',
|
||||
]
|
||||
164
src/chat/actions/plugin_api/stream_api.py
Normal file
164
src/chat/actions/plugin_api/stream_api.py
Normal file
@@ -0,0 +1,164 @@
|
||||
import hashlib
|
||||
from typing import Optional, List, Dict, Any
|
||||
from src.common.logger_manager import get_logger
|
||||
from src.chat.message_receive.chat_stream import ChatManager, ChatStream
|
||||
from maim_message import GroupInfo, UserInfo
|
||||
|
||||
logger = get_logger("stream_api")
|
||||
|
||||
|
||||
class StreamAPI:
|
||||
"""聊天流API模块
|
||||
|
||||
提供了获取聊天流、通过群ID查找聊天流等功能
|
||||
"""
|
||||
|
||||
def get_chat_stream_by_group_id(self, group_id: str, platform: str = "qq") -> Optional[ChatStream]:
|
||||
"""通过QQ群ID获取聊天流
|
||||
|
||||
Args:
|
||||
group_id: QQ群ID
|
||||
platform: 平台标识,默认为"qq"
|
||||
|
||||
Returns:
|
||||
Optional[ChatStream]: 找到的聊天流对象,如果未找到则返回None
|
||||
"""
|
||||
try:
|
||||
chat_manager = ChatManager()
|
||||
|
||||
# 遍历所有已加载的聊天流,查找匹配的群ID
|
||||
for stream_id, stream in chat_manager.streams.items():
|
||||
if (stream.group_info and
|
||||
str(stream.group_info.group_id) == str(group_id) and
|
||||
stream.platform == platform):
|
||||
logger.info(f"{self.log_prefix} 通过群ID {group_id} 找到聊天流: {stream_id}")
|
||||
return stream
|
||||
|
||||
logger.warning(f"{self.log_prefix} 未找到群ID为 {group_id} 的聊天流")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 通过群ID获取聊天流时出错: {e}")
|
||||
return None
|
||||
|
||||
def get_all_group_chat_streams(self, platform: str = "qq") -> List[ChatStream]:
|
||||
"""获取所有群聊的聊天流
|
||||
|
||||
Args:
|
||||
platform: 平台标识,默认为"qq"
|
||||
|
||||
Returns:
|
||||
List[ChatStream]: 所有群聊的聊天流列表
|
||||
"""
|
||||
try:
|
||||
chat_manager = ChatManager()
|
||||
group_streams = []
|
||||
|
||||
for stream in chat_manager.streams.values():
|
||||
if (stream.group_info and
|
||||
stream.platform == platform):
|
||||
group_streams.append(stream)
|
||||
|
||||
logger.info(f"{self.log_prefix} 找到 {len(group_streams)} 个群聊聊天流")
|
||||
return group_streams
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 获取所有群聊聊天流时出错: {e}")
|
||||
return []
|
||||
|
||||
def get_chat_stream_by_user_id(self, user_id: str, platform: str = "qq") -> Optional[ChatStream]:
|
||||
"""通过用户ID获取私聊聊天流
|
||||
|
||||
Args:
|
||||
user_id: 用户ID
|
||||
platform: 平台标识,默认为"qq"
|
||||
|
||||
Returns:
|
||||
Optional[ChatStream]: 找到的私聊聊天流对象,如果未找到则返回None
|
||||
"""
|
||||
try:
|
||||
chat_manager = ChatManager()
|
||||
|
||||
# 遍历所有已加载的聊天流,查找匹配的用户ID(私聊)
|
||||
for stream_id, stream in chat_manager.streams.items():
|
||||
if (not stream.group_info and # 私聊没有群信息
|
||||
stream.user_info and
|
||||
str(stream.user_info.user_id) == str(user_id) and
|
||||
stream.platform == platform):
|
||||
logger.info(f"{self.log_prefix} 通过用户ID {user_id} 找到私聊聊天流: {stream_id}")
|
||||
return stream
|
||||
|
||||
logger.warning(f"{self.log_prefix} 未找到用户ID为 {user_id} 的私聊聊天流")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 通过用户ID获取私聊聊天流时出错: {e}")
|
||||
return None
|
||||
|
||||
def get_chat_streams_info(self) -> List[Dict[str, Any]]:
|
||||
"""获取所有聊天流的基本信息
|
||||
|
||||
Returns:
|
||||
List[Dict[str, Any]]: 包含聊天流基本信息的字典列表
|
||||
"""
|
||||
try:
|
||||
chat_manager = ChatManager()
|
||||
streams_info = []
|
||||
|
||||
for stream_id, stream in chat_manager.streams.items():
|
||||
info = {
|
||||
"stream_id": stream_id,
|
||||
"platform": stream.platform,
|
||||
"chat_type": "group" if stream.group_info else "private",
|
||||
"create_time": stream.create_time,
|
||||
"last_active_time": stream.last_active_time
|
||||
}
|
||||
|
||||
if stream.group_info:
|
||||
info.update({
|
||||
"group_id": stream.group_info.group_id,
|
||||
"group_name": stream.group_info.group_name
|
||||
})
|
||||
|
||||
if stream.user_info:
|
||||
info.update({
|
||||
"user_id": stream.user_info.user_id,
|
||||
"user_nickname": stream.user_info.user_nickname
|
||||
})
|
||||
|
||||
streams_info.append(info)
|
||||
|
||||
logger.info(f"{self.log_prefix} 获取到 {len(streams_info)} 个聊天流信息")
|
||||
return streams_info
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 获取聊天流信息时出错: {e}")
|
||||
return []
|
||||
|
||||
async def get_chat_stream_by_group_id_async(self, group_id: str, platform: str = "qq") -> Optional[ChatStream]:
|
||||
"""异步通过QQ群ID获取聊天流(包括从数据库搜索)
|
||||
|
||||
Args:
|
||||
group_id: QQ群ID
|
||||
platform: 平台标识,默认为"qq"
|
||||
|
||||
Returns:
|
||||
Optional[ChatStream]: 找到的聊天流对象,如果未找到则返回None
|
||||
"""
|
||||
try:
|
||||
# 首先尝试从内存中查找
|
||||
stream = self.get_chat_stream_by_group_id(group_id, platform)
|
||||
if stream:
|
||||
return stream
|
||||
|
||||
# 如果内存中没有,尝试从数据库加载所有聊天流后再查找
|
||||
chat_manager = ChatManager()
|
||||
await chat_manager.load_all_streams()
|
||||
|
||||
# 再次尝试从内存中查找
|
||||
stream = self.get_chat_stream_by_group_id(group_id, platform)
|
||||
return stream
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} 异步通过群ID获取聊天流时出错: {e}")
|
||||
return None
|
||||
Reference in New Issue
Block a user