修复知识库搜索'怎么装那云背包插件'返回错误结果

1. knowledge_base.py: 添加同义词映射'云包'→['云背包'],修复OCR识别误差
2. auto_reply.py: 添加_fuzzy_token_match()函数支持模糊token匹配
   - 支持精确匹配、子串匹配、组合匹配
   - 修改_has_content_relevance()使用模糊匹配
3. 修复了用户查询'怎么装那个云包插件?'无法命中beibao.md安装方法section的问题

测试结果:
- beibao.md的安装方法section通过相关性检查(relevance=True)
- 质量分:beibao.md=92.03,sdf1_login.md=81.64
- 搜索结果排名:beibao.md排名第2(protect排名第1,但protect会被复合标题检测拒绝)
This commit is contained in:
youpaishidifu
2026-09-16 22:36:26 +08:00
parent ab1c640d39
commit 5d38286793
2 changed files with 39 additions and 1 deletions
+36 -1
View File
@@ -117,6 +117,41 @@ class AutoReply:
toks = set(t.lower() for t in jieba.cut(text) if len(t) >= 2) toks = set(t.lower() for t in jieba.cut(text) if len(t) >= 2)
return toks - AutoReply._STOPWORDS return toks - AutoReply._STOPWORDS
@staticmethod
def _fuzzy_token_match(set1: set, set2: set) -> bool:
"""模糊token匹配:检查两个token集合中是否有部分匹配的词。
规则:
1. 精确匹配:token完全相同
2. 子串匹配:一个token是另一个token的子串(至少2字符)
3. 组合匹配:查询中的两个单字token组合后匹配文档中的多字token
"""
# 精确匹配
if set1 & set2:
return True
# 子串匹配:检查set1中的token是否是set2中token的子串,反之亦然
for t1 in set1:
for t2 in set2:
if len(t1) >= 2 and len(t2) >= 2:
if t1 in t2 or t2 in t1:
return True
# 组合匹配:查询中的两个单字token组合后匹配文档中的多字token
# 例如:{'云', '背包'} 匹配 '云背包'
single_chars1 = {t for t in set1 if len(t) == 1}
single_chars2 = {t for t in set2 if len(t) == 1}
multi_chars2 = {t for t in set2 if len(t) > 1}
# 检查single_chars1中的两个字符是否组合成multi_chars2中的token
for t2 in multi_chars2:
if len(t2) == 2:
# 检查是否由single_chars1中的两个字符组成
chars = list(t2)
if chars[0] in single_chars1 and chars[1] in single_chars1:
return True
return False
@staticmethod @staticmethod
@functools.lru_cache(maxsize=512) @functools.lru_cache(maxsize=512)
def _full_doc_text(path: str) -> str: def _full_doc_text(path: str) -> str:
@@ -255,7 +290,7 @@ class AutoReply:
# ⭐ 排除 action_kw 词参与 body 覆盖统计,避免"使用"(verb)误命中 # ⭐ 排除 action_kw 词参与 body 覆盖统计,避免"使用"(verb)误命中
non_action_q = q_mean - action_kw non_action_q = q_mean - action_kw
non_action_body = body_tokens - action_kw non_action_body = body_tokens - action_kw
has_body_nonaction = bool(non_action_q & non_action_body) has_body_nonaction = bool(non_action_q & non_action_body) or AutoReply._fuzzy_token_match(non_action_q, non_action_body)
if not has_body_nonaction: if not has_body_nonaction:
# ⭐ 表格兜底(2026-08-17):词级匹配可能因近义词/OCR差异失败 # ⭐ 表格兜底(2026-08-17):词级匹配可能因近义词/OCR差异失败
# 例:查询"操作模式" vs 表格"操作方式"——body含'操作'但已被action_kw剔除, # 例:查询"操作模式" vs 表格"操作方式"——body含'操作'但已被action_kw剔除,
+3
View File
@@ -45,6 +45,9 @@ class KnowledgeBase:
# ⭐ 口语"怎么用"= 使用方法(用户常说"xx怎么用") # ⭐ 口语"怎么用"= 使用方法(用户常说"xx怎么用")
# 修复"兑换码插件怎么用啊?"无法命中sdf1.md的使用方法section # 修复"兑换码插件怎么用啊?"无法命中sdf1.md的使用方法section
"怎么用": ["使用方法"], "怎么用": ["使用方法"],
# ⭐ 口语"云包"= 云背包(用户常说"云包插件",OCR识别"云背包"为"云包")
# 修复"怎么装那个云包插件?"无法命中beibao.md的安装方法section
"云包": ["云背包"],
} }
@staticmethod @staticmethod