feat(chat): 为回复分割器添加 llmpunctuation 模式

本次更新重构了回复分割功能,引入了 `split_mode` 配置项,允许用户在两种分割模式之间进行选择,提供了更大的灵活性。

- **`llm` 模式**: 延续了由大语言模型通过 `[SPLIT]` 标记决定断句的功能。此模式下的提示词(Prompt)已进一步优化,以引导模型做出更自然的分割。
- **`punctuation` 模式**: 恢复了传统的基于标点符号的分割逻辑。这已设为新的默认模式,确保用户更新后行为与旧版本保持一致。

此外,`at_user` 插件也进行了适配,以正确处理由 `llm` 模式可能产生的多段消息。
This commit is contained in:
tt-P607
2025-09-11 17:12:01 +08:00
parent 62c548ad2b
commit 0cb2fa3373
5 changed files with 36 additions and 19 deletions

View File

@@ -1025,14 +1025,18 @@ class DefaultReplyer:
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]` 标记。
- **动机**: 使用 `[SPLIT]` 的目的是为了让对话节奏更自然,更有层次感,而不是为了分割而分割。
示例: "我刚刚看到一个超好笑的视频![SPLIT]等我找找发给你~"
## 消息分段艺术
为了模仿真实人类的聊天节奏,你可以在需要时将一条回复分成几段发送。
**核心原则**: 只有当分段能**增强表达效果**或**控制信息节奏**时,才在断句处使用 `[SPLIT]` 标记。
**参考场景**:
- 当你想表达一个转折或停顿时。
- 当你想先说结论,再补充说明时。
**任务**: 请结合你的智慧和人设,自然地决定是否需要分段。如果需要,请在最恰当的位置插入 `[SPLIT]` 标记。
"""
# 在 "现在,你说:" 之前插入
parts = prompt_text.rsplit("现在,你说:", 1)

View File

@@ -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:
logger.info("回复分割器已启用。")
if "[SPLIT]" in cleaned_text:
logger.info(f"回复分割器已启用,模式: {global_config.response_splitter.split_mode}")
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]")
# 清理每个句子首尾可能由LLM添加的空格或换行符并移除空句子
split_sentences = [s.strip() for s in split_sentences_raw if s.strip()]
logger.debug(f"LLM 自定义分割结果: {split_sentences}")
else:
# 如果没有 [SPLIT] 标记,则不进行任何分割
split_sentences = [cleaned_text]
if split_mode == "llm":
logger.debug("未检测到 [SPLIT] 标记,本次不进行分割。")
split_sentences = [cleaned_text]
else: # mode == "punctuation"
logger.debug("使用基于标点的传统模式进行分割。")
split_sentences = split_into_sentences_w_remove_punctuation(cleaned_text)
else:
logger.debug("回复分割器已禁用。")
split_sentences = [cleaned_text]

View File

@@ -475,6 +475,7 @@ class ResponseSplitterConfig(ValidatedConfigBase):
"""回复分割器配置类"""
enable: bool = Field(default=True, description="启用")
split_mode: str = Field(default="llm", description="分割模式: 'llm''punctuation'")
max_length: int = Field(default=256, description="最大长度")
max_sentence_num: int = Field(default=3, description="最大句子数")
enable_kaomoji_protection: bool = Field(default=False, description="启用颜文字保护")

View File

@@ -28,9 +28,9 @@ class AtAction(BaseAction):
# === 功能描述(必须填写)===
action_parameters = {"user_name": "需要艾特用户的名字", "at_message": "艾特用户时要发送的消息"}
action_require = [
"需要艾特某个用户时使用",
"当你需要提醒特定用户查看消息时使用",
"在回复中需要明确指向某个用户时使用",
"当用户明确要求你去'''''提醒''艾特'某人时使用",
"当你判断,为了让特定的人看到消息,需要代表用户去呼叫他/她时使用",
"例如:'你去叫一下张三''提醒一下李四开会'",
]
llm_judge_prompt = """
判定是否需要使用艾特用户动作的条件:
@@ -150,11 +150,16 @@ class AtAction(BaseAction):
logger.error("回复器生成回复失败")
return False, "回复生成失败"
final_message = llm_response.get("content", "")
if not final_message:
final_message_raw = llm_response.get("content", "")
if not final_message_raw:
logger.warning("回复器生成了空内容")
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(
"SEND_AT_MESSAGE",
args={"group_id": self.chat_stream.group_info.group_id, "qq_id": user_id, "text": final_message},

View File

@@ -1,5 +1,5 @@
[inner]
version = "6.8.2"
version = "6.8.3"
#----以下是给开发人员阅读的如果你只是部署了MoFox-Bot不需要阅读----
#如果你想要修改配置文件请递增version的值
@@ -321,6 +321,7 @@ word_replace_rate=0.006 # 整词替换概率
[response_splitter]
enable = true # 是否启用回复分割器
split_mode = "punctuation" # 分割模式: "llm" - 由语言模型决定, "punctuation" - 基于标点符号
max_length = 512 # 回复允许的最大长度
max_sentence_num = 8 # 回复允许的最大句子数
enable_kaomoji_protection = false # 是否启用颜文字保护