From 43ac8afe60c1b7dbf253e565513d6f5cd720a156 Mon Sep 17 00:00:00 2001 From: tt-P607 <68868379+tt-P607@users.noreply.github.com> Date: Sun, 9 Nov 2025 12:47:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(replyer):=20=E5=BD=BB=E5=BA=95=E9=87=8D?= =?UTF-8?q?=E6=9E=84=E5=9B=9E=E5=A4=8D=E8=BF=87=E6=BB=A4=E5=99=A8=E4=BB=A5?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=B7=B1=E5=BA=A6=E5=B5=8C=E5=A5=97=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题描述: 此前,模型在生成回复时,会偶发性地模仿并输出Prompt中用于示例的 [回复<...>] 格式。尽管经过多次迭代,原有的正则表达式过滤器仍无法有效处理包含多层嵌套括号的复杂情况,导致清理不彻底,最终发送的消息中仍残留部分不规范文本。 解决方案: 本次提交对 default_generator.py 中的 llm_generate_content 方法进行了彻底的重构,用一套更健壮、更简单的逻辑替换了原有的正则表达式方案: 采用“整体清除”策略: 放弃了复杂的模式匹配,转而实现了一个更直接的清除逻辑。现在,如果一条生成的消息以 [回复 开头,程序会寻找到该消息中 最后一个 ] 字符的位置。 精准切片: 将从消息开头到最后一个 ] 字符(包含该字符)之间的所有内容全部切除,只保留之后的部分作为最终回复。 日志记录: 保留了清晰的 logger.warning,在过滤器生效时,会详细记录原始内容与清理后的内容,便于持续监控模型行为。 优势: 鲁棒性: 这种新方法与括号的嵌套层数完全无关,无论模型生成多么复杂的嵌套结构,都能一举将其完全清除,从根本上解决了问题。 简洁性: 代码逻辑比复杂的正则表达式更清晰、更易于理解和维护。 验证: 创建了专门的测试脚本 Elysia/Bot/scripts/test/test_ultimate_filter.py。 脚本覆盖了多种复杂的、包含深度嵌套的失败案例以及正常的边界情况。 测试结果表明,新的过滤逻辑完美通过了所有测试,达到了预期的效果。 --- src/chat/replyer/default_generator.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/chat/replyer/default_generator.py b/src/chat/replyer/default_generator.py index 5017d5d01..c252a250f 100644 --- a/src/chat/replyer/default_generator.py +++ b/src/chat/replyer/default_generator.py @@ -1743,17 +1743,22 @@ class DefaultReplyer: content = content.replace("[SPLIT]", "") - aggressive_pattern = re.compile(r'\[\s*回复\s*<.+?>.*?\]', re.DOTALL) - original_content_for_aggresive_filter = content - cleaned_content_by_aggresive_filter = aggressive_pattern.sub('', content).strip() + original_content_for_filter = content + cleaned_content = content.strip() - # 再次检查并移除因嵌套括号可能残留的单个 ']' - if cleaned_content_by_aggresive_filter.startswith(']'): - cleaned_content_by_aggresive_filter = cleaned_content_by_aggresive_filter[1:].strip() + # 终极过滤器:处理模型模仿的、可能存在多层嵌套的回复格式 + # 规则:如果消息以 "[回复" 开头,则删除从开头到最后一个 "]" 的所有内容。 + if cleaned_content.startswith("[回复"): + last_bracket_index = cleaned_content.rfind("]") + if last_bracket_index != -1: + cleaned_content = cleaned_content[last_bracket_index + 1 :].strip() - if cleaned_content_by_aggresive_filter != original_content_for_aggresive_filter: - logger.warning(f"检测到并清理了模型生成的不规范回复格式。原始内容: '{original_content_for_aggresive_filter}', 清理后: '{cleaned_content_by_aggresive_filter}'") - content = cleaned_content_by_aggresive_filter + if cleaned_content != original_content_for_filter.strip(): + logger.warning( + "检测到并清理了模型生成的不规范回复格式。" + f"原始内容: '{original_content_for_filter}', 清理后: '{cleaned_content}'" + ) + content = cleaned_content logger.debug(f"replyer生成内容: {content}") return content, reasoning_content, model_name, tool_calls