feat(chat): 为回复分割器添加 llm 与 punctuation 模式
本次更新重构了回复分割功能,引入了 `split_mode` 配置项,允许用户在两种分割模式之间进行选择,提供了更大的灵活性。 - **`llm` 模式**: 延续了由大语言模型通过 `[SPLIT]` 标记决定断句的功能。此模式下的提示词(Prompt)已进一步优化,以引导模型做出更自然的分割。 - **`punctuation` 模式**: 恢复了传统的基于标点符号的分割逻辑。这已设为新的默认模式,确保用户更新后行为与旧版本保持一致。 此外,`at_user` 插件也进行了适配,以正确处理由 `llm` 模式可能产生的多段消息。
This commit is contained in:
@@ -1025,14 +1025,18 @@ class DefaultReplyer:
|
|||||||
prompt_text = await prompt.build()
|
prompt_text = await prompt.build()
|
||||||
|
|
||||||
# --- 动态添加分割指令 ---
|
# --- 动态添加分割指令 ---
|
||||||
if global_config.response_splitter.enable:
|
if global_config.response_splitter.enable and global_config.response_splitter.split_mode == "llm":
|
||||||
split_instruction = """
|
split_instruction = """
|
||||||
## 分割指令
|
## 消息分段艺术
|
||||||
你正在通过一个即时聊天软件发送消息。请模仿一个真实人类的打字和发送习惯:
|
为了模仿真实人类的聊天节奏,你可以在需要时将一条回复分成几段发送。
|
||||||
- **简洁明了**: 如果一句话能说清楚,就一次性发出去,不要添加任何标记。
|
|
||||||
- **自然断句**: 当你想表达一个转折、一个停顿,或者想补充说明时,就像正常人会先发一部分再发另一部分一样,请在断句处插入 `[SPLIT]` 标记。
|
**核心原则**: 只有当分段能**增强表达效果**或**控制信息节奏**时,才在断句处使用 `[SPLIT]` 标记。
|
||||||
- **动机**: 使用 `[SPLIT]` 的目的是为了让对话节奏更自然,更有层次感,而不是为了分割而分割。
|
|
||||||
示例: "我刚刚看到一个超好笑的视频![SPLIT]等我找找发给你~"
|
**参考场景**:
|
||||||
|
- 当你想表达一个转折或停顿时。
|
||||||
|
- 当你想先说结论,再补充说明时。
|
||||||
|
|
||||||
|
**任务**: 请结合你的智慧和人设,自然地决定是否需要分段。如果需要,请在最恰当的位置插入 `[SPLIT]` 标记。
|
||||||
"""
|
"""
|
||||||
# 在 "现在,你说:" 之前插入
|
# 在 "现在,你说:" 之前插入
|
||||||
parts = prompt_text.rsplit("现在,你说:", 1)
|
parts = prompt_text.rsplit("现在,你说:", 1)
|
||||||
|
|||||||
@@ -331,15 +331,21 @@ def process_llm_response(text: str, enable_splitter: bool = True, enable_chinese
|
|||||||
)
|
)
|
||||||
|
|
||||||
if global_config.response_splitter.enable and enable_splitter:
|
if global_config.response_splitter.enable and enable_splitter:
|
||||||
logger.info("回复分割器已启用。")
|
logger.info(f"回复分割器已启用,模式: {global_config.response_splitter.split_mode}。")
|
||||||
if "[SPLIT]" in cleaned_text:
|
|
||||||
|
split_mode = global_config.response_splitter.split_mode
|
||||||
|
|
||||||
|
if split_mode == "llm" and "[SPLIT]" in cleaned_text:
|
||||||
|
logger.debug("检测到 [SPLIT] 标记,使用 LLM 自定义分割。")
|
||||||
split_sentences_raw = cleaned_text.split("[SPLIT]")
|
split_sentences_raw = cleaned_text.split("[SPLIT]")
|
||||||
# 清理每个句子首尾可能由LLM添加的空格或换行符,并移除空句子
|
|
||||||
split_sentences = [s.strip() for s in split_sentences_raw if s.strip()]
|
split_sentences = [s.strip() for s in split_sentences_raw if s.strip()]
|
||||||
logger.debug(f"LLM 自定义分割结果: {split_sentences}")
|
|
||||||
else:
|
else:
|
||||||
# 如果没有 [SPLIT] 标记,则不进行任何分割
|
if split_mode == "llm":
|
||||||
|
logger.debug("未检测到 [SPLIT] 标记,本次不进行分割。")
|
||||||
split_sentences = [cleaned_text]
|
split_sentences = [cleaned_text]
|
||||||
|
else: # mode == "punctuation"
|
||||||
|
logger.debug("使用基于标点的传统模式进行分割。")
|
||||||
|
split_sentences = split_into_sentences_w_remove_punctuation(cleaned_text)
|
||||||
else:
|
else:
|
||||||
logger.debug("回复分割器已禁用。")
|
logger.debug("回复分割器已禁用。")
|
||||||
split_sentences = [cleaned_text]
|
split_sentences = [cleaned_text]
|
||||||
|
|||||||
@@ -475,6 +475,7 @@ class ResponseSplitterConfig(ValidatedConfigBase):
|
|||||||
"""回复分割器配置类"""
|
"""回复分割器配置类"""
|
||||||
|
|
||||||
enable: bool = Field(default=True, description="启用")
|
enable: bool = Field(default=True, description="启用")
|
||||||
|
split_mode: str = Field(default="llm", description="分割模式: 'llm' 或 'punctuation'")
|
||||||
max_length: int = Field(default=256, description="最大长度")
|
max_length: int = Field(default=256, description="最大长度")
|
||||||
max_sentence_num: int = Field(default=3, description="最大句子数")
|
max_sentence_num: int = Field(default=3, description="最大句子数")
|
||||||
enable_kaomoji_protection: bool = Field(default=False, description="启用颜文字保护")
|
enable_kaomoji_protection: bool = Field(default=False, description="启用颜文字保护")
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ class AtAction(BaseAction):
|
|||||||
# === 功能描述(必须填写)===
|
# === 功能描述(必须填写)===
|
||||||
action_parameters = {"user_name": "需要艾特用户的名字", "at_message": "艾特用户时要发送的消息"}
|
action_parameters = {"user_name": "需要艾特用户的名字", "at_message": "艾特用户时要发送的消息"}
|
||||||
action_require = [
|
action_require = [
|
||||||
"当需要艾特某个用户时使用",
|
"当用户明确要求你去'叫'、'喊'、'提醒'或'艾特'某人时使用",
|
||||||
"当你需要提醒特定用户查看消息时使用",
|
"当你判断,为了让特定的人看到消息,需要代表用户去呼叫他/她时使用",
|
||||||
"在回复中需要明确指向某个用户时使用",
|
"例如:'你去叫一下张三','提醒一下李四开会'",
|
||||||
]
|
]
|
||||||
llm_judge_prompt = """
|
llm_judge_prompt = """
|
||||||
判定是否需要使用艾特用户动作的条件:
|
判定是否需要使用艾特用户动作的条件:
|
||||||
@@ -150,11 +150,16 @@ class AtAction(BaseAction):
|
|||||||
logger.error("回复器生成回复失败")
|
logger.error("回复器生成回复失败")
|
||||||
return False, "回复生成失败"
|
return False, "回复生成失败"
|
||||||
|
|
||||||
final_message = llm_response.get("content", "")
|
final_message_raw = llm_response.get("content", "")
|
||||||
if not final_message:
|
if not final_message_raw:
|
||||||
logger.warning("回复器生成了空内容")
|
logger.warning("回复器生成了空内容")
|
||||||
return False, "回复内容为空"
|
return False, "回复内容为空"
|
||||||
|
|
||||||
|
# 对LLM生成的内容进行后处理,解析[SPLIT]标记并将分段消息合并
|
||||||
|
from src.chat.utils.utils import process_llm_response
|
||||||
|
final_message_segments = process_llm_response(final_message_raw, enable_splitter=True, enable_chinese_typo=False)
|
||||||
|
final_message = " ".join(final_message_segments)
|
||||||
|
|
||||||
await self.send_command(
|
await self.send_command(
|
||||||
"SEND_AT_MESSAGE",
|
"SEND_AT_MESSAGE",
|
||||||
args={"group_id": self.chat_stream.group_info.group_id, "qq_id": user_id, "text": final_message},
|
args={"group_id": self.chat_stream.group_info.group_id, "qq_id": user_id, "text": final_message},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[inner]
|
[inner]
|
||||||
version = "6.8.2"
|
version = "6.8.3"
|
||||||
|
|
||||||
#----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读----
|
#----以下是给开发人员阅读的,如果你只是部署了MoFox-Bot,不需要阅读----
|
||||||
#如果你想要修改配置文件,请递增version的值
|
#如果你想要修改配置文件,请递增version的值
|
||||||
@@ -321,6 +321,7 @@ word_replace_rate=0.006 # 整词替换概率
|
|||||||
|
|
||||||
[response_splitter]
|
[response_splitter]
|
||||||
enable = true # 是否启用回复分割器
|
enable = true # 是否启用回复分割器
|
||||||
|
split_mode = "punctuation" # 分割模式: "llm" - 由语言模型决定, "punctuation" - 基于标点符号
|
||||||
max_length = 512 # 回复允许的最大长度
|
max_length = 512 # 回复允许的最大长度
|
||||||
max_sentence_num = 8 # 回复允许的最大句子数
|
max_sentence_num = 8 # 回复允许的最大句子数
|
||||||
enable_kaomoji_protection = false # 是否启用颜文字保护
|
enable_kaomoji_protection = false # 是否启用颜文字保护
|
||||||
|
|||||||
Reference in New Issue
Block a user