总之就是成了!😋😋😋主动思考终于成了

This commit is contained in:
tt-P607
2025-09-09 13:53:17 +08:00
committed by Windpicker-owo
parent dcc67bc9e1
commit 85bfbeb57b
5 changed files with 133 additions and 149 deletions

View File

@@ -122,53 +122,67 @@ class ProactiveThinker:
try:
# 如果是提醒事件,跳过规划器,直接构建默认动作
if trigger_event.source == "reminder_system":
# 1. 获取原始消息上下文
action_message = {}
if trigger_event.related_message_id:
# 直接将从数据库获取的完整消息记录作为 action_message
action_message = await db_get(
Messages, {"message_id": trigger_event.related_message_id}, single_result=True
) or {}
# 1. 获取上下文信息
metadata = trigger_event.metadata or {}
action_message = metadata
reminder_content = trigger_event.reason.replace("定时提醒:", "").strip()
# 2. 智能确定@对象
reason_text = trigger_event.reason.replace("定时提醒:", "").strip()
user_name_match = re.search(r"艾特一下(\S+)", reason_text)
if user_name_match:
user_name = user_name_match.group(1)
at_message = reason_text.replace(f"艾特一下{user_name}", "").strip()
elif action_message.get("user_nickname"):
user_name = action_message.get("user_nickname")
at_message = reason_text
# 2. 确定目标用户名
target_user_name = None
match = re.search(r"艾特一下([^,\s]+)", reminder_content)
if match:
target_user_name = match.group(1)
else:
user_name = ""
at_message = reason_text
from src.person_info.person_info import get_person_info_manager
user_id = metadata.get("user_id")
platform = metadata.get("platform")
if user_id and platform:
person_id = get_person_info_manager().get_person_id(platform, user_id)
target_user_name = await get_person_info_manager().get_value(person_id, "person_name")
if not target_user_name:
logger.warning(f"无法从提醒 '{reminder_content}' 中确定目标用户,回退")
raise Exception("无法确定目标用户")
# 3. 构建动作
action_result = {
"action_type": "at_user",
"reasoning": "执行定时提醒",
"action_data": {
"user_name": user_name,
"at_message": at_message or "时间到啦!"
"user_name": target_user_name,
"at_message": reminder_content
},
"action_message": action_message
}
# 4. 执行或回退
try:
success, _, _ = await self.cycle_processor._handle_action(
original_chat_id = metadata.get("chat_id")
if not original_chat_id:
if trigger_event.related_message_id:
db_message = await db_get(Messages, {"message_id": trigger_event.related_message_id}, single_result=True) or {}
original_chat_id = db_message.get("chat_id")
if not original_chat_id:
raise Exception("提醒事件中缺少chat_id")
from src.chat.heart_flow.heartflow import heartflow
subflow = await heartflow.get_or_create_subheartflow(original_chat_id)
if not subflow:
raise Exception(f"无法为chat_id {original_chat_id} 获取subflow")
success, _, _ = await subflow.heart_fc_instance.cycle_processor._handle_action(
action=action_result["action_type"],
reasoning=action_result["reasoning"],
action_data=action_result["action_data"],
cycle_timers={},
thinking_id="",
action_message=action_result["action_message"]
action_message=action_result["action_message"],
)
if not success:
raise Exception("at_user action failed")
except Exception:
logger.warning(f"{self.context.log_prefix} at_user动作执行失败回退到proactive_reply")
except Exception as e:
logger.warning(f"{self.context.log_prefix} at_user动作执行失败: {e}回退到proactive_reply")
fallback_action = {
"action_type": "proactive_reply",
"action_data": {"topic": trigger_event.reason},

View File

@@ -100,7 +100,7 @@ class SmartReminderAnalyzer:
请判断用户是否想要设置提醒,如果是,请提取:
1. 是否包含提醒请求 (has_reminder: true/false)
2. 置信度 (confidence: 0.0-1.0)
3. 相对时间表达 (relative_time: "3分钟后", "2小时后")
3. 相对时间表达 (relative_time: 标准化的时间表达,例如将'半小时后'转换为'30分钟后', '明天下午三点'转换为'明天15点')
4. 提醒内容 (content: 提醒的具体内容)
5. 分析原因 (reasoning: 判断理由)
@@ -108,7 +108,7 @@ class SmartReminderAnalyzer:
{{
"has_reminder": true/false,
"confidence": 0.0-1.0,
"relative_time": "时间表达",
"relative_time": "标准化的时间表达 (例如 '30分钟后', '2小时后')",
"content": "提醒内容",
"reasoning": "判断理由"
}}"""
@@ -152,7 +152,7 @@ class SmartReminderAnalyzer:
logger.info(f"备用解析成功: {result}")
return result
except Exception as fallback_error:
logger.error(f"备用JSON解析也失败: {fallback_error}")
logger.error(f"备用JSON解析也失败: {fallback_error}")
except Exception as e:
logger.error(f"LLM分析失败: {e}")

View File

@@ -130,9 +130,9 @@ class HeartFCMessageReceiver:
# 获取对应的subheartflow实例
from src.chat.heart_flow.heartflow import heartflow
subflow = await heartflow.get_or_create_subheartflow(chat.stream_id)
subflow = await heartflow.get_or_create_subheartflow(metadata.get("chat_id"))
if not subflow:
logger.error(f"无法获取subheartflow实例: {chat.stream_id}")
logger.error(f"无法获取subheartflow实例: {metadata.get('chat_id')}")
return
# 创建主动思考事件,触发完整的思考流程
@@ -142,11 +142,9 @@ class HeartFCMessageReceiver:
event = ProactiveTriggerEvent(
source="reminder_system",
reason=f"定时提醒:{reminder_content}",
metadata={
"reminder_text": reminder_content,
"trigger_time": datetime.now().isoformat()
}
)
metadata=metadata,
related_message_id=metadata.get("original_message_id")
)
# 通过subflow的HeartFChatting实例触发主动思考
await subflow.heart_fc_instance.proactive_thinker.think(event)
@@ -160,10 +158,11 @@ class HeartFCMessageReceiver:
# Fallback: 如果主动思考失败,直接发送提醒消息
try:
from src.plugin_system.apis.send_api import text_to_stream
reminder_content = metadata.get('content', '提醒时间到了')
await text_to_stream(
text=f"⏰ 提醒:{reminder_content}",
stream_id=chat.stream_id,
stream_id=metadata.get("chat_id"),
typing=False
)
logger.info(f"Fallback提醒消息已发送: {reminder_content}")
@@ -175,6 +174,7 @@ class HeartFCMessageReceiver:
metadata = {
"type": "reminder",
"user_id": reminder_event.user_id,
"platform": chat.platform,
"chat_id": chat.stream_id,
"content": reminder_event.content,
"confidence": reminder_event.confidence,

View File

@@ -50,6 +50,7 @@ def init_prompt():
{time_block}
{identity_block}
{users_in_chat}
{custom_prompt_block}
{chat_context_description},以下是具体的聊天内容。
{chat_content_block}
@@ -154,7 +155,6 @@ def init_prompt():
)
class ActionPlanner:
def __init__(self, chat_id: str, action_manager: ActionManager):
self.chat_id = chat_id
@@ -165,7 +165,6 @@ class ActionPlanner:
self.planner_llm = LLMRequest(
model_set=model_config.model_task_config.planner, request_type="planner"
)
self.last_obs_time_mark = 0.0
async def _get_long_term_memory_context(self) -> str:
@@ -268,14 +267,14 @@ class ActionPlanner:
# 假设消息列表是按时间顺序排列的,最后一个是最新的
return message_id_list[-1].get("message")
def _parse_single_action(
async def _parse_single_action(
self,
action_json: dict,
message_id_list: list, # 使用 planner.py 的 list of dict
current_available_actions: list, # 使用 planner.py 的 list of tuple
) -> List[Dict[str, Any]]:
"""
[注释] 解析单个小脑LLM返回的action JSON并将其转换为标准化的字典。
[注释] 解析单个LLM返回的action JSON并将其转换为标准化的字典。
"""
parsed_actions = []
try:
@@ -312,6 +311,16 @@ class ActionPlanner:
"available_actions": available_actions_dict,
}
)
# 如果是at_user动作且只有user_name尝试转换为user_id
if action == "at_user" and "user_name" in action_data and "user_id" not in action_data:
user_name = action_data["user_name"]
from src.person_info.person_info import get_person_info_manager
user_info = await get_person_info_manager().get_person_info_by_name(user_name)
if user_info and user_info.get("user_id"):
action_data["user_id"] = user_info["user_id"]
logger.info(f"成功将用户名 '{user_name}' 解析为 user_id '{user_info['user_id']}'")
else:
logger.warning(f"无法将用户名 '{user_name}' 解析为 user_id")
except Exception as e:
logger.error(f"{self.log_prefix}解析单个action时出错: {e}")
parsed_actions.append(
@@ -349,22 +358,6 @@ class ActionPlanner:
统一决策是否进行聊天回复(reply)以及执行哪些actions。
"""
# --- 1. 准备上下文信息 ---
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
chat_id=self.chat_id,
timestamp=time.time(),
limit=int(global_config.chat.max_context_size * 0.6),
)
chat_content_block, message_id_list = build_readable_messages_with_id(
messages=message_list_before_now,
timestamp_mode="normal",
read_mark=self.last_obs_time_mark,
truncate=True,
show_actions=True,
)
if pseudo_message:
chat_content_block += f"\n[m99] 刚刚, 用户: {pseudo_message}"
self.last_obs_time_mark = time.time()
is_group_chat, chat_target_info, current_available_actions = self.get_necessary_info()
if available_actions is None:
available_actions = current_available_actions
@@ -377,8 +370,6 @@ class ActionPlanner:
chat_target_info=chat_target_info,
current_available_actions=available_actions,
mode=mode,
chat_content_block_override=chat_content_block,
message_id_list_override=message_id_list,
)
llm_content, _ = await self.planner_llm.generate_response_async(prompt=prompt)
@@ -392,7 +383,7 @@ class ActionPlanner:
if isinstance(parsed_json, list):
for item in parsed_json:
if isinstance(item, dict):
final_actions.extend(self._parse_single_action(item, used_message_id_list, list(available_actions.items())))
final_actions.extend(await self._parse_single_action(item, used_message_id_list, list(available_actions.items())))
# 如果是私聊且开启了强制回复并且没有任何回复性action则强制添加reply
if not is_group_chat and global_config.chat.force_reply_private:
@@ -402,7 +393,7 @@ class ActionPlanner:
"action_type": "reply",
"reasoning": "私聊强制回复",
"action_data": {},
"action_message": self.get_latest_message(message_id_list),
"action_message": self.get_latest_message(used_message_id_list),
"available_actions": available_actions,
})
logger.info(f"{self.log_prefix}私聊强制回复已触发,添加 'reply' 动作")
@@ -444,8 +435,6 @@ class ActionPlanner:
chat_target_info: Optional[dict],
current_available_actions: Dict[str, ActionInfo],
mode: ChatMode = ChatMode.FOCUS,
chat_content_block_override: Optional[str] = None,
message_id_list_override: Optional[List] = None,
refresh_time: bool = False, # 添加缺失的参数
) -> tuple[str, list]:
"""构建 Planner LLM 的提示词 (获取模板并填充数据)"""
@@ -479,7 +468,7 @@ class ActionPlanner:
timestamp=time.time(),
limit=int(global_config.chat.max_context_size * 0.2), # 主动思考时只看少量最近消息
)
chat_content_block, _ = build_readable_messages_with_id(
chat_content_block, message_id_list = build_readable_messages_with_id(
messages=message_list_short,
timestamp_mode="normal",
truncate=False,
@@ -505,7 +494,7 @@ class ActionPlanner:
chat_content_block=chat_content_block or "最近没有聊天内容。",
actions_before_now_block=actions_before_now_block,
)
return prompt, []
return prompt, message_id_list
# --- FOCUS 和 NORMAL 模式的逻辑 ---
message_list_before_now = get_raw_msg_before_timestamp_with_chat(
@@ -513,7 +502,6 @@ class ActionPlanner:
timestamp=time.time(),
limit=int(global_config.chat.max_context_size * 0.6),
)
chat_content_block, message_id_list = build_readable_messages_with_id(
messages=message_list_before_now,
timestamp_mode="normal",
@@ -580,6 +568,14 @@ class ActionPlanner:
custom_prompt_block = ""
if global_config.custom_prompt.planner_custom_prompt_content:
custom_prompt_block = global_config.custom_prompt.planner_custom_prompt_content
from src.person_info.person_info import get_person_info_manager
users_in_chat_str = ""
if is_group_chat and chat_target_info and chat_target_info.get("group_id"):
user_list = await get_person_info_manager().get_specific_value_list("person_name", lambda x: x is not None)
if user_list:
users_in_chat_str = "当前聊天中的用户列表(用于@\n" + "\n".join([f"- {name} (ID: {pid})" for pid, name in user_list.items()]) + "\n"
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt")
prompt = planner_prompt_template.format(
@@ -597,6 +593,7 @@ class ActionPlanner:
identity_block=identity_block,
custom_prompt_block=custom_prompt_block,
bot_name=bot_name,
users_in_chat=users_in_chat_str
)
return prompt, message_id_list
except Exception as e: