杀死checker test

pull/937/head
114514 2025-05-07 19:40:12 +08:00
parent 68572bfbef
commit 8839facadd
3 changed files with 177 additions and 260 deletions

View File

@ -842,21 +842,19 @@ class Conversation:
action_successful: bool = False # 标记动作是否成功执行
final_status: str = "recall" # 动作最终状态,默认为 recall (表示未成功或需重试)
final_reason: str = "动作未成功执行" # 动作最终原因
need_replan_from_checker: bool = False # 标记是否由 ReplyChecker 要求重新规划
# need_replan_from_checker: bool = False # 这个变量在循环内部被赋值
try:
# --- 根据不同的 action 类型执行相应的逻辑 ---
# 1. 处理需要生成、检查、发送的动作
if action in ["direct_reply", "send_new_message"]:
max_reply_attempts: int = 3 # 最多尝试次数 (可配置)
max_reply_attempts: int = global_config.get("pfc_max_reply_attempts", 3) # 最多尝试次数 (可配置)
reply_attempt_count: int = 0
is_suitable: bool = False # 标记回复是否合适
generated_content: str = "" # 存储生成的回复
check_reason: str = "未进行检查" # 存储检查结果原因
# --- [核心修复] 引入重试循环 ---
is_send_decision_from_rg = False # 标记是否由 reply_generator 决定发送
need_replan_from_checker: bool = False # 在循环前初始化
while reply_attempt_count < max_reply_attempts and not is_suitable and not need_replan_from_checker:
reply_attempt_count += 1
@ -878,12 +876,6 @@ class Conversation:
if action == "send_new_message":
is_send_decision_from_rg = True # 标记 send_new_message 的决策来自RG
try:
# 使用 pfc_utils.py 中的 get_items_from_json 来解析
# 注意get_items_from_json 目前主要用于提取固定字段的字典。
# reply_generator 返回的是一个顶级JSON对象。
# 我们需要稍微调整用法或增强 get_items_from_json。
# 简单起见,这里我们先直接用 json.loads后续可以优化。
parsed_json = None
try:
parsed_json = json.loads(raw_llm_output)
@ -923,17 +915,24 @@ class Conversation:
generated_content_for_check_or_send = text_to_process
if not generated_content_for_check_or_send or generated_content_for_check_or_send.startswith("抱歉") or (action == "send_new_message" and generated_content_for_check_or_send == "no"):
logger.warning(f"{log_prefix} 生成内容无效或为错误提示 (或send:no),将进行下一次尝试 (如果适用)。")
check_reason = "生成内容无效或选择不发送"
if not generated_content_for_check_or_send or \
generated_content_for_check_or_send.startswith("抱歉") or \
generated_content_for_check_or_send.strip() == "" or \
(action == "send_new_message" and generated_content_for_check_or_send == "no" and should_send_reply): # should_send_reply is true here means RG said yes, but txt is "no" or empty
warning_msg = f"{log_prefix} 生成内容无效或为错误提示"
if action == "send_new_message" and generated_content_for_check_or_send == "no":
warning_msg += " (ReplyGenerator决定发送但文本为'no')"
logger.warning(warning_msg + ",将进行下一次尝试 (如果适用)。")
check_reason = "生成内容无效或选择不发送" # 统一原因
conversation_info.last_reply_rejection_reason = check_reason
conversation_info.last_rejected_reply_content = generated_content_for_check_or_send
if action == "direct_reply": # direct_reply 失败时才继续尝试
await asyncio.sleep(0.5)
continue
else: # send_new_message 如果是 no不应该继续尝试上面已经break了
pass # 理论上不会到这里如果上面break了
# if reply_attempt_count < max_reply_attempts: # 只有在还有尝试次数时才继续
await asyncio.sleep(0.5) # 暂停一下
continue # 直接进入下一次循环尝试
self.state = ConversationState.CHECKING
if not self.reply_checker:
raise RuntimeError("ReplyChecker 未初始化")
@ -973,10 +972,30 @@ class Conversation:
if not is_suitable:
conversation_info.last_reply_rejection_reason = check_reason
conversation_info.last_rejected_reply_content = generated_content_for_check_or_send
if not need_replan_from_checker and reply_attempt_count < max_reply_attempts:
# 如果是我们特定的复读原因,并且 checker 说不需要重新规划 (这是我们的新逻辑)
if check_reason == "机器人尝试发送重复消息" and not need_replan_from_checker:
logger.warning(f"{log_prefix} 回复因自身重复被拒绝: {check_reason}。将使用相同 Prompt 类型重试。")
# 不需要额外操作,循环会自动继续,因为 is_suitable=False 且 need_replan_from_checker=False
if reply_attempt_count < max_reply_attempts: # 还有尝试次数
await asyncio.sleep(0.5) # 暂停一下
continue # 进入下一次重试
else: # 达到最大次数
logger.warning(f"{log_prefix} 即使是复读,也已达到最大尝试次数。")
break # 结束循环,按失败处理
elif not need_replan_from_checker and reply_attempt_count < max_reply_attempts: # 其他不合适原因,但无需重规划,且可重试
logger.warning(f"{log_prefix} 回复不合适,原因: {check_reason}。将进行下一次尝试。")
await asyncio.sleep(0.5)
# 如果需要重规划或达到最大次数,循环会在下次判断时自动结束
await asyncio.sleep(0.5) # 暂停一下
continue # 进入下一次重试
else: # 需要重规划,或达到最大次数
logger.warning(f"{log_prefix} 回复不合适且(需要重规划或已达最大次数)。原因: {check_reason}")
break # 结束循环,将在循环外部处理
else: # is_suitable is True
# 找到了合适的回复
conversation_info.last_reply_rejection_reason = None # 清除之前的拒绝原因
conversation_info.last_rejected_reply_content = None
break # 成功,跳出循环
# --- 循环结束后处理 ---
if action == "send_new_message" and not should_send_reply and is_send_decision_from_rg:
@ -1013,17 +1032,11 @@ class Conversation:
logger.info(f"[私聊][{self.private_name}] 反思后的新规划动作: {new_action}, 原因: {new_reason}")
# **暂定方案:**
# _handle_action 在这种情况下返回一个特殊标记。
# 为了不立即修改返回类型,我们暂时在这里记录日志,并在 _plan_and_action_loop 中添加逻辑。
# _handle_action 会将 action_successful 设置为 Truefinal_status 为 "done_no_reply"。
# _plan_and_action_loop 之后会检查这个状态。
# (这里的 final_status, final_reason, action_successful 已在上面设置)
elif is_suitable: # 适用于 direct_reply 或 send_new_message (RG决定发送且检查通过)
logger.info(f"[私聊][{self.private_name}] 动作 '{action}': 找到合适的回复,准备发送。")
conversation_info.last_reply_rejection_reason = None
conversation_info.last_rejected_reply_content = None
# conversation_info.last_reply_rejection_reason = None # 已在循环内清除
# conversation_info.last_rejected_reply_content = None
self.generated_reply = generated_content_for_check_or_send
timestamp_before_sending = time.time()
logger.debug(
@ -1035,6 +1048,8 @@ class Conversation:
if send_success:
action_successful = True
final_status = "done" # 明确设置 final_status
final_reason = "成功发送" # 明确设置 final_reason
logger.info(f"[私聊][{self.private_name}] 动作 '{action}': 成功发送回复.")
if self.idle_conversation_starter:
await self.idle_conversation_starter.update_last_message_time(send_end_time)
@ -1103,6 +1118,7 @@ class Conversation:
logger.error(f"[私聊][{self.private_name}] 动作 '{action}': 发送回复失败。")
final_status = "recall"
final_reason = "发送回复时失败"
action_successful = False # 确保 action_successful 为 False
conversation_info.last_successful_reply_action = None
conversation_info.my_message_count = 0 # 发送失败,重置计数
@ -1121,6 +1137,7 @@ class Conversation:
)
final_status = "recall"
final_reason = f"尝试{max_reply_attempts}次后失败: {check_reason}"
action_successful = False
conversation_info.last_successful_reply_action = None
# my_message_count 保持不变
@ -1335,58 +1352,68 @@ class Conversation:
# 2. 更新动作历史记录的最终状态和原因
# 优化:如果动作成功但状态仍是默认的 recall则更新为 done
if final_status == "recall" and action_successful:
final_status = "done"
# 根据动作类型设置更具体的成功原因
if action == "wait":
# 检查是否是因为超时结束的(需要 waiter 返回值,或者检查 goal_list
# 这里简化处理,直接使用通用成功原因
timeout_occurred = (
any("分钟," in g.get("goal", "") for g in conversation_info.goal_list if isinstance(g, dict))
if conversation_info.goal_list
else False
)
final_reason = "等待完成" + (" (超时)" if timeout_occurred else " (收到新消息或中断)")
elif action == "listening":
final_reason = "进入倾听状态"
elif action in ["rethink_goal", "end_conversation", "block_and_ignore"]:
final_reason = f"成功执行 {action}"
elif action in ["direct_reply", "send_new_message", "say_goodbye"]:
# 如果是因为发送成功,设置原因
final_reason = "成功发送"
else:
# 其他未知但标记成功的动作
final_reason = "动作成功完成"
if action_successful:
# 如果动作标记为成功,但 final_status 仍然是初始的 "recall" 或者 "start"
# (因为可能在try块中成功执行了但没有显式更新 final_status 为 "done")
# 或者是 "done_no_reply" 这种特殊的成功状态
if final_status in ["recall", "start"] and action != "send_new_message": # send_new_message + no_reply 是特殊成功
final_status = "done"
if not final_reason or final_reason == "动作未成功执行":
# 为不同类型的成功动作提供更具体的默认成功原因
if action == "wait":
timeout_occurred = (
any("分钟," in g.get("goal", "") for g in conversation_info.goal_list if isinstance(g, dict))
if conversation_info.goal_list
else False
)
final_reason = "等待完成" + (" (超时)" if timeout_occurred else " (收到新消息或中断)")
elif action == "listening":
final_reason = "进入倾听状态"
elif action in ["rethink_goal", "end_conversation", "block_and_ignore", "say_goodbye"]:
final_reason = f"成功执行 {action}"
elif action in ["direct_reply", "send_new_message"]: # 正常发送成功的case
final_reason = "成功发送"
else:
final_reason = f"动作 {action} 成功完成"
# 如果已经是 "done" 或 "done_no_reply",则保留它们和它们对应的 final_reason
else: # action_successful is False
# 如果动作标记为失败,且 final_status 还是 "recall" (初始值) 或 "start"
if final_status in ["recall", "start"]:
# 尝试从 conversation_info 中获取更具体的失败原因(例如 checker 的原因)
# 这个 specific_rejection_reason 是在 try 块中被设置的
specific_rejection_reason = getattr(conversation_info, 'last_reply_rejection_reason', None)
rejected_content = getattr(conversation_info, 'last_rejected_reply_content', None)
elif final_status == "recall" and not action_successful:
# 如果最终是 recall 且未成功,且不是因为检查不通过(比如生成失败),确保原因合理
# 保留之前的逻辑,检查是否已有更具体的失败原因
if not final_reason or final_reason == "动作未成功执行":
# 检查是否有 checker 的原因
checker_reason = conversation_info.last_reply_rejection_reason
if checker_reason:
final_reason = f"回复检查不通过: {checker_reason}"
else:
final_reason = "动作执行失败或被取消" # 通用失败原因
if specific_rejection_reason:
final_reason = f"执行失败: {specific_rejection_reason}"
if rejected_content and specific_rejection_reason == "机器人尝试发送重复消息": # 对复读提供更清晰的日志
final_reason += f" (内容: '{rejected_content[:30]}...')"
elif not final_reason or final_reason == "动作未成功执行": # 如果没有更具体的原因
final_reason = f"动作 {action} 执行失败或被意外中止"
# 如果 final_status 已经是 "error" 或 "cancelled",则保留它们和它们对应的 final_reason
# 更新历史记录字典
# 更新 done_action 中的记录
if conversation_info.done_action and action_index < len(conversation_info.done_action):
# 使用 update 方法更新字典,更安全
# 确保 current_action_record 是最新的(尽管我们是更新它)
# 实际上我们是更新 list 中的元素
conversation_info.done_action[action_index].update(
{
"status": final_status, # 最终状态
"time_completed": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # 完成时间
"final_reason": final_reason, # 最终原因
"duration_ms": int((time.time() - action_start_time) * 1000), # 记录耗时(毫秒)
"status": final_status,
"time_completed": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"final_reason": final_reason,
"duration_ms": int((time.time() - action_start_time) * 1000),
}
)
logger.debug(
f"[私聊][{self.private_name}] 动作 '{action}' 最终状态: {final_status}, 原因: {final_reason}"
)
else:
# 如果索引无效或列表为空,记录错误
logger.error(f"[私聊][{self.private_name}] 无法更新动作历史记录,索引 {action_index} 无效或列表为空。")
# 最终日志输出
log_final_reason = final_reason if final_reason else "无明确原因"
if final_status == "done" and action_successful and action in ["direct_reply", "send_new_message"] and hasattr(self, 'generated_reply'):
log_final_reason += f" (发送内容: '{self.generated_reply[:30]}...')"
logger.info(f"[私聊][{self.private_name}] 动作 '{action}' 处理完成。最终状态: {final_status}, 原因: {log_final_reason}")
async def _send_reply(self) -> bool:
"""发送 `self.generated_reply` 中的内容到聊天流"""
# 检查是否有内容可发送

