feat:统一化模式动作,移除模式配置

This commit is contained in:
SengokuCola
2025-07-12 23:24:02 +08:00
parent 11dbdc2e27
commit 6f1add930b
14 changed files with 67 additions and 290 deletions

View File

@@ -14,7 +14,7 @@ from src.chat.planner_actions.action_manager import ActionManager
from src.config.config import global_config
from src.person_info.relationship_builder_manager import relationship_builder_manager
from src.chat.focus_chat.hfc_utils import CycleDetail
from random import random
import random
from src.chat.focus_chat.hfc_utils import get_recent_message_stats
from src.person_info.person_info import get_person_info_manager
from src.plugin_system.apis import generator_api,send_api,message_api
@@ -228,7 +228,15 @@ class HeartFChatting:
await asyncio.sleep(1)
return True
async def build_reply_to_str(self,message_data:dict):
person_info_manager = get_person_info_manager()
person_id = person_info_manager.get_person_id(
message_data.get("chat_info_platform"), message_data.get("user_id")
)
person_name = await person_info_manager.get_value(person_id, "person_name")
reply_to_str = f"{person_name}:{message_data.get('processed_plain_text')}"
return reply_to_str
async def _observe(self,message_data:dict = None):
@@ -249,42 +257,19 @@ class HeartFChatting:
# 第一步:动作修改
with Timer("动作修改", cycle_timers):
try:
if self.loop_mode == "focus":
await self.action_modifier.modify_actions(
history_loop=self.history_loop,
mode="focus",
)
elif self.loop_mode == "normal":
await self.action_modifier.modify_actions(mode="normal")
available_actions = self.action_manager.get_using_actions_for_mode("normal")
await self.action_modifier.modify_actions()
available_actions = self.action_manager.get_using_actions()
except Exception as e:
logger.error(f"{self.log_prefix} 动作修改失败: {e}")
#如果normal开始一个回复生成进程先准备好回复其实是和planer同时进行的
if self.loop_mode == "normal":
person_info_manager = get_person_info_manager()
person_id = person_info_manager.get_person_id(
message_data.get("chat_info_platform"), message_data.get("user_id")
)
person_name = await person_info_manager.get_value(person_id, "person_name")
reply_to_str = f"{person_name}:{message_data.get('processed_plain_text')}"
reply_to_str = await self.build_reply_to_str(message_data)
gen_task = asyncio.create_task(self._generate_response(message_data, available_actions,reply_to_str))
with Timer("规划器", cycle_timers):
if self.loop_mode == "focus":
if self.action_modifier.should_skip_planning_for_no_reply():
logger.info(f"[{self.log_prefix}] 没有可用动作,跳过规划")
action_type = "no_reply"
else:
plan_result = await self.action_planner.plan(mode="focus")
elif self.loop_mode == "normal":
if self.action_modifier.should_skip_planning_for_no_action():
logger.info(f"[{self.log_prefix}] 没有可用动作,跳过规划")
action_type = "no_action"
else:
plan_result = await self.action_planner.plan(mode="normal")
plan_result = await self.action_planner.plan(mode=self.loop_mode)
@@ -445,9 +430,7 @@ class HeartFChatting:
else:
success, reply_text = result
command = ""
command = self._count_reply_and_exit_focus_chat(action,success)
if reply_text == "timeout":
self.reply_timeout_count += 1
if self.reply_timeout_count > 5:
@@ -464,30 +447,6 @@ class HeartFChatting:
traceback.print_exc()
return False, "", ""
def _count_reply_and_exit_focus_chat(self,action,success):
# 新增:消息计数和疲惫检查
if action == "reply" and success:
self._message_count += 1
current_threshold = max(10, int(30 / global_config.chat.exit_focus_threshold))
logger.info(
f"{self.log_prefix} 已发送第 {self._message_count} 条消息(动态阈值: {current_threshold}, exit_focus_threshold: {global_config.chat.exit_focus_threshold}"
)
# 检查是否达到疲惫阈值只有在auto模式下才会自动退出
if (
global_config.chat.chat_mode == "auto"
and self._message_count >= current_threshold
and not self._fatigue_triggered
):
self._fatigue_triggered = True
logger.info(
f"{self.log_prefix} [auto模式] 已发送 {self._message_count} 条消息,达到疲惫阈值 {current_threshold},麦麦感到疲惫了,准备退出专注聊天模式"
)
# 设置系统命令,在下次循环检查时触发退出
command = "stop_focus_chat"
return command
return ""
async def shutdown(self):
@@ -638,7 +597,7 @@ class HeartFChatting:
f"{message_data.get('processed_plain_text')}[兴趣:{interested_rate:.2f}][回复概率:{reply_probability * 100:.1f}%]"
)
if random() < reply_probability:
if random.random() < reply_probability:
await self.willing_manager.before_generate_reply_handle(message_data.get("message_id"))
await self._observe(message_data = message_data)

View File

