From 0fe4f018ba0d2544add84440d9dd7fd6b417308a Mon Sep 17 00:00:00 2001 From: youpaishidifu Date: Mon, 17 Aug 2026 10:47:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=A0=B8=E5=BF=83=E8=AF=8D=E9=9B=B6?= =?UTF-8?q?=E5=91=BD=E4=B8=AD=E7=A1=AC=E6=8B=92=E7=BB=9D=EF=BC=8C=E5=BD=BB?= =?UTF-8?q?=E5=BA=95=E4=BF=AE=E5=A4=8D=E7=99=BB=E5=BD=95=E6=8F=92=E4=BB=B6?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E5=88=B0=E8=83=8C=E5=8C=85=E7=9A=84=E7=89=9B?= =?UTF-8?q?=E5=A4=B4=E4=B8=8D=E5=AF=B9=E9=A9=AC=E5=98=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:_has_content_relevance 中,'下载'被排除出 core_kw(core_kw={'登录'}), 但 has_ht=True(heading '下载地址' 命中 q_mean 中的'下载'), 导致跳过多关键词覆盖检查和正文覆盖检查,直接 return True。 即使下载意图检查拒绝了 beibao(核心词'登录'未命中),函数仍然返回 True。 修复:下载意图拒绝后、多关键词覆盖检查前,新增核心词零命中硬拒绝: 当 core_kw 非空但 core_hits=0 时无条件 return False。 --- auto_reply.py | 14 ++++++++++++++ monitor.py | 10 ++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/auto_reply.py b/auto_reply.py index e345c03..0463d00 100644 --- a/auto_reply.py +++ b/auto_reply.py @@ -269,6 +269,10 @@ class AutoReply: # 2026-08-17 新增:口语动词"知道"不应作为核心词 # 用户常说"俺想知道""我想知道","知道"是口语填充,不是查询意图 '知道', '想知道', + # 2026-08-17 新增:下载类动词不应作为核心词 + # "下载"是动作而非查询对象,真正核心的是被查询的插件名 + # 例:"登录插件去哪儿下载"的核心词应是{'登录'},而非{'下载'} + '下载', '下到', '哪下', '在哪下', '怎么下', } core_kw = q_mean - non_core_kw doc_text = heading_clean + " " + title.lower() + " " + body_clean[:800] @@ -316,6 +320,15 @@ class AutoReply: logger.debug(f"下载意图放行: query={query[:30]!r} heading={heading[:30]!r}") return True + # ⭐ 核心词零命中拒绝:核心词存在但全部未命中文档 → 无条件拒绝 + # 防止 has_ht=True(仅因通用词如"下载"命中heading)但真正核心词(如"登录")未命中时误放行 + if core_kw and core_hits == 0: + logger.debug( + f"核心词零命中拒绝: query={query[:40]!r} doc_title={title!r} " + f"core_kw={core_kw!r} core_hits=0 has_ht={has_ht}" + ) + return False + # ⭐ 当heading含核心词时(has_ht=True),也需检查覆盖比例 # 防止"草原"等通用词单一命中导致误选sdf1.md等不相关文档 # 规则: @@ -324,6 +337,7 @@ class AutoReply: # - 例:查询含核心词={'草原','近期','公告'} # sdf1.md只含"草原"(1/3)→ 拒绝 # index.md含"近期"+"公告"(2/3)→ 通过 + logger.debug(f"核心词覆盖检查: core_kw={core_kw} len={len(core_kw)} core_hits={core_hits}") if len(core_kw) >= 2: # ⭐ 修复:阈值改为max(1,...),避免只有1个核心词时仍要求≥2个命中 # 例:"服务器最近有哪些公告啊?" 核心词={'公告'}(1个) diff --git a/monitor.py b/monitor.py index 367be6e..b066e69 100644 --- a/monitor.py +++ b/monitor.py @@ -5086,8 +5086,14 @@ class MessageMonitor: # ⭐ Task #1508 防御兜底:剥离后为空但输入非空 → 回退原文 # (宁可保留昵称在消息里,也不能把整条消息吞成空串)。 if not ts.strip() and text.strip(): - logger.warning(f"[qq] 剥离后为空,回退原文防消息丢失: {text.strip()[:80]!r}") - return text.strip() + # 进一步检查:如果原文本身就是单个@或极短文本,直接返回空而不是回退 + # 防止"@"这类无意义字符进入后续处理流程 + cleaned = text.strip() + if len(cleaned) <= 1 or cleaned == '@': + logger.debug(f"[qq] 原文本身就是无意义字符,返回空: {cleaned!r}") + return '' + logger.warning(f"[qq] 剥离后为空,回退原文防消息丢失: {cleaned!r}") + return cleaned return ts.strip() def _sanitize_message(self, text: str) -> str: