137 lines
4.3 KiB
JavaScript
137 lines
4.3 KiB
JavaScript
|
|
/**
|
|||
|
|
* 智能模型路由 — 基于用户意图的模型自动选择
|
|||
|
|
*
|
|||
|
|
* 根据人类说话的意图(关键词匹配),自动选择最合适的模型回复。
|
|||
|
|
* 人类不需要知道背后用了哪个模型,系统自己选。
|
|||
|
|
*
|
|||
|
|
* 与 src/brain/model-router.js(任务型路由)互补:
|
|||
|
|
* - src/brain/model-router.js → 按任务模式(chat/build/review/brain/long)路由
|
|||
|
|
* - 本模块 → 按用户消息内容(关键词意图检测)路由
|
|||
|
|
*
|
|||
|
|
* 版权:国作登字-2026-A-00037559
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
'use strict';
|
|||
|
|
|
|||
|
|
var MODEL_PROFILES = {
|
|||
|
|
// 日常对话、闲聊、简单问答
|
|||
|
|
casual: {
|
|||
|
|
models: ['deepseek-chat', 'glm-4-flash'],
|
|||
|
|
keywords: ['你好', '聊聊', '怎么样', '帮我', '是什么', '谢谢', '请问', '可以吗'],
|
|||
|
|
maxTokens: 2000
|
|||
|
|
},
|
|||
|
|
// 代码相关、技术问题
|
|||
|
|
coding: {
|
|||
|
|
models: ['deepseek-chat', 'gpt-4o'],
|
|||
|
|
keywords: ['代码', 'code', 'bug', '报错', '函数', 'API', '部署', '配置', 'npm', 'git', '编译', '调试', 'debug', '接口', '数据库'],
|
|||
|
|
maxTokens: 4000
|
|||
|
|
},
|
|||
|
|
// 创意写作、长文生成
|
|||
|
|
creative: {
|
|||
|
|
models: ['deepseek-chat', 'moonshot-v1-128k'],
|
|||
|
|
keywords: ['写', '故事', '文案', '小说', '剧情', '人设', '大纲', '创意', '灵感', '文章', '描写'],
|
|||
|
|
maxTokens: 8000
|
|||
|
|
},
|
|||
|
|
// 数据分析、逻辑推理
|
|||
|
|
analytical: {
|
|||
|
|
models: ['deepseek-chat', 'gpt-4o'],
|
|||
|
|
keywords: ['分析', '对比', '数据', '统计', '逻辑', '推理', '策略', '方案', '评估', '优化'],
|
|||
|
|
maxTokens: 4000
|
|||
|
|
},
|
|||
|
|
// 系统指令、架构级操作
|
|||
|
|
system: {
|
|||
|
|
models: ['deepseek-chat', 'gpt-4o'],
|
|||
|
|
keywords: ['指令', '部署', '架构', '系统', '铁律', '天眼', '权限', '工单', '广播', '流程'],
|
|||
|
|
maxTokens: 6000
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 分析用户意图,选择最佳模型
|
|||
|
|
* @param {string} userMessage - 用户消息
|
|||
|
|
* @param {Object} context - 上下文(保留扩展)
|
|||
|
|
* @returns {{ model: string, maxTokens: number, profile: string, fallbacks: string[] }}
|
|||
|
|
*/
|
|||
|
|
function routeToModel(userMessage, context) {
|
|||
|
|
if (!userMessage || typeof userMessage !== 'string') {
|
|||
|
|
var casualConfig = MODEL_PROFILES.casual;
|
|||
|
|
return {
|
|||
|
|
model: casualConfig.models[0],
|
|||
|
|
maxTokens: casualConfig.maxTokens,
|
|||
|
|
profile: 'casual',
|
|||
|
|
fallbacks: casualConfig.models.slice(1)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var msg = userMessage.toLowerCase();
|
|||
|
|
|
|||
|
|
// 计算每个 profile 的匹配分数
|
|||
|
|
var scores = {};
|
|||
|
|
var profileNames = Object.keys(MODEL_PROFILES);
|
|||
|
|
for (var i = 0; i < profileNames.length; i++) {
|
|||
|
|
var profileName = profileNames[i];
|
|||
|
|
var config = MODEL_PROFILES[profileName];
|
|||
|
|
var score = 0;
|
|||
|
|
for (var j = 0; j < config.keywords.length; j++) {
|
|||
|
|
if (msg.includes(config.keywords[j])) {
|
|||
|
|
score++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
scores[profileName] = score;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 选择得分最高的 profile,默认 casual
|
|||
|
|
var bestProfile = 'casual';
|
|||
|
|
var bestScore = 0;
|
|||
|
|
for (var k = 0; k < profileNames.length; k++) {
|
|||
|
|
var pName = profileNames[k];
|
|||
|
|
if (scores[pName] > bestScore) {
|
|||
|
|
bestScore = scores[pName];
|
|||
|
|
bestProfile = pName;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var selected = MODEL_PROFILES[bestProfile];
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
model: selected.models[0],
|
|||
|
|
maxTokens: selected.maxTokens,
|
|||
|
|
profile: bestProfile,
|
|||
|
|
fallbacks: selected.models.slice(1)
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 带降级的 API 调用
|
|||
|
|
* @param {Object} route - routeToModel 的返回值
|
|||
|
|
* @param {Array} messages - 消息列表
|
|||
|
|
* @param {Function} callAPI - 实际的 API 调用函数 (model, messages, maxTokens) => Promise<response>
|
|||
|
|
* @returns {Promise<{ success: boolean, model?: string, response?: *, error?: string }>}
|
|||
|
|
*/
|
|||
|
|
async function callWithFallback(route, messages, callAPI) {
|
|||
|
|
if (typeof callAPI !== 'function') {
|
|||
|
|
return { success: false, error: 'callAPI 函数未提供' };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var models = [route.model].concat(route.fallbacks || []);
|
|||
|
|
|
|||
|
|
for (var i = 0; i < models.length; i++) {
|
|||
|
|
var model = models[i];
|
|||
|
|
try {
|
|||
|
|
var response = await callAPI(model, messages, route.maxTokens);
|
|||
|
|
return { success: true, model: model, response: response };
|
|||
|
|
} catch (err) {
|
|||
|
|
console.warn('[model-router] Model ' + model + ' failed, trying next... ' + (err.message || ''));
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { success: false, error: '所有模型均不可用,请稍后重试。' };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = {
|
|||
|
|
routeToModel: routeToModel,
|
|||
|
|
callWithFallback: callWithFallback,
|
|||
|
|
MODEL_PROFILES: MODEL_PROFILES
|
|||
|
|
};
|