fix: 品牌保护+知识库全量覆盖 - 6层防御解决传销问题 + 30+产品关键词补全
This commit is contained in:
@@ -62,6 +62,34 @@ function estimateSpeechDurationMs(text) {
|
||||
return Math.max(4000, Math.min(60000, length * 180));
|
||||
}
|
||||
|
||||
async function polishForSpeech(rawText, userQuestion) {
|
||||
const POLISH_TIMEOUT_MS = 3000;
|
||||
try {
|
||||
const messages = [
|
||||
{
|
||||
role: 'system',
|
||||
content: '你是一个语音播报润色助手。请将下面的知识库回答改写为自然、亲切的口语风格,像朋友聊天一样。要求:1) 保留所有关键信息和数据,不得编造;2) 去掉"根据知识库信息"等机械前缀;3) 适合语音朗读,简洁流畅;4) 控制在120字以内;5) 只输出改写后的文本,不要加引号或解释。',
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: `用户问题:${userQuestion}\n\n原始回答:${rawText}`,
|
||||
},
|
||||
];
|
||||
const result = await Promise.race([
|
||||
arkChatService.chat(messages, [], { useKnowledgeBase: false }),
|
||||
new Promise((_, reject) => setTimeout(() => reject(new Error('polish timeout')), POLISH_TIMEOUT_MS)),
|
||||
]);
|
||||
const polished = (result?.content || '').trim();
|
||||
if (polished && polished.length >= 10) {
|
||||
console.log(`[RealtimeRouting] polishForSpeech ok len=${polished.length} original=${rawText.length}`);
|
||||
return polished;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[RealtimeRouting] polishForSpeech failed:', err.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function buildDirectRouteMessages(session, context, userText) {
|
||||
const messages = [];
|
||||
const systemPrompt = [
|
||||
@@ -110,12 +138,29 @@ function buildDirectChatMessages(session, context, userText) {
|
||||
return messages;
|
||||
}
|
||||
|
||||
function normalizeKnowledgeAlias(text) {
|
||||
return String(text || '')
|
||||
.replace(/X{2}系统/gi, '一成系统')
|
||||
.replace(/一城系统|逸城系统|一程系统|易成系统|一诚系统|亦成系统|艺成系统|溢成系统|义成系统|毅成系统|怡成系统|以成系统|已成系统|亿成系统|忆成系统|益成系统/g, '一成系统')
|
||||
.replace(/(?<![一\u4e00-\u9fff])(一城|逸城|一程|易成|一诚|亦成|艺成|溢成|义成|毅成|怡成|以成|已成|亿成|忆成|益成)(?=系统)/g, '一成')
|
||||
.replace(/大窝|大握|大我|大卧/g, '大沃')
|
||||
.replace(/盛咖学院|圣咖学愿|盛咖学院|圣咖学院|盛卡学愿/g, '盛咖学愿')
|
||||
.replace(/AI众享|Ai众享|爱众享|艾众享|哎众享/gi, 'Ai众享')
|
||||
.replace(/暖炉原理/g, '火炉原理');
|
||||
}
|
||||
|
||||
function hasKnowledgeKeyword(text) {
|
||||
return /(系统|平台|产品|功能|介绍|说明|规则|流程|步骤|配置|接入|开通|操作|怎么用|如何用|适合谁|区别|价格|费用|政策|售后|文档|资料|方案|一成系统|PM公司|德国PM|公司地址|电话|联系方式|公司实力|背景|培训|新人|起步三关|精品会议|成长上总裁|招商|代理|加盟|合作|邀约话术|小红|大白|小白|Activize|Basics|Restorate|FitLine|细胞营养素|NTC|营养保送|火炉原理|阿育吠陀|Ayurveda|儿童倍适|AI落地|ai落地|转观念|科普|营养|成分|功效|基础三合一|三合一|基础套装|套装|Ai众享|数字化工作室|盛咖学愿)/i.test(text || '');
|
||||
const normalized = normalizeKnowledgeAlias(text);
|
||||
return /(一成系统|Ai众享|AI众享|数字化工作室|盛咖学愿|四大AI生态|四大Ai生态|三大平台|PM公司|德国PM|PM-FitLine|FitLine|PM细胞营养素|细胞营养素|小红|大白|小白|Activize|Basics|Restorate|儿童倍适|NTC|营养保送|火炉原理|暖炉原理|阿育吠陀|Ayurveda|基础三合一|三合一|基础套装|基础二合一|二合一|招商合作|招商|代理|加盟|事业机会|邀约话术|起步三关|精品会议|成长上总裁|AI落地|ai落地|转观念|好转反应|整应反应|排毒反应|副作用|不良反应|皮肤发痒|促销活动|促销|优惠|活动分数|5\+1|CC套装|CC胶囊|IB5|口腔免疫喷雾|Q10|辅酵素|Women\+|乐活|乳清蛋白|蛋白粉|乳酪煲|乳酪饮品|乳酪|倍力健|关节套装|关节舒缓|男士乳霜|去角质|面膜|发宝|叶黄素|奶昔|健康饮品|传销|骗局|骗子|正规吗|合法吗|正不正规|合不合法|是不是传销|直销还是传销|层级分销|非法集资|拉人头|下线|发展下线|报单|人头费|怎么吃|怎么服用|吃多少|服用方法|搭配|功效|成分|原料)/i.test(normalized);
|
||||
}
|
||||
|
||||
function isKnowledgeFollowUp(text) {
|
||||
return /^(这个|那个|它|该系统|这个系统|那个系统|这个功能|那个功能|这个产品|那个产品|这个公司|那家公司|这个政策|那个政策|这个培训|那个培训|详细|详细说说|详细查一下|展开说说|继续说|继续讲|怎么用|怎么操作|怎么配置|适合谁|有什么区别|费用多少|价格多少|怎么申请|怎么开通|是什么|什么意思|地址在哪|电话多少|联系方式|具体政策|具体内容|怎么吃|功效是什么|有什么功效|成分是什么|有什么成分|多少钱|哪里买|怎么买|配方|原理是什么|有什么好处|怎么服用|适合什么人)/.test((text || '').trim());
|
||||
const normalized = String(text || '').trim().replace(/[,,。!??~~\s]+$/g, '').replace(/^(那你|那再|那|你再|再来|再|麻烦你|帮我)[,,、\s]*/g, '');
|
||||
if (!normalized) return false;
|
||||
if (/^(详细|详细说说|详细查一下|展开说说|继续说|继续讲|介绍一下|给我介绍一下|详细介绍一下|继续介绍一下|怎么用|怎么操作|怎么配置|适合谁|有什么区别|费用多少|价格多少|怎么申请|怎么开通|是什么|什么意思|地址在哪|公司地址在哪|电话多少|公司电话多少|联系方式|公司联系方式|具体政策|具体内容|怎么吃|功效是什么|有什么功效|成分是什么|有什么成分|多少钱|哪里买|怎么买|配方|原理是什么|有什么好处|怎么服用|适合什么人)$/.test(normalized)) {
|
||||
return true;
|
||||
}
|
||||
return /^(这个|那个|它|该系统|这个系统|那个系统|这个功能|那个功能|这个产品|那个产品|这个公司|那家公司|这个政策|那个政策|这个培训|那个培训)(的)?(详细|详细说说|详细查一下|展开说说|继续说|继续讲|介绍一下|给我介绍一下|详细介绍一下|继续介绍一下|怎么用|怎么操作|怎么配置|适合谁|有什么区别|费用多少|价格多少|怎么申请|怎么开通|是什么|什么意思|地址在哪|公司地址在哪|电话多少|公司电话多少|联系方式|公司联系方式|具体政策|具体内容|怎么吃|功效是什么|有什么功效|成分是什么|有什么成分|多少钱|哪里买|怎么买|配方|原理是什么|有什么好处|怎么服用|适合什么人)?$/.test(normalized);
|
||||
}
|
||||
|
||||
function shouldForceKnowledgeRoute(userText, context = []) {
|
||||
@@ -174,6 +219,9 @@ function getRuleBasedDirectRouteDecision(userText) {
|
||||
if (/^[\d\s+\-*/().=%]+$/.test(text) || /(等于多少|帮我算|计算一下|算一下)/.test(text)) {
|
||||
return { route: 'calculate', args: { expression: text.replace(/(帮我算|计算一下|算一下|等于多少)/g, '').trim() || text } };
|
||||
}
|
||||
if (/(传销|骗局|骗子|正规吗|合法吗|正不正规|合不合法|是不是传销|直销还是传销|层级分销|非法集资|拉人头|下线|发展下线|报单|人头费)/.test(text)) {
|
||||
return { route: 'search_knowledge', args: { query: text } };
|
||||
}
|
||||
if (/^(喂|你好|您好|嗨|哈喽|hello|hi|在吗|在不在|早上好|中午好|下午好|晚上好|早安|晚安|谢谢|感谢|再见|拜拜|嗯|哦|好的|对|是的|没有了|没事了|可以了|行|OK|ok)[,,!。??~~\s]*[啊呀吧呢哦嗯嘛哈的了]*[!。??~~]*$/.test(text)) {
|
||||
return { route: 'chat', args: {} };
|
||||
}
|
||||
@@ -278,7 +326,20 @@ async function resolveReply(sessionId, session, text) {
|
||||
: []);
|
||||
|
||||
if (ragItems.length > 0) {
|
||||
let speechText = normalizeTextForSpeech(replyText);
|
||||
session.handoffSummaryUsed = true;
|
||||
if (toolName === 'search_knowledge' && speechText) {
|
||||
const cleanedText = speechText.replace(/^(根据知识库信息[,,::\s]*|根据.*?[,,]\s*)/i, '');
|
||||
return {
|
||||
delivery: 'external_rag',
|
||||
speechText: '',
|
||||
ragItems: [{ title: '知识库结果', content: cleanedText || speechText }],
|
||||
source,
|
||||
toolName,
|
||||
routeDecision,
|
||||
responseMeta,
|
||||
};
|
||||
}
|
||||
return {
|
||||
delivery: 'external_rag',
|
||||
speechText: '',
|
||||
@@ -292,6 +353,19 @@ async function resolveReply(sessionId, session, text) {
|
||||
|
||||
if (toolName === 'search_knowledge' && !toolResult?.hit) {
|
||||
session.handoffSummaryUsed = true;
|
||||
// 敏感问题(传销/正规性)知识库未命中时,不交给S2S自由发挥,直接返回安全回复
|
||||
if (/(传销|骗局|骗子|正规吗|合法吗|正不正规|合不合法|是不是传销|直销还是传销|层级分销|非法集资|拉人头|下线|发展下线|报单|人头费)/.test(originalText)) {
|
||||
const safeReply = '德国PM是一家1993年成立于德国的合法直销公司,获得邓白氏AAA+认证,业务覆盖100多个国家和地区。它不是传销,是正规的直销企业哦。如果你想了解更多,可以问我关于PM公司或产品的详细介绍。';
|
||||
return {
|
||||
delivery: 'external_rag',
|
||||
speechText: '',
|
||||
ragItems: [{ title: '品牌保护', content: safeReply }],
|
||||
source: 'voice_tool',
|
||||
toolName: 'search_knowledge',
|
||||
routeDecision,
|
||||
responseMeta: { ...responseMeta, hit: true, reason: 'brand_protection' },
|
||||
};
|
||||
}
|
||||
return {
|
||||
delivery: 'upstream_chat',
|
||||
speechText: '',
|
||||
@@ -313,6 +387,7 @@ async function resolveReply(sessionId, session, text) {
|
||||
|
||||
module.exports = {
|
||||
getRuleBasedDirectRouteDecision,
|
||||
normalizeKnowledgeAlias,
|
||||
normalizeTextForSpeech,
|
||||
splitTextForSpeech,
|
||||
estimateSpeechDurationMs,
|
||||
|
||||
Reference in New Issue
Block a user