feat(chat): 增加已读标记以聚焦未读消息
为聊天上下文生成逻辑引入了“已读标记” (read_mark) 机制。 当生成回复时,可以在历史消息中插入一个明确的分隔符,以告知模型哪些消息是它已经看过的旧消息,哪些是需要关注的新消息。 这有助于模型更好地聚焦于未读内容,提升上下文感知能力和回复的相关性。 同时,将 Prompt 模板中的“群聊”等硬编码文本参数化,以更好地适配私聊等不同聊天场景。
This commit is contained in:
@@ -267,6 +267,7 @@ class CycleProcessor:
|
|||||||
enable_tool=global_config.tool.enable_tool,
|
enable_tool=global_config.tool.enable_tool,
|
||||||
request_type="chat.replyer",
|
request_type="chat.replyer",
|
||||||
from_plugin=False,
|
from_plugin=False,
|
||||||
|
read_mark=action_info.get("action_message", {}).get("time", 0.0),
|
||||||
)
|
)
|
||||||
if not success or not response_set:
|
if not success or not response_set:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -83,12 +83,12 @@ def init_prompt():
|
|||||||
- {schedule_block}
|
- {schedule_block}
|
||||||
|
|
||||||
## 历史记录
|
## 历史记录
|
||||||
### 当前群聊中的所有人的聊天记录:
|
### {chat_context_type}中的所有人的聊天记录:
|
||||||
{background_dialogue_prompt}
|
{background_dialogue_prompt}
|
||||||
|
|
||||||
{cross_context_block}
|
{cross_context_block}
|
||||||
|
|
||||||
### 当前群聊中正在与你对话的聊天记录
|
### {chat_context_type}中正在与你对话的聊天记录
|
||||||
{core_dialogue_prompt}
|
{core_dialogue_prompt}
|
||||||
|
|
||||||
## 表达方式
|
## 表达方式
|
||||||
@@ -110,11 +110,10 @@ def init_prompt():
|
|||||||
|
|
||||||
## 任务
|
## 任务
|
||||||
|
|
||||||
*你正在一个QQ群里聊天,你需要理解整个群的聊天动态和话题走向,并做出自然的回应。*
|
*你正在一个{chat_context_type}里聊天,你需要理解整个{chat_context_type}的聊天动态和话题走向,并做出自然的回应。*
|
||||||
|
|
||||||
### 核心任务
|
### 核心任务
|
||||||
- 你现在的主要任务是和 {sender_name} 聊天。同时,也有其他用户会参与聊天,你可以参考他们的回复内容,但是你现在想回复{sender_name}的发言。
|
- 你现在的主要任务是和 {sender_name} 聊天。
|
||||||
|
|
||||||
- {reply_target_block} ,你需要生成一段紧密相关且能推动对话的回复。
|
- {reply_target_block} ,你需要生成一段紧密相关且能推动对话的回复。
|
||||||
|
|
||||||
## 规则
|
## 规则
|
||||||
@@ -236,6 +235,7 @@ class DefaultReplyer:
|
|||||||
from_plugin: bool = True,
|
from_plugin: bool = True,
|
||||||
stream_id: Optional[str] = None,
|
stream_id: Optional[str] = None,
|
||||||
reply_message: Optional[Dict[str, Any]] = None,
|
reply_message: Optional[Dict[str, Any]] = None,
|
||||||
|
read_mark: float = 0.0,
|
||||||
) -> Tuple[bool, Optional[Dict[str, Any]], Optional[str]]:
|
) -> Tuple[bool, Optional[Dict[str, Any]], Optional[str]]:
|
||||||
# sourcery skip: merge-nested-ifs
|
# sourcery skip: merge-nested-ifs
|
||||||
"""
|
"""
|
||||||
@@ -268,6 +268,7 @@ class DefaultReplyer:
|
|||||||
available_actions=available_actions,
|
available_actions=available_actions,
|
||||||
enable_tool=enable_tool,
|
enable_tool=enable_tool,
|
||||||
reply_message=reply_message,
|
reply_message=reply_message,
|
||||||
|
read_mark=read_mark,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not prompt:
|
if not prompt:
|
||||||
@@ -723,10 +724,8 @@ class DefaultReplyer:
|
|||||||
truncate=True,
|
truncate=True,
|
||||||
show_actions=True,
|
show_actions=True,
|
||||||
)
|
)
|
||||||
core_dialogue_prompt = f"""--------------------------------
|
core_dialogue_prompt = f"""
|
||||||
这是你和{sender}的对话,你们正在交流中:
|
|
||||||
{core_dialogue_prompt_str}
|
{core_dialogue_prompt_str}
|
||||||
--------------------------------
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return core_dialogue_prompt, all_dialogue_prompt
|
return core_dialogue_prompt, all_dialogue_prompt
|
||||||
@@ -783,6 +782,7 @@ class DefaultReplyer:
|
|||||||
available_actions: Optional[Dict[str, ActionInfo]] = None,
|
available_actions: Optional[Dict[str, ActionInfo]] = None,
|
||||||
enable_tool: bool = True,
|
enable_tool: bool = True,
|
||||||
reply_message: Optional[Dict[str, Any]] = None,
|
reply_message: Optional[Dict[str, Any]] = None,
|
||||||
|
read_mark: float = 0.0,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
构建回复器上下文
|
构建回复器上下文
|
||||||
@@ -859,7 +859,7 @@ class DefaultReplyer:
|
|||||||
target = "(无消息内容)"
|
target = "(无消息内容)"
|
||||||
|
|
||||||
person_info_manager = get_person_info_manager()
|
person_info_manager = get_person_info_manager()
|
||||||
person_id = await person_info_manager.get_person_id_by_person_name(sender)
|
person_id = person_info_manager.get_person_id(platform, reply_message.get("user_id")) if reply_message else None
|
||||||
platform = chat_stream.platform
|
platform = chat_stream.platform
|
||||||
|
|
||||||
target = replace_user_references_sync(target, chat_stream.platform, replace_bot_name=True)
|
target = replace_user_references_sync(target, chat_stream.platform, replace_bot_name=True)
|
||||||
@@ -891,7 +891,7 @@ class DefaultReplyer:
|
|||||||
replace_bot_name=True,
|
replace_bot_name=True,
|
||||||
merge_messages=False,
|
merge_messages=False,
|
||||||
timestamp_mode="relative",
|
timestamp_mode="relative",
|
||||||
read_mark=0.0,
|
read_mark=read_mark,
|
||||||
show_actions=True,
|
show_actions=True,
|
||||||
)
|
)
|
||||||
# 获取目标用户信息,用于s4u模式
|
# 获取目标用户信息,用于s4u模式
|
||||||
@@ -1081,6 +1081,7 @@ class DefaultReplyer:
|
|||||||
reply_target_block=reply_target_block,
|
reply_target_block=reply_target_block,
|
||||||
mood_prompt=mood_prompt,
|
mood_prompt=mood_prompt,
|
||||||
action_descriptions=action_descriptions,
|
action_descriptions=action_descriptions,
|
||||||
|
read_mark=read_mark,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 使用新的统一Prompt系统 - 使用正确的模板名称
|
# 使用新的统一Prompt系统 - 使用正确的模板名称
|
||||||
@@ -1167,7 +1168,7 @@ class DefaultReplyer:
|
|||||||
replace_bot_name=True,
|
replace_bot_name=True,
|
||||||
merge_messages=False,
|
merge_messages=False,
|
||||||
timestamp_mode="relative",
|
timestamp_mode="relative",
|
||||||
read_mark=0.0,
|
read_mark=read_mark,
|
||||||
show_actions=True,
|
show_actions=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -520,6 +520,7 @@ async def _build_readable_messages_internal(
|
|||||||
pic_counter: int = 1,
|
pic_counter: int = 1,
|
||||||
show_pic: bool = True,
|
show_pic: bool = True,
|
||||||
message_id_list: Optional[List[Dict[str, Any]]] = None,
|
message_id_list: Optional[List[Dict[str, Any]]] = None,
|
||||||
|
read_mark: float = 0.0,
|
||||||
) -> Tuple[str, List[Tuple[float, str, str]], Dict[str, str], int]:
|
) -> Tuple[str, List[Tuple[float, str, str]], Dict[str, str], int]:
|
||||||
"""
|
"""
|
||||||
内部辅助函数,构建可读消息字符串和原始消息详情列表。
|
内部辅助函数,构建可读消息字符串和原始消息详情列表。
|
||||||
@@ -726,11 +727,10 @@ async def _build_readable_messages_internal(
|
|||||||
"is_action": is_action,
|
"is_action": is_action,
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# 如果是同一个人发送的连续消息且时间间隔小于等于60秒
|
# 如果是同一个人发送的连续消息且时间间隔小于等于60秒
|
||||||
if name == current_merge["name"] and (timestamp - current_merge["end_time"] <= 60):
|
if name == current_merge["name"] and (timestamp - current_merge["end_time"] <= 60):
|
||||||
current_merge["content"].append(content)
|
current_merge["content"].append(content)
|
||||||
current_merge["end_time"] = timestamp # 更新最后消息时间
|
current_merge["end_time"] = timestamp
|
||||||
else:
|
else:
|
||||||
# 保存上一个合并块
|
# 保存上一个合并块
|
||||||
merged_messages.append(current_merge)
|
merged_messages.append(current_merge)
|
||||||
@@ -758,8 +758,14 @@ async def _build_readable_messages_internal(
|
|||||||
|
|
||||||
# 4 & 5: 格式化为字符串
|
# 4 & 5: 格式化为字符串
|
||||||
output_lines = []
|
output_lines = []
|
||||||
|
read_mark_inserted = False
|
||||||
|
|
||||||
for _i, merged in enumerate(merged_messages):
|
for _i, merged in enumerate(merged_messages):
|
||||||
|
# 检查是否需要插入已读标记
|
||||||
|
if read_mark > 0 and not read_mark_inserted and merged["start_time"] >= read_mark:
|
||||||
|
output_lines.append("\n--- 以上消息是你已经看过,请关注以下未读的新消息---\n")
|
||||||
|
read_mark_inserted = True
|
||||||
|
|
||||||
# 使用指定的 timestamp_mode 格式化时间
|
# 使用指定的 timestamp_mode 格式化时间
|
||||||
readable_time = translate_timestamp_to_human_readable(merged["start_time"], mode=timestamp_mode)
|
readable_time = translate_timestamp_to_human_readable(merged["start_time"], mode=timestamp_mode)
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ class PromptParameters:
|
|||||||
|
|
||||||
# 可用动作信息
|
# 可用动作信息
|
||||||
available_actions: Optional[Dict[str, Any]] = None
|
available_actions: Optional[Dict[str, Any]] = None
|
||||||
|
read_mark: float = 0.0
|
||||||
|
|
||||||
def validate(self) -> List[str]:
|
def validate(self) -> List[str]:
|
||||||
"""参数验证"""
|
"""参数验证"""
|
||||||
@@ -449,7 +450,8 @@ class Prompt:
|
|||||||
core_dialogue, background_dialogue = await self._build_s4u_chat_history_prompts(
|
core_dialogue, background_dialogue = await self._build_s4u_chat_history_prompts(
|
||||||
self.parameters.message_list_before_now_long,
|
self.parameters.message_list_before_now_long,
|
||||||
self.parameters.target_user_info.get("user_id") if self.parameters.target_user_info else "",
|
self.parameters.target_user_info.get("user_id") if self.parameters.target_user_info else "",
|
||||||
self.parameters.sender
|
self.parameters.sender,
|
||||||
|
read_mark=self.parameters.read_mark,
|
||||||
)
|
)
|
||||||
|
|
||||||
context_data["core_dialogue_prompt"] = core_dialogue
|
context_data["core_dialogue_prompt"] = core_dialogue
|
||||||
@@ -465,7 +467,7 @@ class Prompt:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def _build_s4u_chat_history_prompts(
|
async def _build_s4u_chat_history_prompts(
|
||||||
message_list_before_now: List[Dict[str, Any]], target_user_id: str, sender: str
|
message_list_before_now: List[Dict[str, Any]], target_user_id: str, sender: str, read_mark: float = 0.0
|
||||||
) -> Tuple[str, str]:
|
) -> Tuple[str, str]:
|
||||||
"""构建S4U风格的分离对话prompt"""
|
"""构建S4U风格的分离对话prompt"""
|
||||||
# 实现逻辑与原有SmartPromptBuilder相同
|
# 实现逻辑与原有SmartPromptBuilder相同
|
||||||
@@ -491,6 +493,7 @@ class Prompt:
|
|||||||
replace_bot_name=True,
|
replace_bot_name=True,
|
||||||
timestamp_mode="normal",
|
timestamp_mode="normal",
|
||||||
truncate=True,
|
truncate=True,
|
||||||
|
read_mark=read_mark,
|
||||||
)
|
)
|
||||||
all_dialogue_prompt = f"所有用户的发言:\n{all_dialogue_prompt_str}"
|
all_dialogue_prompt = f"所有用户的发言:\n{all_dialogue_prompt_str}"
|
||||||
|
|
||||||
@@ -510,7 +513,7 @@ class Prompt:
|
|||||||
replace_bot_name=True,
|
replace_bot_name=True,
|
||||||
merge_messages=False,
|
merge_messages=False,
|
||||||
timestamp_mode="normal_no_YMD",
|
timestamp_mode="normal_no_YMD",
|
||||||
read_mark=0.0,
|
read_mark=read_mark,
|
||||||
truncate=True,
|
truncate=True,
|
||||||
show_actions=True,
|
show_actions=True,
|
||||||
)
|
)
|
||||||
@@ -764,6 +767,7 @@ class Prompt:
|
|||||||
"keywords_reaction_prompt": self.parameters.keywords_reaction_prompt or context_data.get("keywords_reaction_prompt", ""),
|
"keywords_reaction_prompt": self.parameters.keywords_reaction_prompt or context_data.get("keywords_reaction_prompt", ""),
|
||||||
"moderation_prompt": self.parameters.moderation_prompt_block or context_data.get("moderation_prompt", ""),
|
"moderation_prompt": self.parameters.moderation_prompt_block or context_data.get("moderation_prompt", ""),
|
||||||
"safety_guidelines_block": self.parameters.safety_guidelines_block or context_data.get("safety_guidelines_block", ""),
|
"safety_guidelines_block": self.parameters.safety_guidelines_block or context_data.get("safety_guidelines_block", ""),
|
||||||
|
"chat_context_type": "群聊" if self.parameters.is_group_chat else "私聊",
|
||||||
}
|
}
|
||||||
|
|
||||||
def _prepare_normal_params(self, context_data: Dict[str, Any]) -> Dict[str, Any]:
|
def _prepare_normal_params(self, context_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ async def generate_reply(
|
|||||||
return_prompt: bool = False,
|
return_prompt: bool = False,
|
||||||
request_type: str = "generator_api",
|
request_type: str = "generator_api",
|
||||||
from_plugin: bool = True,
|
from_plugin: bool = True,
|
||||||
|
read_mark: float = 0.0,
|
||||||
) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
|
) -> Tuple[bool, List[Tuple[str, Any]], Optional[str]]:
|
||||||
"""生成回复
|
"""生成回复
|
||||||
|
|
||||||
@@ -129,6 +130,7 @@ async def generate_reply(
|
|||||||
from_plugin=from_plugin,
|
from_plugin=from_plugin,
|
||||||
stream_id=chat_stream.stream_id if chat_stream else chat_id,
|
stream_id=chat_stream.stream_id if chat_stream else chat_id,
|
||||||
reply_message=reply_message,
|
reply_message=reply_message,
|
||||||
|
read_mark=read_mark,
|
||||||
)
|
)
|
||||||
if not success:
|
if not success:
|
||||||
logger.warning("[GeneratorAPI] 回复生成失败")
|
logger.warning("[GeneratorAPI] 回复生成失败")
|
||||||
|
|||||||
Reference in New Issue
Block a user