refactor(chat): 移除亲和力流模块并将其重构为插件架构

BREAKING CHANGE: 原有的亲和力流相关模块(src/chat/affinity_flow/)已被完全移除,相关功能已重构为插件形式。需要更新配置文件和相关依赖。

- 删除 src/chat/affinity_flow/ 目录下的所有文件
- 将 AFC 管理器功能移至 chatter 插件中实现
- 更新相关导入路径和引用
- 重构关系追踪器和兴趣评分系统的初始化逻辑
- 调整聊天管理器和消息管理器以适应新的插件架构
This commit is contained in:
Windpicker-owo
2025-09-23 13:14:38 +08:00
parent ddcae01612
commit a218b932fb
29 changed files with 511 additions and 1068 deletions

View File

@@ -1,10 +0,0 @@
"""
亲和力流模块初始化文件
提供全局的AFC管理器实例
"""
# Avoid importing submodules at package import time to prevent circular imports.
# Consumers should import specific submodules directly, for example:
# from src.chat.affinity_flow.afc_manager import afc_manager
__all__ = ["afc_manager", "AFCManager", "AffinityFlowChatter"]

View File

@@ -1,131 +0,0 @@
"""
亲和力聊天处理流管理器
管理不同聊天流的亲和力聊天处理流,统一获取新消息并分发到对应的亲和力聊天处理流
"""
import time
import traceback
from typing import Dict, Optional, List
from src.chat.planner_actions.action_manager import ActionManager
from src.chat.planner_actions.planner import ActionPlanner
from src.chat.affinity_flow.chatter import AffinityFlowChatter
from src.common.data_models.message_manager_data_model import StreamContext
from src.common.logger import get_logger
logger = get_logger("afc_manager")
class AFCManager:
"""亲和力聊天处理流管理器"""
def __init__(self):
self.affinity_flow_chatters: Dict[str, "AffinityFlowChatter"] = {}
"""所有聊天流的亲和力聊天处理流stream_id -> affinity_flow_chatter"""
# 动作管理器
self.action_manager = ActionManager()
# 管理器统计
self.manager_stats = {
"total_messages_processed": 0,
"total_plans_created": 0,
"total_actions_executed": 0,
"active_chatters": 0,
"last_activity_time": time.time(),
}
def get_or_create_chatter(self, stream_id: str) -> "AffinityFlowChatter":
"""获取或创建聊天流处理器"""
if stream_id not in self.affinity_flow_chatters:
# 创建增强版规划器
planner = ActionPlanner(stream_id, self.action_manager)
chatter = AffinityFlowChatter(stream_id=stream_id, planner=planner, action_manager=self.action_manager)
self.affinity_flow_chatters[stream_id] = chatter
logger.info(f"创建新的亲和力聊天处理器: {stream_id}")
return self.affinity_flow_chatters[stream_id]
async def process_stream_context(self, stream_id: str, context: StreamContext) -> Dict[str, any]:
"""处理StreamContext对象"""
try:
# 获取或创建聊天处理器
chatter = self.get_or_create_chatter(stream_id)
# 处理StreamContext
result = await chatter.process_stream_context(context)
# 更新统计
self.manager_stats["total_messages_processed"] += 1
self.manager_stats["total_actions_executed"] += result.get("executed_count", 0)
self.manager_stats["last_activity_time"] = time.time()
return result
except Exception as e:
logger.error(f"处理StreamContext时出错: {e}\n{traceback.format_exc()}")
return {
"success": False,
"error_message": str(e),
"executed_count": 0,
}
def get_chatter_stats(self, stream_id: str) -> Optional[Dict[str, any]]:
"""获取聊天处理器统计"""
if stream_id in self.affinity_flow_chatters:
return self.affinity_flow_chatters[stream_id].get_stats()
return None
def get_manager_stats(self) -> Dict[str, any]:
"""获取管理器统计"""
stats = self.manager_stats.copy()
stats["active_chatters"] = len(self.affinity_flow_chatters)
return stats
def cleanup_inactive_chatters(self, max_inactive_minutes: int = 60):
"""清理不活跃的聊天处理器"""
current_time = time.time()
max_inactive_seconds = max_inactive_minutes * 60
inactive_streams = []
for stream_id, chatter in self.affinity_flow_chatters.items():
if current_time - chatter.last_activity_time > max_inactive_seconds:
inactive_streams.append(stream_id)
for stream_id in inactive_streams:
del self.affinity_flow_chatters[stream_id]
logger.info(f"清理不活跃聊天处理器: {stream_id}")
def get_planner_stats(self, stream_id: str) -> Optional[Dict[str, any]]:
"""获取规划器统计"""
if stream_id in self.affinity_flow_chatters:
return self.affinity_flow_chatters[stream_id].get_planner_stats()
return None
def get_interest_scoring_stats(self, stream_id: str) -> Optional[Dict[str, any]]:
"""获取兴趣度评分统计"""
if stream_id in self.affinity_flow_chatters:
return self.affinity_flow_chatters[stream_id].get_interest_scoring_stats()
return None
def get_relationship_stats(self, stream_id: str) -> Optional[Dict[str, any]]:
"""获取用户关系统计"""
if stream_id in self.affinity_flow_chatters:
return self.affinity_flow_chatters[stream_id].get_relationship_stats()
return None
def get_user_relationship(self, stream_id: str, user_id: str) -> float:
"""获取用户关系分"""
if stream_id in self.affinity_flow_chatters:
return self.affinity_flow_chatters[stream_id].get_user_relationship(user_id)
return 0.3 # 默认新用户关系分
def update_interest_keywords(self, stream_id: str, new_keywords: dict):
"""更新兴趣关键词"""
if stream_id in self.affinity_flow_chatters:
self.affinity_flow_chatters[stream_id].update_interest_keywords(new_keywords)
logger.info(f"已更新聊天流 {stream_id} 的兴趣关键词: {list(new_keywords.keys())}")
afc_manager = AFCManager()

View File

