feat:进一步完善hfc私聊支持

This commit is contained in:
SengokuCola
2025-05-01 22:33:59 +08:00
parent 0fdaff6f3d
commit f4e9721e36
4 changed files with 534 additions and 407 deletions

View File

@@ -20,34 +20,62 @@ logger = get_logger("sub_heartflow")
def init_prompt(): def init_prompt():
prompt = "" # --- Group Chat Prompt ---
prompt += "{extra_info}\n" group_prompt = """
prompt += "{relation_prompt}\n" {extra_info}
prompt += "你的名字是{bot_name},{prompt_personality}\n" {relation_prompt}
prompt += "{last_loop_prompt}\n" 你的名字是{bot_name},{prompt_personality}
prompt += "{cycle_info_block}\n" {last_loop_prompt}
prompt += "现在是{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容\n{chat_observe_info}\n" {cycle_info_block}
prompt += "\n现在{mood_info}\n" 现在{time_now}你正在上网和qq群里的网友们聊天以下是正在进行的聊天内容
prompt += "请仔细阅读当前群聊内容,分析讨论话题和群成员关系,分析你刚刚发言和别人对你的发言的反应,思考你要不要回复。然后思考你是否需要使用函数工具。" {chat_observe_info}
prompt += "思考并输出你的内心想法\n"
prompt += "输出要求:\n"
prompt += "1. 根据聊天内容生成你的想法,{hf_do_next}\n"
prompt += "2. 不要分点、不要使用表情符号\n"
prompt += "3. 避免多余符号(冒号、引号、括号等)\n"
prompt += "4. 语言简洁自然,不要浮夸\n"
prompt += "5. 如果你刚发言,并且没有人回复你,不要回复\n"
prompt += "工具使用说明:\n"
prompt += "1. 输出想法后考虑是否需要使用工具\n"
prompt += "2. 工具可获取信息或执行操作\n"
prompt += "3. 如需处理消息或回复,请使用工具\n"
Prompt(prompt, "sub_heartflow_prompt_before") 你现在{mood_info}
请仔细阅读当前群聊内容,分析讨论话题和群成员关系,分析你刚刚发言和别人对你的发言的反应,思考你要不要回复。然后思考你是否需要使用函数工具。
思考并输出你的内心想法
输出要求:
1. 根据聊天内容生成你的想法,{hf_do_next}
2. 不要分点、不要使用表情符号
3. 避免多余符号(冒号、引号、括号等)
4. 语言简洁自然,不要浮夸
5. 如果你刚发言,并且没有人回复你,不要回复
工具使用说明:
1. 输出想法后考虑是否需要使用工具
2. 工具可获取信息或执行操作
3. 如需处理消息或回复,请使用工具。"""
Prompt(group_prompt, "sub_heartflow_prompt_before")
prompt = "" # --- Private Chat Prompt ---
prompt += "刚刚你的内心想法是:{current_thinking_info}\n" private_prompt = """
prompt += "{if_replan_prompt}\n" {extra_info}
{relation_prompt}
你的名字是{bot_name},{prompt_personality}
{last_loop_prompt}
{cycle_info_block}
现在是{time_now},你正在上网,和 {chat_target_name} 私聊,以下是你们的聊天内容:
{chat_observe_info}
Prompt(prompt, "last_loop") 你现在{mood_info}
请仔细阅读聊天内容,分析你和 {chat_target_name} 的关系,分析你刚刚发言和对方的反应,思考你要不要回复。然后思考你是否需要使用函数工具。
思考并输出你的内心想法
输出要求:
1. 根据聊天内容生成你的想法,{hf_do_next}
2. 不要分点、不要使用表情符号
3. 避免多余符号(冒号、引号、括号等)
4. 语言简洁自然,不要浮夸
5. 如果你刚发言,对方没有回复你,请谨慎回复
工具使用说明:
1. 输出想法后考虑是否需要使用工具
2. 工具可获取信息或执行操作
3. 如需处理消息或回复,请使用工具。"""
Prompt(private_prompt, "sub_heartflow_prompt_private_before") # New template name
# --- Last Loop Prompt (remains the same) ---
last_loop_t = """
刚刚你的内心想法是:{current_thinking_info}
{if_replan_prompt}
"""
Prompt(last_loop_t, "last_loop")
def calculate_similarity(text_a: str, text_b: str) -> float: def calculate_similarity(text_a: str, text_b: str) -> float:
@@ -122,12 +150,19 @@ class SubMind:
mood_info = self.chat_state.mood mood_info = self.chat_state.mood
# 获取观察对象 # 获取观察对象
observation = self.observations[0] observation = self.observations[0] if self.observations else None
if not observation: if not observation or not hasattr(observation, 'is_group_chat'): # Ensure it's ChattingObservation or similar
logger.error(f"{self.log_prefix} 无法获取观察对象") logger.error(f"{self.log_prefix} 无法获取有效的观察对象或缺少聊天类型信息")
self.update_current_mind("(我没看到任何聊天内容...)") self.update_current_mind("(观察出错了...)")
return self.current_mind, self.past_mind return self.current_mind, self.past_mind
is_group_chat = observation.is_group_chat
chat_target_info = observation.chat_target_info
chat_target_name = "对方" # Default for private
if not is_group_chat and chat_target_info:
chat_target_name = chat_target_info.get('person_name') or chat_target_info.get('user_nickname') or chat_target_name
# --- End getting observation info ---
# 获取观察内容 # 获取观察内容
chat_observe_info = observation.get_observe_info() chat_observe_info = observation.get_observe_info()
person_list = observation.person_list person_list = observation.person_list
@@ -238,9 +273,11 @@ class SubMind:
)[0] )[0]
# ---------- 4. 构建最终提示词 ---------- # ---------- 4. 构建最终提示词 ----------
# 获取提示词模板并填充数据 # --- Choose template based on chat type ---
prompt = (await global_prompt_manager.get_prompt_async("sub_heartflow_prompt_before")).format( if is_group_chat:
extra_info="", # 可以在这里添加额外信息 template_name = "sub_heartflow_prompt_before"
prompt = (await global_prompt_manager.get_prompt_async(template_name)).format(
extra_info="",
prompt_personality=prompt_personality, prompt_personality=prompt_personality,
relation_prompt=relation_prompt, relation_prompt=relation_prompt,
bot_name=individuality.name, bot_name=individuality.name,
@@ -250,7 +287,24 @@ class SubMind:
hf_do_next=hf_do_next, hf_do_next=hf_do_next,
last_loop_prompt=last_loop_prompt, last_loop_prompt=last_loop_prompt,
cycle_info_block=cycle_info_block, cycle_info_block=cycle_info_block,
# chat_target_name is not used in group prompt
) )
else: # Private chat
template_name = "sub_heartflow_prompt_private_before"
prompt = (await global_prompt_manager.get_prompt_async(template_name)).format(
extra_info="",
prompt_personality=prompt_personality,
relation_prompt=relation_prompt, # Might need adjustment for private context
bot_name=individuality.name,
time_now=time_now,
chat_target_name=chat_target_name, # Pass target name
chat_observe_info=chat_observe_info,
mood_info=mood_info,
hf_do_next=hf_do_next,
last_loop_prompt=last_loop_prompt,
cycle_info_block=cycle_info_block,
)
# --- End choosing template ---
# ---------- 5. 执行LLM请求并处理响应 ---------- # ---------- 5. 执行LLM请求并处理响应 ----------
content = "" # 初始化内容变量 content = "" # 初始化内容变量

