mirror of https://github.com/Mai-with-u/MaiBot.git
better:优化planner,提及时消耗更少,连续no_reply时降低敏感度
parent
250919f892
commit
82a87f4926
|
|
@ -111,6 +111,9 @@ class HeartFChatting:
|
|||
self.question_probability_multiplier = 1
|
||||
self.questioned = False
|
||||
|
||||
# 跟踪连续 no_reply 次数,用于动态调整阈值
|
||||
self.consecutive_no_reply_count = 0
|
||||
|
||||
# 聊天内容概括器
|
||||
self.chat_history_summarizer = ChatHistorySummarizer(chat_id=self.stream_id)
|
||||
|
||||
|
|
@ -192,43 +195,21 @@ class HeartFChatting:
|
|||
filter_command=True,
|
||||
)
|
||||
|
||||
question_probability = 0
|
||||
if time.time() - self.last_active_time > 7200:
|
||||
question_probability = 0.0003
|
||||
elif time.time() - self.last_active_time > 3600:
|
||||
question_probability = 0.0001
|
||||
|
||||
|
||||
|
||||
# 根据连续 no_reply 次数动态调整阈值
|
||||
# 3次 no_reply 时,阈值调高到 1.5(50%概率为1,50%概率为2)
|
||||
# 5次 no_reply 时,提高到 2(大于等于两条消息的阈值)
|
||||
if self.consecutive_no_reply_count >= 5:
|
||||
threshold = 2
|
||||
elif self.consecutive_no_reply_count >= 3:
|
||||
# 1.5 的含义:50%概率为1,50%概率为2
|
||||
threshold = 2 if random.random() < 0.5 else 1
|
||||
else:
|
||||
question_probability = 0.00003
|
||||
|
||||
question_probability = question_probability * global_config.chat.get_auto_chat_value(self.stream_id) * self.question_probability_multiplier
|
||||
threshold = 1
|
||||
|
||||
#暂时禁用
|
||||
|
||||
# print(f"{self.log_prefix} questioned: {self.questioned},len: {len(global_conflict_tracker.get_questions_by_chat_id(self.stream_id))}")
|
||||
# if question_probability > 0 and not self.questioned and len(global_conflict_tracker.get_questions_by_chat_id(self.stream_id)) == 0: #长久没有回复,可以试试主动发言,提问概率随着时间增加
|
||||
# # logger.info(f"{self.log_prefix} 长久没有回复,可以试试主动发言,概率: {question_probability}")
|
||||
# if random.random() < question_probability: # 30%概率主动发言
|
||||
# try:
|
||||
# self.questioned = True
|
||||
# self.last_active_time = time.time()
|
||||
# # print(f"{self.log_prefix} 长久没有回复,可以试试主动发言,开始生成问题")
|
||||
# logger.info(f"{self.log_prefix} 长久没有回复,可以试试主动发言,开始生成问题")
|
||||
# cycle_timers, thinking_id = self.start_cycle()
|
||||
# question_maker = QuestionMaker(self.stream_id)
|
||||
# question, context,conflict_context = await question_maker.make_question()
|
||||
# if question:
|
||||
# logger.info(f"{self.log_prefix} 问题: {question}")
|
||||
# await global_conflict_tracker.track_conflict(question, conflict_context, True, self.stream_id)
|
||||
# await self._lift_question_reply(question,context,thinking_id)
|
||||
# else:
|
||||
# logger.info(f"{self.log_prefix} 无问题")
|
||||
# # self.end_cycle(cycle_timers, thinking_id)
|
||||
# except Exception as e:
|
||||
# logger.error(f"{self.log_prefix} 主动提问失败: {e}")
|
||||
# print(traceback.format_exc())
|
||||
|
||||
|
||||
if len(recent_messages_list) >= 1:
|
||||
if len(recent_messages_list) >= threshold:
|
||||
# for message in recent_messages_list:
|
||||
# print(message.processed_plain_text)
|
||||
# !处理no_reply_until_call逻辑
|
||||
|
|
@ -332,14 +313,15 @@ class HeartFChatting:
|
|||
available_actions: Dict[str, ActionInfo],
|
||||
cycle_timers: Dict[str, float],
|
||||
) -> List[ActionPlannerInfo]:
|
||||
"""执行planner,但不包含reply动作(用于并行执行场景)"""
|
||||
"""执行planner,但不包含reply动作(用于并行执行场景,提及时使用简化版提示词)"""
|
||||
try:
|
||||
with Timer("规划器", cycle_timers):
|
||||
action_to_use_info = await self.action_planner.plan(
|
||||
loop_start_time=self.last_read_time,
|
||||
available_actions=available_actions,
|
||||
is_mentioned=True, # 标记为提及时,使用简化版提示词
|
||||
)
|
||||
# 过滤掉reply动作
|
||||
# 过滤掉reply动作(虽然提及时不应该有reply,但为了安全还是过滤一下)
|
||||
return [action for action in action_to_use_info if action.action_type != "reply"]
|
||||
except Exception as e:
|
||||
logger.error(f"{self.log_prefix} Planner执行失败: {e}")
|
||||
|
|
@ -356,6 +338,8 @@ class HeartFChatting:
|
|||
"""当被提及时,独立生成回复的任务"""
|
||||
try:
|
||||
self.questioned = False
|
||||
# 重置连续 no_reply 计数
|
||||
self.consecutive_no_reply_count = 0
|
||||
reason = "有人提到了你,进行回复"
|
||||
|
||||
await database_api.store_action_info(
|
||||
|
|
@ -675,76 +659,6 @@ class HeartFChatting:
|
|||
traceback.print_exc()
|
||||
return False, ""
|
||||
|
||||
async def _lift_question_reply(self, question: str, question_context: str, thinking_id: str):
|
||||
reason = f"在聊天中:\n{question_context}\n你对问题\"{question}\"感到好奇,想要和群友讨论"
|
||||
new_msg = get_raw_msg_before_timestamp_with_chat(
|
||||
chat_id=self.stream_id,
|
||||
timestamp=time.time(),
|
||||
limit=1,
|
||||
)
|
||||
|
||||
reply_action_info = ActionPlannerInfo(
|
||||
action_type="reply",
|
||||
reasoning= "",
|
||||
action_data={},
|
||||
action_message=new_msg[0],
|
||||
available_actions=None,
|
||||
loop_start_time=time.time(),
|
||||
action_reasoning=reason)
|
||||
self.action_planner.add_plan_log(reasoning=f"你对问题\"{question}\"感到好奇,想要和群友讨论", actions=[reply_action_info])
|
||||
|
||||
success, llm_response = await generator_api.rewrite_reply(
|
||||
chat_stream=self.chat_stream,
|
||||
reply_data={
|
||||
"raw_reply": f"我对这个问题感到好奇:{question}",
|
||||
"reason": reason,
|
||||
},
|
||||
)
|
||||
|
||||
if not success or not llm_response or not llm_response.reply_set:
|
||||
logger.info("主动提问发言失败")
|
||||
self.action_planner.add_plan_excute_log(result="主动回复生成失败")
|
||||
return {"action_type": "reply", "success": False, "result": "主动回复生成失败", "loop_info": None}
|
||||
|
||||
if success:
|
||||
for reply_seg in llm_response.reply_set.reply_data:
|
||||
send_data = reply_seg.content
|
||||
await send_api.text_to_stream(
|
||||
text=send_data,
|
||||
stream_id=self.stream_id,
|
||||
)
|
||||
|
||||
await database_api.store_action_info(
|
||||
chat_stream=self.chat_stream,
|
||||
action_build_into_prompt=False,
|
||||
action_prompt_display=reason,
|
||||
action_done=True,
|
||||
thinking_id=thinking_id,
|
||||
action_data={"reply_text": llm_response.reply_set.reply_data[0].content},
|
||||
action_name="reply",
|
||||
)
|
||||
|
||||
# 构建循环信息
|
||||
loop_info: Dict[str, Any] = {
|
||||
"loop_plan_info": {
|
||||
"action_result": [reply_action_info],
|
||||
},
|
||||
"loop_action_info": {
|
||||
"action_taken": True,
|
||||
"reply_text": llm_response.reply_set.reply_data[0].content,
|
||||
"command": "",
|
||||
"taken_time": time.time(),
|
||||
},
|
||||
}
|
||||
self.last_active_time = time.time()
|
||||
self.action_planner.add_plan_excute_log(result=f"你提问:{question}")
|
||||
|
||||
return {
|
||||
"action_type": "reply",
|
||||
"success": True,
|
||||
"result": f"你提问:{question}",
|
||||
"loop_info": loop_info,
|
||||
}
|
||||
|
||||
|
||||
async def _send_response(
|
||||
|
|
@ -808,6 +722,9 @@ class HeartFChatting:
|
|||
reason = action_planner_info.reasoning or "选择不回复"
|
||||
# logger.info(f"{self.log_prefix} 选择不回复,原因: {reason}")
|
||||
|
||||
# 增加连续 no_reply 计数
|
||||
self.consecutive_no_reply_count += 1
|
||||
|
||||
await database_api.store_action_info(
|
||||
chat_stream=self.chat_stream,
|
||||
action_build_into_prompt=False,
|
||||
|
|
@ -827,6 +744,8 @@ class HeartFChatting:
|
|||
logger.info(f"{self.log_prefix} 保持沉默,直到有人直接叫的名字")
|
||||
reason = action_planner_info.reasoning or "选择不回复"
|
||||
|
||||
# 增加连续 no_reply 计数
|
||||
self.consecutive_no_reply_count += 1
|
||||
self.no_reply_until_call = True
|
||||
await database_api.store_action_info(
|
||||
chat_stream=self.chat_stream,
|
||||
|
|
@ -844,6 +763,8 @@ class HeartFChatting:
|
|||
# 直接当场执行reply逻辑
|
||||
self.questioned = False
|
||||
# 刷新主动发言状态
|
||||
# 重置连续 no_reply 计数
|
||||
self.consecutive_no_reply_count = 0
|
||||
|
||||
reason = action_planner_info.reasoning or "选择回复"
|
||||
await database_api.store_action_info(
|
||||
|
|
|
|||
|
|
@ -83,6 +83,42 @@ no_reply
|
|||
"planner_prompt",
|
||||
)
|
||||
|
||||
Prompt(
|
||||
"""{time_block}
|
||||
{name_block}
|
||||
{chat_context_description},以下是具体的聊天内容
|
||||
**聊天内容**
|
||||
{chat_content_block}
|
||||
|
||||
**可选的action**
|
||||
no_reply
|
||||
动作描述:
|
||||
没有合适的可以使用的动作,不使用action
|
||||
{{"action":"no_reply"}}
|
||||
|
||||
{action_options_text}
|
||||
|
||||
**你之前的action执行和思考记录**
|
||||
{actions_before_now_block}
|
||||
|
||||
请选择**可选的**且符合使用条件的action,并说明触发action的消息id(消息id格式:m+数字)
|
||||
先输出你的简短的选择思考理由,再输出你选择的action,理由不要分点,精简。
|
||||
**动作选择要求**
|
||||
请你根据聊天内容,用户的最新消息和以下标准选择合适的动作:
|
||||
1.思考**所有**的可用的action中的**每个动作**是否符合当下条件,如果动作使用条件符合聊天内容就使用
|
||||
2.如果相同的内容已经被执行,请不要重复执行
|
||||
{moderation_prompt}
|
||||
|
||||
请选择所有符合使用要求的action,动作用json格式输出,用```json包裹,如果输出多个json,每个json都要单独一行放在同一个```json代码块内,你可以重复使用同一个动作或不同动作:
|
||||
**示例**
|
||||
// 理由文本(简短)
|
||||
```json
|
||||
{{"action":"动作名", "target_message_id":"m123", "reason":"原因"}}
|
||||
{{"action":"动作名", "target_message_id":"m456", "reason":"原因"}}
|
||||
```""",
|
||||
"planner_prompt_mentioned",
|
||||
)
|
||||
|
||||
Prompt(
|
||||
"""
|
||||
{action_name}
|
||||
|
|
@ -205,6 +241,7 @@ class ActionPlanner:
|
|||
self,
|
||||
available_actions: Dict[str, ActionInfo],
|
||||
loop_start_time: float = 0.0,
|
||||
is_mentioned: bool = False,
|
||||
) -> List[ActionPlannerInfo]:
|
||||
# sourcery skip: use-named-expression
|
||||
"""
|
||||
|
|
@ -244,6 +281,11 @@ class ActionPlanner:
|
|||
|
||||
logger.debug(f"{self.log_prefix}过滤后有{len(filtered_actions)}个可用动作")
|
||||
|
||||
# 如果是提及时且没有可用动作,直接返回空列表,不调用LLM以节省token
|
||||
if is_mentioned and not filtered_actions:
|
||||
logger.info(f"{self.log_prefix}提及时没有可用动作,跳过plan调用")
|
||||
return []
|
||||
|
||||
# 构建包含所有动作的提示词
|
||||
prompt, message_id_list = await self.build_planner_prompt(
|
||||
is_group_chat=is_group_chat,
|
||||
|
|
@ -252,6 +294,7 @@ class ActionPlanner:
|
|||
chat_content_block=chat_content_block,
|
||||
message_id_list=message_id_list,
|
||||
interest=global_config.personality.interest,
|
||||
is_mentioned=is_mentioned,
|
||||
)
|
||||
|
||||
# 调用LLM获取决策
|
||||
|
|
@ -355,6 +398,7 @@ class ActionPlanner:
|
|||
message_id_list: List[Tuple[str, "DatabaseMessages"]],
|
||||
chat_content_block: str = "",
|
||||
interest: str = "",
|
||||
is_mentioned: bool = False,
|
||||
) -> tuple[str, List[Tuple[str, "DatabaseMessages"]]]:
|
||||
"""构建 Planner LLM 的提示词 (获取模板并填充数据)"""
|
||||
try:
|
||||
|
|
@ -367,17 +411,6 @@ class ActionPlanner:
|
|||
# 构建动作选项块
|
||||
action_options_block = await self._build_action_options_block(current_available_actions)
|
||||
|
||||
# 检查是否有连续3次以上no_reply,如果有则添加no_reply_until_call选项
|
||||
no_reply_until_call_block = ""
|
||||
if self._has_consecutive_no_reply(min_count=3):
|
||||
no_reply_until_call_block = """no_reply_until_call
|
||||
动作描述:
|
||||
保持沉默,直到有人直接叫你的名字
|
||||
当前话题不感兴趣时使用,或有人不喜欢你的发言时使用
|
||||
当你频繁选择no_reply时使用,表示话题暂时与你无关
|
||||
{{"action":"no_reply_until_call"}}
|
||||
"""
|
||||
|
||||
# 其他信息
|
||||
moderation_prompt_block = "请不要输出违法违规内容,不要输出色情,暴力,政治相关内容,如有敏感内容,请规避。"
|
||||
time_block = f"当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
|
||||
|
|
@ -387,20 +420,47 @@ class ActionPlanner:
|
|||
)
|
||||
name_block = f"你的名字是{bot_name}{bot_nickname},请注意哪些是你自己的发言。"
|
||||
|
||||
# 获取主规划器模板并填充
|
||||
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt")
|
||||
prompt = planner_prompt_template.format(
|
||||
time_block=time_block,
|
||||
chat_context_description=chat_context_description,
|
||||
chat_content_block=chat_content_block,
|
||||
actions_before_now_block=actions_before_now_block,
|
||||
action_options_text=action_options_block,
|
||||
no_reply_until_call_block=no_reply_until_call_block,
|
||||
moderation_prompt=moderation_prompt_block,
|
||||
name_block=name_block,
|
||||
interest=interest,
|
||||
plan_style=global_config.personality.plan_style,
|
||||
)
|
||||
# 根据是否是提及时选择不同的模板
|
||||
if is_mentioned:
|
||||
# 提及时使用简化版提示词,不需要reply、no_reply、no_reply_until_call
|
||||
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt_mentioned")
|
||||
prompt = planner_prompt_template.format(
|
||||
time_block=time_block,
|
||||
chat_context_description=chat_context_description,
|
||||
chat_content_block=chat_content_block,
|
||||
actions_before_now_block=actions_before_now_block,
|
||||
action_options_text=action_options_block,
|
||||
moderation_prompt=moderation_prompt_block,
|
||||
name_block=name_block,
|
||||
interest=interest,
|
||||
plan_style=global_config.personality.plan_style,
|
||||
)
|
||||
else:
|
||||
# 正常流程使用完整版提示词
|
||||
# 检查是否有连续3次以上no_reply,如果有则添加no_reply_until_call选项
|
||||
no_reply_until_call_block = ""
|
||||
if self._has_consecutive_no_reply(min_count=3):
|
||||
no_reply_until_call_block = """no_reply_until_call
|
||||
动作描述:
|
||||
保持沉默,直到有人直接叫你的名字
|
||||
当前话题不感兴趣时使用,或有人不喜欢你的发言时使用
|
||||
当你频繁选择no_reply时使用,表示话题暂时与你无关
|
||||
{{"action":"no_reply_until_call"}}
|
||||
"""
|
||||
|
||||
planner_prompt_template = await global_prompt_manager.get_prompt_async("planner_prompt")
|
||||
prompt = planner_prompt_template.format(
|
||||
time_block=time_block,
|
||||
chat_context_description=chat_context_description,
|
||||
chat_content_block=chat_content_block,
|
||||
actions_before_now_block=actions_before_now_block,
|
||||
action_options_text=action_options_block,
|
||||
no_reply_until_call_block=no_reply_until_call_block,
|
||||
moderation_prompt=moderation_prompt_block,
|
||||
name_block=name_block,
|
||||
interest=interest,
|
||||
plan_style=global_config.personality.plan_style,
|
||||
)
|
||||
|
||||
return prompt, message_id_list
|
||||
except Exception as e:
|
||||
|
|
|
|||
Loading…
Reference in New Issue