From 0154c8fedd9869e71665daf14c08899c63c4a625 Mon Sep 17 00:00:00 2001 From: Windpicker-owo <3431391539@qq.com> Date: Mon, 1 Dec 2025 09:20:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E8=BF=9E=E7=BB=AD?= =?UTF-8?q?=E8=B6=85=E6=97=B6=E8=AE=A1=E6=95=B0=E5=92=8C=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E6=9C=80=E5=90=8E=E5=9B=9E=E5=A4=8D=E6=97=B6=E9=97=B4=EF=BC=8C?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B6=85=E6=97=B6=E5=86=B3=E7=AD=96=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E6=96=87=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kokoro_flow_chatter/proactive_thinker.py | 42 ++++++++++++++++++- .../kokoro_flow_chatter/prompt/builder.py | 19 +++++++++ .../kokoro_flow_chatter/prompt/prompts.py | 7 +++- .../built_in/kokoro_flow_chatter/session.py | 20 ++++++++- 4 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py b/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py index 0cee53028..b24161808 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py +++ b/src/plugins/built_in/kokoro_flow_chatter/proactive_thinker.py @@ -385,7 +385,13 @@ class ProactiveThinker: ) return - logger.info(f"[ProactiveThinker] 等待超时: user={session.user_id}") + # 增加连续超时计数 + session.consecutive_timeout_count += 1 + + logger.info( + f"[ProactiveThinker] 等待超时: user={session.user_id}, " + f"consecutive_timeout={session.consecutive_timeout_count}" + ) try: # 获取用户名 @@ -403,6 +409,18 @@ class ProactiveThinker: action_modifier = ActionModifier(action_manager, session.stream_id) await action_modifier.modify_actions(chatter_name="KokoroFlowChatter") + # 计算用户最后回复距今的时间 + time_since_user_reply = None + if session.last_user_message_at: + time_since_user_reply = time.time() - session.last_user_message_at + + # 构建超时上下文信息 + extra_context = { + "consecutive_timeout_count": session.consecutive_timeout_count, + "time_since_user_reply": time_since_user_reply, + "time_since_user_reply_str": self._format_duration(time_since_user_reply) if time_since_user_reply else "未知", + } + # 调用 Planner 生成超时决策 plan_response = await generate_plan( session=session, @@ -410,6 +428,7 @@ class ProactiveThinker: situation_type="timeout", chat_stream=chat_stream, available_actions=action_manager.get_using_actions(), + extra_context=extra_context, ) # 为 kfc_reply 动作注入必要的上下文信息 @@ -419,6 +438,7 @@ class ProactiveThinker: action.params["user_name"] = user_name action.params["thought"] = plan_response.thought action.params["situation_type"] = "timeout" + action.params["extra_context"] = extra_context # 执行动作(回复生成在 Action.execute() 中完成) for action in plan_response.actions: @@ -457,7 +477,8 @@ class ProactiveThinker: logger.info( f"[ProactiveThinker] 超时决策完成: user={session.user_id}, " f"actions={[a.type for a in plan_response.actions]}, " - f"continue_wait={plan_response.max_wait_seconds > 0}" + f"continue_wait={plan_response.max_wait_seconds > 0}, " + f"consecutive_timeout={session.consecutive_timeout_count}" ) except Exception as e: @@ -681,6 +702,23 @@ class ProactiveThinker: # 回退到 user_id return user_id + def _format_duration(self, seconds: float | None) -> str: + """格式化时间间隔为人类可读的字符串""" + if seconds is None or seconds < 0: + return "未知" + + if seconds < 60: + return f"{int(seconds)} 秒" + elif seconds < 3600: + minutes = seconds / 60 + return f"{minutes:.0f} 分钟" + elif seconds < 86400: + hours = seconds / 3600 + return f"{hours:.1f} 小时" + else: + days = seconds / 86400 + return f"{days:.1f} 天" + def get_stats(self) -> dict: """获取统计信息""" return { diff --git a/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py b/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py index 94ed55263..4f0ea1316 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py +++ b/src/plugins/built_in/kokoro_flow_chatter/prompt/builder.py @@ -531,6 +531,24 @@ class PromptBuilder: elapsed = session.waiting_config.get_elapsed_seconds() max_wait = session.waiting_config.max_wait_seconds expected = session.waiting_config.expected_reaction + + # 构建连续超时上下文 + timeout_context_parts = [] + + # 添加连续超时次数信息 + consecutive_count = extra_context.get("consecutive_timeout_count", 0) + if consecutive_count > 1: + timeout_context_parts.append(f"⚠️ 这已经是你连续第 {consecutive_count} 次等到超时了。") + + # 添加距离用户上次回复的时间 + time_since_user_reply_str = extra_context.get("time_since_user_reply_str") + if time_since_user_reply_str: + timeout_context_parts.append(f"距离 {user_name} 上一次回复你已经过去了 {time_since_user_reply_str}。") + + timeout_context = "\n".join(timeout_context_parts) + if timeout_context: + timeout_context = "\n" + timeout_context + "\n" + return await global_prompt_manager.format_prompt( PROMPT_NAMES["situation_timeout"], current_time=current_time, @@ -538,6 +556,7 @@ class PromptBuilder: elapsed_minutes=elapsed / 60, max_wait_minutes=max_wait / 60, expected_reaction=expected or "对方能回复点什么", + timeout_context=timeout_context, ) elif situation_type == "proactive": diff --git a/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py b/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py index 80b1d29e9..b798b84b9 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py +++ b/src/plugins/built_in/kokoro_flow_chatter/prompt/prompts.py @@ -123,12 +123,15 @@ kfc_SITUATION_TIMEOUT = Prompt( 你之前发了消息后一直在等 {user_name} 的回复。 你原本打算最多等 {max_wait_minutes:.1f} 分钟,现在已经等了 {elapsed_minutes:.1f} 分钟了,对方还是没回。 你当时期待的反应是:"{expected_reaction}" - +{timeout_context} 你需要决定: 1. 继续等待(设置新的 max_wait_seconds) 2. 主动说点什么打破沉默 3. 做点别的事情(执行其他动作) -4. 算了不等了(max_wait_seconds = 0)""", +4. 算了不等了(max_wait_seconds = 0) + +【注意】如果已经连续多次超时,对方可能暂时不方便回复。频繁主动发消息可能会打扰到对方。 +考虑是否应该暂时放下期待,让对方有空间。""", ) kfc_SITUATION_PROACTIVE = Prompt( diff --git a/src/plugins/built_in/kokoro_flow_chatter/session.py b/src/plugins/built_in/kokoro_flow_chatter/session.py index fe26714a3..8e5254a73 100644 --- a/src/plugins/built_in/kokoro_flow_chatter/session.py +++ b/src/plugins/built_in/kokoro_flow_chatter/session.py @@ -66,6 +66,12 @@ class KokoroSession: # 上次主动思考时间 self.last_proactive_at: Optional[float] = None + + # 连续超时计数(用于避免过度打扰用户) + self.consecutive_timeout_count: int = 0 + + # 用户最后发消息的时间(用于计算距离用户上次回复的时间) + self.last_user_message_at: Optional[float] = None @property def status(self) -> SessionStatus: @@ -95,14 +101,20 @@ class KokoroSession: timestamp: Optional[float] = None, ) -> MentalLogEntry: """添加用户消息事件""" + msg_time = timestamp or time.time() + entry = MentalLogEntry( event_type=EventType.USER_MESSAGE, - timestamp=timestamp or time.time(), + timestamp=msg_time, content=content, user_name=user_name, user_id=user_id, ) + # 收到用户消息,重置连续超时计数 + self.consecutive_timeout_count = 0 + self.last_user_message_at = msg_time + # 如果之前在等待,记录收到回复的情况 if self.status == SessionStatus.WAITING and self.waiting_config.is_active(): elapsed = self.waiting_config.get_elapsed_seconds() @@ -213,6 +225,8 @@ class KokoroSession: "last_activity_at": self.last_activity_at, "total_interactions": self.total_interactions, "last_proactive_at": self.last_proactive_at, + "consecutive_timeout_count": self.consecutive_timeout_count, + "last_user_message_at": self.last_user_message_at, } @classmethod @@ -244,6 +258,10 @@ class KokoroSession: session.total_interactions = data.get("total_interactions", 0) session.last_proactive_at = data.get("last_proactive_at") + # 连续超时相关 + session.consecutive_timeout_count = data.get("consecutive_timeout_count", 0) + session.last_user_message_at = data.get("last_user_message_at") + return session