View File

@@ -45,19 +45,14 @@ async def get_chat_type_and_target_info(chat_id: str) -> Tuple[bool, Optional[Di
'person_name': None 'person_name': None
} }
# Try to fetch person info (assuming person_info_manager methods are sync) # Try to fetch person info
try: try:
# Use asyncio.to_thread for potentially blocking sync calls # Assume get_person_id is sync (as per original code), keep using to_thread
person_id = await asyncio.to_thread(person_info_manager.get_person_id, platform, user_id) person_id = await asyncio.to_thread(person_info_manager.get_person_id, platform, user_id)
person_name = None person_name = None
if person_id: if person_id:
person_name = await asyncio.to_thread(person_info_manager.get_value, person_id, "person_name") # get_value is async, so await it directly
person_name = await person_info_manager.get_value(person_id, "person_name")
# If person_info_manager methods are async, await them directly:
# person_id = await person_info_manager.get_person_id(platform, user_id)
# person_name = None
# if person_id:
# person_name = await person_info_manager.get_value(person_id, "person_name")
target_info['person_id'] = person_id target_info['person_id'] = person_id
target_info['person_name'] = person_name target_info['person_name'] = person_name

View File

@@ -851,18 +851,15 @@ class HeartFChatting:
f"{self.log_prefix}[Planner] 临时移除的动作: {actions_to_remove_temporarily}, 当前可用: {list(current_available_actions.keys())}" f"{self.log_prefix}[Planner] 临时移除的动作: {actions_to_remove_temporarily}, 当前可用: {list(current_available_actions.keys())}"
) )
# --- 构建提示词 (调用修改后的 _build_planner_prompt) --- # --- 构建提示词 (调用修改后的 PromptBuilder 方法) ---
# replan_prompt_str = "" # 暂时简化 prompt = await prompt_builder.build_planner_prompt(
# if is_re_planned: is_group_chat=self.is_group_chat, # <-- Pass HFC state
# replan_prompt_str = await self._build_replan_prompt( chat_target_info=self.chat_target_info, # <-- Pass HFC state
# self._current_cycle.action_type, self._current_cycle.reasoning cycle_history=self._cycle_history, # <-- Pass HFC state
# ) observed_messages_str=observed_messages_str, # <-- Pass local variable
prompt = await self._build_planner_prompt( current_mind=current_mind, # <-- Pass argument
observed_messages_str, structured_info=self.sub_mind.structured_info, # <-- Pass SubMind info
current_mind, current_available_actions=current_available_actions # <-- Pass determined actions
self.sub_mind.structured_info,
"", # replan_prompt_str,
current_available_actions, # <--- 传入当前可用动作
) )
# --- 调用 LLM (普通文本生成) --- # --- 调用 LLM (普通文本生成) ---
@@ -1126,217 +1123,6 @@ class HeartFChatting:
return prompt return prompt
async def _build_planner_prompt(
self,
observed_messages_str: str,
current_mind: Optional[str],
structured_info: Dict[str, Any],
replan_prompt: str,
current_available_actions: Dict[str, str],
) -> str:
"""构建 Planner LLM 的提示词 (获取模板并填充数据)"""
try:
# 准备结构化信息块
structured_info_block = ""
if structured_info:
structured_info_block = f"以下是一些额外的信息:\n{structured_info}\n"
# 准备聊天内容块
chat_content_block = ""
if observed_messages_str:
chat_content_block = "观察到的最新聊天内容如下:\n---\n"
chat_content_block += observed_messages_str
chat_content_block += "\n---"
else:
chat_content_block = "当前没有观察到新的聊天内容。\n"
# 准备当前思维块 (修改以匹配模板)
current_mind_block = ""
if current_mind:
# 模板中占位符是 {current_mind_block},它期望包含"你的内心想法:"的前缀
current_mind_block = f"你的内心想法:\n{current_mind}"
else:
current_mind_block = "你的内心想法:\n[没有特别的想法]"
# 准备循环信息块 (分析最近的活动循环)
recent_active_cycles = []
for cycle in reversed(self._cycle_history):
# 只关心实际执行了动作的循环
if cycle.action_taken:
recent_active_cycles.append(cycle)
# 最多找最近的3个活动循环
if len(recent_active_cycles) == 3:
break
cycle_info_block = ""
consecutive_text_replies = 0
responses_for_prompt = []
# 检查这最近的活动循环中有多少是连续的文本回复 (从最近的开始看)
for cycle in recent_active_cycles:
if cycle.action_type == "text_reply":
consecutive_text_replies += 1
# 获取回复内容,如果不存在则返回'[空回复]'
response_text = cycle.response_info.get("response_text", [])
# 使用简单的 join 来格式化回复内容列表
formatted_response = "[空回复]" if not response_text else " ".join(response_text)
responses_for_prompt.append(formatted_response)
else:
# 一旦遇到非文本回复,连续性中断
break
# 根据连续文本回复的数量构建提示信息
# 注意: responses_for_prompt 列表是从最近到最远排序的
if consecutive_text_replies >= 3: # 如果最近的三个活动都是文本回复
cycle_info_block = f'你已经连续回复了三条消息(最近: "{responses_for_prompt[0]}",第二近: "{responses_for_prompt[1]}",第三近: "{responses_for_prompt[2]}")。你回复的有点多了,请注意'
elif consecutive_text_replies == 2: # 如果最近的两个活动是文本回复
cycle_info_block = f'你已经连续回复了两条消息(最近: "{responses_for_prompt[0]}",第二近: "{responses_for_prompt[1]}"),请注意'
elif consecutive_text_replies == 1: # 如果最近的一个活动是文本回复
cycle_info_block = f'你刚刚已经回复一条消息(内容: "{responses_for_prompt[0]}"'
# 包装提示块,增加可读性,即使没有连续回复也给个标记
if cycle_info_block:
# 模板中占位符是 {cycle_info_block},它期望包含"【近期回复历史】"的前缀
cycle_info_block = f"\n【近期回复历史】\n{cycle_info_block}\n"
else:
# 如果最近的活动循环不是文本回复,或者没有活动循环
cycle_info_block = "\n【近期回复历史】\n(最近没有连续文本回复)\n"
individuality = Individuality.get_instance()
# 模板中占位符是 {prompt_personality}
prompt_personality = individuality.get_prompt(x_person=2, level=2)
# --- 构建可用动作描述 (用于填充模板中的 {action_options_text}) ---
action_options_text = "当前你可以选择的行动有:\n"
action_keys = list(current_available_actions.keys())
for name in action_keys:
desc = current_available_actions[name]
action_options_text += f"- '{name}': {desc}\n"
# --- 选择一个示例动作键 (用于填充模板中的 {example_action}) ---
example_action_key = action_keys[0] if action_keys else "no_reply"
# --- 获取提示词模板 ---
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt")
# --- 填充模板 ---
prompt = planner_prompt_template.format(
bot_name=global_config.BOT_NICKNAME,
prompt_personality=prompt_personality,
structured_info_block=structured_info_block,
chat_content_block=chat_content_block,
current_mind_block=current_mind_block,
replan="", # 暂时留空 replan 信息
cycle_info_block=cycle_info_block,
action_options_text=action_options_text, # 传入可用动作描述
example_action=example_action_key, # 传入示例动作键
)
return prompt
except Exception as e:
logger.error(f"{self.log_prefix}[Planner] 构建提示词时出错: {e}")
logger.error(traceback.format_exc())
return "[构建 Planner Prompt 时出错]" # 返回错误提示,避免空字符串
# --- 回复器 (Replier) 的定义 --- #
async def _replier_work(
self,
reason: str,
anchor_message: MessageRecv,
thinking_id: str,
) -> Optional[List[str]]:
"""
回复器 (Replier): 核心逻辑,负责生成回复文本。
(已整合原 HeartFCGenerator 的功能)
"""
try:
# 1. 获取情绪影响因子并调整模型温度
arousal_multiplier = MoodManager.get_instance().get_arousal_multiplier()
current_temp = global_config.llm_normal["temp"] * arousal_multiplier
self.model_normal.temperature = current_temp # 动态调整温度
# 2. 获取信息捕捉器
info_catcher = info_catcher_manager.get_info_catcher(thinking_id)
# 3. 构建 Prompt
with Timer("构建Prompt", {}): # 内部计时器,可选保留
prompt = await prompt_builder.build_prompt(
build_mode="focus",
reason=reason,
current_mind_info=self.sub_mind.current_mind,
structured_info=self.sub_mind.structured_info,
message_txt="", # 似乎是固定的空字符串
sender_name="", # 似乎是固定的空字符串
chat_stream=anchor_message.chat_stream,
)
# 4. 调用 LLM 生成回复
content = None
reasoning_content = None
model_name = "unknown_model"
try:
with Timer("LLM生成", {}): # 内部计时器,可选保留
content, reasoning_content, model_name = await self.model_normal.generate_response(prompt)
# logger.info(f"{self.log_prefix}[Replier-{thinking_id}]\\nPrompt:\\n{prompt}\\n生成回复: {content}\\n")
# 捕捉 LLM 输出信息
info_catcher.catch_after_llm_generated(
prompt=prompt, response=content, reasoning_content=reasoning_content, model_name=model_name
)
except Exception as llm_e:
# 精简报错信息
logger.error(f"{self.log_prefix}[Replier-{thinking_id}] LLM 生成失败: {llm_e}")
return None # LLM 调用失败则无法生成回复
# 5. 处理 LLM 响应
if not content:
logger.warning(f"{self.log_prefix}[Replier-{thinking_id}] LLM 生成了空内容。")
return None
with Timer("处理响应", {}): # 内部计时器,可选保留
processed_response = process_llm_response(content)
if not processed_response:
logger.warning(f"{self.log_prefix}[Replier-{thinking_id}] 处理后的回复为空。")
return None
return processed_response
except Exception as e:
# 更通用的错误处理,精简信息
logger.error(f"{self.log_prefix}[Replier-{thinking_id}] 回复生成意外失败: {e}")
# logger.error(traceback.format_exc()) # 可以取消注释这行以在调试时查看完整堆栈
return None
# --- Methods moved from HeartFCController start ---
async def _create_thinking_message(self, anchor_message: Optional[MessageRecv]) -> Optional[str]:
"""创建思考消息 (尝试锚定到 anchor_message)"""
if not anchor_message or not anchor_message.chat_stream:
logger.error(f"{self.log_prefix} 无法创建思考消息,缺少有效的锚点消息或聊天流。")
return None
chat = anchor_message.chat_stream
messageinfo = anchor_message.message_info
bot_user_info = UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=messageinfo.platform,
)
thinking_time_point = round(time.time(), 2)
thinking_id = "mt" + str(thinking_time_point)
thinking_message = MessageThinking(
message_id=thinking_id,
chat_stream=chat,
bot_user_info=bot_user_info,
reply=anchor_message, # 回复的是锚点消息
thinking_start_time=thinking_time_point,
)
# Access MessageManager directly
await self.heart_fc_sender.register_thinking(thinking_message)
return thinking_id
async def _send_response_messages( async def _send_response_messages(
self, anchor_message: Optional[MessageRecv], response_set: List[str], thinking_id: str self, anchor_message: Optional[MessageRecv], response_set: List[str], thinking_id: str
) -> Optional[MessageSending]: ) -> Optional[MessageSending]:
@@ -1472,3 +1258,114 @@ class HeartFChatting:
if self._cycle_history: if self._cycle_history:
return self._cycle_history[-1].to_dict() return self._cycle_history[-1].to_dict()
return None return None
# --- 回复器 (Replier) 的定义 --- #
async def _replier_work(
self,
reason: str,
anchor_message: MessageRecv,
thinking_id: str,
) -> Optional[List[str]]:
"""
回复器 (Replier): 核心逻辑,负责生成回复文本。
(已整合原 HeartFCGenerator 的功能)
"""
try:
# 1. 获取情绪影响因子并调整模型温度
arousal_multiplier = MoodManager.get_instance().get_arousal_multiplier()
current_temp = global_config.llm_normal["temp"] * arousal_multiplier
self.model_normal.temperature = current_temp # 动态调整温度
# 2. 获取信息捕捉器
info_catcher = info_catcher_manager.get_info_catcher(thinking_id)
# --- Determine sender_name for private chat ---
sender_name_for_prompt = "某人" # Default for group or if info unavailable
if not self.is_group_chat and self.chat_target_info:
# Prioritize person_name, then nickname
sender_name_for_prompt = self.chat_target_info.get('person_name') or self.chat_target_info.get('user_nickname') or sender_name_for_prompt
# --- End determining sender_name ---
# 3. 构建 Prompt
with Timer("构建Prompt", {}): # 内部计时器,可选保留
prompt = await prompt_builder.build_prompt(
build_mode="focus",
chat_stream=self.chat_stream, # Pass the stream object
# Focus specific args:
reason=reason,
current_mind_info=self.sub_mind.current_mind,
structured_info=self.sub_mind.structured_info,
sender_name=sender_name_for_prompt, # Pass determined name
# Normal specific args (not used in focus mode):
# message_txt="",
)
# 4. 调用 LLM 生成回复
content = None
reasoning_content = None
model_name = "unknown_model"
if not prompt:
logger.error(f"{self.log_prefix}[Replier-{thinking_id}] Prompt 构建失败,无法生成回复。")
return None
try:
with Timer("LLM生成", {}): # 内部计时器,可选保留
content, reasoning_content, model_name = await self.model_normal.generate_response(prompt)
# logger.info(f"{self.log_prefix}[Replier-{thinking_id}]\nPrompt:\n{prompt}\n生成回复: {content}\n")
# 捕捉 LLM 输出信息
info_catcher.catch_after_llm_generated(
prompt=prompt, response=content, reasoning_content=reasoning_content, model_name=model_name
)
except Exception as llm_e:
# 精简报错信息
logger.error(f"{self.log_prefix}[Replier-{thinking_id}] LLM 生成失败: {llm_e}")
return None # LLM 调用失败则无法生成回复
# 5. 处理 LLM 响应
if not content:
logger.warning(f"{self.log_prefix}[Replier-{thinking_id}] LLM 生成了空内容。")
return None
with Timer("处理响应", {}): # 内部计时器,可选保留
processed_response = process_llm_response(content)
if not processed_response:
logger.warning(f"{self.log_prefix}[Replier-{thinking_id}] 处理后的回复为空。")
return None
return processed_response
except Exception as e:
# 更通用的错误处理,精简信息
logger.error(f"{self.log_prefix}[Replier-{thinking_id}] 回复生成意外失败: {e}")
# logger.error(traceback.format_exc()) # 可以取消注释这行以在调试时查看完整堆栈
return None
# --- Methods moved from HeartFCController start ---
async def _create_thinking_message(self, anchor_message: Optional[MessageRecv]) -> Optional[str]:
"""创建思考消息 (尝试锚定到 anchor_message)"""
if not anchor_message or not anchor_message.chat_stream:
logger.error(f"{self.log_prefix} 无法创建思考消息,缺少有效的锚点消息或聊天流。")
return None
chat = anchor_message.chat_stream
messageinfo = anchor_message.message_info
bot_user_info = UserInfo(
user_id=global_config.BOT_QQ,
user_nickname=global_config.BOT_NICKNAME,
platform=messageinfo.platform,
)
thinking_time_point = round(time.time(), 2)
thinking_id = "mt" + str(thinking_time_point)
thinking_message = MessageThinking(
message_id=thinking_id,
chat_stream=chat,
bot_user_info=bot_user_info,
reply=anchor_message, # 回复的是锚点消息
thinking_start_time=thinking_time_point,
)
# Access MessageManager directly (using heart_fc_sender)
await self.heart_fc_sender.register_thinking(thinking_message)
return thinking_id

