From ecadaaa9aeb066c8b5209f6122745d3ccf93b48a Mon Sep 17 00:00:00 2001 From: youpaishidifu Date: Mon, 17 Aug 2026 09:22:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E7=B1=BB=E6=9F=A5=E8=AF=A2=E8=A2=ABURL=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E8=AF=AF=E5=8C=B9=E9=85=8D=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: - 用户问"那个登录插件去哪下载",beibao.md(背包插件)被错误选中 - 下载意图检查正确拒绝了beibao(因为不含"登录"核心词) - 但子串回退逻辑却放行了:因为"插件"出现在URL路径 /plugin/ 中 根因: 子串回退检查phrase in full时,没有排除URL路径中的匹配 导致通用词"插件"在URL中出现就误判为相关文档 修复: 1. 下载类查询要求:核心名词短语(如"登录")必须在文档正文中出现 不能只是"插件"这种通用词在URL路径中命中 2. 如果核心名词未命中,直接拒绝子串回退 3. 额外检查:如果phrase只在URL中出现,也拒绝 测试预期: - '那个登录插件去哪下载' → beibao拒绝(不含"登录"),sdf1_login通过(含"登录") - '哪个插件下载' → beibao可能通过(只有"插件"通用词) --- auto_reply.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/auto_reply.py b/auto_reply.py index 487ea72..86e64ad 100644 --- a/auto_reply.py +++ b/auto_reply.py @@ -360,10 +360,49 @@ class AutoReply: # 没有 meaningful_token 命中,即使有子串匹配也拒绝 logger.debug(f"无有意义token命中拒绝: query={query[:40]!r} doc_heading={heading[:30]!r}") return False + + # ⭐ 新增:下载类查询的特殊处理(2026-08-17 修复牛头不对马嘴) + # 如果查询含"下载"且已有明确的"下载意图拒绝"日志,说明核心词检查已通过但语义不匹配 + # 此时子串回退不应放行(防止"插件"等通用词在URL中误匹配) + _is_download_query = any(w in query for w in ('下载', '下到', '哪下', '在哪下', '怎么下')) + if _is_download_query: + # 下载类查询要求:子串必须包含查询的核心名词(如"登录插件") + # 不能只是"插件"这种通用词在URL路径中命中 + _download_core_phrases = [] + for kw in q_mean: + if kw not in {'下载', '下到', '哪下', '在哪下', '怎么下', '哪个', '哪里', '去哪'}: + _download_core_phrases.append(kw) + if _download_core_phrases: + # 检查是否有核心名词短语在文档中完整出现 + _has_core_noun_match = any( + phrase in full + for phrase in _download_core_phrases + if len(phrase) >= 2 + ) + if not _has_core_noun_match: + logger.debug( + f"下载查询子串回退拒绝(核心名词未命中): query={query[:40]!r} " + f"doc_heading={heading[:30]!r} core_nouns={_download_core_phrases!r}" + ) + return False + for qlen in range(min(len(stripped), 6), 3, -1): for start in range(len(stripped) - qlen + 1): phrase = stripped[start:start + qlen] if phrase in full: + # ⭐ 新增:下载类查询跳过URL路径中的匹配 + # 防止"插件"在/plugin/路径中误匹配 + if _is_download_query and 'http' in full: + # 检查phrase是否在URL路径中(而非正文) + _url_pattern = r'https?://[^\s\)]+' + _urls = re.findall(_url_pattern, full) + _in_url_only = all(phrase in url for url in _urls if phrase in url) + if _in_url_only: + logger.debug( + f"下载查询子串回退拒绝(URL路径匹配): query={query[:40]!r} " + f"phrase={phrase!r} in URL only" + ) + continue logger.debug( f"子串回退命中: phrase={phrase!r} in doc={doc.get('heading', '')[:30]!r}" )