修复[知识库搜索]:排除链接文本干扰,防止php.md误匹配sdf1插件内容

- Task #1720: 修复兑换码插件怎么用查询返回php.md而非sdf1.md的问题
- 根因:php.md的链接文本[sdf1插件](sdf1.md)被误判为内容关键词
- 修复:auto_reply.py中排除链接文本进行核心词匹配
- 修复:使用body_no_links替代body_clean进行关键词匹配
- 修复:动作类查询要求标题和正文都包含核心词
- Task #1719: 修复旧消息被环形缓冲区淘汰后重新回复
- 修复:record_user_message()增加跨缓冲区查重
- 修复:第二关增加is_user_message_replied()检查
This commit is contained in:
youpaishidifu
2026-09-15 21:45:18 +08:00
parent 83bfbff40a
commit 81839bbe91
2 changed files with 51 additions and 13 deletions
+16 -5
View File
@@ -196,9 +196,15 @@ class AutoReply:
# ⭐ 移除代码块内容:避免配置示例/问答数据等代码块污染相关性检查
# 修复"用户组是怎么配置的"被sdf1_game"题目配置格式"(body含代码块)误匹配的问题
body_clean = re.sub(r'```.*?```', '', body_clean, flags=re.DOTALL)
# ⭐ 移除整个链接(包括链接文本),用于核心词匹配
# 防止php.md的"[sdf1插件](sdf1.md)"链接文本被误判为内容关键词
# 链接文本是引用,不是真正的内容,不应参与核心词匹配
body_no_links = _link.sub('', body).lower()
body_no_links = re.sub(r'```.*?```', '', body_no_links, flags=re.DOTALL)
ht_tokens = AutoReply._meaningful_tokens(heading_clean + " " + title)
body_tokens = AutoReply._meaningful_tokens(body_clean[:800])
# ⭐ 使用body_no_links计算body_tokens,排除链接文本干扰
body_tokens = AutoReply._meaningful_tokens(body_no_links[:800])
has_ht = bool(q_mean & ht_tokens)
has_body = bool(q_mean & body_tokens)
@@ -240,7 +246,8 @@ class AutoReply:
# 规则:heading主体命中(has_ht) + body是表格(|分隔) + 查询动作词在表格中出现 → 放行
_is_table_body = ('|' in (body or '')) or ('-|-' in (body or ''))
# 注意:不能用 set(body_clean)——字符集不包含多字符词,须用子串判断
_action_hits_body = any(kw in body_clean[:800] for kw in (q_mean & action_kw))
# ⭐ 使用body_no_links进行动作词匹配,排除链接文本干扰
_action_hits_body = any(kw in body_no_links[:800] for kw in (q_mean & action_kw))
if has_ht and _is_table_body and _action_hits_body:
logger.debug(
f"动作查询表格兜底放行: query={query[:40]!r} "
@@ -267,7 +274,8 @@ class AutoReply:
has_body = has_body_nonaction
# ⭐ 后台/前台关键词区分:查询含"后台"但文档不含"后台"→ 不相关
full = heading_clean + " " + title.lower() + " " + body_clean[:800]
# ⭐ 使用body_no_links进行关键词匹配,排除链接文本干扰
full = heading_clean + " " + title.lower() + " " + body_no_links[:800]
# 注意:"管理后台"是整体概念,拆分后"后台"可能不在heading中,但"管理员"+"后端"已表达管理意图
# 所以当heading含"管理员"或"后端"时,不应因缺"后台"而拒绝
if "后台" in query and "后台" not in full:
@@ -367,7 +375,9 @@ class AutoReply:
# ⭐ OCR碎片过滤:纯ASCII且≤2字符的词(如"丿IJ"切成'ij')是OCR噪声
# 不参与核心词覆盖判定——否则垃圾词抬高分母,真核心词反而达不到阈值
core_kw = {kw for kw in core_kw if not (kw.isascii() and len(kw) <= 2)}
doc_text = heading_clean + " " + title.lower() + " " + body_clean[:800]
# ⭐ 使用body_no_links进行核心词匹配,排除链接文本干扰
# 防止php.md的"[sdf1插件](sdf1.md)"链接文本被误判为内容关键词
doc_text = heading_clean + " " + title.lower() + " " + body_no_links[:800]
core_hits = sum(1 for kw in core_kw if kw in doc_text)
# ⭐ 下载意图检查提前到核心词检查之前
@@ -523,7 +533,8 @@ class AutoReply:
return True
# 子串回退:jieba 可能产生碎片 token,导致交集为空但文档确实含查询短语
full = heading_clean + " " + title.lower() + " " + body_clean[:800]
# ⭐ 使用body_no_links进行子串回退检查,排除链接文本干扰
full = heading_clean + " " + title.lower() + " " + body_no_links[:800]
stripped = re.sub(r'[??!!。,,\s]', '', query).lower()
if len(stripped) >= 4:
# ⭐ 修复:子串回退必须同时满足两个条件: