feat(kb-routing): expand 5-way keyword routing coverage
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user