View File

@@ -7,13 +7,15 @@ from src.plugins.utils.chat_message_builder import build_readable_messages, get_
from src.plugins.person_info.relationship_manager import relationship_manager from src.plugins.person_info.relationship_manager import relationship_manager
from src.plugins.chat.utils import get_embedding from src.plugins.chat.utils import get_embedding
import time import time
from typing import Union, Optional from typing import Union, Optional, Deque, Dict, Any
from ...common.database import db from ...common.database import db
from ..chat.utils import get_recent_group_speaker from ..chat.utils import get_recent_group_speaker
from ..moods.moods import MoodManager from ..moods.moods import MoodManager
from ..memory_system.Hippocampus import HippocampusManager from ..memory_system.Hippocampus import HippocampusManager
from ..schedule.schedule_generator import bot_schedule from ..schedule.schedule_generator import bot_schedule
from ..knowledge.knowledge_lib import qa_manager from ..knowledge.knowledge_lib import qa_manager
import traceback
from .heartFC_Cycleinfo import CycleInfo
logger = get_logger("prompt") logger = get_logger("prompt")
@@ -49,7 +51,7 @@ def init_prompt():
# Planner提示词 - 修改为要求 JSON 输出 # Planner提示词 - 修改为要求 JSON 输出
Prompt( Prompt(
"""你的名字是{bot_name},{prompt_personality}你现在正在一个群聊中。需要基于以下信息决定如何参与对话: """你的名字是{bot_name},{prompt_personality}{chat_context_description}。需要基于以下信息决定如何参与对话:
{structured_info_block} {structured_info_block}
{chat_content_block} {chat_content_block}
{current_mind_block} {current_mind_block}
@@ -59,25 +61,25 @@ def init_prompt():
【回复原则】 【回复原则】
1. 不回复(no_reply)适用: 1. 不回复(no_reply)适用:
- 话题无关/无聊/不感兴趣 - 话题无关/无聊/不感兴趣
- 最后一条消息是你自己发的且无人回应你 - 最后一条消息是你自己发的且无人回应你
- 讨论你不懂的专业话题 - 讨论你不懂的专业话题
- 你发送了太多消息,且无人回复 - 你发送了太多消息,且无人回复
2. 文字回复(text_reply)适用: 2. 文字回复(text_reply)适用:
- 有实质性内容需要表达 - 有实质性内容需要表达
- 有人提到你,但你还没有回应他 - 有人提到你,但你还没有回应他
- 可以追加emoji_query表达情绪(emoji_query填写表情包的适用场合也就是当前场合) - 可以追加emoji_query表达情绪(emoji_query填写表情包的适用场合也就是当前场合)
- 不要追加太多表情 - 不要追加太多表情
3. 纯表情回复(emoji_reply)适用: 3. 纯表情回复(emoji_reply)适用:
- 适合用表情回应的场景 - 适合用表情回应的场景
- 需提供明确的emoji_query - 需提供明确的emoji_query
4. 自我对话处理: 4. 自我对话处理:
- 如果是自己发的消息想继续,需自然衔接 - 如果是自己发的消息想继续,需自然衔接
- 避免重复或评价自己的发言 - 避免重复或评价自己的发言
- 不要和自己聊天 - 不要和自己聊天
决策任务 决策任务
{action_options_text} {action_options_text}
@@ -91,8 +93,8 @@ JSON 结构如下,包含三个字段 "action", "reasoning", "emoji_query":
"emoji_query": "string" // 可选。如果行动是 'emoji_reply',必须提供表情主题(填写表情包的适用场合);如果行动是 'text_reply' 且你想附带表情,也在此提供表情主题,否则留空字符串 ""。遵循回复原则,不要滥用。 "emoji_query": "string" // 可选。如果行动是 'emoji_reply',必须提供表情主题(填写表情包的适用场合);如果行动是 'text_reply' 且你想附带表情,也在此提供表情主题,否则留空字符串 ""。遵循回复原则,不要滥用。
}} }}
请输出你的决策 JSON 请输出你的决策 JSON
""", # 使用三引号避免内部引号问题 """,
"planner_prompt", # 保持名称不变,替换内容 "planner_prompt",
) )
Prompt( Prompt(
@@ -136,24 +138,67 @@ JSON 结构如下,包含三个字段 "action", "reasoning", "emoji_query":
Prompt("你现在正在做的事情是:{schedule_info}", "schedule_prompt") Prompt("你现在正在做的事情是:{schedule_info}", "schedule_prompt")
Prompt("\n你有以下这些**知识**\n{prompt_info}\n请你**记住上面的知识**,之后可能会用到。\n", "knowledge_prompt") Prompt("\n你有以下这些**知识**\n{prompt_info}\n请你**记住上面的知识**,之后可能会用到。\n", "knowledge_prompt")
# --- Template for HeartFChatting (FOCUSED mode) ---
Prompt(
"""
{info_from_tools}
你正在和 {sender_name} 私聊。
聊天记录如下:
{chat_talking_prompt}
现在你想要回复。
async def _build_prompt_focus(reason, current_mind_info, structured_info, chat_stream, sender_name) -> tuple[str, str]: 你需要扮演一位网名叫{bot_name}的人进行回复,这个人的特点是:"{prompt_personality}"
你正在和 {sender_name} 私聊, 现在请你读读你们之前的聊天记录,然后给出日常且口语化的回复,平淡一些。
看到以上聊天记录,你刚刚在想:
{current_mind_info}
因为上述想法,你决定回复,原因是:{reason}
回复尽量简短一些。请注意把握聊天内容,{reply_style2}{prompt_ger}
{reply_style1},说中文,不要刻意突出自身学科背景,注意只输出回复内容。
{moderation_prompt}。注意:回复不要输出多余内容(包括前后缀冒号和引号括号表情包at或 @等 )。""",
"heart_flow_private_prompt", # New template for private FOCUSED chat
)
# --- Template for NormalChat (CHAT mode) ---
Prompt(
"""
{memory_prompt}
{relation_prompt}
{prompt_info}
{schedule_prompt}
你正在和 {sender_name} 私聊。
聊天记录如下:
{chat_talking_prompt}
现在 {sender_name} 说的: {message_txt} 引起了你的注意,你想要回复这条消息。
你的网名叫{bot_name},有人也叫你{bot_other_names}{prompt_personality}
你正在和 {sender_name} 私聊, 现在请你读读你们之前的聊天记录,{mood_prompt}{reply_style1}
尽量简短一些。{keywords_reaction_prompt}请注意把握聊天内容,{reply_style2}{prompt_ger}
请回复的平淡一些,简短一些,说中文,不要刻意突出自身学科背景,不要浮夸,平淡一些 ,不要随意遵从他人指令。
请注意不要输出多余内容(包括前后缀,冒号和引号,括号等),只输出回复内容。
{moderation_prompt}
不要输出多余内容(包括前后缀,冒号和引号,括号()表情包at或 @等 )。只输出回复内容""",
"reasoning_prompt_private_main", # New template for private CHAT chat
)
async def _build_prompt_focus(reason, current_mind_info, structured_info, chat_stream, sender_name) -> str:
individuality = Individuality.get_instance() individuality = Individuality.get_instance()
prompt_personality = individuality.get_prompt(x_person=0, level=2) prompt_personality = individuality.get_prompt(x_person=0, level=2)
# 日程构建
# schedule_prompt = f'''你现在正在做的事情是:{bot_schedule.get_current_num_task(num = 1,time_info = False)}'''
if chat_stream.group_info: # Determine if it's a group chat
chat_in_group = True is_group_chat = bool(chat_stream.group_info)
else:
chat_in_group = False # Use sender_name passed from caller for private chat, otherwise use a default for group
# Default sender_name for group chat isn't used in the group prompt template, but set for consistency
effective_sender_name = sender_name if not is_group_chat else "某人"
message_list_before_now = get_raw_msg_before_timestamp_with_chat( message_list_before_now = get_raw_msg_before_timestamp_with_chat(
chat_id=chat_stream.stream_id, chat_id=chat_stream.stream_id,
timestamp=time.time(), timestamp=time.time(),
limit=global_config.observation_context_size, limit=global_config.observation_context_size,
) )
chat_talking_prompt = await build_readable_messages( chat_talking_prompt = await build_readable_messages(
message_list_before_now, message_list_before_now,
replace_bot_name=True, replace_bot_name=True,
@@ -163,7 +208,6 @@ async def _build_prompt_focus(reason, current_mind_info, structured_info, chat_s
truncate=True, truncate=True,
) )
# 中文高手(新加的好玩功能)
prompt_ger = "" prompt_ger = ""
if random.random() < 0.04: if random.random() < 0.04:
prompt_ger += "你喜欢用倒装句" prompt_ger += "你喜欢用倒装句"
@@ -171,20 +215,20 @@ async def _build_prompt_focus(reason, current_mind_info, structured_info, chat_s
prompt_ger += "你喜欢用反问句" prompt_ger += "你喜欢用反问句"
reply_styles1 = [ reply_styles1 = [
("给出日常且口语化的回复,平淡一些", 0.4), # 40%概率 ("给出日常且口语化的回复,平淡一些", 0.4),
("给出非常简短的回复", 0.4), # 40%概率 ("给出非常简短的回复", 0.4),
("给出缺失主语的回复,简短", 0.15), # 15%概率 ("给出缺失主语的回复,简短", 0.15),
("给出带有语病的回复,朴实平淡", 0.05), # 5%概率 ("给出带有语病的回复,朴实平淡", 0.05),
] ]
reply_style1_chosen = random.choices( reply_style1_chosen = random.choices(
[style[0] for style in reply_styles1], weights=[style[1] for style in reply_styles1], k=1 [style[0] for style in reply_styles1], weights=[style[1] for style in reply_styles1], k=1
)[0] )[0]
reply_styles2 = [ reply_styles2 = [
("不要回复的太有条理,可以有个性", 0.6), # 60%概率 ("不要回复的太有条理,可以有个性", 0.6),
("不要回复的太有条理,可以复读", 0.15), # 15%概率 ("不要回复的太有条理,可以复读", 0.15),
("回复的认真一些", 0.2), # 20%概率 ("回复的认真一些", 0.2),
("可以回复单个表情符号", 0.05), # 5%概率 ("可以回复单个表情符号", 0.05),
] ]
reply_style2_chosen = random.choices( reply_style2_chosen = random.choices(
[style[0] for style in reply_styles2], weights=[style[1] for style in reply_styles2], k=1 [style[0] for style in reply_styles2], weights=[style[1] for style in reply_styles2], k=1
@@ -197,31 +241,51 @@ async def _build_prompt_focus(reason, current_mind_info, structured_info, chat_s
else: else:
structured_info_prompt = "" structured_info_prompt = ""
logger.debug("开始构建prompt") logger.debug("开始构建 focus prompt")
# --- Choose template based on chat type ---
if is_group_chat:
template_name = "heart_flow_prompt"
# Group specific formatting variables (already fetched or default)
chat_target_1 = await global_prompt_manager.get_prompt_async("chat_target_group1")
chat_target_2 = await global_prompt_manager.get_prompt_async("chat_target_group2")
prompt = await global_prompt_manager.format_prompt( prompt = await global_prompt_manager.format_prompt(
"heart_flow_prompt", template_name,
info_from_tools=structured_info_prompt, info_from_tools=structured_info_prompt,
chat_target=await global_prompt_manager.get_prompt_async("chat_target_group1") chat_target=chat_target_1, # Used in group template
if chat_in_group
else await global_prompt_manager.get_prompt_async("chat_target_private1"),
chat_talking_prompt=chat_talking_prompt, chat_talking_prompt=chat_talking_prompt,
bot_name=global_config.BOT_NICKNAME, bot_name=global_config.BOT_NICKNAME,
prompt_personality=prompt_personality, prompt_personality=prompt_personality,
chat_target_2=await global_prompt_manager.get_prompt_async("chat_target_group2") chat_target_2=chat_target_2, # Used in group template
if chat_in_group
else await global_prompt_manager.get_prompt_async("chat_target_private2"),
current_mind_info=current_mind_info, current_mind_info=current_mind_info,
reply_style2=reply_style2_chosen, reply_style2=reply_style2_chosen,
reply_style1=reply_style1_chosen, reply_style1=reply_style1_chosen,
reason=reason, reason=reason,
prompt_ger=prompt_ger, prompt_ger=prompt_ger,
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"), moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
sender_name=sender_name, # sender_name is not used in the group template
) )
else: # Private chat
template_name = "heart_flow_private_prompt"
prompt = await global_prompt_manager.format_prompt(
template_name,
info_from_tools=structured_info_prompt,
sender_name=effective_sender_name, # Used in private template
chat_talking_prompt=chat_talking_prompt,
bot_name=global_config.BOT_NICKNAME,
prompt_personality=prompt_personality,
# chat_target and chat_target_2 are not used in private template
current_mind_info=current_mind_info,
reply_style2=reply_style2_chosen,
reply_style1=reply_style1_chosen,
reason=reason,
prompt_ger=prompt_ger,
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
)
# --- End choosing template ---
logger.debug(f"focus_chat_prompt: \n{prompt}") logger.debug(f"focus_chat_prompt (is_group={is_group_chat}): \n{prompt}")
return prompt return prompt
@@ -233,13 +297,15 @@ class PromptBuilder:
async def build_prompt( async def build_prompt(
self, self,
build_mode, build_mode,
reason, chat_stream,
current_mind_info, reason=None,
structured_info, current_mind_info=None,
message_txt: str, structured_info=None,
sender_name: str = "某人", message_txt=None,
chat_stream=None, sender_name = "某人",
) -> Optional[tuple[str, str]]: ) -> Optional[str]:
is_group_chat = bool(chat_stream.group_info)
if build_mode == "normal": if build_mode == "normal":
return await self._build_prompt_normal(chat_stream, message_txt, sender_name) return await self._build_prompt_normal(chat_stream, message_txt, sender_name)
@@ -253,54 +319,48 @@ class PromptBuilder:
) )
return None return None
async def _build_prompt_normal(self, chat_stream, message_txt: str, sender_name: str = "某人") -> tuple[str, str]: async def _build_prompt_normal(self, chat_stream, message_txt: str, sender_name: str = "某人") -> str:
individuality = Individuality.get_instance() individuality = Individuality.get_instance()
prompt_personality = individuality.get_prompt(x_person=2, level=2) prompt_personality = individuality.get_prompt(x_person=2, level=2)
is_group_chat = bool(chat_stream.group_info)
# 关系 who_chat_in_group = []
who_chat_in_group = [ if is_group_chat:
(chat_stream.user_info.platform, chat_stream.user_info.user_id, chat_stream.user_info.user_nickname) who_chat_in_group = get_recent_group_speaker(
]
who_chat_in_group += get_recent_group_speaker(
chat_stream.stream_id, chat_stream.stream_id,
(chat_stream.user_info.platform, chat_stream.user_info.user_id), (chat_stream.user_info.platform, chat_stream.user_info.user_id) if chat_stream.user_info else None,
limit=global_config.observation_context_size, limit=global_config.observation_context_size,
) )
elif chat_stream.user_info:
who_chat_in_group.append((chat_stream.user_info.platform, chat_stream.user_info.user_id, chat_stream.user_info.user_nickname))
relation_prompt = "" relation_prompt = ""
for person in who_chat_in_group: for person in who_chat_in_group:
if len(person) >= 3 and person[0] and person[1]:
relation_prompt += await relationship_manager.build_relationship_info(person) relation_prompt += await relationship_manager.build_relationship_info(person)
# print(f"relation_prompt: {relation_prompt}") else:
logger.warning(f"Invalid person tuple encountered for relationship prompt: {person}")
# print(f"relat11111111ion_prompt: {relation_prompt}")
# 心情
mood_manager = MoodManager.get_instance() mood_manager = MoodManager.get_instance()
mood_prompt = mood_manager.get_prompt() mood_prompt = mood_manager.get_prompt()
# logger.info(f"心情prompt: {mood_prompt}")
reply_styles1 = [ reply_styles1 = [
("然后给出日常且口语化的回复,平淡一些", 0.4), # 40%概率 ("然后给出日常且口语化的回复,平淡一些", 0.4),
("给出非常简短的回复", 0.4), # 40%概率 ("给出非常简短的回复", 0.4),
("给出缺失主语的回复", 0.15), # 15%概率 ("给出缺失主语的回复", 0.15),
("给出带有语病的回复", 0.05), # 5%概率 ("给出带有语病的回复", 0.05),
] ]
reply_style1_chosen = random.choices( reply_style1_chosen = random.choices(
[style[0] for style in reply_styles1], weights=[style[1] for style in reply_styles1], k=1 [style[0] for style in reply_styles1], weights=[style[1] for style in reply_styles1], k=1
)[0] )[0]
reply_styles2 = [ reply_styles2 = [
("不要回复的太有条理,可以有个性", 0.6), # 60%概率 ("不要回复的太有条理,可以有个性", 0.6),
("不要回复的太有条理,可以复读", 0.15), # 15%概率 ("不要回复的太有条理,可以复读", 0.15),
("回复的认真一些", 0.2), # 20%概率 ("回复的认真一些", 0.2),
("可以回复单个表情符号", 0.05), # 5%概率 ("可以回复单个表情符号", 0.05),
] ]
reply_style2_chosen = random.choices( reply_style2_chosen = random.choices(
[style[0] for style in reply_styles2], weights=[style[1] for style in reply_styles2], k=1 [style[0] for style in reply_styles2], weights=[style[1] for style in reply_styles2], k=1
)[0] )[0]
# 调取记忆
memory_prompt = "" memory_prompt = ""
related_memory = await HippocampusManager.get_instance().get_memory_from_text( related_memory = await HippocampusManager.get_instance().get_memory_from_text(
text=message_txt, max_memory_num=2, max_memory_length=2, max_depth=3, fast_retrieval=False text=message_txt, max_memory_num=2, max_memory_length=2, max_depth=3, fast_retrieval=False
@@ -309,23 +369,14 @@ class PromptBuilder:
if related_memory: if related_memory:
for memory in related_memory: for memory in related_memory:
related_memory_info += memory[1] related_memory_info += memory[1]
# memory_prompt = f"你想起你之前见过的事情:{related_memory_info}。\n以上是你的回忆不一定是目前聊天里的人说的也不一定是现在发生的事情请记住。\n"
memory_prompt = await global_prompt_manager.format_prompt( memory_prompt = await global_prompt_manager.format_prompt(
"memory_prompt", related_memory_info=related_memory_info "memory_prompt", related_memory_info=related_memory_info
) )
# 获取聊天上下文
if chat_stream.group_info:
chat_in_group = True
else:
chat_in_group = False
message_list_before_now = get_raw_msg_before_timestamp_with_chat( message_list_before_now = get_raw_msg_before_timestamp_with_chat(
chat_id=chat_stream.stream_id, chat_id=chat_stream.stream_id,
timestamp=time.time(), timestamp=time.time(),
limit=global_config.observation_context_size, limit=global_config.observation_context_size,
) )
chat_talking_prompt = await build_readable_messages( chat_talking_prompt = await build_readable_messages(
message_list_before_now, message_list_before_now,
replace_bot_name=True, replace_bot_name=True,
@@ -369,13 +420,12 @@ class PromptBuilder:
start_time = time.time() start_time = time.time()
prompt_info = await self.get_prompt_info(message_txt, threshold=0.38) prompt_info = await self.get_prompt_info(message_txt, threshold=0.38)
if prompt_info: if prompt_info:
# prompt_info = f"""\n你有以下这些**知识**\n{prompt_info}\n请你**记住上面的知识**,之后可能会用到。\n"""
prompt_info = await global_prompt_manager.format_prompt("knowledge_prompt", prompt_info=prompt_info) prompt_info = await global_prompt_manager.format_prompt("knowledge_prompt", prompt_info=prompt_info)
end_time = time.time() end_time = time.time()
logger.debug(f"知识检索耗时: {(end_time - start_time):.3f}") logger.debug(f"知识检索耗时: {(end_time - start_time):.3f}")
logger.debug("开始构建prompt")
if global_config.ENABLE_SCHEDULE_GEN: if global_config.ENABLE_SCHEDULE_GEN:
schedule_prompt = await global_prompt_manager.format_prompt( schedule_prompt = await global_prompt_manager.format_prompt(
@@ -384,25 +434,28 @@ class PromptBuilder:
else: else:
schedule_prompt = "" schedule_prompt = ""
logger.debug("开始构建 normal prompt")
# --- Choose template and format based on chat type ---
if is_group_chat:
template_name = "reasoning_prompt_main"
effective_sender_name = sender_name
chat_target_1 = await global_prompt_manager.get_prompt_async("chat_target_group1")
chat_target_2 = await global_prompt_manager.get_prompt_async("chat_target_group2")
prompt = await global_prompt_manager.format_prompt( prompt = await global_prompt_manager.format_prompt(
"reasoning_prompt_main", template_name,
relation_prompt=relation_prompt, relation_prompt=relation_prompt,
sender_name=sender_name, sender_name=effective_sender_name,
memory_prompt=memory_prompt, memory_prompt=memory_prompt,
prompt_info=prompt_info, prompt_info=prompt_info,
schedule_prompt=schedule_prompt, schedule_prompt=schedule_prompt,
chat_target=await global_prompt_manager.get_prompt_async("chat_target_group1") chat_target=chat_target_1,
if chat_in_group chat_target_2=chat_target_2,
else await global_prompt_manager.get_prompt_async("chat_target_private1"),
chat_target_2=await global_prompt_manager.get_prompt_async("chat_target_group2")
if chat_in_group
else await global_prompt_manager.get_prompt_async("chat_target_private2"),
chat_talking_prompt=chat_talking_prompt, chat_talking_prompt=chat_talking_prompt,
message_txt=message_txt, message_txt=message_txt,
bot_name=global_config.BOT_NICKNAME, bot_name=global_config.BOT_NICKNAME,
bot_other_names="/".join( bot_other_names="/".join(global_config.BOT_ALIAS_NAMES),
global_config.BOT_ALIAS_NAMES,
),
prompt_personality=prompt_personality, prompt_personality=prompt_personality,
mood_prompt=mood_prompt, mood_prompt=mood_prompt,
reply_style1=reply_style1_chosen, reply_style1=reply_style1_chosen,
@@ -411,6 +464,30 @@ class PromptBuilder:
prompt_ger=prompt_ger, prompt_ger=prompt_ger,
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"), moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
) )
else:
template_name = "reasoning_prompt_private_main"
effective_sender_name = sender_name
prompt = await global_prompt_manager.format_prompt(
template_name,
relation_prompt=relation_prompt,
sender_name=effective_sender_name,
memory_prompt=memory_prompt,
prompt_info=prompt_info,
schedule_prompt=schedule_prompt,
chat_talking_prompt=chat_talking_prompt,
message_txt=message_txt,
bot_name=global_config.BOT_NICKNAME,
bot_other_names="/".join(global_config.BOT_ALIAS_NAMES),
prompt_personality=prompt_personality,
mood_prompt=mood_prompt,
reply_style1=reply_style1_chosen,
reply_style2=reply_style2_chosen,
keywords_reaction_prompt=keywords_reaction_prompt,
prompt_ger=prompt_ger,
moderation_prompt=await global_prompt_manager.get_prompt_async("moderation_prompt"),
)
# --- End choosing template ---
return prompt return prompt
@@ -670,6 +747,110 @@ class PromptBuilder:
# 返回所有找到的内容,用换行分隔 # 返回所有找到的内容,用换行分隔
return "\n".join(str(result["content"]) for result in results) return "\n".join(str(result["content"]) for result in results)
async def build_planner_prompt(
self,
is_group_chat: bool, # Now passed as argument
chat_target_info: Optional[dict], # Now passed as argument
cycle_history: Deque["CycleInfo"], # Now passed as argument (Type hint needs import or string)
observed_messages_str: str,
current_mind: Optional[str],
structured_info: Dict[str, Any],
current_available_actions: Dict[str, str],
# replan_prompt: str, # Replan logic still simplified
) -> str:
"""构建 Planner LLM 的提示词 (获取模板并填充数据)"""
try:
# --- Determine chat context ---
chat_context_description = "你现在正在一个群聊中"
chat_target_name = None # Only relevant for private
if not is_group_chat and chat_target_info:
chat_target_name = chat_target_info.get('person_name') or chat_target_info.get('user_nickname') or "对方"
chat_context_description = f"你正在和 {chat_target_name} 私聊"
# --- End determining chat context ---
# ... (Copy logic from HeartFChatting._build_planner_prompt here) ...
# Structured info block
structured_info_block = ""
if structured_info:
structured_info_block = f"以下是一些额外的信息:\n{structured_info}\n"
# Chat content block
chat_content_block = ""
if observed_messages_str:
# Use triple quotes for multi-line string literal
chat_content_block = f"""观察到的最新聊天内容如下:
---
{observed_messages_str}
---"""
else:
chat_content_block = "当前没有观察到新的聊天内容。\\n"
# Current mind block
current_mind_block = ""
if current_mind:
current_mind_block = f"你的内心想法:\n{current_mind}"
else:
current_mind_block = "你的内心想法:\n[没有特别的想法]"
# Cycle info block (using passed cycle_history)
cycle_info_block = ""
recent_active_cycles = []
for cycle in reversed(cycle_history):
if cycle.action_taken:
recent_active_cycles.append(cycle)
if len(recent_active_cycles) == 3:
break
consecutive_text_replies = 0
responses_for_prompt = []
for cycle in recent_active_cycles:
if cycle.action_type == "text_reply":
consecutive_text_replies += 1
response_text = cycle.response_info.get("response_text", [])
formatted_response = "[空回复]" if not response_text else " ".join(response_text)
responses_for_prompt.append(formatted_response)
else:
break
if consecutive_text_replies >= 3:
cycle_info_block = f'你已经连续回复了三条消息(最近: "{responses_for_prompt[0]}",第二近: "{responses_for_prompt[1]}",第三近: "{responses_for_prompt[2]}")。你回复的有点多了,请注意'
elif consecutive_text_replies == 2:
cycle_info_block = f'你已经连续回复了两条消息(最近: "{responses_for_prompt[0]}",第二近: "{responses_for_prompt[1]}"),请注意'
elif consecutive_text_replies == 1:
cycle_info_block = f'你刚刚已经回复一条消息(内容: "{responses_for_prompt[0]}"'
if cycle_info_block:
cycle_info_block = f"\n【近期回复历史】\n{cycle_info_block}\n"
else:
cycle_info_block = "\n【近期回复历史】\n(最近没有连续文本回复)\n"
individuality = Individuality.get_instance()
prompt_personality = individuality.get_prompt(x_person=2, level=2)
action_options_text = "当前你可以选择的行动有:\n"
action_keys = list(current_available_actions.keys())
for name in action_keys:
desc = current_available_actions[name]
action_options_text += f"- '{name}': {desc}\n"
example_action_key = action_keys[0] if action_keys else "no_reply"
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt")
prompt = planner_prompt_template.format(
bot_name=global_config.BOT_NICKNAME,
prompt_personality=prompt_personality,
chat_context_description=chat_context_description,
structured_info_block=structured_info_block,
chat_content_block=chat_content_block,
current_mind_block=current_mind_block,
cycle_info_block=cycle_info_block,
action_options_text=action_options_text,
example_action=example_action_key,
)
return prompt
except Exception as e:
logger.error(f"[PromptBuilder] 构建 Planner 提示词时出错: {e}")
logger.error(traceback.format_exc())
return "[构建 Planner Prompt 时出错]"
init_prompt() init_prompt()
prompt_builder = PromptBuilder() prompt_builder = PromptBuilder()