@@ -1,206 +0,0 @@
"""
亲和力聊天处理器
单个聊天流的处理器,负责处理特定聊天流的完整交互流程
"""
import time
import traceback
from datetime import datetime
from typing import Dict
from src.chat.planner_actions.action_manager import ActionManager
from src.chat.planner_actions.planner import ActionPlanner
from src.common.data_models.message_manager_data_model import StreamContext
from src.plugin_system.base.base_chatter import BaseChatter
from src.plugin_system.base.component_types import ChatMode
from src.common.logger import get_logger
logger = get_logger("affinity_chatter")
class AffinityFlowChatter(BaseChatter):
"""单个亲和力聊天处理器"""
def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ActionManager):
"""
初始化亲和力聊天处理器
Args:
stream_id: 聊天流ID
planner: 动作规划器
action_manager: 动作管理器
"""
self.stream_id = stream_id
self.planner = planner
self.action_manager = action_manager
# 处理器统计
self.stats = {
"messages_processed": 0,
"plans_created": 0,
"actions_executed": 0,
"successful_executions": 0,
"failed_executions": 0,
}
self.last_activity_time = time.time()
async def execute(self, context: StreamContext) -> dict:
"""
处理StreamContext对象
Args:
context: StreamContext对象包含聊天流的所有消息信息
Returns:
处理结果字典
"""
try:
unread_messages = context.get_unread_messages()
# 使用增强版规划器处理消息
actions, target_message = await self.planner.plan(mode=ChatMode.FOCUS, context=context)
self.stats["plans_created"] += 1
# 执行动作(如果规划器返回了动作)
execution_result = {"executed_count": len(actions) if actions else 0}
if actions:
logger.debug(f"聊天流 {self.stream_id} 生成了 {len(actions)} 个动作")
# 更新统计
self.stats["messages_processed"] += 1
self.stats["actions_executed"] += execution_result.get("executed_count", 0)
self.stats["successful_executions"] += 1
self.last_activity_time = time.time()
result = {
"success": True,
"stream_id": self.stream_id,
"plan_created": True,
"actions_count": len(actions) if actions else 0,
"has_target_message": target_message is not None,
"unread_messages_processed": len(unread_messages),
**execution_result,
}
logger.info(
f"聊天流 {self.stream_id} StreamContext处理成功: 动作数={result['actions_count']}, 未读消息={result['unread_messages_processed']}"
)
return result
except Exception as e:
logger.error(f"亲和力聊天处理器 {self.stream_id} 处理StreamContext时出错: {e}\n{traceback.format_exc()}")
self.stats["failed_executions"] += 1
self.last_activity_time = time.time()
return {
"success": False,
"stream_id": self.stream_id,
"error_message": str(e),
"executed_count": 0,
}
def get_stats(self) -> Dict[str, any]:
"""
获取处理器统计信息
Returns:
统计信息字典
"""
return self.stats.copy()
def get_planner_stats(self) -> Dict[str, any]:
"""
获取规划器统计信息
Returns:
规划器统计信息字典
"""
return self.planner.get_planner_stats()
def get_interest_scoring_stats(self) -> Dict[str, any]:
"""
获取兴趣度评分统计信息
Returns:
兴趣度评分统计信息字典
"""
return self.planner.get_interest_scoring_stats()
def get_relationship_stats(self) -> Dict[str, any]:
"""
获取用户关系统计信息
Returns:
用户关系统计信息字典
"""
return self.planner.get_relationship_stats()
def get_user_relationship(self, user_id: str) -> float:
"""
获取用户关系分
Args:
user_id: 用户ID
Returns:
用户关系分 (0.0-1.0)
"""
return self.planner.get_user_relationship(user_id)
def update_interest_keywords(self, new_keywords: dict):
"""
更新兴趣关键词
Args:
new_keywords: 新的兴趣关键词字典
"""
self.planner.update_interest_keywords(new_keywords)
logger.info(f"聊天流 {self.stream_id} 已更新兴趣关键词: {list(new_keywords.keys())}")
def reset_stats(self):
"""重置统计信息"""
self.stats = {
"messages_processed": 0,
"plans_created": 0,
"actions_executed": 0,
"successful_executions": 0,
"failed_executions": 0,
}
def is_active(self, max_inactive_minutes: int = 60) -> bool:
"""
检查处理器是否活跃
Args:
max_inactive_minutes: 最大不活跃分钟数
Returns:
是否活跃
"""
current_time = time.time()
max_inactive_seconds = max_inactive_minutes * 60
return (current_time - self.last_activity_time) < max_inactive_seconds
def get_activity_time(self) -> float:
"""
获取最后活动时间
Returns:
最后活动时间戳
"""
return self.last_activity_time
def __str__(self) -> str:
"""字符串表示"""
return f"AffinityFlowChatter(stream_id={self.stream_id}, messages={self.stats['messages_processed']})"
def __repr__(self) -> str:
"""详细字符串表示"""
return (
f"AffinityFlowChatter(stream_id={self.stream_id}, "
f"messages_processed={self.stats['messages_processed']}, "
f"plans_created={self.stats['plans_created']}, "
f"last_activity={datetime.fromtimestamp(self.last_activity_time)})"
)

View File

@@ -1,68 +0,0 @@
"""
回复后关系追踪集成初始化脚本
此脚本用于设置回复后关系追踪系统的全局变量和初始化连接
确保各组件能正确协同工作
"""
from src.chat.affinity_flow.relationship_tracker import UserRelationshipTracker
from src.chat.affinity_flow.interest_scoring import interest_scoring_system
from src.common.logger import get_logger
logger = get_logger("relationship_integration")
# 全局关系追踪器实例
relationship_tracker = None
def initialize_relationship_tracking():
"""初始化关系追踪系统"""
global relationship_tracker
try:
logger.info("🚀 初始化回复后关系追踪系统...")
# 创建关系追踪器实例
relationship_tracker = UserRelationshipTracker(interest_scoring_system=interest_scoring_system)
# 设置兴趣度评分系统的关系追踪器引用
interest_scoring_system.relationship_tracker = relationship_tracker
logger.info("✅ 回复后关系追踪系统初始化完成")
logger.info("📋 系统功能:")
logger.info(" 🔄 自动回复后关系追踪")
logger.info(" 💾 数据库持久化存储")
logger.info(" 🧠 LLM智能关系分析")
logger.info(" ⏰ 5分钟追踪间隔")
logger.info(" 🎯 兴趣度评分集成")
return relationship_tracker
except Exception as e:
logger.error(f"❌ 关系追踪系统初始化失败: {e}")
logger.debug("错误详情:", exc_info=True)
return None
def get_relationship_tracker():
"""获取全局关系追踪器实例"""
global relationship_tracker
return relationship_tracker
def setup_plan_executor_relationship_tracker(plan_executor):
"""为PlanExecutor设置关系追踪器"""
global relationship_tracker
if relationship_tracker and plan_executor:
plan_executor.set_relationship_tracker(relationship_tracker)
logger.info("✅ PlanExecutor关系追踪器设置完成")
return True
logger.warning("⚠️ 无法设置PlanExecutor关系追踪器")
return False
# 自动初始化
if __name__ == "__main__":
initialize_relationship_tracking()

View File

@@ -2,15 +2,15 @@ from typing import Dict, List, Optional, Any
import time import time
from src.plugin_system.base.base_chatter import BaseChatter from src.plugin_system.base.base_chatter import BaseChatter
from src.common.data_models.message_manager_data_model import StreamContext from src.common.data_models.message_manager_data_model import StreamContext
from src.chat.planner_actions.planner import ActionPlanner from src.plugins.built_in.chatter.planner import ChatterActionPlanner as ActionPlanner
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ChatterActionManager
from src.plugin_system.base.component_types import ChatType, ComponentType from src.plugin_system.base.component_types import ChatType, ComponentType
from src.common.logger import get_logger from src.common.logger import get_logger
logger = get_logger("chatter_manager") logger = get_logger("chatter_manager")
class ChatterManager: class ChatterManager:
def __init__(self, action_manager: ActionManager): def __init__(self, action_manager: ChatterActionManager):
self.action_manager = action_manager self.action_manager = action_manager
self.chatter_classes: Dict[ChatType, List[type]] = {} self.chatter_classes: Dict[ChatType, List[type]] = {}
self.instances: Dict[str, BaseChatter] = {} self.instances: Dict[str, BaseChatter] = {}

View File

@@ -21,7 +21,7 @@ from datetime import datetime
from typing import Dict, Optional from typing import Dict, Optional
from src.common.logger import get_logger from src.common.logger import get_logger
from src.chat.affinity_flow.afc_manager import afc_manager # AFC manager has been moved to chatter plugin
# TODO: 需要重新实现主动思考和睡眠管理功能 # TODO: 需要重新实现主动思考和睡眠管理功能
from .analyzer import chat_frequency_analyzer from .analyzer import chat_frequency_analyzer
@@ -61,8 +61,9 @@ class FrequencyBasedTrigger:
# continue # continue
# 2. 获取所有已知的聊天ID # 2. 获取所有已知的聊天ID
# 亲和力流系统中聊天ID直接从管理器获取 # 注意AFC管理器已移至chatter插件此功能暂时禁用
all_chat_ids = list(afc_manager.affinity_flow_chatters.keys()) # all_chat_ids = list(afc_manager.affinity_flow_chatters.keys())
all_chat_ids = [] # 暂时禁用此功能
if not all_chat_ids: if not all_chat_ids:
continue continue
@@ -77,26 +78,10 @@ class FrequencyBasedTrigger:
# 4. 检查当前是否是该用户的高峰聊天时间 # 4. 检查当前是否是该用户的高峰聊天时间
if chat_frequency_analyzer.is_in_peak_time(chat_id, now): if chat_frequency_analyzer.is_in_peak_time(chat_id, now):
# 5. 检查用户当前是否已有活跃的处理任务 # 5. 检查用户当前是否已有活跃的处理任务
# 亲和力流系统不直接提供循环状态,通过检查最后活动时间来判断是否忙碌 # 注意AFC管理器已移至chatter插件此功能暂时禁用
chatter = afc_manager.get_or_create_chatter(chat_id) # chatter = afc_manager.get_or_create_chatter(chat_id)
if not chatter: logger.info(f"检测到用户 {chat_id} 处于聊天高峰期但AFC功能已移至chatter插件")
logger.warning(f"无法为 {chat_id} 获取或创建亲和力聊天处理器。") continue
continue
# 检查是否在活跃状态最近1分钟内有活动
current_time = time.time()
if current_time - chatter.get_activity_time() < 60:
logger.debug(f"用户 {chat_id} 的亲和力处理器正忙,本次不触发。")
continue
logger.info(f"检测到用户 {chat_id} 处于聊天高峰期,且处理器空闲,准备触发主动思考。")
# 6. TODO: 亲和力流系统的主动思考机制需要另行实现
# 目前先记录日志,等待后续实现
logger.info(f"用户 {chat_id} 处于高峰期,但亲和力流的主动思考功能暂未实现")
# 7. 更新触发时间,进入冷却
self._last_triggered[chat_id] = time.time()
except asyncio.CancelledError: except asyncio.CancelledError:
logger.info("频率触发器任务被取消。") logger.info("频率触发器任务被取消。")

View File

@@ -12,7 +12,7 @@ from src.common.logger import get_logger
from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.database_data_model import DatabaseMessages
from src.common.data_models.message_manager_data_model import StreamContext, MessageManagerStats, StreamStats from src.common.data_models.message_manager_data_model import StreamContext, MessageManagerStats, StreamStats
from src.chat.chatter_manager import ChatterManager from src.chat.chatter_manager import ChatterManager
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ChatterActionManager
if TYPE_CHECKING: if TYPE_CHECKING:
from src.common.data_models.message_manager_data_model import StreamContext from src.common.data_models.message_manager_data_model import StreamContext
@@ -33,7 +33,7 @@ class MessageManager:
self.stats = MessageManagerStats() self.stats = MessageManagerStats()
# 初始化chatter manager # 初始化chatter manager
self.action_manager = ActionManager() self.action_manager = ChatterActionManager()
self.chatter_manager = ChatterManager(self.action_manager) self.chatter_manager = ChatterManager(self.action_manager)
async def start(self): async def start(self):

View File

@@ -18,7 +18,7 @@ from src.plugin_system.apis import generator_api, database_api, send_api, messag
logger = get_logger("action_manager") logger = get_logger("action_manager")
class ActionManager: class ChatterActionManager:
""" """
动作管理器,用于管理各种类型的动作 动作管理器,用于管理各种类型的动作
@@ -34,7 +34,7 @@ class ActionManager:
# 初始化时将默认动作加载到使用中的动作 # 初始化时将默认动作加载到使用中的动作
self._using_actions = component_registry.get_default_actions() self._using_actions = component_registry.get_default_actions()
self.log_prefix: str = "ActionManager" self.log_prefix: str = "ChatterActionManager"
# === 执行Action方法 === # === 执行Action方法 ===
@@ -449,7 +449,7 @@ class ActionManager:
data = "".join(map(str, data)) data = "".join(map(str, data))
reply_text += data reply_text += data
# 如果是主动思考且内容为沉默,则不发送 # 如果是主动思考且内容为"沉默",则不发送
if is_proactive_thinking and data.strip() == "沉默": if is_proactive_thinking and data.strip() == "沉默":
logger.info(f"{self.log_prefix} 主动思考决定保持沉默,不发送消息") logger.info(f"{self.log_prefix} 主动思考决定保持沉默,不发送消息")
continue continue

View File

@@ -8,7 +8,7 @@ from src.common.logger import get_logger
from src.config.config import global_config, model_config from src.config.config import global_config, model_config
from src.llm_models.utils_model import LLMRequest from src.llm_models.utils_model import LLMRequest
from src.chat.message_receive.chat_stream import get_chat_manager, ChatMessageContext from src.chat.message_receive.chat_stream import get_chat_manager, ChatMessageContext
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ChatterActionManager
from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat, build_readable_messages from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat, build_readable_messages
from src.plugin_system.base.component_types import ActionInfo, ActionActivationType from src.plugin_system.base.component_types import ActionInfo, ActionActivationType
from src.plugin_system.core.global_announcement_manager import global_announcement_manager from src.plugin_system.core.global_announcement_manager import global_announcement_manager
@@ -27,7 +27,7 @@ class ActionModifier:
支持并行判定和智能缓存优化。 支持并行判定和智能缓存优化。
""" """
def __init__(self, action_manager: ActionManager, chat_id: str): def __init__(self, action_manager: ChatterActionManager, chat_id: str):
"""初始化动作处理器""" """初始化动作处理器"""
self.chat_id = chat_id self.chat_id = chat_id
self.chat_stream: ChatStream = get_chat_manager().get_stream(self.chat_id) # type: ignore self.chat_stream: ChatStream = get_chat_manager().get_stream(self.chat_id) # type: ignore

View File

@@ -1,132 +0,0 @@
"""
PlanGenerator: 负责搜集和汇总所有决策所需的信息,生成一个未经筛选的“原始计划” (Plan)。
"""
import time
from typing import Dict
from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat
from src.chat.utils.utils import get_chat_type_and_target_info
from src.common.data_models.database_data_model import DatabaseMessages
from src.common.data_models.info_data_model import Plan, TargetPersonInfo
from src.config.config import global_config
from src.plugin_system.base.component_types import ActionActivationType, ActionInfo, ChatMode, ChatType, ComponentType
from src.plugin_system.core.component_registry import component_registry
class PlanGenerator:
"""
PlanGenerator 负责在规划流程的初始阶段收集所有必要信息。
它会汇总以下信息来构建一个“原始”的 Plan 对象,该对象后续会由 PlanFilter 进行筛选:
- 当前聊天信息 (ID, 目标用户)
- 当前可用的动作列表
- 最近的聊天历史记录
Attributes:
chat_id (str): 当前聊天的唯一标识符。
action_manager (ActionManager): 用于获取可用动作列表的管理器。
"""
def __init__(self, chat_id: str):
"""
初始化 PlanGenerator。
Args:
chat_id (str): 当前聊天的 ID。
"""
from src.chat.planner_actions.action_manager import ActionManager
self.chat_id = chat_id
# 注意ActionManager 可能需要根据实际情况初始化
self.action_manager = ActionManager()
async def generate(self, mode: ChatMode) -> Plan:
"""
收集所有信息,生成并返回一个初始的 Plan 对象。
这个 Plan 对象包含了决策所需的所有上下文信息。
Args:
mode (ChatMode): 当前的聊天模式。
Returns:
Plan: 一个填充了初始上下文信息的 Plan 对象。
"""
_is_group_chat, chat_target_info_dict = get_chat_type_and_target_info(self.chat_id)
target_info = None
if chat_target_info_dict:
target_info = TargetPersonInfo(**chat_target_info_dict)
available_actions = self._get_available_actions()
chat_history_raw = get_raw_msg_before_timestamp_with_chat(
chat_id=self.chat_id,
timestamp=time.time(),
limit=int(global_config.chat.max_context_size),
)
chat_history = [DatabaseMessages(**msg) for msg in chat_history_raw]
plan = Plan(
chat_id=self.chat_id,
mode=mode,
available_actions=available_actions,
chat_history=chat_history,
target_info=target_info,
)
return plan
def _get_available_actions(self) -> Dict[str, "ActionInfo"]:
"""
从 ActionManager 和组件注册表中获取当前所有可用的动作。
它会合并已注册的动作和系统级动作(如 "no_reply"
并以字典形式返回。
Returns:
Dict[str, "ActionInfo"]: 一个字典,键是动作名称,值是 ActionInfo 对象。
"""
current_available_actions_dict = self.action_manager.get_using_actions()
all_registered_actions: Dict[str, ActionInfo] = component_registry.get_components_by_type( # type: ignore
ComponentType.ACTION
)
current_available_actions = {}
for action_name in current_available_actions_dict:
if action_name in all_registered_actions:
current_available_actions[action_name] = all_registered_actions[action_name]
reply_info = ActionInfo(
name="reply",
component_type=ComponentType.ACTION,
description="系统级动作:选择回复消息的决策",
action_parameters={"content": "回复的文本内容", "reply_to_message_id": "要回复的消息ID"},
action_require=[
"你想要闲聊或者随便附和",
"当用户提到你或艾特你时",
"当需要回答用户的问题时",
"当你想参与对话时",
"当用户分享有趣的内容时",
],
activation_type=ActionActivationType.ALWAYS,
activation_keywords=[],
associated_types=["text", "reply"],
plugin_name="SYSTEM",
enabled=True,
parallel_action=False,
mode_enable=ChatMode.ALL,
chat_type_allow=ChatType.ALL,
)
no_reply_info = ActionInfo(
name="no_reply",
component_type=ComponentType.ACTION,
description="系统级动作:选择不回复消息的决策",
action_parameters={},
activation_keywords=[],
plugin_name="SYSTEM",
enabled=True,
parallel_action=False,
)
current_available_actions["no_reply"] = no_reply_info
current_available_actions["reply"] = reply_info
return current_available_actions