@@ -8,7 +8,6 @@ from src.chat.message_receive.chat_stream import get_chat_manager
from src.chat.message_receive.message import MessageRecv
from src.experimental.only_message_process import MessageProcessor
from src.chat.message_receive.storage import MessageStorage
from src.experimental.PFC.pfc_manager import PFCManager
from src.chat.heart_flow.heartflow_message_processor import HeartFCMessageReceiver
from src.chat.utils.prompt_builder import Prompt, global_prompt_manager
from src.config.config import global_config
@@ -82,7 +81,6 @@ class ChatBot:
# 创建初始化PFC管理器的任务会在_ensure_started时执行
self.only_process_chat = MessageProcessor()
self.pfc_manager = PFCManager.get_instance()
self.s4u_message_processor = S4UMessageProcessor()
async def _ensure_started(self):

View File

@@ -181,29 +181,6 @@ class ActionManager:
"""获取当前正在使用的动作集合"""
return self._using_actions.copy()
def get_using_actions_for_mode(self, mode: str) -> Dict[str, ActionInfo]:
"""
根据聊天模式获取可用的动作集合
Args:
mode: 聊天模式 ("focus", "normal", "all")
Returns:
Dict[str, ActionInfo]: 在指定模式下可用的动作集合
"""
filtered_actions = {}
for action_name, action_info in self._using_actions.items():
action_mode = action_info.get("mode_enable", "all")
# 检查动作是否在当前模式下启用
if action_mode == "all" or action_mode == mode:
filtered_actions[action_name] = action_info
logger.debug(f"动作 {action_name} 在模式 {mode} 下可用 (mode_enable: {action_mode})")
logger.debug(f"模式 {mode} 下可用动作: {list(filtered_actions.keys())}")
return filtered_actions
def add_action_to_using(self, action_name: str) -> bool:
"""
添加已注册的动作到当前使用的动作集

View File

@@ -44,7 +44,6 @@ class ActionModifier:
async def modify_actions(
self,
history_loop=None,
mode: str = "focus",
message_content: str = "",
):
"""
@@ -62,7 +61,7 @@ class ActionModifier:
removals_s2 = []
self.action_manager.restore_actions()
all_actions = self.action_manager.get_using_actions_for_mode(mode)
all_actions = self.action_manager.get_using_actions()
message_list_before_now_half = get_raw_msg_before_timestamp_with_chat(
chat_id=self.chat_stream.stream_id,
@@ -82,10 +81,10 @@ class ActionModifier:
chat_content = chat_content + "\n" + f"现在,最新的消息是:{message_content}"
# === 第一阶段:传统观察处理 ===
if history_loop:
removals_from_loop = await self.analyze_loop_actions(history_loop)
if removals_from_loop:
removals_s1.extend(removals_from_loop)
# if history_loop:
# removals_from_loop = await self.analyze_loop_actions(history_loop)
# if removals_from_loop:
# removals_s1.extend(removals_from_loop)
# 检查动作的关联类型
chat_context = self.chat_stream.context
@@ -104,12 +103,11 @@ class ActionModifier:
logger.debug(f"{self.log_prefix}开始激活类型判定阶段")
# 获取当前使用的动作集(经过第一阶段处理)
current_using_actions = self.action_manager.get_using_actions_for_mode(mode)
current_using_actions = self.action_manager.get_using_actions()
# 获取因激活类型判定而需要移除的动作
removals_s2 = await self._get_deactivated_actions_by_type(
current_using_actions,
mode,
chat_content,
)
@@ -124,7 +122,7 @@ class ActionModifier:
removals_summary = " | ".join([f"{name}({reason})" for name, reason in all_removals])
logger.info(
f"{self.log_prefix}{mode}模式动作修改流程结束,最终可用动作: {list(self.action_manager.get_using_actions_for_mode(mode).keys())}||移除记录: {removals_summary}"
f"{self.log_prefix} 动作修改流程结束,最终可用动作: {list(self.action_manager.get_using_actions().keys())}||移除记录: {removals_summary}"
)
def _check_action_associated_types(self, all_actions, chat_context):
@@ -141,7 +139,6 @@ class ActionModifier:
async def _get_deactivated_actions_by_type(
self,
actions_with_info: Dict[str, Any],
mode: str = "focus",
chat_content: str = "",
) -> List[tuple[str, str]]:
"""
@@ -163,7 +160,7 @@ class ActionModifier:
random.shuffle(actions_to_check)
for action_name, action_info in actions_to_check:
activation_type = f"{mode}_activation_type"
activation_type = "focus_activation_type"
activation_type = action_info.get(activation_type, "always")
if activation_type == "always":
@@ -186,6 +183,11 @@ class ActionModifier:
elif activation_type == "llm_judge":
llm_judge_actions[action_name] = action_info
elif activation_type == "never":
reason = f"激活类型为never"
deactivated_actions.append((action_name, reason))
logger.debug(f"{self.log_prefix}未激活动作: {action_name},原因: 激活类型为never")
else:
logger.warning(f"{self.log_prefix}未知的激活类型: {activation_type},跳过处理")
@@ -203,35 +205,6 @@ class ActionModifier:
return deactivated_actions
async def process_actions_for_planner(
self, observed_messages_str: str = "", chat_context: Optional[str] = None, extra_context: Optional[str] = None
) -> Dict[str, Any]:
"""
[已废弃] 此方法现在已被整合到 modify_actions() 中
为了保持向后兼容性而保留,但建议直接使用 ActionManager.get_using_actions()
规划器应该直接从 ActionManager 获取最终的可用动作集,而不是调用此方法
新的架构:
1. 主循环调用 modify_actions() 处理完整的动作管理流程
2. 规划器直接使用 ActionManager.get_using_actions() 获取最终动作集
"""
logger.warning(
f"{self.log_prefix}process_actions_for_planner() 已废弃,建议规划器直接使用 ActionManager.get_using_actions()"
)
# 为了向后兼容,仍然返回当前使用的动作集
current_using_actions = self.action_manager.get_using_actions()
all_registered_actions = self.action_manager.get_registered_actions()
# 构建完整的动作信息
result = {}
for action_name in current_using_actions.keys():
if action_name in all_registered_actions:
result[action_name] = all_registered_actions[action_name]
return result
def _generate_context_hash(self, chat_content: str) -> str:
"""生成上下文的哈希值用于缓存"""
context_content = f"{chat_content}"

View File

@@ -76,7 +76,7 @@ class ActionPlanner:
self.last_obs_time_mark = 0.0
async def plan(self,mode: str = "focus") -> Dict[str, Any]:
async def plan(self,mode:str = "focus") -> Dict[str, Any]:
"""
规划器 (Planner): 使用LLM根据上下文决定做出什么动作。
"""
@@ -91,7 +91,7 @@ class ActionPlanner:
is_group_chat, chat_target_info = get_chat_type_and_target_info(self.chat_id)
logger.debug(f"{self.log_prefix}获取到聊天信息 - 群聊: {is_group_chat}, 目标信息: {chat_target_info}")
current_available_actions_dict = self.action_manager.get_using_actions_for_mode(mode)
current_available_actions_dict = self.action_manager.get_using_actions()
# 获取完整的动作信息
all_registered_actions = self.action_manager.get_registered_actions()
@@ -247,7 +247,23 @@ class ActionPlanner:
if mode == "focus":
by_what = "聊天内容"
no_action_block = ""
no_action_block = """重要说明1
- 'no_reply' 表示只进行不进行回复,等待合适的回复时机
- 当你刚刚发送了消息没有人回复时选择no_reply
- 当你一次发送了太多消息为了避免打扰聊天节奏选择no_reply
动作reply
动作描述:参与聊天回复,发送文本进行表达
- 你想要闲聊或者随便附和
- 有人提到你
- 如果你刚刚进行了回复,不要对同一个话题重复回应
{
"action": "reply",
"reply_to":"你要回复的对方的发言内容,格式:(用户名:发言内容可以为none"
"reason":"回复的原因"
}
"""
else:
by_what = "聊天内容和用户的最新消息"
no_action_block = """重要说明:

View File

@@ -29,6 +29,8 @@ from src.tools.tool_executor import ToolExecutor
logger = get_logger("replyer")
ENABLE_S2S_MODE = True
def init_prompt():
Prompt("你正在qq群里聊天下面是群里在聊的内容", "chat_target_group1")
@@ -504,13 +506,14 @@ class DefaultReplyer:
show_actions=True,
)
message_list_before_now_half = get_raw_msg_before_timestamp_with_chat(
message_list_before_short = get_raw_msg_before_timestamp_with_chat(
chat_id=chat_id,
timestamp=time.time(),
limit=int(global_config.chat.max_context_size * 0.5),
limit=int(global_config.chat.max_context_size * 0.33),
)
chat_talking_prompt_half = build_readable_messages(
message_list_before_now_half,
chat_talking_prompt_short = build_readable_messages(
message_list_before_short,
replace_bot_name=True,
merge_messages=False,
timestamp_mode="relative",
@@ -521,14 +524,14 @@ class DefaultReplyer:
# 并行执行四个构建任务
task_results = await asyncio.gather(
self._time_and_run_task(
self.build_expression_habits(chat_talking_prompt_half, target), "build_expression_habits"
self.build_expression_habits(chat_talking_prompt_short, target), "build_expression_habits"
),
self._time_and_run_task(
self.build_relation_info(reply_data, chat_talking_prompt_half), "build_relation_info"
self.build_relation_info(reply_data, chat_talking_prompt_short), "build_relation_info"
),
self._time_and_run_task(self.build_memory_block(chat_talking_prompt_half, target), "build_memory_block"),
self._time_and_run_task(self.build_memory_block(chat_talking_prompt_short, target), "build_memory_block"),
self._time_and_run_task(
self.build_tool_info(reply_data, chat_talking_prompt_half, enable_tool=enable_tool), "build_tool_info"
self.build_tool_info(reply_data, chat_talking_prompt_short, enable_tool=enable_tool), "build_tool_info"
),
)