PFC优化:增加一个新的决策

增加了一个可先的新的屏蔽决策,防止机器人受到骚扰信息消耗token,以前的结束对话结束以后,如果收到新的骚扰信息依然会再次进入决策,这次的屏蔽则是直接屏蔽10分钟(无任何决策),在之后实例自我销毁结束。
This commit is contained in:
114514
2025-04-27 10:10:18 +08:00
parent 2a5184ba46
commit cbaed95938
4 changed files with 50 additions and 5 deletions

View File

@@ -244,7 +244,7 @@ class ActionPlanner:
last_action_context += f"- 该行动当前状态: {status}\n" last_action_context += f"- 该行动当前状态: {status}\n"
# --- 构建最终的 Prompt --- # --- 构建最终的 Prompt ---
prompt = f"""{persona_text}。现在你在参与一场QQ私聊请根据以下【所有信息】审慎且灵活的决策下一步行动可以发言可以等待可以倾听可以调取知识 prompt = f"""{persona_text}。现在你在参与一场QQ私聊请根据以下【所有信息】审慎且灵活的决策下一步行动可以发言可以等待可以倾听可以调取知识,甚至可以屏蔽对方
【当前对话目标】 【当前对话目标】
{goals_str if goals_str.strip() else "- 目前没有明确对话目标,请考虑设定一个。"} {goals_str if goals_str.strip() else "- 目前没有明确对话目标,请考虑设定一个。"}
@@ -261,12 +261,13 @@ class ActionPlanner:
------ ------
可选行动类型以及解释: 可选行动类型以及解释:
etch_knowledge: 需要调取知识,当需要专业知识或特定信息时选择,对方若提到你太认识的人名或实体也可以尝试 etch_knowledge: 需要调取知识,当需要专业知识或特定信息时选择,对方若提到你太认识的人名或实体也可以尝试选择
wait: 暂时不说话,等待对方回复(尤其是在你刚发言后、或上次发言因重复、发言过多被拒时、或不确定做什么时,这是较安全的选择) wait: 暂时不说话,等待对方回复(尤其是在你刚发言后、或上次发言因重复、发言过多被拒时、或不确定做什么时,这是较安全的选择)
listening: 倾听对方发言,当你认为对方话才说到一半,发言明显未结束时采用 listening: 倾听对方发言,当你认为对方话才说到一半,发言明显未结束时选择
direct_reply: 直接回复或发送新消息,允许适当的追问和深入话题,**但是避免在因重复被拒后立即使用,也不要在对方没有回复的情况下过多的“消息轰炸”或重复发言** direct_reply: 直接回复或发送新消息,允许适当的追问和深入话题,**但是避免在因重复被拒后立即使用,也不要在对方没有回复的情况下过多的“消息轰炸”或重复发言**
rethink_goal: 重新思考对话目标,当发现对话目标不再适用或对话卡住时选择,注意私聊的环境是灵活的,有可能需要经常选择 rethink_goal: 重新思考对话目标,当发现对话目标不再适用或对话卡住时选择,注意私聊的环境是灵活的,有可能需要经常选择
end_conversation: 结束对话,对方长时间没回复或者当你觉得对话告一段落时可以选择 end_conversation: 结束对话,对方长时间没回复或者当你觉得对话告一段落时可以选择
block_and_ignore: 更加极端的结束对话方式,直接结束对话并在一段时间内无视对方所有发言(屏蔽),当对话让你感到十分不适,或你遭到各类骚扰时选择
请以JSON格式输出你的决策 请以JSON格式输出你的决策
{{ {{
@@ -292,7 +293,7 @@ end_conversation: 结束对话,对方长时间没回复或者当你觉得对
reason = result.get("reason", "LLM未提供原因默认等待") reason = result.get("reason", "LLM未提供原因默认等待")
# 验证action类型 # 验证action类型
valid_actions = ["direct_reply", "fetch_knowledge", "wait", "listening", "rethink_goal", "end_conversation"] valid_actions = ["direct_reply", "fetch_knowledge", "wait", "listening", "rethink_goal", "end_conversation", "block_and_ignore"]
if action not in valid_actions: if action not in valid_actions:
logger.warning(f"LLM返回了未知的行动类型: '{action}',强制改为 wait") logger.warning(f"LLM返回了未知的行动类型: '{action}',强制改为 wait")
reason = f"(原始行动'{action}'无效已强制改为wait) {reason}" reason = f"(原始行动'{action}'无效已强制改为wait) {reason}"

View File

@@ -4,7 +4,7 @@ import datetime
# from .message_storage import MongoDBMessageStorage # from .message_storage import MongoDBMessageStorage
from src.plugins.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat from src.plugins.utils.chat_message_builder import get_raw_msg_before_timestamp_with_chat
from ...config.config import global_config from ...config.config import global_config
from typing import Dict, Any from typing import Dict, Any, Optional
from ..chat.message import Message from ..chat.message import Message
from .pfc_types import ConversationState from .pfc_types import ConversationState
from .pfc import ChatObserver, GoalAnalyzer, DirectMessageSender from .pfc import ChatObserver, GoalAnalyzer, DirectMessageSender
@@ -36,6 +36,7 @@ class Conversation:
self.stream_id = stream_id self.stream_id = stream_id
self.state = ConversationState.INIT self.state = ConversationState.INIT
self.should_continue = False self.should_continue = False
self.ignore_until_timestamp: Optional[float] = None
# 回复相关 # 回复相关
self.generated_reply = "" self.generated_reply = ""
@@ -125,6 +126,18 @@ class Conversation:
async def _plan_and_action_loop(self): async def _plan_and_action_loop(self):
"""思考步PFC核心循环模块""" """思考步PFC核心循环模块"""
while self.should_continue: while self.should_continue:
if self.ignore_until_timestamp and time.time() < self.ignore_until_timestamp:
# 仍在忽略期间,等待下次检查
await asyncio.sleep(30) # 每 30 秒检查一次
continue # 跳过本轮循环的剩余部分
elif self.ignore_until_timestamp and time.time() >= self.ignore_until_timestamp:
# 忽略期结束,现在正常地结束对话
logger.info(f"忽略时间已到 {self.stream_id},准备结束对话。")
self.ignore_until_timestamp = None # 清除时间戳
self.should_continue = False # 现在停止循环
# (可选)在这里记录一个 'end_conversation' 动作
# 或者确保管理器会基于 should_continue 为 False 来清理它
continue # 跳过本轮循环的剩余部分,让它终止
try: try:
# --- 在规划前记录当前新消息数量 --- # --- 在规划前记录当前新消息数量 ---
initial_new_message_count = 0 initial_new_message_count = 0
@@ -399,6 +412,21 @@ class Conversation:
) )
# 这里不需要 return主循环会在下一轮检查 should_continue # 这里不需要 return主循环会在下一轮检查 should_continue
elif action == "block_and_ignore":
logger.info("不想再理你了...")
# 1. 标记对话为暂时忽略
ignore_duration_seconds = 10 * 60 # 10 分钟
self.ignore_until_timestamp = time.time() + ignore_duration_seconds
logger.info(f"将忽略此对话直到: {datetime.datetime.fromtimestamp(self.ignore_until_timestamp)}")
conversation_info.done_action[action_index].update(
{
"status": "done", # 或者一个自定义状态,比如 "ignored"
"final_reason": "Detected potential harassment, ignoring temporarily.", # 检测到潜在骚扰,暂时忽略
"time": datetime.datetime.now().strftime("%H:%M:%S"),
}
)
self.state = ConversationState.IGNORED
else: # 对应 'wait' 动作 else: # 对应 'wait' 动作
self.state = ConversationState.WAITING self.state = ConversationState.WAITING
logger.info("等待更多信息...") logger.info("等待更多信息...")

View File

@@ -1,3 +1,4 @@
import time
from typing import Dict, Optional from typing import Dict, Optional
from src.common.logger import get_module_logger from src.common.logger import get_module_logger
from .conversation import Conversation from .conversation import Conversation
@@ -44,7 +45,21 @@ class PFCManager:
if stream_id in self._instances and self._instances[stream_id].should_continue: if stream_id in self._instances and self._instances[stream_id].should_continue:
logger.debug(f"使用现有会话实例: {stream_id}") logger.debug(f"使用现有会话实例: {stream_id}")
return self._instances[stream_id] return self._instances[stream_id]
if stream_id in self._instances:
instance = self._instances[stream_id]
if hasattr(instance, 'ignore_until_timestamp') and \
instance.ignore_until_timestamp and \
time.time() < instance.ignore_until_timestamp:
logger.debug(f"会话实例当前处于忽略状态: {stream_id}")
# 返回 None 阻止交互。或者可以返回实例但标记它被忽略了喵?
# 还是返回 None 吧喵。
return None
# 检查 should_continue 状态
if instance.should_continue:
logger.debug(f"使用现有会话实例: {stream_id}")
return instance
# else: 实例存在但不应继续
try: try:
# 创建新实例 # 创建新实例
logger.info(f"创建新的对话实例: {stream_id}") logger.info(f"创建新的对话实例: {stream_id}")

View File

@@ -17,6 +17,7 @@ class ConversationState(Enum):
LISTENING = "倾听" LISTENING = "倾听"
ENDED = "结束" ENDED = "结束"
JUDGING = "判断" JUDGING = "判断"
IGNORED = "屏蔽"
ActionType = Literal["direct_reply", "fetch_knowledge", "wait"] ActionType = Literal["direct_reply", "fetch_knowledge", "wait"]