View File

@@ -1,175 +0,0 @@
"""
本文件集中管理所有与规划器Planner相关的提示词Prompt模板。
通过将提示词与代码逻辑分离,可以更方便地对模型的行为进行迭代和优化,
而无需修改核心代码。
"""
from src.chat.utils.prompt import Prompt
def init_prompts():
"""
初始化并向 Prompt 注册系统注册所有规划器相关的提示词。
这个函数会在模块加载时自动调用,确保所有提示词在系统启动时都已准备就绪。
"""
# 核心规划器提示词,用于在接收到新消息时决定如何回应。
# 它构建了一个复杂的上下文,包括历史记录、可用动作、角色设定等,
# 并要求模型以 JSON 格式输出一个或多个动作组合。
Prompt(
"""
{mood_block}
{time_block}
{identity_block}
{users_in_chat}
{custom_prompt_block}
{chat_context_description},以下是具体的聊天内容。
## 📜 已读历史消息(仅供参考)
{read_history_block}
## 📬 未读历史消息(动作执行对象)
{unread_history_block}
{moderation_prompt}
**任务: 构建一个完整的响应**
你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成:
1. **主要动作**: 这是响应的核心,通常是 `reply`(如果有)。
2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。
**决策流程:**
1. **重要:已读历史消息仅作为当前聊天情景的参考,帮助你理解对话上下文。**
2. **重要:所有动作的执行对象只能是未读历史消息中的消息,不能对已读消息执行动作。**
3. 在未读历史消息中,优先对兴趣值高的消息做出动作(兴趣值标注在消息末尾)。
4. 首先,决定是否要对未读消息进行 `reply`(如果有)。
5. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格。
6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合。
7. 如果用户明确要求了某个动作,请务必优先满足。
**如果可选动作中没有reply请不要使用**
**可用动作:**
{actions_before_now_block}
{no_action_block}
{action_options_text}
**输出格式:**
你必须以严格的 JSON 格式输出返回一个包含所有选定动作的JSON列表。如果没有任何合适的动作返回一个空列表[]。
**单动作示例 (仅回复):**
[
{{
"action": "reply",
"target_message_id": "m123",
"reason": "回答用户的问题"
}}
]
**组合动作示例 (回复 + 表情包):**
[
{{
"action": "reply",
"target_message_id": "m123",
"reason": "回答用户的问题"
}},
{{
"action": "emoji",
"target_message_id": "m123",
"reason": "根据我将要回复的文本内容,选择一个最匹配的表情包来增强表达效果。回复的文本是:<TEXT>"
}}
]
**重要规则:**
1. 当 `reply` 和 `emoji` 动作同时被选择时,`emoji` 动作的 `reason` 字段必须包含 `reply` 动作最终生成的回复文本内容。你需要将 `<TEXT>` 占位符替换为 `reply` 动作的 `reason` 字段内容,以确保表情包的选择与回复文本高度相关。
2. **动作执行限制所有动作的target_message_id必须是未读历史消息中的消息ID(消息ID格式:m123)。**
3. **兴趣度优先:在多个未读消息中,优先选择兴趣值高的消息进行回复。**
不要输出markdown格式```json等内容直接输出且仅包含 JSON 列表内容:
""",
"planner_prompt",
)
# 主动思考规划器提示词,用于在没有新消息时决定是否要主动发起对话。
# 它模拟了人类的自发性思考,允许模型根据长期记忆和最近的对话来决定是否开启新话题。
Prompt(
"""
# 主动思考决策
## 你的内部状态
{time_block}
{identity_block}
{mood_block}
## 长期记忆摘要
{long_term_memory_block}
## 最近的聊天内容
{chat_content_block}
## 最近的动作历史
{actions_before_now_block}
## 任务
你现在要决定是否主动说些什么。就像一个真实的人一样,有时候会突然想起之前聊到的话题,或者对朋友的近况感到好奇,想主动询问或关心一下。
**重要提示**:你的日程安排仅供你个人参考,不应作为主动聊天话题的主要来源。请更多地从聊天内容和朋友的动态中寻找灵感。
请基于聊天内容,用你的判断力来决定是否要主动发言。不要按照固定规则,而是像人类一样自然地思考:
- 是否想起了什么之前提到的事情,想问问后来怎么样了?
- 是否注意到朋友提到了什么值得关心的事情?
- 是否有什么话题突然想到,觉得现在聊聊很合适?
- 或者觉得现在保持沉默更好?
## 可用动作
动作proactive_reply
动作描述:主动发起对话,可以是关心朋友、询问近况、延续之前的话题,或分享想法。
- 当你突然想起之前的话题,想询问进展时
- 当你想关心朋友的情况时
- 当你有什么想法想分享时
- 当你觉得现在是个合适的聊天时机时
{{
"action": "proactive_reply",
"reason": "你决定主动发言的具体原因",
"topic": "你想说的内容主题(简洁描述)"
}}
动作do_nothing
动作描述:保持沉默,不主动发起对话。
- 当你觉得现在不是合适的时机时
- 当最近已经说得够多了时
- 当对话氛围不适合插入时
{{
"action": "do_nothing",
"reason": "决定保持沉默的原因"
}}
你必须从上面列出的可用action中选择一个。要像真人一样自然地思考和决策。
请以严格的 JSON 格式输出,且仅包含 JSON 内容:
""",
"proactive_planner_prompt",
)
# 单个动作的格式化提示词模板。
# 用于将每个可用动作的信息格式化后,插入到主提示词的 {action_options_text} 占位符中。
Prompt(
"""
动作:{action_name}
动作描述:{action_description}
{action_require}
{{
"action": "{action_name}",
"target_message_id": "触发action的消息id",
"reason": "触发action的原因"{action_parameters}
}}
""",
"action_prompt",
)
# 在模块加载时自动调用,完成提示词的注册。
init_prompts()

View File

@@ -875,7 +875,7 @@ class DefaultReplyer:
interest_scores = {} interest_scores = {}
try: try:
from src.chat.affinity_flow.interest_scoring import interest_scoring_system from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system as interest_scoring_system
from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.database_data_model import DatabaseMessages
# 转换消息格式 # 转换消息格式
@@ -1528,9 +1528,11 @@ class DefaultReplyer:
# 使用AFC关系追踪器获取关系信息 # 使用AFC关系追踪器获取关系信息
try: try:
from src.chat.affinity_flow.relationship_integration import get_relationship_tracker from src.plugins.built_in.chatter.relationship_tracker import ChatterRelationshipTracker
relationship_tracker = get_relationship_tracker() # 创建关系追踪器实例
from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system
relationship_tracker = ChatterRelationshipTracker(chatter_interest_scoring_system)
if relationship_tracker: if relationship_tracker:
# 获取用户信息以获取真实的user_id # 获取用户信息以获取真实的user_id
user_info = await person_info_manager.get_values(person_id, ["user_id", "platform"]) user_info = await person_info_manager.get_values(person_id, ["user_id", "platform"])

View File

@@ -84,7 +84,7 @@ class Individuality:
full_personality = f"{personality_result}{identity_result}" full_personality = f"{personality_result}{identity_result}"
# 获取全局兴趣评分系统实例 # 获取全局兴趣评分系统实例
from src.chat.affinity_flow.interest_scoring import interest_scoring_system from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system as interest_scoring_system
# 初始化智能兴趣系统 # 初始化智能兴趣系统
await interest_scoring_system.initialize_smart_interests( await interest_scoring_system.initialize_smart_interests(

View File

@@ -250,13 +250,16 @@ MoFox_Bot(第三方修改版)
logger.info("表情包管理器初始化成功") logger.info("表情包管理器初始化成功")
# 初始化回复后关系追踪系统 # 初始化回复后关系追踪系统
from src.chat.affinity_flow.relationship_integration import initialize_relationship_tracking try:
from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system
from src.plugins.built_in.chatter.relationship_tracker import ChatterRelationshipTracker
relationship_tracker = initialize_relationship_tracking() relationship_tracker = ChatterRelationshipTracker(interest_scoring_system=chatter_interest_scoring_system)
if relationship_tracker: chatter_interest_scoring_system.relationship_tracker = relationship_tracker
logger.info("回复后关系追踪系统初始化成功") logger.info("回复后关系追踪系统初始化成功")
else: except Exception as e:
logger.warning("回复后关系追踪系统初始化失败") logger.error(f"回复后关系追踪系统初始化失败: {e}")
relationship_tracker = None
# 启动情绪管理器 # 启动情绪管理器
await mood_manager.start() await mood_manager.start()

View File

@@ -5,8 +5,8 @@ from .component_types import ChatType
from src.plugin_system.base.component_types import ChatterInfo, ComponentType from src.plugin_system.base.component_types import ChatterInfo, ComponentType
if TYPE_CHECKING: if TYPE_CHECKING:
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ChatterActionManager
from src.chat.planner_actions.planner import ActionPlanner from src.plugins.built_in.chatter.planner import ChatterActionPlanner as ActionPlanner
class BaseChatter(ABC): class BaseChatter(ABC):
chatter_name: str = "" chatter_name: str = ""
@@ -15,7 +15,7 @@ class BaseChatter(ABC):
"""Chatter组件的描述""" """Chatter组件的描述"""
chat_types: List[ChatType] = [ChatType.PRIVATE, ChatType.GROUP] chat_types: List[ChatType] = [ChatType.PRIVATE, ChatType.GROUP]
def __init__(self, stream_id: str, planner: 'ActionPlanner', action_manager: 'ActionManager'): def __init__(self, stream_id: str, planner: 'ActionPlanner', action_manager: 'ChatterActionManager'):
""" """
初始化聊天处理器 初始化聊天处理器

View File

@@ -34,10 +34,10 @@
```python ```python
from src.chat.chatter_manager import ChatterManager from src.chat.chatter_manager import ChatterManager
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ChatterActionManager
# 初始化 # 初始化
action_manager = ActionManager() action_manager = ChatterActionManager()
chatter_manager = ChatterManager(action_manager) chatter_manager = ChatterManager(action_manager)
# 处理消息流 # 处理消息流

View File

@@ -0,0 +1,7 @@
"""
亲和力聊天处理器插件
"""
from .plugin import AffinityChatterPlugin
__all__ = ["AffinityChatterPlugin"]

View File

@@ -11,8 +11,8 @@ from typing import Dict, Any
from src.plugin_system.base.base_chatter import BaseChatter from src.plugin_system.base.base_chatter import BaseChatter
from src.plugin_system.base.component_types import ChatType, ChatMode from src.plugin_system.base.component_types import ChatType, ChatMode
from src.common.data_models.message_manager_data_model import StreamContext from src.common.data_models.message_manager_data_model import StreamContext
from src.chat.planner_actions.planner import ActionPlanner from src.plugins.built_in.chatter.planner import ChatterActionPlanner as ActionPlanner
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ChatterActionManager
from src.common.logger import get_logger from src.common.logger import get_logger
logger = get_logger("affinity_chatter") logger = get_logger("affinity_chatter")
@@ -24,7 +24,7 @@ class AffinityChatter(BaseChatter):
chatter_description: str = "基于亲和力模型的智能聊天处理器,支持多种聊天类型" chatter_description: str = "基于亲和力模型的智能聊天处理器,支持多种聊天类型"
chat_types: list[ChatType] = [ChatType.ALL] # 支持所有聊天类型 chat_types: list[ChatType] = [ChatType.ALL] # 支持所有聊天类型
def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ActionManager): def __init__(self, stream_id: str, planner: ActionPlanner, action_manager: ChatterActionManager):
""" """
初始化亲和力聊天处理器 初始化亲和力聊天处理器

View File

@@ -13,10 +13,10 @@ from src.chat.interest_system import bot_interest_manager
from src.common.logger import get_logger from src.common.logger import get_logger
from src.config.config import global_config from src.config.config import global_config
logger = get_logger("interest_scoring") logger = get_logger("chatter_interest_scoring")
class InterestScoringSystem: class ChatterInterestScoringSystem:
"""兴趣度评分系统""" """兴趣度评分系统"""
def __init__(self): def __init__(self):
@@ -230,9 +230,9 @@ class InterestScoringSystem:
else: else:
# 尝试从全局关系追踪器获取 # 尝试从全局关系追踪器获取
try: try:
from src.chat.affinity_flow.relationship_integration import get_relationship_tracker from .relationship_tracker import ChatterRelationshipTracker
global_tracker = get_relationship_tracker() global_tracker = ChatterRelationshipTracker()
if global_tracker: if global_tracker:
relationship_score = global_tracker.get_user_relationship_score(user_id) relationship_score = global_tracker.get_user_relationship_score(user_id)
# 同时更新内存缓存 # 同时更新内存缓存
@@ -365,4 +365,4 @@ class InterestScoringSystem:
# 创建全局兴趣评分系统实例 # 创建全局兴趣评分系统实例
interest_scoring_system = InterestScoringSystem() chatter_interest_scoring_system = ChatterInterestScoringSystem()

View File

@@ -9,14 +9,14 @@ import time
from typing import Dict, List from typing import Dict, List
from src.config.config import global_config from src.config.config import global_config
from src.chat.planner_actions.action_manager import ActionManager from src.chat.planner_actions.action_manager import ChatterActionManager
from src.common.data_models.info_data_model import Plan, ActionPlannerInfo from src.common.data_models.info_data_model import Plan, ActionPlannerInfo
from src.common.logger import get_logger from src.common.logger import get_logger
logger = get_logger("plan_executor") logger = get_logger("plan_executor")
class PlanExecutor: class ChatterPlanExecutor:
""" """
增强版PlanExecutor集成用户关系追踪机制 增强版PlanExecutor集成用户关系追踪机制
@@ -27,12 +27,12 @@ class PlanExecutor:
4. 提供完整的执行统计和监控 4. 提供完整的执行统计和监控
""" """
def __init__(self, action_manager: ActionManager): def __init__(self, action_manager: ChatterActionManager):
""" """
初始化增强版PlanExecutor 初始化增强版PlanExecutor
Args: Args:
action_manager (ActionManager): 用于实际执行各种动作的管理器实例 action_manager (ChatterActionManager): 用于实际执行各种动作的管理器实例
""" """
self.action_manager = action_manager self.action_manager = action_manager

View File

@@ -28,7 +28,7 @@ from src.schedule.schedule_manager import schedule_manager
logger = get_logger("plan_filter") logger = get_logger("plan_filter")
class PlanFilter: class ChatterPlanFilter:
""" """
根据 Plan 中的模式和信息筛选并决定最终的动作 根据 Plan 中的模式和信息筛选并决定最终的动作
""" """
@@ -321,7 +321,7 @@ class PlanFilter:
interest_scores = {} interest_scores = {}
try: try:
from src.chat.affinity_flow.interest_scoring import interest_scoring_system from src.plugins.built_in.chatter.interest_scoring import chatter_interest_scoring_system as interest_scoring_system
from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.database_data_model import DatabaseMessages
# 转换消息格式 # 转换消息格式

View File

@@ -0,0 +1,167 @@
"""
PlanGenerator: 负责搜集和汇总所有决策所需的信息,生成一个未经筛选的"原始计划" (Plan)。
"""
import time
from typing import Dict
from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat
from src.chat.utils.utils import get_chat_type_and_target_info
from src.common.data_models.database_data_model import DatabaseMessages
from src.common.data_models.info_data_model import Plan, TargetPersonInfo
from src.config.config import global_config
from src.plugin_system.base.component_types import ActionActivationType, ActionInfo, ChatMode, ChatType, ComponentType
from src.plugin_system.core.component_registry import component_registry
class ChatterPlanGenerator:
"""
ChatterPlanGenerator 负责在规划流程的初始阶段收集所有必要信息。
它会汇总以下信息来构建一个"原始"的 Plan 对象,该对象后续会由 PlanFilter 进行筛选:
- 当前聊天信息 (ID, 目标用户)
- 当前可用的动作列表
- 最近的聊天历史记录
Attributes:
chat_id (str): 当前聊天的唯一标识符。
action_manager (ActionManager): 用于获取可用动作列表的管理器。
"""
def __init__(self, chat_id: str):
"""
初始化 ChatterPlanGenerator。
Args:
chat_id (str): 当前聊天的 ID。
"""
from src.chat.planner_actions.action_manager import ChatterActionManager
self.chat_id = chat_id
# 注意ChatterActionManager 可能需要根据实际情况初始化
self.action_manager = ChatterActionManager()
async def generate(self, mode: ChatMode) -> Plan:
"""
收集所有信息,生成并返回一个初始的 Plan 对象。
这个 Plan 对象包含了决策所需的所有上下文信息。
Args:
mode (ChatMode): 当前的聊天模式。
Returns:
Plan: 包含所有上下文信息的初始计划对象。
"""
try:
# 获取聊天类型和目标信息
chat_type, target_info = get_chat_type_and_target_info(self.chat_id)
# 获取可用动作列表
available_actions = await self._get_available_actions(chat_type, mode)
# 获取聊天历史记录
recent_messages = await self._get_recent_messages()
# 构建计划对象
plan = Plan(
chat_id=self.chat_id,
mode=mode,
target_info=target_info,
available_actions=available_actions,
chat_history=recent_messages,
)
return plan
except Exception as e:
# 如果生成失败,返回一个基本的空计划
return Plan(
chat_id=self.chat_id,
mode=mode,
target_info=TargetPersonInfo(),
available_actions={},
chat_history=[],
)
async def _get_available_actions(self, chat_type: ChatType, mode: ChatMode) -> Dict[str, ActionInfo]:
"""
获取当前可用的动作列表。
Args:
chat_type (ChatType): 聊天类型。
mode (ChatMode): 聊天模式。
Returns:
Dict[str, ActionInfo]: 可用动作的字典。
"""
try:
# 从组件注册表获取可用动作
available_actions = component_registry.get_enabled_actions()
# 根据聊天类型和模式筛选动作
filtered_actions = {}
for action_name, action_info in available_actions.items():
# 检查动作是否支持当前聊天类型
if chat_type in action_info.chat_types:
# 检查动作是否支持当前模式
if mode in action_info.chat_modes:
filtered_actions[action_name] = action_info
return filtered_actions
except Exception as e:
# 如果获取失败,返回空字典
return {}
async def _get_recent_messages(self) -> list[DatabaseMessages]:
"""
获取最近的聊天历史记录。
Returns:
list[DatabaseMessages]: 最近的聊天消息列表。
"""
try:
# 获取最近的消息记录
raw_messages = get_raw_msg_before_timestamp_with_chat(
chat_id=self.chat_id,
timestamp=time.time(),
limit=global_config.memory.short_memory_length
)
# 转换为 DatabaseMessages 对象
recent_messages = []
for msg in raw_messages:
try:
db_msg = DatabaseMessages(
message_id=msg.get("message_id", ""),
time=float(msg.get("time", 0)),
chat_id=msg.get("chat_id", ""),
processed_plain_text=msg.get("processed_plain_text", ""),
user_id=msg.get("user_id", ""),
user_nickname=msg.get("user_nickname", ""),
user_platform=msg.get("user_platform", ""),
)
recent_messages.append(db_msg)
except Exception as e:
# 跳过格式错误的消息
continue
return recent_messages
except Exception as e:
# 如果获取失败,返回空列表
return []
def get_generator_stats(self) -> Dict:
"""
获取生成器统计信息。
Returns:
Dict: 统计信息字典。
"""
return {
"chat_id": self.chat_id,
"action_count": len(self.action_manager._using_actions) if hasattr(self.action_manager, '_using_actions') else 0,
"generation_time": time.time()
}

View File

@@ -7,28 +7,28 @@ from dataclasses import asdict
from typing import TYPE_CHECKING, Dict, List, Optional, Tuple from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
from src.plugin_system.base.component_types import ChatMode from src.plugin_system.base.component_types import ChatMode
from src.chat.planner_actions.plan_executor import PlanExecutor from src.plugins.built_in.chatter.plan_executor import ChatterPlanExecutor
from src.chat.planner_actions.plan_filter import PlanFilter from src.plugins.built_in.chatter.plan_filter import ChatterPlanFilter
from src.chat.planner_actions.plan_generator import PlanGenerator from src.plugins.built_in.chatter.plan_generator import ChatterPlanGenerator
from src.chat.affinity_flow.interest_scoring import InterestScoringSystem from src.plugins.built_in.chatter.interest_scoring import ChatterInterestScoringSystem
from src.chat.affinity_flow.relationship_tracker import UserRelationshipTracker from src.plugins.built_in.chatter.relationship_tracker import ChatterRelationshipTracker
from src.common.logger import get_logger from src.common.logger import get_logger
from src.config.config import global_config from src.config.config import global_config
if TYPE_CHECKING: if TYPE_CHECKING:
from src.chat.planner_actions.action_manager import ActionManager
from src.common.data_models.message_manager_data_model import StreamContext from src.common.data_models.message_manager_data_model import StreamContext
from src.common.data_models.info_data_model import Plan from src.common.data_models.info_data_model import Plan
from src.chat.planner_actions.action_manager import ChatterActionManager
# 导入提示词模块以确保其被初始化 # 导入提示词模块以确保其被初始化
from src.chat.planner_actions import planner_prompts # noqa from src.plugins.built_in.chatter import planner_prompts # noqa
logger = get_logger("planner") logger = get_logger("planner")
class ActionPlanner: class ChatterActionPlanner:
""" """
增强版ActionPlanner集成兴趣度评分和用户关系追踪机制 增强版ActionPlanner集成兴趣度评分和用户关系追踪机制
@@ -39,42 +39,26 @@ class ActionPlanner:
4. 完整的规划流程生成筛选执行的完整三阶段流程 4. 完整的规划流程生成筛选执行的完整三阶段流程
""" """
def __init__(self, chat_id: str, action_manager: "ActionManager"): def __init__(self, chat_id: str, action_manager: "ChatterActionManager"):
""" """
初始化增强版ActionPlanner 初始化增强版ActionPlanner
Args: Args:
chat_id (str): 当前聊天的 ID chat_id (str): 当前聊天的 ID
action_manager (ActionManager): 一个 ActionManager 实例 action_manager (ChatterActionManager): 一个 ChatterActionManager 实例
""" """
self.chat_id = chat_id self.chat_id = chat_id
self.action_manager = action_manager self.action_manager = action_manager
self.generator = PlanGenerator(chat_id) self.generator = ChatterPlanGenerator(chat_id)
self.filter = PlanFilter() self.filter = ChatterPlanFilter()
self.executor = PlanExecutor(action_manager) self.executor = ChatterPlanExecutor(action_manager)
# 初始化兴趣度评分系统 # 初始化兴趣度评分系统
self.interest_scoring = InterestScoringSystem() self.interest_scoring = ChatterInterestScoringSystem()
# 尝试获取全局关系追踪器,如果没有则创建新的 # 创建新的关系追踪器
try: self.relationship_tracker = ChatterRelationshipTracker(self.interest_scoring)
from src.chat.affinity_flow.relationship_integration import get_relationship_tracker logger.info("创建新的关系追踪器实例")
global_relationship_tracker = get_relationship_tracker()
if global_relationship_tracker:
# 使用全局关系追踪器
self.relationship_tracker = global_relationship_tracker
# 设置兴趣度评分系统的关系追踪器引用
self.interest_scoring.relationship_tracker = self.relationship_tracker
logger.info("使用全局关系追踪器")
else:
# 创建新的关系追踪器
self.relationship_tracker = UserRelationshipTracker(self.interest_scoring)
logger.info("创建新的关系追踪器实例")
except Exception as e:
logger.warning(f"获取全局关系追踪器失败: {e}")
# 创建新的关系追踪器
self.relationship_tracker = UserRelationshipTracker(self.interest_scoring)
# 设置执行器的关系追踪器 # 设置执行器的关系追踪器
self.executor.set_relationship_tracker(self.relationship_tracker) self.executor.set_relationship_tracker(self.relationship_tracker)

View File

@@ -0,0 +1,260 @@
"""
本文件集中管理所有与规划器Planner相关的提示词Prompt模板。
通过将提示词与代码逻辑分离,可以更方便地对模型的行为进行迭代和优化,
而无需修改核心代码。
"""
from src.chat.utils.prompt import Prompt
def init_prompts():
"""
初始化并向 Prompt 注册系统注册所有规划器相关的提示词。
这个函数会在模块加载时自动调用,确保所有提示词在系统启动时都已准备就绪。
"""
# 核心规划器提示词,用于在接收到新消息时决定如何回应。
# 它构建了一个复杂的上下文,包括历史记录、可用动作、角色设定等,
# 并要求模型以 JSON 格式输出一个或多个动作组合。
Prompt(
"""
{mood_block}
{time_block}
{identity_block}
{users_in_chat}
{custom_prompt_block}
{chat_context_description},以下是具体的聊天内容。
## 📜 已读历史消息(仅供参考)
{read_history_block}
## 📬 未读历史消息(动作执行对象)
{unread_history_block}
{moderation_prompt}
**任务: 构建一个完整的响应**
你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成:
1. **主要动作**: 这是响应的核心,通常是 `reply`(如果有)。
2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。
**决策流程:**
1. **重要:已读历史消息仅作为当前聊天情景的参考,帮助你理解对话上下文。**
2. **重要:所有动作的执行对象只能是未读历史消息中的消息,不能对已读消息执行动作。**
3. 在未读历史消息中,优先对兴趣值高的消息做出动作(兴趣值标注在消息末尾)。
4. 首先,决定是否要对未读消息进行 `reply`(如果有)。
5. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格。
6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合。
7. 如果用户明确要求了某个动作,请务必优先满足。
**动作限制:**
- 在私聊中,你只能使用 `reply` 动作。私聊中不允许使用任何其他动作。
- 在群聊中,你可以自由选择是否使用辅助动作。
**重要提醒:**
- **回复消息时必须遵循对话的流程,不要重复已经说过的话。**
- **确保回复与上下文紧密相关,回应要针对用户的消息内容。**
- **保持角色设定的一致性,使用符合你性格的语言风格。**
**输出格式:**
请严格按照以下 JSON 格式输出,包含 `thinking` 和 `actions` 字段:
```json
{{
"thinking": "你的思考过程,分析当前情况并说明为什么选择这些动作",
"actions": [
{{
"action_type": "动作类型reply, emoji等",
"reasoning": "选择该动作的理由",
"action_data": {{
"target_message_id": "目标消息ID",
"content": "回复内容或其他动作所需数据"
}}
}}
]
}}
```
如果没有合适的回复对象或不需要回复,输出空的 actions 数组:
```json
{{
"thinking": "说明为什么不需要回复",
"actions": []
}}
```
""",
"planner_prompt",
)
# 主动规划器提示词,用于主动场景和前瞻性规划
Prompt(
"""
{mood_block}
{time_block}
{identity_block}
{users_in_chat}
{custom_prompt_block}
{chat_context_description},以下是具体的聊天内容。
## 📜 已读历史消息(仅供参考)
{read_history_block}
## 📬 未读历史消息(动作执行对象)
{unread_history_block}
{moderation_prompt}
**任务: 构建一个完整的响应**
你的任务是根据当前的聊天内容,构建一个完整的、人性化的响应。一个完整的响应由两部分组成:
1. **主要动作**: 这是响应的核心,通常是 `reply`(如果有)。
2. **辅助动作 (可选)**: 这是为了增强表达效果的附加动作,例如 `emoji`(发送表情包)或 `poke_user`(戳一戳)。
**决策流程:**
1. **重要:已读历史消息仅作为当前聊天情景的参考,帮助你理解对话上下文。**
2. **重要:所有动作的执行对象只能是未读历史消息中的消息,不能对已读消息执行动作。**
3. 在未读历史消息中,优先对兴趣值高的消息做出动作(兴趣值标注在消息末尾)。
4. 首先,决定是否要对未读消息进行 `reply`(如果有)。
5. 然后,评估当前的对话气氛和用户情绪,判断是否需要一个**辅助动作**来让你的回应更生动、更符合你的性格。
6. 如果需要,选择一个最合适的辅助动作与 `reply`(如果有) 组合。
7. 如果用户明确要求了某个动作,请务必优先满足。
**动作限制:**
- 在私聊中,你只能使用 `reply` 动作。私聊中不允许使用任何其他动作。
- 在群聊中,你可以自由选择是否使用辅助动作。
**重要提醒:**
- **回复消息时必须遵循对话的流程,不要重复已经说过的话。**
- **确保回复与上下文紧密相关,回应要针对用户的消息内容。**
- **保持角色设定的一致性,使用符合你性格的语言风格。**
**输出格式:**
请严格按照以下 JSON 格式输出,包含 `thinking` 和 `actions` 字段:
```json
{{
"thinking": "你的思考过程,分析当前情况并说明为什么选择这些动作",
"actions": [
{{
"action_type": "动作类型reply, emoji等",
"reasoning": "选择该动作的理由",
"action_data": {{
"target_message_id": "目标消息ID",
"content": "回复内容或其他动作所需数据"
}}
}}
]
}}
```
如果没有合适的回复对象或不需要回复,输出空的 actions 数组:
```json
{{
"thinking": "说明为什么不需要回复",
"actions": []
}}
```
""",
"proactive_planner_prompt",
)
# 轻量级规划器提示词,用于快速决策和简单场景
Prompt(
"""
{identity_block}
## 当前聊天情景
{chat_context_description}
## 未读消息
{unread_history_block}
**任务:快速决策**
请根据当前聊天内容,快速决定是否需要回复。
**决策规则:**
1. 如果有人直接提到你或问你问题,优先回复
2. 如果消息内容符合你的兴趣,考虑回复
3. 如果只是群聊中的普通聊天且与你无关,可以不回复
**输出格式:**
```json
{{
"thinking": "简要分析",
"actions": [
{{
"action_type": "reply",
"reasoning": "回复理由",
"action_data": {{
"target_message_id": "目标消息ID",
"content": "回复内容"
}}
}}
]
}}
```
""",
"chatter_planner_lite",
)
# 动作筛选器提示词,用于筛选和优化规划器生成的动作
Prompt(
"""
{identity_block}
## 原始动作计划
{original_plan}
## 聊天上下文
{chat_context}
**任务:动作筛选优化**
请对原始动作计划进行筛选和优化,确保动作的合理性和有效性。
**筛选原则:**
1. 移除重复或不必要的动作
2. 确保动作之间的逻辑顺序
3. 优化动作的具体参数
4. 考虑当前聊天环境和个人设定
**输出格式:**
```json
{{
"thinking": "筛选优化思考",
"actions": [
{{
"action_type": "优化后的动作类型",
"reasoning": "优化理由",
"action_data": {{
"target_message_id": "目标消息ID",
"content": "优化后的内容"
}}
}}
]
}}
```
""",
"chatter_plan_filter",
)
# 动作提示词,用于格式化动作选项
Prompt(
"""
## 动作: {action_name}
**描述**: {action_description}
**参数**:
{action_parameters}
**要求**:
{action_require}
**使用说明**:
请根据上述信息判断是否需要使用此动作。
""",
"action_prompt",
)
# 确保提示词在模块加载时初始化
init_prompts()

View File

@@ -15,10 +15,10 @@ from src.common.database.sqlalchemy_models import UserRelationships, Messages
from sqlalchemy import select, desc from sqlalchemy import select, desc
from src.common.data_models.database_data_model import DatabaseMessages from src.common.data_models.database_data_model import DatabaseMessages
logger = get_logger("relationship_tracker") logger = get_logger("chatter_relationship_tracker")
class UserRelationshipTracker: class ChatterRelationshipTracker:
"""用户关系追踪器""" """用户关系追踪器"""
def __init__(self, interest_scoring_system=None): def __init__(self, interest_scoring_system=None):

View File

@@ -1,8 +0,0 @@
"""
亲和力聊天处理器插件
"""
from .plugin import AffinityChatterPlugin
from .affinity_chatter import AffinityChatter
__all__ = ["AffinityChatterPlugin", "AffinityChatter"]

View File

@@ -1,235 +0,0 @@
# 从消息接收到执行Action的完整流程图
## 整体流程概览
```mermaid
flowchart TD
A[原始消息数据] --> B[消息接收层<br>src/chat/message_receive/bot.py]
B --> C[消息解析<br>src/chat/message_receive/message.py]
C --> D[会话管理<br>src/chat/message_receive/chat_stream.py]
D --> E[亲和力流分发<br>src/chat/affinity_flow/afc_manager.py]
E --> F[聊天处理器<br>src/chat/affinity_flow/chatter.py]
F --> G[智能规划决策<br>三层架构]
G --> H[动作执行管理<br>src/chat/planner_actions/action_manager.py]
H --> I[最终执行<br>src/chat/planner_actions/plan_executor.py]
I --> J[Action执行结果]
```
## 详细分阶段流程图
### 1. 消息接收与预处理阶段
```mermaid
flowchart TD
A[原始消息数据] --> B[message_process入口]
B --> C{消息切片重组}
C -- 完整消息 --> D[平台类型判断]
C -- 切片消息 --> E[等待更多切片]
D --> F{S4U平台?}
F -- 是 --> G[S4U特殊处理]
F -- 否 --> H[创建MessageRecv对象]
H --> I[过滤检查<br>违禁词/正则]
I --> J[命令处理系统]
J --> K{PlusCommand?}
K -- 是 --> L[执行PlusCommand]
K -- 否 --> M[执行BaseCommand]
L --> N[事件触发]
M --> N
N --> O[模板处理]
O --> P[预处理完成]
```
### 2. 消息解析阶段
```mermaid
flowchart TD
A[预处理完成消息] --> B[MessageRecv.process]
B --> C{消息类型判断}
C -- 文本 --> D[直接提取文本]
C -- 图片 --> E[图片识别处理]
C -- 表情 --> F[表情包描述]
C -- 语音 --> G[语音转文本]
C -- 视频 --> H[视频内容分析]
C -- AT消息 --> I[提取用户信息]
C -- 其他 --> J[通用处理]
D --> K[生成纯文本]
E --> K
F --> K
G --> K
H --> K
I --> K
J --> K
K --> L[消息解析完成]
```
### 3. 会话管理阶段
```mermaid
flowchart TD
A[解析后消息] --> B[ChatManager.register_message]
B --> C[生成stream_id<br>platform+user+group]
C --> D{会话是否存在?}
D -- 内存中存在 --> E[获取现有会话]
D -- 内存中不存在 --> F[数据库查询]
F --> G{数据库存在?}
G -- 是 --> H[从数据库加载]
G -- 否 --> I[创建新会话]
H --> J[更新会话信息]
I --> J
J --> K[设置消息上下文]
K --> L[会话管理完成]
```
### 4. 智能规划决策阶段(三层架构)
```mermaid
flowchart TD
A[会话管理完成] --> B[规划器入口 ActionPlanner]
B --> C[PlanGenerator生成初始Plan]
C --> D[兴趣度评分系统]
D --> E[提取未读消息]
E --> F[计算多维评分]
F --> G[兴趣匹配度]
F --> H[用户关系分]
F --> I[提及度评分]
G --> J[加权总分计算]
H --> J
I --> J
J --> K{是否回复?}
K -- 是 --> L[保留reply动作]
K -- 否 --> M[移除reply动作]
L --> N[PlanFilter筛选]
M --> N
N --> O[LLM决策最终动作]
O --> P[规划决策完成]
```
### 5. 动作执行阶段
```mermaid
flowchart TD
A[规划决策完成] --> B[ActionManager执行]
B --> C{动作类型判断}
C -- no_action --> D[记录不动作]
C -- no_reply --> E[记录不回复]
C -- reply --> F[生成回复内容]
C -- 其他动作 --> G[执行具体动作]
D --> H[执行完成]
E --> H
F --> I[发送回复消息]
G --> J[动作处理器执行]
I --> H
J --> H
H --> K[PlanExecutor最终执行]
K --> L[用户关系追踪]
L --> M[执行统计记录]
M --> N[动作执行完成]
```
## 完整端到端流程
```mermaid
flowchart LR
A[消息接收] --> B[消息解析]
B --> C[会话管理]
C --> D[消息分发]
D --> E[聊天处理]
E --> F[兴趣度评分]
F --> G[规划生成]
G --> H[LLM筛选]
H --> I[动作管理]
I --> J[最终执行]
J --> K[结果返回]
subgraph 智能决策层
F
G
H
end
subgraph 执行层
I
J
K
end
style 智能决策层 fill:#e1f5fe
style 执行层 fill:#f3e5f5
```
## 关键组件交互关系
```mermaid
flowchart TD
Bot[Bot.message_process] --> Message[MessageRecv]
Message --> ChatManager[ChatManager]
ChatManager --> AFCManager[AFCManager]
AFCManager --> Chatter[AffinityFlowChatter]
Chatter --> Planner[ActionPlanner]
Planner --> Generator[PlanGenerator]
Planner --> Scorer[InterestScoringSystem]
Planner --> Filter[PlanFilter]
Filter --> ActionManager[ActionManager]
ActionManager --> Executor[PlanExecutor]
Executor --> Result[执行结果]
%% 数据流
Message -.-> |消息数据| Chatter
Scorer -.-> |兴趣评分| Filter
Generator -.-> |初始Plan| Filter
Filter -.-> |最终Plan| Executor
```
## 异常处理流程
```mermaid
flowchart TD
A[开始处理] --> B[正常流程]
B --> C[处理完成]
B --> D{发生异常?}
D -- 是 --> E[异常捕获]
D -- 否 --> C
E --> F[日志记录错误]
F --> G[错误类型判断]
G -- 消息解析失败 --> H[返回解析错误]
G -- 会话不存在 --> I[创建新会话重试]
G -- LLM决策失败 --> J[使用默认动作]
G -- 动作执行失败 --> K[动作回退机制]
G -- 其他错误 --> L[返回通用错误]
H --> M[异常处理完成]
I --> B
J --> M
K --> M
L --> M
```
这个流程图详细展示了从消息接收到执行action的完整流程包括各个阶段的处理逻辑、组件交互关系以及异常处理机制。整个系统采用了模块化设计具有清晰的职责分离和良好的可扩展性。