View File

@ -1,193 +1,79 @@
import json
from typing import Tuple, List, Dict, Any
from src.common.logger import get_module_logger
from ..models.utils_model import LLMRequest
from ...config.config import global_config
# LLMRequest 和 global_config 不再需要直接在此文件中使用(除非 ReplyChecker 以后有其他功能)
# from ..models.utils_model import LLMRequest # <--- 移除
# from ...config.config import global_config # <--- 移除,但下面会用到 bot_id
from ...config.config import global_config # 为了获取 BOT_QQ
from .chat_observer import ChatObserver
from maim_message import UserInfo
from maim_message import UserInfo # 保持,可能用于未来扩展,但当前逻辑不直接使用
logger = get_module_logger("reply_checker")
class ReplyChecker:
"""回复检查器"""
"""回复检查器 - 新版:仅检查机器人自身发言的精确重复"""
def __init__(self, stream_id: str, private_name: str):
self.llm = LLMRequest(
model=global_config.llm_PFC_reply_checker, temperature=0.50, max_tokens=1000, request_type="reply_check"
)
# self.llm = LLMRequest(...) # <--- 移除 LLM 初始化
self.name = global_config.BOT_NICKNAME
self.private_name = private_name
self.chat_observer = ChatObserver.get_instance(stream_id, private_name)
self.max_retries = 3 # 最大重试次数
# self.max_retries = 3 # 这个 max_retries 属性在当前设计下不再由 checker 控制,而是由 conversation.py 控制
self.bot_qq_str = str(global_config.BOT_QQ) # 获取机器人QQ号用于识别自身消息
async def check(
self, reply: str, goal: str, chat_history: List[Dict[str, Any]], chat_history_text: str,current_time_str: str, retry_count: int = 0
self, reply: str, goal: str, chat_history: List[Dict[str, Any]], chat_history_text: str, current_time_str: str, retry_count: int = 0
) -> Tuple[bool, str, bool]:
"""检查生成的回复是否合适
"""检查生成的回复是否与机器人之前的发言完全一致长度大于4
Args:
reply: 生成的回复
goal: 对话目标
chat_history: 对话历史记录
chat_history_text: 对话历史记录文本
retry_count: 当前重试次数
reply: 待检查的机器人回复内容
goal: 当前对话目标 (新逻辑中未使用)
chat_history: 对话历史记录 (包含用户和机器人的消息字典列表)
chat_history_text: 对话历史记录的文本格式 (新逻辑中未使用)
current_time_str: 当前时间的字符串格式 (新逻辑中未使用)
retry_count: 当前重试次数 (新逻辑中未使用)
Returns:
Tuple[bool, str, bool]: (是否合适, 原因, 是否需要重新规划)
对于重复消息: (False, "机器人尝试发送重复消息", False)
对于非重复消息: (True, "消息内容未与机器人历史发言重复。", False)
"""
# 不再从 observer 获取,直接使用传入的 chat_history
# messages = self.chat_observer.get_cached_messages(limit=20)
if not self.bot_qq_str:
logger.error(f"[私聊][{self.private_name}] ReplyChecker: BOT_QQ 未配置,无法检查机器人自身消息。")
return True, "BOT_QQ未配置跳过重复检查。", False # 无法检查则默认通过
if len(reply) <= 4:
return True, "消息长度小于等于4字符跳过重复检查。", False
try:
# 筛选出最近由 Bot 自己发送的消息
bot_messages = []
for msg in reversed(chat_history):
user_info = UserInfo.from_dict(msg.get("user_info", {}))
if str(user_info.user_id) == str(global_config.BOT_QQ): # 确保比较的是字符串
bot_messages.append(msg.get("processed_plain_text", ""))
if len(bot_messages) >= 2: # 只和最近的两条比较
break
# 进行比较
if bot_messages:
# 可以用简单比较,或者更复杂的相似度库 (如 difflib)
# 简单比较:是否完全相同
if reply == bot_messages[0]: # 和最近一条完全一样
logger.warning(
f"[私聊][{self.private_name}]ReplyChecker 检测到回复与上一条 Bot 消息完全相同: '{reply}'"
)
return (
False,
"被逻辑检查拒绝:回复内容与你上一条发言完全相同,可以选择深入话题或寻找其它话题或等待",
True,
) # 不合适,需要返回至决策层
# 2. 相似度检查 (如果精确匹配未通过)
import difflib # 导入 difflib 库
for msg_dict in chat_history:
if not isinstance(msg_dict, dict):
continue
# 计算编辑距离相似度ratio() 返回 0 到 1 之间的浮点数
similarity_ratio = difflib.SequenceMatcher(None, reply, bot_messages[0]).ratio()
logger.debug(f"[私聊][{self.private_name}]ReplyChecker - 相似度: {similarity_ratio:.2f}")
user_info_data = msg_dict.get("user_info")
if not isinstance(user_info_data, dict):
continue
# 设置一个相似度阈值
similarity_threshold = 0.9
if similarity_ratio > similarity_threshold:
logger.warning(
f"[私聊][{self.private_name}]ReplyChecker 检测到回复与上一条 Bot 消息高度相似 (相似度 {similarity_ratio:.2f}): '{reply}'"
)
return (
False,
f"被逻辑检查拒绝:回复内容与你上一条发言高度相似 (相似度 {similarity_ratio:.2f}),可以选择深入话题或寻找其它话题或等待。",
True,
)
sender_id = str(user_info_data.get("user_id"))
# 只检查机器人自己发送过的历史消息
if sender_id == self.bot_qq_str:
historical_message_text = msg_dict.get("processed_plain_text", "")
if reply == historical_message_text:
logger.warning(
f"[私聊][{self.private_name}] ReplyChecker 检测到机器人自身重复消息: '{reply}'"
)
return (False, "机器人尝试发送重复消息", False) # is_suitable=False, reason, need_replan=False
# 如果循环结束都没有找到重复
return (True, "消息内容未与机器人历史发言重复。", False)
except Exception as e:
import traceback
logger.error(f"[私聊][{self.private_name}]检查回复时出错: 类型={type(e)}, 值={e}")
logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}") # 打印详细的回溯信息
prompt_template = """
当前时间{current_time_str}
你是一个聊天逻辑检查器请检查以下回复或消息是否合适
对话记录
{chat_history_text}
待检查的消息
{reply}
请结合聊天记录检查以下几点
1. 这条消息是否与最新的对话记录保持连贯性当话题切换时须保证平滑切换
2. 是否存在重复发言或重复表达同质内容尤其是只是换一种方式表达了相同的含义
3. 这条消息是否包含违规内容例如血腥暴力政治敏感等
4. 这条消息是否以发送者的角度发言不要让发送者自己回复自己的消息
5. 这条消息是否通俗易懂
6. 这条消息是否有些多余例如在对方没有回复的情况下依然连续多次消息轰炸尤其是已经连续发送3条信息的情况这很可能不合理需要着重判断
7. 这条消息是否使用了完全没必要的修辞
8. 这条消息是否逻辑通顺
9. 这条消息是否太过冗长了通常私聊的每条消息长度在20字以内除非特殊情况
10. 在连续多次发送消息的情况下这条消息是否衔接自然会不会显得奇怪例如连续两条消息中部分内容重叠
请以JSON格式输出包含以下字段
1. suitable: 是否合适 (true/false)
2. reason: 原因说明
3. need_replan: 是否需要重新决策 (true/false)当你认为此时已经不适合发消息需要规划其它行动时设为true
输出格式示例
{{
"suitable": true,
"reason": "回复符合要求,虽然有可能略微偏离目标,但是整体内容流畅得体",
"need_replan": false
}}
注意请严格按照JSON格式输出不要包含任何其他内容"""
prompt = prompt_template.format(
current_time_str=current_time_str, # 使用传入的参数
goal=goal,
chat_history_text=chat_history_text,
reply=reply
)
# 调用 LLM
content, _ = await self.llm.generate_response_async(prompt)
try:
content, _ = await self.llm.generate_response_async(prompt)
logger.debug(f"[私聊][{self.private_name}]检查回复的原始返回: {content}")
# 清理内容尝试提取JSON部分
content = content.strip()
try:
# 尝试直接解析
result = json.loads(content)
except json.JSONDecodeError:
# 如果直接解析失败尝试查找和提取JSON部分
import re
json_pattern = r"\{[^{}]*\}"
json_match = re.search(json_pattern, content)
if json_match:
try:
result = json.loads(json_match.group())
except json.JSONDecodeError:
# 如果JSON解析失败尝试从文本中提取结果
is_suitable = "不合适" not in content.lower() and "违规" not in content.lower()
reason = content[:100] if content else "无法解析响应"
need_replan = "重新规划" in content.lower() or "目标不适合" in content.lower()
return is_suitable, reason, need_replan
else:
# 如果找不到JSON从文本中判断
is_suitable = "不合适" not in content.lower() and "违规" not in content.lower()
reason = content[:100] if content else "无法解析响应"
need_replan = "重新规划" in content.lower() or "目标不适合" in content.lower()
return is_suitable, reason, need_replan
# 验证JSON字段
suitable = result.get("suitable", None)
reason = result.get("reason", "未提供原因")
need_replan = result.get("need_replan", False)
# 如果suitable字段是字符串转换为布尔值
if isinstance(suitable, str):
suitable = suitable.lower() == "true"
# 如果suitable字段不存在或不是布尔值从reason中判断
if suitable is None:
suitable = "不合适" not in reason.lower() and "违规" not in reason.lower()
# 如果不合适且未达到最大重试次数,返回需要重试
if not suitable and retry_count < self.max_retries:
return False, reason, False
# 如果不合适且已达到最大重试次数,返回需要重新规划
if not suitable and retry_count >= self.max_retries:
return False, f"多次重试后仍不合适: {reason}", True
return suitable, reason, need_replan
except Exception as e:
logger.error(f"[私聊][{self.private_name}]检查回复时出错: {e}")
# 如果出错且已达到最大重试次数,建议重新规划
if retry_count >= self.max_retries:
return False, "多次检查失败,建议重新规划", True
return False, f"检查过程出错,建议重试: {str(e)}", False
logger.error(f"[私聊][{self.private_name}] ReplyChecker 检查重复时出错: 类型={type(e)}, 值={e}")
logger.error(f"[私聊][{self.private_name}]{traceback.format_exc()}")
# 发生未知错误时,为安全起见,默认通过,并记录原因
return (True, f"检查重复时发生内部错误: {str(e)}", False)

View File

@ -215,19 +215,31 @@ class ReplyGenerator:
last_content = getattr(conversation_info, "last_rejected_reply_content", None)
if last_reason and last_content:
last_rejection_info_str = (
f"\n------\n"
f"【重要提示:你上一次尝试回复时失败了,以下是详细信息】\n"
f"上次试图发送的消息内容: “{last_content}\n"
f"失败原因: “{last_reason}\n"
f"请根据【消息内容】和【失败原因】调整你的新回复,避免重复之前的错误。\n"
f"------\n"
)
logger.info(
f"[私聊][{self.private_name}]检测到上次回复失败信息,将加入 Prompt:\n"
f" 内容: {last_content}\n"
f" 原因: {last_reason}"
)
if last_reason == "机器人尝试发送重复消息": # 这是我们从 ReplyChecker 设置的特定原因
last_rejection_info_str = (
f"\n------\n"
f"【重要提示:你上一次尝试发送的消息 “{last_content}” 与你更早之前发送过的某条消息完全相同。这属于复读行为,请避免。】\n"
f"请根据此提示调整你的新回复,确保内容新颖,不要重复你已经说过的话。\n"
f"------\n"
)
logger.info(
f"[私聊][{self.private_name}] (ReplyGenerator) 检测到自身复读,将加入特定警告到 Prompt:\n"
f" 内容: {last_content}"
)
else: # 其他类型的拒绝原因,保持原有格式
last_rejection_info_str = (
f"\n------\n"
f"【重要提示:你上一次尝试回复时失败了,以下是详细信息】\n"
f"上次试图发送的消息内容: “{last_content}\n"
f"失败原因: “{last_reason}\n"
f"请根据【消息内容】和【失败原因】调整你的新回复,避免重复之前的错误。\n"
f"------\n"
)
logger.info(
f"[私聊][{self.private_name}] (ReplyGenerator) 检测到上次回复失败信息,将加入 Prompt:\n"
f" 内容: {last_content}\n"
f" 原因: {last_reason}"
)
# 新增:构建刷屏警告信息 for PROMPT_SEND_NEW_MESSAGE
spam_warning_message = ""
@ -324,12 +336,4 @@ class ReplyGenerator:
else:
return "抱歉,我现在有点混乱,让我重新思考一下..."
# check_reply 方法保持不变
async def check_reply(
self, reply: str, goal: str, chat_history: List[Dict[str, Any]], chat_history_str: str, current_time_str: str, retry_count: int = 0
) -> Tuple[bool, str, bool]:
"""检查回复是否合适
(此方法逻辑保持不变, 但注意 current_time_str 参数的传递)
"""
# 确保 current_time_str 被正确传递给 reply_checker.check
return await self.reply_checker.check(reply, goal, chat_history, chat_history_str, current_time_str, retry_count)
# check_reply 方法在 ReplyGenerator 中不再需要