feat: 为normal增加action_plan能力

This commit is contained in:
tcmofashi
2025-06-02 21:06:00 +08:00
parent 13c3a40ca5
commit d932b48444
11 changed files with 867 additions and 21 deletions

View File

@@ -20,6 +20,10 @@ from src.chat.emoji_system.emoji_manager import emoji_manager
from src.chat.normal_chat.willing.willing_manager import willing_manager
from src.chat.normal_chat.normal_chat_utils import get_recent_message_stats
from src.config.config import global_config
from src.chat.focus_chat.planners.action_manager import ActionManager
from src.chat.normal_chat.normal_chat_planner import NormalChatPlanner
from src.chat.normal_chat.normal_chat_action_modifier import NormalChatActionModifier
from src.chat.normal_chat.normal_chat_expressor import NormalChatExpressor
logger = get_logger("normal_chat")
@@ -48,6 +52,12 @@ class NormalChat:
self._chat_task: Optional[asyncio.Task] = None
self._initialized = False # Track initialization status
# Planner相关初始化
self.action_manager = ActionManager()
self.planner = NormalChatPlanner(self.stream_name, self.action_manager)
self.action_modifier = NormalChatActionModifier(self.action_manager, self.stream_id, self.stream_name)
self.enable_planner = global_config.normal_chat.enable_planner # 从配置中读取是否启用planner
# 记录最近的回复内容,每项包含: {time, user_message, response, is_mentioned, is_reference_reply}
self.recent_replies = []
self.max_replies_history = 20 # 最多保存最近20条回复记录
@@ -64,6 +74,10 @@ class NormalChat:
self.is_group_chat, self.chat_target_info = await get_chat_type_and_target_info(self.stream_id)
self.stream_name = chat_manager.get_stream_name(self.stream_id) or self.stream_id
# 初始化Normal Chat专用表达器
self.expressor = NormalChatExpressor(self.chat_stream, self.stream_name)
self._initialized = True
logger.debug(f"[{self.stream_name}] NormalChat 初始化完成 (异步部分)。")
@@ -281,19 +295,108 @@ class NormalChat:
info_catcher = info_catcher_manager.get_info_catcher(thinking_id)
info_catcher.catch_decide_to_response(message)
try:
with Timer("生成回复", timing_results):
response_set = await self.gpt.generate_response(
# 定义并行执行的任务
async def generate_normal_response():
"""生成普通回复"""
try:
# 如果启用planner获取可用actions
enable_planner = self.enable_planner
available_actions = None
if enable_planner:
try:
await self.action_modifier.modify_actions_for_normal_chat(
self.chat_stream, self.recent_replies
)
available_actions = self.action_manager.get_using_actions()
except Exception as e:
logger.warning(f"[{self.stream_name}] 获取available_actions失败: {e}")
available_actions = None
return await self.gpt.generate_response(
message=message,
thinking_id=thinking_id,
enable_planner=enable_planner,
available_actions=available_actions,
)
except Exception as e:
logger.error(f"[{self.stream_name}] 回复生成出现错误:{str(e)} {traceback.format_exc()}")
return None
info_catcher.catch_after_generate_response(timing_results["生成回复"])
except Exception as e:
logger.error(f"[{self.stream_name}] 回复生成出现错误:{str(e)} {traceback.format_exc()}")
response_set = None # 确保出错时 response_set 为 None
async def plan_and_execute_actions():
"""规划和执行额外动作"""
if not self.enable_planner:
logger.debug(f"[{self.stream_name}] Planner未启用跳过动作规划")
return None
if not response_set:
try:
# 并行执行动作修改和规划准备
async def modify_actions():
"""修改可用动作集合"""
return await self.action_modifier.modify_actions_for_normal_chat(
self.chat_stream, self.recent_replies
)
async def prepare_planning():
"""准备规划所需的信息"""
return self._get_sender_name(message)
# 并行执行动作修改和准备工作
_, sender_name = await asyncio.gather(modify_actions(), prepare_planning())
# 检查是否应该跳过规划
if self.action_modifier.should_skip_planning():
logger.debug(f"[{self.stream_name}] 没有可用动作,跳过规划")
return None
# 执行规划
plan_result = await self.planner.plan(message, sender_name)
action_type = plan_result["action_result"]["action_type"]
action_data = plan_result["action_result"]["action_data"]
reasoning = plan_result["action_result"]["reasoning"]
logger.info(f"[{self.stream_name}] Planner决策: {action_type}, 理由: {reasoning}")
self.action_type = action_type # 更新实例属性
# 如果规划器决定不执行任何动作
if action_type == "no_action":
logger.debug(f"[{self.stream_name}] Planner决定不执行任何额外动作")
return None
# 执行额外的动作(不影响回复生成)
action_result = await self._execute_action(action_type, action_data, message, thinking_id)
if action_result is not None:
logger.info(f"[{self.stream_name}] 额外动作 {action_type} 执行完成")
else:
logger.warning(f"[{self.stream_name}] 额外动作 {action_type} 执行失败")
return {"action_type": action_type, "action_data": action_data, "reasoning": reasoning}
except Exception as e:
logger.error(f"[{self.stream_name}] Planner执行失败: {e}")
return None
# 并行执行回复生成和动作规划
self.action_type = None # 初始化动作类型
with Timer("并行生成回复和规划", timing_results):
response_set, plan_result = await asyncio.gather(
generate_normal_response(), plan_and_execute_actions(), return_exceptions=True
)
# 处理生成回复的结果
if isinstance(response_set, Exception):
logger.error(f"[{self.stream_name}] 回复生成异常: {response_set}")
response_set = None
elif response_set:
info_catcher.catch_after_generate_response(timing_results["并行生成回复和规划"])
# 处理规划结果(可选,不影响回复)
if isinstance(plan_result, Exception):
logger.error(f"[{self.stream_name}] 动作规划异常: {plan_result}")
elif plan_result:
logger.debug(f"[{self.stream_name}] 额外动作处理完成: {plan_result['action_type']}")
if not response_set or (self.enable_planner and self.action_type != "no_action"):
logger.info(f"[{self.stream_name}] 模型未生成回复内容")
# 如果模型未生成回复,移除思考消息
container = await message_manager.get_container(self.stream_id) # 使用 self.stream_id
@@ -523,3 +626,59 @@ class NormalChat:
self.willing_amplifier = 5
elif self.willing_amplifier < 0.1:
self.willing_amplifier = 0.1
def _get_sender_name(self, message: MessageRecv) -> str:
"""获取发送者名称用于planner"""
if message.chat_stream.user_info:
user_info = message.chat_stream.user_info
if user_info.user_cardname and user_info.user_nickname:
return f"[{user_info.user_nickname}][群昵称:{user_info.user_cardname}]"
elif user_info.user_nickname:
return f"[{user_info.user_nickname}]"
else:
return f"用户({user_info.user_id})"
return "某人"
async def _execute_action(
self, action_type: str, action_data: dict, message: MessageRecv, thinking_id: str
) -> Optional[bool]:
"""执行具体的动作,只返回执行成功与否"""
try:
# 创建动作处理器实例
action_handler = self.action_manager.create_action(
action_name=action_type,
action_data=action_data,
reasoning=action_data.get("reasoning", ""),
cycle_timers={}, # normal_chat使用空的cycle_timers
thinking_id=thinking_id,
observations=[], # normal_chat不使用observations
expressor=self.expressor, # 使用normal_chat专用的expressor
chat_stream=self.chat_stream,
log_prefix=self.stream_name,
shutting_down=self._disabled,
)
if action_handler:
# 执行动作
result = await action_handler.handle_action()
if result and isinstance(result, tuple) and len(result) >= 2:
# handle_action返回 (success: bool, message: str)
success, _ = result[0], result[1]
return success
elif result:
# 如果返回了其他结果,假设成功
return True
except Exception as e:
logger.error(f"[{self.stream_name}] 执行动作 {action_type} 失败: {e}")
return False
def set_planner_enabled(self, enabled: bool):
"""设置是否启用planner"""
self.enable_planner = enabled
logger.info(f"[{self.stream_name}] Planner {'启用' if enabled else '禁用'}")
def get_action_manager(self) -> ActionManager:
"""获取动作管理器实例"""
return self.action_manager