fix: 核心词零命中硬拒绝,彻底修复登录插件匹配到背包的牛头不对马嘴
根因:_has_content_relevance 中,'下载'被排除出 core_kw(core_kw={'登录'}),
但 has_ht=True(heading '下载地址' 命中 q_mean 中的'下载'),
导致跳过多关键词覆盖检查和正文覆盖检查,直接 return True。
即使下载意图检查拒绝了 beibao(核心词'登录'未命中),函数仍然返回 True。
修复:下载意图拒绝后、多关键词覆盖检查前,新增核心词零命中硬拒绝:
当 core_kw 非空但 core_hits=0 时无条件 return False。
This commit is contained in:
@@ -269,6 +269,10 @@ class AutoReply:
|
|||||||
# 2026-08-17 新增:口语动词"知道"不应作为核心词
|
# 2026-08-17 新增:口语动词"知道"不应作为核心词
|
||||||
# 用户常说"俺想知道""我想知道","知道"是口语填充,不是查询意图
|
# 用户常说"俺想知道""我想知道","知道"是口语填充,不是查询意图
|
||||||
'知道', '想知道',
|
'知道', '想知道',
|
||||||
|
# 2026-08-17 新增:下载类动词不应作为核心词
|
||||||
|
# "下载"是动作而非查询对象,真正核心的是被查询的插件名
|
||||||
|
# 例:"登录插件去哪儿下载"的核心词应是{'登录'},而非{'下载'}
|
||||||
|
'下载', '下到', '哪下', '在哪下', '怎么下',
|
||||||
}
|
}
|
||||||
core_kw = q_mean - non_core_kw
|
core_kw = q_mean - non_core_kw
|
||||||
doc_text = heading_clean + " " + title.lower() + " " + body_clean[:800]
|
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}")
|
logger.debug(f"下载意图放行: query={query[:30]!r} heading={heading[:30]!r}")
|
||||||
return True
|
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),也需检查覆盖比例
|
# ⭐ 当heading含核心词时(has_ht=True),也需检查覆盖比例
|
||||||
# 防止"草原"等通用词单一命中导致误选sdf1.md等不相关文档
|
# 防止"草原"等通用词单一命中导致误选sdf1.md等不相关文档
|
||||||
# 规则:
|
# 规则:
|
||||||
@@ -324,6 +337,7 @@ class AutoReply:
|
|||||||
# - 例:查询含核心词={'草原','近期','公告'}
|
# - 例:查询含核心词={'草原','近期','公告'}
|
||||||
# sdf1.md只含"草原"(1/3)→ 拒绝
|
# sdf1.md只含"草原"(1/3)→ 拒绝
|
||||||
# index.md含"近期"+"公告"(2/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:
|
if len(core_kw) >= 2:
|
||||||
# ⭐ 修复:阈值改为max(1,...),避免只有1个核心词时仍要求≥2个命中
|
# ⭐ 修复:阈值改为max(1,...),避免只有1个核心词时仍要求≥2个命中
|
||||||
# 例:"服务器最近有哪些公告啊?" 核心词={'公告'}(1个)
|
# 例:"服务器最近有哪些公告啊?" 核心词={'公告'}(1个)
|
||||||
|
|||||||
+8
-2
@@ -5086,8 +5086,14 @@ class MessageMonitor:
|
|||||||
# ⭐ Task #1508 防御兜底:剥离后为空但输入非空 → 回退原文
|
# ⭐ Task #1508 防御兜底:剥离后为空但输入非空 → 回退原文
|
||||||
# (宁可保留昵称在消息里,也不能把整条消息吞成空串)。
|
# (宁可保留昵称在消息里,也不能把整条消息吞成空串)。
|
||||||
if not ts.strip() and text.strip():
|
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()
|
return ts.strip()
|
||||||
|
|
||||||
def _sanitize_message(self, text: str) -> str:
|
def _sanitize_message(self, text: str) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user