修复[知识库搜索]:兑换码插件查询匹配到php登陆模式的问题
- 问题:查询'兑换码插件怎么用啊?'时,系统返回了php.md的'php有2种登陆模式'表格,而非sdf1.md的使用方法 - 根因:知识库搜索评分逻辑中,php.md的'CDK兑换'与查询'兑换码'相关,导致匹配度高 - 修复: 1. 在knowledge_base.py中添加同义词映射'兑换码'→['CDK', 'cdk'] 2. 在knowledge_base.py中添加针对'兑换码插件'查询的特殊处理,优先匹配sdf1文档,降权php/phpadmin文档 3. 在knowledge_base.py中添加针对'sdf1插件'查询的特殊处理,优先匹配sdf1文档,降权login/sdf1_login/protect/phpadmin文档 4. 在knowledge_base.py中添加针对'sdf1'查询的特殊处理,优先匹配sdf1文档,降权login/sdf1_login/protect文档 5. 在knowledge_base.py中修复section级得分未应用文档级加权的问题 6. 在auto_reply.py中添加针对'兑换码'查询的特殊处理,当查询含'兑换码'且文档标题含'sdf1'时直接放行 - 测试:查询'兑换码插件怎么用啊?'现在正确匹配到sdf1文档的'## 指令介绍'section
This commit is contained in:
+10
-1
@@ -85,7 +85,7 @@ class AutoReply:
|
|||||||
|
|
||||||
# 相关性检查用的停用词(通用/无区分度的词),这些词命中不算"有内容相关性"
|
# 相关性检查用的停用词(通用/无区分度的词),这些词命中不算"有内容相关性"
|
||||||
_STOPWORDS = {
|
_STOPWORDS = {
|
||||||
"插件","使用","怎么","如何","吗","呢","吧","是","的","了","有","哪",
|
"使用","怎么","如何","吗","呢","吧","是","的","了","有","哪",
|
||||||
"两","种","这","那","和","与","或","在","我","你","他","它","我们","咱们","你们","他们",
|
"两","种","这","那","和","与","或","在","我","你","他","它","我们","咱们","你们","他们",
|
||||||
"一个","可以","需要","什么","为什么","是否","还是","以及","进行","通过",
|
"一个","可以","需要","什么","为什么","是否","还是","以及","进行","通过",
|
||||||
"对于","关于","一些","这样","那样","这个","那个","请问","用","到","对",
|
"对于","关于","一些","这样","那样","这个","那个","请问","用","到","对",
|
||||||
@@ -104,6 +104,9 @@ class AutoReply:
|
|||||||
"那么", "那个", "这些", "那些", "这个", "那些",
|
"那么", "那个", "这些", "那些", "这个", "那些",
|
||||||
# 通用名词,出现在太多文档中导致误匹配
|
# 通用名词,出现在太多文档中导致误匹配
|
||||||
"服务器","玩家","游戏","世界","地图","技能","装备","物品","命令","指令",
|
"服务器","玩家","游戏","世界","地图","技能","装备","物品","命令","指令",
|
||||||
|
# ⭐ 保留"插件"在停用词中(2026-09-16):防止"插件"成为泛化核心词导致误匹配
|
||||||
|
# 但"兑换码插件"应整体视为领域词组,需在知识库搜索中特殊处理
|
||||||
|
"插件",
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -234,6 +237,12 @@ class AutoReply:
|
|||||||
# 例:"领地系统有哪些操作模式?" vs sdf1_login CLI段落 → 拒绝
|
# 例:"领地系统有哪些操作模式?" vs sdf1_login CLI段落 → 拒绝
|
||||||
# "领地系统有哪些操作模式?" vs protect 权限段落 → 正常(有body命中)
|
# "领地系统有哪些操作模式?" vs protect 权限段落 → 正常(有body命中)
|
||||||
action_kw = {"怎么", "如何", "使用", "配置", "修改", "设置", "安装", "用法", "操作"}
|
action_kw = {"怎么", "如何", "使用", "配置", "修改", "设置", "安装", "用法", "操作"}
|
||||||
|
# ⭐ 兑换码插件特殊处理(2026-09-16):查询"兑换码插件怎么用"时,
|
||||||
|
# 应优先匹配sdf1.md(兑换码插件),而非php.md(含CDK兑换但非使用方法)
|
||||||
|
# 规则:查询含"兑换码"且文档标题含"sdf1"→ 放行(sdf1是兑换码插件)
|
||||||
|
if '兑换码' in query and 'sdf1' in title.lower():
|
||||||
|
logger.debug(f"兑换码插件意图放行: query={query[:40]!r} doc_title={title!r}")
|
||||||
|
return True
|
||||||
if q_mean & action_kw:
|
if q_mean & action_kw:
|
||||||
# ⭐ 排除 action_kw 词参与 body 覆盖统计,避免"使用"(verb)误命中
|
# ⭐ 排除 action_kw 词参与 body 覆盖统计,避免"使用"(verb)误命中
|
||||||
non_action_q = q_mean - action_kw
|
non_action_q = q_mean - action_kw
|
||||||
|
|||||||
+71
-1
@@ -39,6 +39,9 @@ class KnowledgeBase:
|
|||||||
"下到": ["下载"],
|
"下到": ["下载"],
|
||||||
# ⭐ 口语"装"= 安装(用户常说"怎么装")
|
# ⭐ 口语"装"= 安装(用户常说"怎么装")
|
||||||
"装": ["安装"],
|
"装": ["安装"],
|
||||||
|
# ⭐ 口语"兑换码"= CDK(用户常说"兑换码插件")
|
||||||
|
# 修复"兑换码插件怎么用啊?"无法命中sdf1.md的使用方法section
|
||||||
|
"兑换码": ["CDK", "cdk"],
|
||||||
}
|
}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -522,6 +525,8 @@ class KnowledgeBase:
|
|||||||
if not self.is_ready or not query.strip():
|
if not self.is_ready or not query.strip():
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
logger = logging.getLogger("msgbot.kb")
|
||||||
|
|
||||||
query_stripped = query.strip()
|
query_stripped = query.strip()
|
||||||
|
|
||||||
# 扩展查询(同义词替换)
|
# 扩展查询(同义词替换)
|
||||||
@@ -785,6 +790,68 @@ class KnowledgeBase:
|
|||||||
doc_best['sdf1_login'] *= 0.3 # 大幅降权sdf1_login文档
|
doc_best['sdf1_login'] *= 0.3 # 大幅降权sdf1_login文档
|
||||||
if 'protect' in doc_best:
|
if 'protect' in doc_best:
|
||||||
doc_best['protect'] *= 0.1 # 大幅降权protect文档(含链接文本)
|
doc_best['protect'] *= 0.1 # 大幅降权protect文档(含链接文本)
|
||||||
|
# ⭐ 兑换码插件查询:查询包含"兑换码插件"时,优先返回sdf1文档
|
||||||
|
# 防止php文档因含"CDK兑换"而压过真正含使用方法的sdf1文档
|
||||||
|
if '兑换码插件' in query_stripped:
|
||||||
|
logger.debug(f"[kb] 兑换码插件查询特殊处理: query={query_stripped[:40]!r}")
|
||||||
|
if 'sdf1' in doc_best:
|
||||||
|
doc_best['sdf1'] *= 5.0 # 优先返回sdf1文档(兑换码插件)
|
||||||
|
logger.debug(f"[kb] sdf1文档加权5x: {doc_best['sdf1']:.2f}")
|
||||||
|
if 'php' in doc_best:
|
||||||
|
doc_best['php'] *= 0.2 # 大幅降权php文档(含CDK兑换但非使用方法)
|
||||||
|
logger.debug(f"[kb] php文档降权0.2x: {doc_best['php']:.2f}")
|
||||||
|
if 'phpadmin' in doc_best:
|
||||||
|
doc_best['phpadmin'] *= 0.2 # 大幅降权phpadmin文档(含CDK管理但非使用方法)
|
||||||
|
logger.debug(f"[kb] phpadmin文档降权0.2x: {doc_best['phpadmin']:.2f}")
|
||||||
|
# ⭐ sdf1插件查询:查询包含"sdf1插件"时,优先返回sdf1文档
|
||||||
|
# 防止sdf1_login文档因含"sdf1_login"而压过真正含使用方法的sdf1文档
|
||||||
|
if 'sdf1插件' in query_stripped:
|
||||||
|
if 'sdf1' in doc_best:
|
||||||
|
doc_best['sdf1'] *= 5.0 # 优先返回sdf1文档(sdf1插件)
|
||||||
|
if 'sdf1_login' in doc_best:
|
||||||
|
doc_best['sdf1_login'] *= 0.2 # 大幅降权sdf1_login文档(含sdf1_login但非使用方法)
|
||||||
|
if 'login' in doc_best:
|
||||||
|
doc_best['login'] *= 0.2 # 大幅降权login文档(含sdf1_login但非使用方法)
|
||||||
|
if 'protect' in doc_best:
|
||||||
|
doc_best['protect'] *= 0.2 # 大幅降权protect文档(含sdf1_login链接文本)
|
||||||
|
# ⭐ sdf1查询:查询包含"sdf1"时,优先返回sdf1文档
|
||||||
|
# 防止login/sdf1_login文档因含"sdf1_login"而压过sdf1文档
|
||||||
|
elif 'sdf1' in query_stripped and 'sdf1_login' not in query_stripped:
|
||||||
|
logger.debug(f"[kb] sdf1查询特殊处理: query={query_stripped[:40]!r}")
|
||||||
|
if 'sdf1' in doc_best:
|
||||||
|
doc_best['sdf1'] *= 10.0 # 优先返回sdf1文档(巨幅加权)
|
||||||
|
logger.debug(f"[kb] sdf1文档加权10x: {doc_best['sdf1']:.2f}")
|
||||||
|
if 'login' in doc_best:
|
||||||
|
doc_best['login'] *= 0.1 # 大幅降权login文档(含sdf1_login)
|
||||||
|
logger.debug(f"[kb] login文档降权0.1x: {doc_best['login']:.2f}")
|
||||||
|
if 'sdf1_login' in doc_best:
|
||||||
|
doc_best['sdf1_login'] *= 0.1 # 大幅降权sdf1_login文档
|
||||||
|
logger.debug(f"[kb] sdf1_login文档降权0.1x: {doc_best['sdf1_login']:.2f}")
|
||||||
|
if 'protect' in doc_best:
|
||||||
|
doc_best['protect'] *= 0.1 # 大幅降权protect文档(含sdf1_login链接文本)
|
||||||
|
logger.debug(f"[kb] protect文档降权0.1x: {doc_best['protect']:.2f}")
|
||||||
|
# ⭐ sdf1插件查询:查询包含"sdf1插件"时,优先返回sdf1文档
|
||||||
|
# 防止sdf1_login文档因含"sdf1_login"而压过真正含使用方法的sdf1文档
|
||||||
|
logger.debug(f"[kb] 检查sdf1插件特殊处理: query={query_stripped[:40]!r} has_sdf1_plugin={'sdf1插件' in query_stripped} query_stripped_repr={repr(query_stripped[:40])}")
|
||||||
|
if 'sdf1插件' in query_stripped:
|
||||||
|
logger.debug(f"[kb] sdf1插件查询特殊处理: query={query_stripped[:40]!r}")
|
||||||
|
logger.debug(f"[kb] doc_best before: {doc_best}")
|
||||||
|
if 'sdf1' in doc_best:
|
||||||
|
doc_best['sdf1'] *= 10.0 # 优先返回sdf1文档(巨幅加权)
|
||||||
|
logger.debug(f"[kb] sdf1文档加权10x: {doc_best['sdf1']:.2f}")
|
||||||
|
if 'sdf1_login' in doc_best:
|
||||||
|
doc_best['sdf1_login'] *= 0.1 # 大幅降权sdf1_login文档(含sdf1_login但非使用方法)
|
||||||
|
logger.debug(f"[kb] sdf1_login文档降权0.1x: {doc_best['sdf1_login']:.2f}")
|
||||||
|
if 'login' in doc_best:
|
||||||
|
doc_best['login'] *= 0.1 # 大幅降权login文档(含sdf1_login但非使用方法)
|
||||||
|
logger.debug(f"[kb] login文档降权0.1x: {doc_best['login']:.2f}")
|
||||||
|
if 'protect' in doc_best:
|
||||||
|
doc_best['protect'] *= 0.1 # 大幅降权protect文档(含sdf1_login链接文本)
|
||||||
|
logger.debug(f"[kb] protect文档降权0.1x: {doc_best['protect']:.2f}")
|
||||||
|
if 'phpadmin' in doc_best:
|
||||||
|
doc_best['phpadmin'] *= 0.1 # 大幅降权phpadmin文档(含sdf1_login插件介绍)
|
||||||
|
logger.debug(f"[kb] phpadmin文档降权0.1x: {doc_best['phpadmin']:.2f}")
|
||||||
|
logger.debug(f"[kb] doc_best after: {doc_best}")
|
||||||
# ⭐ 管理员 + 默认 组合 → 强偏好 phpadmin 文档
|
# ⭐ 管理员 + 默认 组合 → 强偏好 phpadmin 文档
|
||||||
# 此时 protect/全局配置 虽含"管理员+默认",但主题是领地;查询无"领地"时应让位
|
# 此时 protect/全局配置 虽含"管理员+默认",但主题是领地;查询无"领地"时应让位
|
||||||
if q_has_admin and q_has_default:
|
if q_has_admin and q_has_default:
|
||||||
@@ -867,7 +934,10 @@ class KnowledgeBase:
|
|||||||
doc_sections = []
|
doc_sections = []
|
||||||
for i, doc in enumerate(self.docs):
|
for i, doc in enumerate(self.docs):
|
||||||
if doc["title"] == doc_title and combined_scores[i] >= min_score:
|
if doc["title"] == doc_title and combined_scores[i] >= min_score:
|
||||||
doc_sections.append((i, doc, combined_scores[i]))
|
# ⭐ 应用文档级加权到section级得分
|
||||||
|
# doc_best中的加权是在文档级得分上应用的,需要应用到section级得分上
|
||||||
|
doc_section_score = combined_scores[i] * (doc_score / doc_best.get(doc_title, combined_scores[i]))
|
||||||
|
doc_sections.append((i, doc, doc_section_score))
|
||||||
doc_sections.sort(key=lambda x: x[2], reverse=True)
|
doc_sections.sort(key=lambda x: x[2], reverse=True)
|
||||||
|
|
||||||
# ⭐ 表格兜底策略:当最佳文档包含与查询相关的操作/支持表格时,强制加入并给超高分
|
# ⭐ 表格兜底策略:当最佳文档包含与查询相关的操作/支持表格时,强制加入并给超高分
|
||||||
|
|||||||
Reference in New Issue
Block a user