187 lines
5.2 KiB
JavaScript
Raw Normal View History

/**
* connectors/model-router 模型调用路由
*
* 职责
* - 提供统一的模型调用入口
* - 支持多模型后端Anthropic / OpenAI / 通义千问 / DeepSeek
* - 支持本地代理模型api-proxy.js / persona-studio
* - 按优先级自动选择最佳可用模型
* - 不写死任何模型密钥统一通过环境变量管理
*
* AGE OS v1.0 适配规则
* 系统自动检测可用模型列表按优先级选择
* 支持多模型后端密钥统一存放在仓库 Secrets
*
* 调用方式
* node connectors/model-router [status]
*/
const path = require('path');
const fs = require('fs');
const ROOT = path.resolve(__dirname, '../..');
/**
* 本地代理模型注册表向后兼容
*/
const MODEL_REGISTRY = {
'default': {
name: 'default',
endpoint: 'http://localhost:3721/api/chat',
description: 'AI Chat API 代理api-proxy.js'
},
'persona': {
name: 'persona',
endpoint: 'http://localhost:3002/api/ps/chat',
description: '人格工作室 API'
}
};
/**
* 云端模型后端定义AGE OS v1.0 多模型支持
* 按优先级排序不写死任何模型
*/
const CLOUD_BACKENDS = [
{
name: 'anthropic',
envKey: 'ANTHROPIC_API_KEY',
baseUrl: 'https://api.anthropic.com',
format: 'anthropic',
defaultModels: ['claude-sonnet-4', 'claude-3-5-sonnet-20241022', 'claude-3-5-sonnet', 'claude-3-haiku'],
description: 'Anthropic Claude 系列'
},
{
name: 'openai',
envKey: 'OPENAI_API_KEY',
baseUrl: 'https://api.openai.com/v1',
format: 'openai',
defaultModels: ['gpt-4o', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'],
description: 'OpenAI GPT 系列'
},
{
name: 'dashscope',
envKey: 'DASHSCOPE_API_KEY',
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
format: 'openai',
defaultModels: ['qwen-max', 'qwen-plus', 'qwen-turbo'],
description: '通义千问系列'
},
{
name: 'deepseek',
envKey: 'DEEPSEEK_API_KEY',
baseUrl: 'https://api.deepseek.com/v1',
format: 'openai',
defaultModels: ['deepseek-chat', 'deepseek-reasoner'],
description: 'DeepSeek 系列'
},
{
name: 'custom',
envKey: 'LLM_API_KEY',
baseUrlEnv: 'LLM_BASE_URL',
format: 'openai',
defaultModels: [],
description: '自定义 LLM 平台(通过 LLM_BASE_URL 配置)'
}
];
/**
* 获取本地代理模型配置
*/
function getModel(modelName = 'default') {
return MODEL_REGISTRY[modelName] || MODEL_REGISTRY['default'];
}
/**
* 列出所有本地代理模型
*/
function listModels() {
return Object.values(MODEL_REGISTRY);
}
/**
* 检测可用的云端模型后端
*/
function detectCloudBackends() {
const available = [];
for (const backend of CLOUD_BACKENDS) {
const apiKey = process.env[backend.envKey] || '';
if (!apiKey) continue;
const baseUrl = backend.baseUrlEnv
? (process.env[backend.baseUrlEnv] || '').replace(/\/+$/, '')
: backend.baseUrl;
if (!baseUrl) continue;
available.push({ ...backend, baseUrl });
}
return available;
}
/**
* 列出所有可用模型本地 + 云端
*/
function listAllModels() {
const local = listModels();
const cloud = detectCloudBackends();
return { local, cloud };
}
/**
* 检查模型路由状态
*/
function status() {
console.log('🤖 模型路由状态 (AGE OS v1.0):');
console.log('═'.repeat(40));
// 本地代理模型
console.log('\n📌 本地代理模型:');
const models = listModels();
for (const model of models) {
console.log(` 📌 ${model.name}`);
console.log(` 端点: ${model.endpoint}`);
console.log(` 说明: ${model.description}`);
}
// 云端模型后端
console.log('\n☁ 云端模型后端:');
const cloud = detectCloudBackends();
if (cloud.length === 0) {
console.log(' ⚠️ 未检测到可用的云端模型后端');
} else {
for (const backend of cloud) {
console.log(`${backend.name}${backend.description}`);
console.log(` 格式: ${backend.format}`);
console.log(` 端点: ${backend.baseUrl}`);
if (backend.defaultModels.length > 0) {
console.log(` 默认模型: ${backend.defaultModels.join(', ')}`);
}
}
}
// 所有支持的后端(含未配置的)
console.log('\n📋 支持的后端列表:');
for (const backend of CLOUD_BACKENDS) {
const configured = !!process.env[backend.envKey];
console.log(` ${configured ? '✅' : '⏭️ '} ${backend.name} (${backend.envKey}) — ${backend.description}`);
}
// 检查 api-proxy 配置
const proxyPath = path.join(ROOT, 'backend-integration/api-proxy.js');
const proxyExists = fs.existsSync(proxyPath);
console.log(`\n ${proxyExists ? '✅' : '❌'} api-proxy.js 存在`);
// 检查 persona-studio 配置
const psPath = path.join(ROOT, 'persona-studio/backend/server.js');
const psExists = fs.existsSync(psPath);
console.log(` ${psExists ? '✅' : '❌'} persona-studio server.js 存在`);
return { models, cloud, proxy: proxyExists, persona_studio: psExists };
}
// CLI 入口
if (require.main === module) {
status();
}
module.exports = { getModel, listModels, listAllModels, detectCloudBackends, status, MODEL_REGISTRY, CLOUD_BACKENDS };