refactor(chat): 重构主动思考模块以提升回复质量和逻辑清晰度(哪个大聪明把我联网搜索烦了)
将主动思考流程拆分为两个主要阶段:规划和内容生成。 在规划阶段(`ActionPlanner`),模型现在会结合最新的聊天上下文来决定是否发起主动对话,并确定一个合适的主题。这使得决策更加贴近当前对话氛围。 在内容生成阶段(`ProactiveThinker`),系统会围绕规划好的主题,主动搜集相关实时信息(如日程、网络资讯),并结合角色设定、心情和聊天历史,构建一个更丰富、更具上下文情境的提示词,从而生成更自然、更有趣的主动回复。 主要变更: - `ActionPlanner` 在主动模式下增加对近期聊天记录的分析,决策更精准。 - `ProactiveThinker` 新增 `_generate_proactive_content_and_send` 方法,负责整合多源信息(日程、搜索、上下文)生成最终回复。 - 简化了 `ProactiveThinker` 的主逻辑,使其专注于执行 `proactive_reply` 动作,而非处理多种动作类型。 - 优化了相关提示词,使其更专注于生成高质量的主动对话内容。
This commit is contained in:
committed by
Windpicker-owo
parent
5f1fd4305e
commit
667be49a95
@@ -1,12 +1,19 @@
|
||||
import time
|
||||
import traceback
|
||||
from typing import TYPE_CHECKING
|
||||
import orjson
|
||||
from typing import TYPE_CHECKING, Dict, Any
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.plugin_system.base.component_types import ChatMode
|
||||
from ..hfc_context import HfcContext
|
||||
from .events import ProactiveTriggerEvent
|
||||
from src.plugin_system.apis import generator_api
|
||||
from src.schedule.schedule_manager import schedule_manager
|
||||
from src.plugin_system import tool_api
|
||||
from src.plugin_system.base.component_types import ComponentType
|
||||
from src.config.config import global_config
|
||||
from src.chat.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat, build_readable_messages_with_id
|
||||
from src.mood.mood_manager import mood_manager
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..cycle_processor import CycleProcessor
|
||||
@@ -20,6 +27,7 @@ class ProactiveThinker:
|
||||
当接收到 ProactiveTriggerEvent 时,它会根据事件内容进行一系列决策和操作,
|
||||
例如调整情绪、调用规划器生成行动,并最终可能产生一个主动的回复。
|
||||
"""
|
||||
|
||||
def __init__(self, context: HfcContext, cycle_processor: "CycleProcessor"):
|
||||
"""
|
||||
初始化主动思考器。
|
||||
@@ -75,9 +83,6 @@ class ProactiveThinker:
|
||||
return
|
||||
|
||||
try:
|
||||
# 动态导入情绪管理器,避免循环依赖
|
||||
from src.mood.mood_manager import mood_manager
|
||||
|
||||
# 获取当前聊天的情绪对象
|
||||
mood_obj = mood_manager.get_mood_by_chat_id(self.context.stream_id)
|
||||
new_mood = None
|
||||
@@ -112,29 +117,17 @@ class ProactiveThinker:
|
||||
"""
|
||||
try:
|
||||
# 调用规划器的 PROACTIVE 模式,让其决定下一步的行动
|
||||
actions, target_message = await self.cycle_processor.action_planner.plan(mode=ChatMode.PROACTIVE)
|
||||
actions, _ = await self.cycle_processor.action_planner.plan(mode=ChatMode.PROACTIVE)
|
||||
|
||||
# 通常只关心规划出的第一个动作
|
||||
action_result = actions[0] if actions else {}
|
||||
|
||||
# 检查规划出的动作是否是“什么都不做”
|
||||
if action_result and action_result.get("action_type") != "do_nothing":
|
||||
# 如果动作是“回复”
|
||||
if action_result.get("action_type") == "reply":
|
||||
# 调用生成器API来创建回复内容
|
||||
success, response_set, _ = await generator_api.generate_reply(
|
||||
chat_stream=self.context.chat_stream,
|
||||
reply_message=action_result["action_message"],
|
||||
available_actions={}, # 主动回复不考虑工具使用
|
||||
enable_tool=False,
|
||||
request_type="chat.replyer.proactive", # 标记请求类型
|
||||
from_plugin=False,
|
||||
)
|
||||
# 如果成功生成回复,则发送出去
|
||||
if success and response_set:
|
||||
await self.cycle_processor.response_handler.send_response(
|
||||
response_set, time.time(), action_result["action_message"]
|
||||
)
|
||||
action_type = action_result.get("action_type")
|
||||
|
||||
if action_type == "proactive_reply":
|
||||
await self._generate_proactive_content_and_send(action_result)
|
||||
elif action_type != "do_nothing":
|
||||
logger.warning(f"{self.context.log_prefix} 主动思考返回了未知的动作类型: {action_type}")
|
||||
else:
|
||||
# 如果规划结果是“什么都不做”,则记录日志
|
||||
logger.info(f"{self.context.log_prefix} 主动思考决策: 保持沉默")
|
||||
@@ -142,3 +135,98 @@ class ProactiveThinker:
|
||||
except Exception as e:
|
||||
logger.error(f"{self.context.log_prefix} 主动思考执行异常: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
async def _generate_proactive_content_and_send(self, action_result: Dict[str, Any]):
|
||||
"""
|
||||
获取实时信息,构建最终的生成提示词,并生成和发送主动回复。
|
||||
|
||||
Args:
|
||||
action_result (Dict[str, Any]): 规划器返回的动作结果。
|
||||
"""
|
||||
try:
|
||||
topic = action_result.get("action_data", {}).get("topic", "随便聊聊")
|
||||
logger.info(f"{self.context.log_prefix} 主动思考确定主题: '{topic}'")
|
||||
|
||||
# 1. 获取日程信息
|
||||
schedule_block = "你今天没有日程安排。"
|
||||
if global_config.planning_system.schedule_enable:
|
||||
if current_activity := schedule_manager.get_current_activity():
|
||||
schedule_block = f"你当前正在:{current_activity}。"
|
||||
|
||||
# 2. 网络搜索
|
||||
news_block = "暂时没有获取到最新资讯。"
|
||||
try:
|
||||
web_search_tool = tool_api.get_tool_instance("web_search")
|
||||
if web_search_tool:
|
||||
tool_args = {"query": topic, "max_results": 10}
|
||||
# 调用工具,并传递参数
|
||||
search_result_dict = await web_search_tool.execute(**tool_args)
|
||||
if search_result_dict and not search_result_dict.get("error"):
|
||||
news_block = search_result_dict.get("content", "未能提取有效资讯。")
|
||||
else:
|
||||
logger.warning(f"{self.context.log_prefix} 网络搜索返回错误: {search_result_dict.get('error')}")
|
||||
else:
|
||||
logger.warning(f"{self.context.log_prefix} 未找到 web_search 工具实例。")
|
||||
except Exception as e:
|
||||
logger.error(f"{self.context.log_prefix} 主动思考时网络搜索失败: {e}")
|
||||
|
||||
# 3. 获取最新的聊天上下文
|
||||
message_list = get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=self.context.stream_id,
|
||||
timestamp=time.time(),
|
||||
limit=int(global_config.chat.max_context_size * 0.3),
|
||||
)
|
||||
chat_context_block, _ = build_readable_messages_with_id(messages=message_list)
|
||||
|
||||
# 4. 构建最终的生成提示词
|
||||
bot_name = global_config.bot.nickname
|
||||
identity_block = f"你的名字是{bot_name},你{global_config.personality.personality_core}:"
|
||||
mood_block = f"你现在的心情是:{mood_manager.get_mood_by_chat_id(self.context.stream_id).mood_state}"
|
||||
|
||||
final_prompt = f"""
|
||||
# 主动对话生成
|
||||
|
||||
## 你的角色
|
||||
{identity_block}
|
||||
|
||||
## 你的心情
|
||||
{mood_block}
|
||||
|
||||
## 你今天的日程安排
|
||||
{schedule_block}
|
||||
|
||||
## 关于你准备讨论的话题“{topic}”的最新信息
|
||||
{news_block}
|
||||
|
||||
## 最近的聊天内容
|
||||
{chat_context_block}
|
||||
|
||||
## 任务
|
||||
你之前决定要发起一个关于“{topic}”的对话。现在,请结合以上所有信息,自然地开启这个话题。
|
||||
|
||||
## 要求
|
||||
- 你的发言要听起来像是自发的,而不是在念报告。
|
||||
- 巧妙地将日程安排或最新信息融入到你的开场白中。
|
||||
- 风格要符合你的角色设定。
|
||||
- 直接输出你想要说的内容,不要包含其他额外信息。
|
||||
"""
|
||||
|
||||
# 5. 调用生成器API并发送
|
||||
response_text = await generator_api.generate_response_custom(
|
||||
chat_stream=self.context.chat_stream,
|
||||
prompt=final_prompt,
|
||||
request_type="chat.replyer.proactive",
|
||||
)
|
||||
|
||||
if response_text:
|
||||
# 将纯文本包装成 ResponseSet 格式
|
||||
response_set = [{"type": "text", "data": {"text": response_text}}]
|
||||
await self.cycle_processor.response_handler.send_response(
|
||||
response_set, time.time(), action_result.get("action_message")
|
||||
)
|
||||
else:
|
||||
logger.error(f"{self.context.log_prefix} 主动思考生成回复失败。")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"{self.context.log_prefix} 生成主动回复内容时异常: {e}")
|
||||
logger.error(traceback.format_exc())
|
||||
|
||||
@@ -90,12 +90,31 @@ def init_prompt():
|
||||
## 长期记忆摘要
|
||||
{long_term_memory_block}
|
||||
|
||||
## 最近的聊天内容
|
||||
{chat_content_block}
|
||||
|
||||
## 任务
|
||||
基于以上所有信息,分析当前情况,决定是否需要主动做些什么。
|
||||
如果你认为不需要,就选择 'do_nothing'。
|
||||
基于以上所有信息(特别是最近的聊天内容),分析当前情况,决定是否适合主动开启一个**新的、但又与当前氛围相关**的话题。
|
||||
|
||||
## 可用动作
|
||||
{action_options_text}
|
||||
动作:proactive_reply
|
||||
动作描述:在当前对话的基础上,主动发起一个新的对话,分享一个有趣的想法、见闻或者对未来的计划。
|
||||
- 当你觉得可以说些什么来活跃气氛,并且内容与当前聊天氛围不冲突时
|
||||
- 当你有一些新的想法或计划想要分享,并且可以自然地衔接当前话题时
|
||||
{{
|
||||
"action": "proactive_reply",
|
||||
"reason": "决定主动发起对话的具体原因",
|
||||
"topic": "你想要发起对话的主题或内容(需要简洁)"
|
||||
}}
|
||||
|
||||
动作:do_nothing
|
||||
动作描述:保持沉默,不主动发起任何动作或对话。
|
||||
- 当你分析了所有信息后,觉得当前不是一个发起互动的好时机时
|
||||
- 当最近的聊天内容很连贯,你的插入会打断别人时
|
||||
{{
|
||||
"action": "do_nothing",
|
||||
"reason":"决定保持沉默的具体原因"
|
||||
}}
|
||||
|
||||
你必须从上面列出的可用action中选择一个。
|
||||
请以严格的 JSON 格式输出,且仅包含 JSON 内容:
|
||||
@@ -643,7 +662,19 @@ class ActionPlanner:
|
||||
# --- 根据模式构建不同的Prompt ---
|
||||
if mode == ChatMode.PROACTIVE:
|
||||
long_term_memory_block = await self._get_long_term_memory_context()
|
||||
action_options_text = await self._build_action_options(current_available_actions, mode)
|
||||
|
||||
# 获取最近的聊天记录用于主动思考决策
|
||||
message_list_short = get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=self.chat_id,
|
||||
timestamp=time.time(),
|
||||
limit=int(global_config.chat.max_context_size * 0.2), # 主动思考时只看少量最近消息
|
||||
)
|
||||
chat_content_block, _ = build_readable_messages_with_id(
|
||||
messages=message_list_short,
|
||||
timestamp_mode="normal",
|
||||
truncate=False,
|
||||
show_actions=False,
|
||||
)
|
||||
|
||||
prompt_template = await global_prompt_manager.get_prompt_async("proactive_planner_prompt")
|
||||
prompt = prompt_template.format(
|
||||
@@ -652,7 +683,7 @@ class ActionPlanner:
|
||||
schedule_block=schedule_block,
|
||||
mood_block=mood_block,
|
||||
long_term_memory_block=long_term_memory_block,
|
||||
action_options_text=action_options_text,
|
||||
chat_content_block=chat_content_block or "最近没有聊天内容。",
|
||||
)
|
||||
return prompt, []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user