feat(kb-routing): expand 5-way keyword routing coverage

This commit is contained in:
User
2026-03-20 10:56:29 +08:00
parent d13084cc0f
commit 93b8135d51
4 changed files with 1195 additions and 171 deletions

View File

@@ -1,25 +1,51 @@
const axios = require('axios');
const arkChatService = require('./arkChatService');
const contextKeywordTracker = require('./contextKeywordTracker');
const {
hasCanonicalKnowledgeTerm: hasCanonicalKnowledgeTermMatch,
extractKnowledgeEntityMatches,
hasKeywordFromList,
SYSTEM_ROUTE_KEYWORDS,
COMPANY_ROUTE_KEYWORDS,
PRODUCT_ROUTE_KEYWORDS,
FAQ_ROUTE_KEYWORDS,
SCIENCE_TRAINING_ROUTE_KEYWORDS,
} = require('./knowledgeKeywords');
// KB查询缓存相同effectiveQuery + datasetIds在TTL内直接返回缓存结果
const KB_CACHE_TTL_MS = 5 * 60 * 1000; // 5分钟
const KB_CACHE_MAX_SIZE = 100;
const kbQueryCache = new Map();
function getKbCacheKey(query, datasetIds) {
return `${(query || '').trim()}|${(datasetIds || []).sort().join(',')}`;
}
function getKbCache(key) {
const entry = kbQueryCache.get(key);
if (!entry) return null;
if (Date.now() - entry.timestamp > KB_CACHE_TTL_MS) {
kbQueryCache.delete(key);
return null;
}
return entry.result;
}
function setKbCache(key, result) {
if (kbQueryCache.size >= KB_CACHE_MAX_SIZE) {
const oldest = kbQueryCache.keys().next().value;
kbQueryCache.delete(oldest);
}
kbQueryCache.set(key, { result, timestamp: Date.now() });
}
class ToolExecutor {
static hasCanonicalKnowledgeTerm(query) {
return /(一成系统|PM-FitLine|PM细胞营养素|NTC营养保送系统|Activize Oxyplus|小红产品|Basics|大白产品|Restorate|小白产品|儿童倍适|火炉原理|阿育吠陀)/i.test(String(query || ''));
return hasCanonicalKnowledgeTermMatch(query);
}
static extractKnowledgeEntities(text) {
const matches = String(text || '').match(/(一成系统|Ai众享|AI众享|数字化工作室|盛咖学愿|三大平台|四大Ai生态|四大生态|德国PM|PM公司|PM-FitLine|PM细胞营养素|细胞营养素|小红产品|小红|大白产品|大白|小白产品|小白|Activize Oxyplus|Activize|Basics|Restorate|儿童倍适|乐活奶昔|Basic Power|CitrusCare|NutriSunny|Omega|肽美|艾特维|德丽|德维|宝丽|美固健|葡萄籽|白藜芦醇|益生菌|胶原蛋白肽|Q10|NTC营养保送系统|火炉原理|阿育吠陀|PM事业)/gi) || [];
const deduped = [];
for (const item of matches) {
const normalized = String(item || '').trim();
if (!normalized) {
continue;
}
if (!deduped.some((existing) => existing.toLowerCase() === normalized.toLowerCase())) {
deduped.push(normalized);
}
}
return deduped;
return extractKnowledgeEntityMatches(text);
}
static classifyQuestionSlot(query) {
@@ -66,7 +92,44 @@ class ToolExecutor {
const lowerText = text.toLowerCase();
const slot = this.classifyQuestionSlot(query);
const entities = this.extractKnowledgeEntities(query);
const mentionsEntity = entities.length === 0 || entities.some((entity) => lowerText.includes(String(entity || '').toLowerCase()));
// 中英文别名映射改写后的query可能包含英文实体但方舟回答用中文名
const ENTITY_ALIAS_MAP = {
'activize oxyplus': ['小红', 'activize', '艾特维'],
'activize': ['小红', '艾特维'],
'basics': ['大白', '倍适'],
'basic power': ['大白', 'basics'],
'restorate': ['小白', '维适多'],
'fitline': ['pm-fitline', 'pm细胞营养素', '细胞营养素'],
'pm-fitline': ['fitline', '细胞营养素'],
'ntc营养保送系统': ['ntc', '营养保送', '吸收利用'],
'ntc': ['ntc营养保送系统', '营养保送'],
'儿童倍适': ['powercocktail junior', '儿童'],
'cc-cell': ['cc套装', 'cc胶囊', 'cc乳霜'],
'd-drink': ['小绿', '排毒饮', '排毒d饮料'],
'proshape amino': ['氨基酸', 'bcaa'],
'herbal tea': ['草本茶'],
'hair+': ['发宝', '发健'],
'med hair+': ['发宝', '发健'],
'fitness-drink': ['运动饮料', '健康饮品'],
'topshape': ['纤萃', '减肥'],
'generation 50+': ['乐活50+', '乐活'],
'apple antioxy': ['细胞抗氧素', '苹果'],
'zellschutz': ['细胞抗氧素'],
'women+': ['women'],
'men face': ['男士乳霜', '男士护肤'],
'med dental+': ['牙膏', '草本护理'],
'ib5': ['口腔免疫喷雾'],
'q10': ['辅酵素', '氧修护'],
'一成系统': ['三大平台', '四大ai生态', 'ai众享', '数字化工作室', '盛咖学愿'],
};
const expandedEntities = [];
for (const entity of entities) {
const lower = String(entity || '').toLowerCase();
expandedEntities.push(lower);
const aliases = ENTITY_ALIAS_MAP[lower];
if (aliases) expandedEntities.push(...aliases);
}
const mentionsEntity = entities.length === 0 || expandedEntities.some((entity) => lowerText.includes(String(entity || '').toLowerCase()));
if (/德国PM是一家1993年成立于德国的合法直销公司/.test(text) && slot !== 'legality') {
return false;
@@ -137,46 +200,63 @@ class ToolExecutor {
.split(',')
.map((id) => id.trim())
.filter(Boolean);
const rules = this.getKnowledgeBaseRoutingRules();
if (!rules.length) {
return {
datasetIds: defaultDatasetIds,
matchedRoutes: defaultDatasetIds.length ? ['default'] : [],
};
}
const text = String(query || '').trim();
const recentContextText = (Array.isArray(context) ? context : [])
.slice(-6)
.map((item) => String(item?.content || '').trim())
.filter(Boolean)
.join('\n');
const haystack = `${String(query || '').trim()}\n${recentContextText}`.toLowerCase();
const haystack = `${text}\n${recentContextText}`.toLowerCase();
// 5路意图检测system > company > faq > science > product
const hasSystemIntent = hasKeywordFromList(haystack, SYSTEM_ROUTE_KEYWORDS);
const hasCompanyIntent = hasKeywordFromList(haystack, COMPANY_ROUTE_KEYWORDS);
const hasProductIntent = hasKeywordFromList(haystack, PRODUCT_ROUTE_KEYWORDS);
const hasFaqIntent = hasKeywordFromList(haystack, FAQ_ROUTE_KEYWORDS);
const hasScienceIntent = hasKeywordFromList(haystack, SCIENCE_TRAINING_ROUTE_KEYWORDS);
// 确定优先路由:按特异性从高到低排列
const priorityRouteNames = [];
const hasSystemIntent = /(一成系统|ai众享|数字化工作室|盛咖学愿|赋能工具|四大ai生态|四大生态|三大平台|智能生产力|线上拓客|陌生客户|邀约)/i.test(haystack);
const hasCompanyIntent = /(pm公司|德国pm(?!事业|细胞|营养|产品|fitline|\s*基础|\s*大白|\s*小红|\s*小白)|公司地址|联系方式|电话|公司实力|公司背景|总部|分公司|邓白氏|aaa\+|公司介绍)/i.test(haystack);
const hasProductIntent = /(细胞营养素|基础套装|基础三合一|三合一|大白产品|小红产品|小白产品|activize|basics|restorate|fitline|儿童倍适|乐活奶昔|奶昔|ntc营养保送|火炉原理|阿育吠陀|产品.*介绍|介绍.*产品|产品有哪些|产品列表|产品.*(全套|区别|见效|治病|副作用|作用|功效|成分|用法)|为什么.*产品|保健品区别|多久见效)/i.test(haystack);
if (hasSystemIntent) {
priorityRouteNames.push('system');
}
if (hasCompanyIntent && !hasSystemIntent && !hasProductIntent) {
priorityRouteNames.push('company');
}
// FAQ意图当同时命中产品+FAQ时优先FAQ用户在问产品相关的问题
if (hasFaqIntent && !hasSystemIntent && !hasCompanyIntent) {
priorityRouteNames.push('faq');
// FAQ场景下如果同时命中产品实体也加入产品库以提供更完整上下文
if (hasProductIntent) {
priorityRouteNames.push('product');
}
}
if (hasScienceIntent && !hasSystemIntent && !hasProductIntent && !hasFaqIntent) {
priorityRouteNames.push('science');
}
// 纯产品意图
if (hasProductIntent && !hasFaqIntent && !hasSystemIntent && !hasScienceIntent) {
priorityRouteNames.push('product');
}
if (priorityRouteNames.length > 0) {
const priorityRules = rules.filter((rule) => priorityRouteNames.includes(rule.name));
const routingRules = this.getKnowledgeBaseRoutingRules();
const priorityRules = routingRules.filter((rule) => priorityRouteNames.includes(rule.name));
const priorityDatasetIds = [...new Set(priorityRules.flatMap((rule) => rule.dataset_ids).filter(Boolean))];
if (priorityDatasetIds.length > 0) {
console.log(`[ToolExecutor] KB 5-way route: intents=[${priorityRouteNames.join(',')}] datasets=[${priorityDatasetIds.join(',')}]`);
return {
datasetIds: priorityDatasetIds,
matchedRoutes: [...new Set(priorityRules.map((rule) => rule.name))],
matchedRoutes: [...new Set(priorityRouteNames)],
};
}
}
// 通用env规则匹配回退
const matchedDatasetIds = [];
const matchedRoutes = [];
for (const rule of rules) {
for (const rule of this.getKnowledgeBaseRoutingRules()) {
if (rule.keywords.some((keyword) => haystack.includes(keyword.toLowerCase()))) {
matchedRoutes.push(rule.name);
matchedDatasetIds.push(...rule.dataset_ids);
@@ -214,6 +294,16 @@ class ToolExecutor {
if (/(三大平台|四大生态|Ai生态)/i.test(text)) return '一成系统 三大平台 四大Ai生态';
return '一成系统 德国PM事业发展的强大赋能工具 三大平台 四大Ai生态';
}
if (/(身未动,?梦已成|批发式晋级)/i.test(text)) return '一成系统 身未动梦已成 批发式晋级 三大平台 四大Ai生态';
if (/行动圈/i.test(text)) return '一成系统 行动圈 数字化工作室 团队管理 目标考核';
if (/盟主社区/i.test(text)) return '一成系统 盟主社区 AI众享 社区盟主 引流 转化';
if (/(宣明会|世界宣明会)/i.test(text)) return '德国PM 宣明会 世界宣明会 慈善合作';
if (/BFH/i.test(text)) return '德国PM BFH AAA+ 合作伙伴收益';
if (/DSN/i.test(text)) return '德国PM DSN 全球100强 欧洲第1';
if (/(邓白氏|AAA\+)/i.test(text)) return '德国PM 邓白氏 AAA+ 99分';
if (/(ELAB|科隆名单|Halal|GMP)/i.test(text)) return '德国PM ELAB 科隆名单 Halal GMP 安全认证';
if (/(Rolf Sorg|斯派尔|Speyer|卢森堡)/i.test(text)) return '德国PM Rolf Sorg 斯派尔 卢森堡 总部 公司介绍';
if (/(培安|烟台)/i.test(text)) return '德国PM 培安 烟台 中国市场投资';
if (/(PM公司|德国PM|公司地址|联系方式|电话|公司实力|公司背景|总部|分公司)/i.test(text)) {
if (/(产品|细胞营养素|基础套装|基础三合一|小红|大白|小白|activize|basics|restorate|fitline|儿童倍适)/i.test(text)) {
return '德国PM FitLine 细胞营养素产品 大白Basics 小红Activize 小白Restorate 儿童倍适';
@@ -225,7 +315,7 @@ class ToolExecutor {
if (/(德国PM介绍|介绍德国PM|德国PM公司介绍|PM公司介绍|PM介绍)/i.test(text)) return '德国PM 1993年 创立 100多个国家 FitLine 公司介绍 邓白氏 99分 AAA+';
if (/(NTC.*(核心优势|核心竞争力|优势|原理|厉害)|核心优势.*NTC|核心竞争力.*NTC)/i.test(text)) return 'NTC营养保送系统 核心优势 吸收利用 原理';
if (/(PM基础三合一介绍|基础三合一介绍|PM基础套装介绍|基础套装介绍)/i.test(text)) return '德国PM细胞营养素 基础套装 大白 小红 小白 介绍';
if (/儿童倍适/i.test(text)) return '儿童倍适';
if (/儿童倍适/i.test(text)) return questionDimension ? `儿童倍适 ${questionDimension[0]}` : '儿童倍适';
if (/(小红产品|小红|Activize Oxyplus|Activize)/i.test(text)) return questionDimension ? `Fitline小红产品 Activize ${questionDimension[0]}` : 'Fitline小红产品提升能量原理';
if (/(大白产品|大白|倍适|Basics)/i.test(text)) return questionDimension ? `德国PM细胞营养素 大白 Basics ${questionDimension[0]}` : '德国PM细胞营养素 大白 Basics';
if (/(小白产品|小白|维适多|Restorate)/i.test(text)) return questionDimension ? `德国PM细胞营养素 小白 Restorate ${questionDimension[0]}` : '德国PM细胞营养素 小白';
@@ -236,7 +326,7 @@ class ToolExecutor {
if (/(我们公司.*产品|公司.*产品|产品.*推荐|推荐.*产品|产品有哪些|产品介绍|产品列表)/i.test(text)) return '德国PM FitLine 细胞营养素产品 大白Basics 小红Activize 小白Restorate 儿童倍适';
if (/(治病吗|能治病吗|产品治病|治疗疾病|替代药|是不是药)/i.test(text)) return 'PM产品 不是药 不能替代药物 保健食品 营养补充';
if (/(多久见效|多久有效|多久能见效|多长时间见效|几天见效|什么时候见效)/i.test(text)) return 'PM产品 多久见效 吸收利用 周期 个体差异';
if (/(为什么.*(全套|搭配|三合一)|为什么要.*(全套|搭配|三合一)|产品需要全套)/i.test(text)) return '德国PM细胞营养素 全套搭配 NTC营养保送系统 协同作用';
if (/(为什么.*(全套|搭配|三合一)|为什么要.*(全套|搭配|三合一)|为何.*(全套|搭配|三合一)|产品需要全套)/i.test(text)) return '德国PM细胞营养素 全套搭配 NTC营养保送系统 协同作用';
if (/(与其它保健品区别|与其他保健品区别|和其它保健品区别|和其他保健品区别|保健品区别)/i.test(text)) return 'PM产品 与其他保健品区别 NTC营养保送系统 吸收利用';
if (/(新人起步三关|起步三关)/i.test(text)) return '培训新人起步三关';
if (/(精品会议|会议组织)/i.test(text)) return '培训打造精品会议具体如下';
@@ -254,35 +344,66 @@ class ToolExecutor {
if (/(好转反应|整应反应|排毒反应|副作用|不良反应|皮肤发痒)/i.test(text)) return 'PM产品整应反应好转反应解析';
if (/(促销活动|促销|优惠|打折|活动分数|5\+1)/i.test(text)) return '促销活动 5+1活动分数';
if (/暖炉原理/i.test(text)) return '火炉原理';
if (/(CC套装|CC胶囊)/i.test(text)) return 'CC套装 CC胶囊';
if (/(IB5|口腔免疫喷雾)/i.test(text)) return 'IB5口腔免疫喷雾';
if (/(Q10|辅酵素|氧修护)/i.test(text)) return 'Q10辅酵素氧修护';
if (/Women\+/i.test(text)) return 'Women+';
if (/乐活奶昔|乐活/i.test(text)) return '乐活奶昔';
if (/(乳清蛋白|蛋白粉)/i.test(text)) return '乳清蛋白粉';
if (/(乳酪煲|乳酪饮品|乳酪)/i.test(text)) return '乳酪煲 乳酪饮品';
if (/(基础二合一|二合一)/i.test(text)) return '基础二合一';
if (/倍力健/i.test(text)) return '倍力健';
if (/(关节套装|关节舒缓)/i.test(text)) return '关节套装 关节舒缓膏';
if (/(男士乳霜|男士护肤)/i.test(text)) return '全效男士乳霜';
if (/(去角质|面膜)/i.test(text)) return '去角质面膜';
if (/发宝/i.test(text)) return '发宝';
if (/叶黄素/i.test(text)) return '叶黄素';
if (/(奶昔)/i.test(text)) return '奶昔';
if (/(健康饮品)/i.test(text)) return '健康饮品';
if (/(CC套装|CC胶囊)/i.test(text)) return questionDimension ? `CC套装 CC胶囊 ${questionDimension[0]}` : 'CC套装 CC胶囊';
if (/(IB5|口腔免疫喷雾)/i.test(text)) return questionDimension ? `IB5 口腔免疫喷雾 ${questionDimension[0]}` : 'IB5 口腔免疫喷雾';
if (/(Q10|辅酵素|氧修护)/i.test(text)) return questionDimension ? `Q10 辅酵素 氧修护 ${questionDimension[0]}` : 'Q10 辅酵素 氧修护';
if (/(Med Dental\+|Dental\+|草本护理牙膏)/i.test(text)) return questionDimension ? `Med Dental+ 草本护理牙膏 ${questionDimension[0]}` : 'Med Dental+ 草本护理牙膏';
if (/(Men Face|全效男士护肤抗衰乳霜)/i.test(text)) return questionDimension ? `Men Face 全效男士护肤抗衰乳霜 ${questionDimension[0]}` : 'Men Face 全效男士护肤抗衰乳霜';
if (/(CC-Cell|CC Cell|CC乳霜)/i.test(text)) return questionDimension ? `CC-Cell 胶囊 乳霜 ${questionDimension[0]}` : 'CC-Cell 胶囊 乳霜';
if (/(D-Drink|小绿排毒饮|14天排毒D饮料Plus)/i.test(text)) return questionDimension ? `D-Drink 小绿排毒饮 14天排毒D饮料Plus ${questionDimension[0]}` : 'D-Drink 小绿排毒饮 14天排毒D饮料Plus';
if (/(ProShape|ProShape® Amino|氨基酸|支链氨基酸|BCAA)/i.test(text)) return questionDimension ? `ProShape Amino 氨基酸 BCAA ${questionDimension[0]}` : 'ProShape Amino 氨基酸 BCAA';
if (/(Herbal Tea|草本茶)/i.test(text)) return questionDimension ? `Herbal Tea 草本茶 ${questionDimension[0]}` : 'Herbal Tea 草本茶';
if (/(Hair\+|med Hair\+|口服发宝|外用发健)/i.test(text)) return questionDimension ? `Hair+ med Hair+ 口服发宝 外用发健 ${questionDimension[0]}` : 'Hair+ med Hair+ 口服发宝 外用发健';
if (/(Fitness-Drink|运动饮料健康饮品|运动饮料)/i.test(text)) return questionDimension ? `Fitness-Drink 运动饮料健康饮品 ${questionDimension[0]}` : 'Fitness-Drink 运动饮料健康饮品';
if (/(TopShape|孅萃TopShape纤萃减肥|纤萃减肥)/i.test(text)) return questionDimension ? `TopShape 孅萃TopShape纤萃减肥 ${questionDimension[0]}` : 'TopShape 孅萃TopShape纤萃减肥';
if (/(Generation 50\+|乐活50\+)/i.test(text)) return questionDimension ? `乐活50+ Generation 50+ ${questionDimension[0]}` : '乐活50+ Generation 50+';
if (/(Apple Antioxy|苹果细胞抗氧素|Antioxy|Zellschutz|细胞抗氧素)/i.test(text)) return questionDimension ? `Apple Antioxy Zellschutz 细胞抗氧素 ${questionDimension[0]}` : 'Apple Antioxy Zellschutz 细胞抗氧素';
if (/Women\+/i.test(text)) return questionDimension ? `Women+ ${questionDimension[0]}` : 'Women+';
if (/乐活奶昔|乐活/i.test(text)) return questionDimension ? `乐活奶昔 ${questionDimension[0]}` : '乐活奶昔';
if (/(乳清蛋白|蛋白粉)/i.test(text)) return questionDimension ? `乳清蛋白粉 ${questionDimension[0]}` : '乳清蛋白粉';
if (/(乳酪煲|乳酪饮品|乳酪)/i.test(text)) return questionDimension ? `乳酪煲 乳酪饮品 ${questionDimension[0]}` : '乳酪煲 乳酪饮品';
if (/(基础二合一|二合一)/i.test(text)) return questionDimension ? `基础二合一 ${questionDimension[0]}` : '基础二合一';
if (/倍力健/i.test(text)) return questionDimension ? `倍力健 ${questionDimension[0]}` : '倍力健';
if (/(关节套装|关节舒缓)/i.test(text)) return questionDimension ? `关节套装 关节舒缓膏 ${questionDimension[0]}` : '关节套装 关节舒缓膏';
if (/(男士乳霜|男士护肤)/i.test(text)) return questionDimension ? `全效男士乳霜 ${questionDimension[0]}` : '全效男士乳霜';
if (/(去角质|面膜)/i.test(text)) return questionDimension ? `去角质面膜 ${questionDimension[0]}` : '去角质面膜';
if (/发宝/i.test(text)) return questionDimension ? `发宝 ${questionDimension[0]}` : '发宝';
if (/叶黄素/i.test(text)) return questionDimension ? `叶黄素 ${questionDimension[0]}` : '叶黄素';
if (/(奶昔)/i.test(text)) return questionDimension ? `奶昔 ${questionDimension[0]}` : '奶昔';
if (/(健康饮品)/i.test(text)) return questionDimension ? `健康饮品 ${questionDimension[0]}` : '健康饮品';
// 第二层:当前文本是追问/代词,才通过上下文推断主题
const isFollowUp = /^(这个|那个|它|该|详细|继续|怎么|为什么|适合谁|什么意思|怎么用|怎么吃|功效|成分|好处|原理)/.test(text);
if (isFollowUp) {
if (/(基础三合一|三合一基础套|基础套装|大白小红小白)/i.test(recentContextText)) return '德国PM细胞营养素 基础套装 大白 小红 小白';
if (/(基础三合一|三合一基础套|基础套装|大白小红小白)/i.test(recentContextText)) return questionDimension ? `德国PM细胞营养素 基础套装 大白 小红 小白 ${questionDimension[0]}` : '德国PM细胞营养素 基础套装 大白 小红 小白';
if (/(身未动,?梦已成|批发式晋级)/i.test(recentContextText)) return '一成系统 身未动梦已成 批发式晋级 三大平台 四大Ai生态';
if (/行动圈/i.test(recentContextText)) return '一成系统 行动圈 数字化工作室 团队管理 目标考核';
if (/盟主社区/i.test(recentContextText)) return '一成系统 盟主社区 AI众享 社区盟主 引流 转化';
if (/(一成系统|Ai众享|数字化工作室|盛咖学愿)/i.test(recentContextText)) return '一成系统 德国PM事业发展的强大赋能工具 三大平台 四大Ai生态';
if (/(小红产品|小红|Activize)/i.test(recentContextText)) return 'Fitline小红产品提升能量原理';
if (/(大白产品|大白|Basics)/i.test(recentContextText)) return '德国PM细胞营养素 大白 Basics';
if (/(小白产品|小白|Restorate)/i.test(recentContextText)) return '德国PM细胞营养素 小白';
if (/儿童倍适/i.test(recentContextText)) return '儿童倍适';
if (/DSN/i.test(recentContextText)) return '德国PM DSN 全球100强 欧洲第1';
if (/(ELAB|科隆名单|Halal|GMP)/i.test(recentContextText)) return '德国PM ELAB 科隆名单 Halal GMP 安全认证';
if (/(邓白氏|AAA\+)/i.test(recentContextText)) return '德国PM 邓白氏 AAA+ 99分';
if (/(宣明会|世界宣明会)/i.test(recentContextText)) return '德国PM 宣明会 世界宣明会 慈善合作';
if (/(Rolf Sorg|斯派尔|Speyer|卢森堡)/i.test(recentContextText)) return '德国PM Rolf Sorg 斯派尔 卢森堡 总部 公司介绍';
if (/(培安|烟台)/i.test(recentContextText)) return '德国PM 培安 烟台 中国市场投资';
if (/(小红产品|小红|Activize)/i.test(recentContextText)) return questionDimension ? `Fitline小红产品 Activize ${questionDimension[0]}` : 'Fitline小红产品提升能量原理';
if (/(大白产品|大白|Basics)/i.test(recentContextText)) return questionDimension ? `德国PM细胞营养素 大白 Basics ${questionDimension[0]}` : '德国PM细胞营养素 大白 Basics';
if (/(小白产品|小白|Restorate)/i.test(recentContextText)) return questionDimension ? `德国PM细胞营养素 小白 Restorate ${questionDimension[0]}` : '德国PM细胞营养素 小白';
if (/儿童倍适/i.test(recentContextText)) return questionDimension ? `儿童倍适 ${questionDimension[0]}` : '儿童倍适';
if (/火炉原理/i.test(recentContextText)) return '火炉原理';
if (/(阿育吠陀|Ayurveda)/i.test(recentContextText)) return '阿育吠陀医学原理';
if (/(NTC营养保送系统)/i.test(recentContextText)) return 'NTC营养保送系统';
if (/(Med Dental\+|草本护理牙膏)/i.test(recentContextText)) return questionDimension ? `Med Dental+ 草本护理牙膏 ${questionDimension[0]}` : 'Med Dental+ 草本护理牙膏';
if (/(Men Face|全效男士护肤抗衰乳霜)/i.test(recentContextText)) return questionDimension ? `Men Face 全效男士护肤抗衰乳霜 ${questionDimension[0]}` : 'Men Face 全效男士护肤抗衰乳霜';
if (/(CC-Cell|CC胶囊|CC乳霜)/i.test(recentContextText)) return questionDimension ? `CC-Cell 胶囊 乳霜 ${questionDimension[0]}` : 'CC-Cell 胶囊 乳霜';
if (/(D-Drink|小绿排毒饮|14天排毒D饮料Plus)/i.test(recentContextText)) return questionDimension ? `D-Drink 小绿排毒饮 14天排毒D饮料Plus ${questionDimension[0]}` : 'D-Drink 小绿排毒饮 14天排毒D饮料Plus';
if (/(ProShape|氨基酸|BCAA)/i.test(recentContextText)) return questionDimension ? `ProShape Amino 氨基酸 BCAA ${questionDimension[0]}` : 'ProShape Amino 氨基酸 BCAA';
if (/(Herbal Tea|草本茶)/i.test(recentContextText)) return questionDimension ? `Herbal Tea 草本茶 ${questionDimension[0]}` : 'Herbal Tea 草本茶';
if (/(Hair\+|med Hair\+|口服发宝|外用发健)/i.test(recentContextText)) return questionDimension ? `Hair+ med Hair+ 口服发宝 外用发健 ${questionDimension[0]}` : 'Hair+ med Hair+ 口服发宝 外用发健';
if (/(Fitness-Drink|运动饮料健康饮品|运动饮料)/i.test(recentContextText)) return questionDimension ? `Fitness-Drink 运动饮料健康饮品 ${questionDimension[0]}` : 'Fitness-Drink 运动饮料健康饮品';
if (/(TopShape|孅萃TopShape纤萃减肥|纤萃减肥)/i.test(recentContextText)) return questionDimension ? `TopShape 孅萃TopShape纤萃减肥 ${questionDimension[0]}` : 'TopShape 孅萃TopShape纤萃减肥';
if (/(Generation 50\+|乐活50\+)/i.test(recentContextText)) return questionDimension ? `乐活50+ Generation 50+ ${questionDimension[0]}` : '乐活50+ Generation 50+';
if (/(Apple Antioxy|苹果细胞抗氧素|Antioxy|Zellschutz|细胞抗氧素)/i.test(recentContextText)) return questionDimension ? `Apple Antioxy Zellschutz 细胞抗氧素 ${questionDimension[0]}` : 'Apple Antioxy Zellschutz 细胞抗氧素';
}
return '';
}
@@ -329,24 +450,34 @@ class ToolExecutor {
return {
hit: false,
reason: 'empty',
reply: `知识库中暂未找到与${query}直接相关的信息,请换个更具体的问法再试。`,
reply: `知识库中暂未找到与"${query}"直接相关的信息,请换个更具体的问法再试。`,
};
}
const strictNoHitPattern = /未检索到|没有检索到|没有相关内容|暂无相关内容|未找到相关内容|未找到相关信息|没有找到相关信息|知识库中没有相关内容|知识库中没有关于|知识库中没有找到|没有找到具体|没有.*具体信息|没有.*相关说明|暂未找到与.*直接相关的信息|无法基于知识库.*回答|知识库未明确提到|知识库未提到/;
const strictNoHitPattern = /未检索到|没有检索到|没有相关内容|暂无相关内容|未找到相关内容|未找到相关信息|没有找到相关信息|知识库中没有相关内容|知识库中没有关于|知识库中没有找到|没有找到具体|没有.*具体信息|没有.*相关说明|暂未找到与.*直接相关的信息|无法基于知识库.*回答|知识库未明确提到|知识库未提到|很抱歉.*没有.*资料|超出.*知识范围|目前没有.*方面的|无法提供.*相关信息|暂时无法回答|不在.*知识范围|没有.*相关记录/;
if (strictNoHitPattern.test(text)) {
return {
hit: false,
reason: 'no_hit',
reply: `知识库中暂未找到与${query}直接相关的信息,请换个更具体的问法再试。`,
reply: `知识库中暂未找到与"${query}"直接相关的信息,请换个更具体的问法再试。`,
};
}
if (!this.answerMatchesQuestionSlot(query, text)) {
// 长度兜底:回答内容足够长(>=60字且不含无结果模式时倾向判定为hit
// 这避免了方舟LLM用同义词表达导致slot正则不匹配的误杀
if (text.length >= 60 && !strictNoHitPattern.test(text)) {
console.log(`[ToolExecutor] slot_mismatch overridden by length fallback: query="${query}" len=${text.length}`);
return {
hit: true,
reason: 'length_fallback',
reply: text,
};
}
return {
hit: false,
reason: 'slot_mismatch',
reply: `知识库中暂未找到与${query}直接相关的信息,请换个更具体的问法再试。`,
reply: `知识库中暂未找到与"${query}"直接相关的信息,请换个更具体的问法再试。`,
};
}
@@ -471,10 +602,30 @@ class ToolExecutor {
};
}
try {
// 缓存检查相同effectiveQuery + datasetIds命中缓存时直接返回避免重复API调用
const cacheKey = getKbCacheKey(effectiveQuery, kbTarget.datasetIds);
const cached = getKbCache(cacheKey);
if (cached) {
const latencyMs = Date.now() - startTime;
console.log(`[ToolExecutor] Ark KB cache hit in ${latencyMs}ms key="${cacheKey.slice(0, 60)}"`);
return {
...cached,
original_query: query,
rewritten_query: effectiveQuery,
selected_dataset_ids: kbTarget.datasetIds,
selected_kb_routes: kbTarget.matchedRoutes,
latency_ms: latencyMs,
cache_hit: true,
};
}
console.log('[ToolExecutor] Trying Ark Knowledge Search...');
const result = await this.searchArkKnowledge(effectiveQuery, [], responseMode, kbTarget.datasetIds, query);
const latencyMs = Date.now() - startTime;
console.log(`[ToolExecutor] Ark KB search succeeded in ${latencyMs}ms`);
// 仅缓存命中的结果,避免缓存错误或无结果
if (result.hit) {
setKbCache(cacheKey, result);
}
return {
...result,
original_query: query,