2026-08-01 16:48:01 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* H5 Chat Intent Router — FAQ / fast-path rule library.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Add patterns here for messages that should bypass LLM routing latency.
|
|
|
|
|
|
* Consumed by chat-intent-router.mjs → classifyWithRules().
|
|
|
|
|
|
*
|
|
|
|
|
|
* Keep rules conservative: task execution, page generation, and realtime lookup
|
|
|
|
|
|
* must stay on Agent paths (checked via FAQ_EXCLUSION_PATTERNS).
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** Block FAQ match when the message clearly needs Agent / tools. */
|
|
|
|
|
|
export const FAQ_EXCLUSION_PATTERNS = [
|
|
|
|
|
|
/\bpublic\/[^\s"'<>]+\.html\b/i,
|
|
|
|
|
|
/MindSpace\/[^/\s]+\/public\/[^\s"'<>]+\.html/i,
|
|
|
|
|
|
/(?:生成|创建|制作|做|写|设计|发布|搭建).{0,24}(?:H5|h5|HTML|html|网页|页面|活动页|宣传页|落地页|分享页|链接)/u,
|
|
|
|
|
|
/(?:H5|h5|HTML|html|网页|页面).{0,24}(?:生成|创建|制作|做|写|设计|发布|链接)/u,
|
|
|
|
|
|
/(?:写|做|生成|制作|设计).{0,16}主题(?:页面|文章)/u,
|
2026-09-09 18:11:39 +08:00
|
|
|
|
/(?:帮我.{0,12})?(?:做|写|生成|整理).{0,48}(?:游玩|旅行|旅游)?(?:攻略|指南|行程)/u,
|
|
|
|
|
|
/(?:我要|我想|想要|需要).{0,16}(?:游玩|旅行|旅游)?(?:攻略|指南|行程|线路图|路线图|行程图)/u,
|
|
|
|
|
|
/(?:帮我|给我).{0,12}(?:做|生成|制作).{0,24}(?:线路图|路线图|行程图|行程表)/u,
|
2026-08-01 16:48:01 +08:00
|
|
|
|
/(?:服务号|公众号).{0,16}(?:页面|文章|推文|图文)/u,
|
|
|
|
|
|
/(?:今天|今日|现在|最新|当前|实时).{0,12}(?:新闻|赛况|比分|天气|行情|股价|汇率|热点)/u,
|
|
|
|
|
|
/(?:查(?:一下|查)?|搜索|打听).{0,16}(?:今天|今日|现在|最新|当前)/u,
|
|
|
|
|
|
/(?:世界杯|欧冠|NBA|英超).{0,16}(?:赛况|赛程|比分)/u,
|
|
|
|
|
|
/(?:load_skill|page-data|sqlite|express|后端服务)/iu,
|
|
|
|
|
|
/(?:修|改|测试|回归|verify).{0,12}(?:bug|问卷|policy|public)/iu,
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @typedef {{ id: string, reason: string, patterns: RegExp[] }} DirectChatFaqRule
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {DirectChatFaqRule[]} */
|
|
|
|
|
|
export const DIRECT_CHAT_FAQ_RULES = [
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'concept_what_is',
|
|
|
|
|
|
reason: '概念解释类问答(FAQ)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^什么是[\s\S]{1,48}[??]?$/u,
|
|
|
|
|
|
/^何为[\s\S]{1,48}[??]?$/u,
|
|
|
|
|
|
/^什么叫[\s\S]{1,48}[??]?$/u,
|
|
|
|
|
|
/^[\s\S]{1,40}是什么[??]?$/u,
|
|
|
|
|
|
/^[\s\S]{1,40}是什么意思[??]?$/u,
|
|
|
|
|
|
/^[\s\S]{1,40}(?:是什么东西|指什么|啥意思)[??]?$/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'concept_explain',
|
|
|
|
|
|
reason: '解释说明类问答(FAQ)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^(?:请)?(?:解释|说明|介绍|讲解|阐述)(?:一下|下)?[\s\S]{1,48}[??]?$/u,
|
|
|
|
|
|
/^帮我(?:解释|说明|介绍|讲解)(?:一下|下)?[\s\S]{1,48}[??]?$/u,
|
|
|
|
|
|
/^能(?:不能|否)(?:解释|说明|介绍)(?:一下|下)?[\s\S]{1,40}[??]?$/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'concept_compare',
|
|
|
|
|
|
reason: '概念对比类问答(FAQ)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^[\s\S]{1,32}(?:和|与|跟)[\s\S]{1,32}(?:的)?(?:区别|差异|不同|对比|比较)[是什么]?[??]?$/u,
|
|
|
|
|
|
/^(?:对比|比较)(?:一下|下)?[\s\S]{1,48}[??]?$/u,
|
|
|
|
|
|
/^[\s\S]{1,24}(?:vs|VS|Vs)[\s\S]{1,24}(?:区别|差异|不同)?[??]?$/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'concept_how_works',
|
|
|
|
|
|
reason: '原理/机制类问答(FAQ)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^[\s\S]{1,40}(?:是怎么|是如何)(?:工作|运行|实现|运作)的[??]?$/u,
|
|
|
|
|
|
/^[\s\S]{1,40}(?:原理|机制|流程)(?:是什么|是怎样的)[??]?$/u,
|
|
|
|
|
|
/^为什么[\s\S]{1,48}[??]?$/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'text_transform',
|
|
|
|
|
|
reason: '纯文字处理(总结/翻译/改写)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^(?:请)?(?:帮我|帮忙)?(?:总结|概括|归纳|提炼)(?:一下|下)?[\s\S]{1,80}[??]?$/u,
|
|
|
|
|
|
/^(?:请)?(?:帮我|帮忙)?(?:翻译|改写|润色|扩写|缩写|校对)(?:一下|下)?[\s\S]{1,80}[??]?$/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'tech_acronym',
|
|
|
|
|
|
reason: '常见技术名词解释(FAQ)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^(?:什么是|解释一下|介绍一下)?\s*(?:SSE|WebSocket|REST(?:ful)?|GraphQL|JWT|OAuth|RAG|Embedding|向量数据库|Server-Sent Events)[\s\S]{0,24}[??]?$/iu,
|
|
|
|
|
|
/^(?:SSE|WebSocket|REST(?:ful)?|GraphQL|JWT|OAuth|RAG)(?:是什么|什么意思|怎么用)[??]?$/iu,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'learning_advice',
|
|
|
|
|
|
reason: '学习/选型建议(纯文字)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^(?:学|学习|入门).{0,24}(?:应该|该|推荐|建议).{0,32}(?:先|从哪|哪个)[??]?$/u,
|
|
|
|
|
|
/^(?:初学者|新手|入门).{0,24}(?:应该|该|推荐|建议).{0,32}[??]?$/u,
|
|
|
|
|
|
/^.{0,24}(?:先学|从哪学|怎么学).{0,32}[??]?$/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'casual_opinion',
|
|
|
|
|
|
reason: '主观建议/闲聊(无任务执行)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/^你觉得.{1,48}[??]?$/u,
|
|
|
|
|
|
/^你认为.{1,48}[??]?$/u,
|
|
|
|
|
|
/^(?:随便|随意)(?:聊|说说|谈谈).{0,24}[??]?$/u,
|
|
|
|
|
|
/^.{0,16}(?:有什么建议|给点建议|怎么看)[??]?$/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
2026-08-25 15:13:22 +08:00
|
|
|
|
{
|
|
|
|
|
|
id: 'text_only_declined_page',
|
|
|
|
|
|
reason: '明确要求纯文字、不生成页面/链接',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/(?:不要|别|无需|不需要|禁止).{0,12}(?:生成|做|制作|创建|发布).{0,8}(?:页面|网页|HTML|html|H5|h5|链接)/u,
|
|
|
|
|
|
/(?:纯文字|只要文字|文字回答|不要页面|不用页面|别做页面)/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: 'brief_intro',
|
|
|
|
|
|
reason: '短篇幅介绍/说明(纯文字)',
|
|
|
|
|
|
patterns: [
|
|
|
|
|
|
/(?:用|以).{0,6}(?:一|两|二|三|四|五|几|\d+).{0,4}(?:句话|句).{0,32}(?:介绍|说明|描述|讲讲|推荐)/u,
|
|
|
|
|
|
/^(?:简单|简要|大概|概括)(?:介绍|说明|描述|讲讲).{0,48}[??]?$/u,
|
|
|
|
|
|
/^简要介绍.{0,48}(?:区别|差异|不同|对比|比较)[??]?$/u,
|
|
|
|
|
|
/^(?:推荐|介绍)(?:一个|一下).{0,32}(?:理由|原因)[,,]?一句话/u,
|
|
|
|
|
|
/(?:推荐|介绍).{0,32}一句话.{0,16}(?:说明|讲讲).{0,12}(?:理由|原因)/u,
|
|
|
|
|
|
],
|
|
|
|
|
|
},
|
2026-08-01 16:48:01 +08:00
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const MAX_FAQ_TEXT_LENGTH = 200;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @param {string} text
|
|
|
|
|
|
* @returns {{ id: string, reason: string } | null}
|
|
|
|
|
|
*/
|
2026-08-25 15:13:22 +08:00
|
|
|
|
const EXPLICIT_TEXT_ONLY_PAGE_DECLINE = /(?:不要|别|无需|不需要|禁止).{0,12}(?:生成|做|制作|创建|发布).{0,8}(?:页面|网页|HTML|html|H5|h5|链接)/u;
|
|
|
|
|
|
|
|
|
|
|
|
export function isExplicitTextOnlyRequest(text) {
|
|
|
|
|
|
const normalized = String(text ?? '').trim();
|
|
|
|
|
|
if (!normalized) return false;
|
|
|
|
|
|
return EXPLICIT_TEXT_ONLY_PAGE_DECLINE.test(normalized)
|
|
|
|
|
|
|| /(?:纯文字|只要文字|文字回答|不要页面|不用页面|别做页面)/u.test(normalized);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-01 16:48:01 +08:00
|
|
|
|
export function matchDirectChatFaqRule(text) {
|
|
|
|
|
|
const normalized = String(text ?? '').trim();
|
|
|
|
|
|
if (!normalized || normalized.length > MAX_FAQ_TEXT_LENGTH) return null;
|
2026-08-25 15:13:22 +08:00
|
|
|
|
const declinedPage = EXPLICIT_TEXT_ONLY_PAGE_DECLINE.test(normalized)
|
|
|
|
|
|
|| /(?:纯文字|只要文字|文字回答|不要页面|不用页面|别做页面)/u.test(normalized);
|
|
|
|
|
|
if (
|
|
|
|
|
|
!declinedPage
|
|
|
|
|
|
&& FAQ_EXCLUSION_PATTERNS.some((pattern) => pattern.test(normalized))
|
|
|
|
|
|
) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
2026-08-01 16:48:01 +08:00
|
|
|
|
for (const rule of DIRECT_CHAT_FAQ_RULES) {
|
|
|
|
|
|
if (rule.patterns.some((pattern) => pattern.test(normalized))) {
|
|
|
|
|
|
return { id: rule.id, reason: rule.reason };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|