AI API集成与调用技巧
📖 概述
本文深入探讨AI API的集成策略和调用技巧,涵盖主流AI服务的接入方法、最佳实践、性能优化、错误处理等核心内容。通过实战案例和代码示例,帮助开发者掌握高效、稳定、安全的AI API集成技术。
🌐 主流AI API服务对比
服务提供商全景
| 提供商 | 主要服务 | 定价模式 | 特色功能 | 适用场景 |
|---|---|---|---|---|
| OpenAI | GPT系列、DALL-E、Whisper | 按Token计费 | 强大的生成能力 | 通用AI应用 |
| Anthropic | Claude系列 | 按Token计费 | 安全性、长上下文 | 企业级应用 |
| Gemini、PaLM | 按请求计费 | 多模态能力 | 搜索、分析 | |
| Microsoft | Azure OpenAI | 按Token计费 | 企业级部署 | 企业集成 |
| 百度 | 文心一言 | 按调用计费 | 中文优化 | 中文应用 |
| 阿里云 | 通义千问 | 按Token计费 | 云服务集成 | 阿里生态 |
| 腾讯 | 混元大模型 | 按调用计费 | 腾讯生态 | 社交、游戏 |
API能力矩阵
| 功能类型 | OpenAI | Anthropic | 百度 | 阿里云 | 腾讯 | |
|---|---|---|---|---|---|---|
| 文本生成 | ✅ GPT-4 | ✅ Claude-3 | ✅ Gemini | ✅ 文心 | ✅ 通义 | ✅ 混元 |
| 代码生成 | ✅ Codex | ✅ Claude | ✅ Gemini | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 图像生成 | ✅ DALL-E | ❌ | ✅ Imagen | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 语音识别 | ✅ Whisper | ❌ | ✅ Speech | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 多模态 | ✅ GPT-4V | ✅ Claude-3 | ✅ Gemini | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 函数调用 | ✅ 支持 | ✅ 工具使用 | ✅ 支持 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
🔧 统一API调用框架
抽象API客户端
const axios = require('axios');
const EventEmitter = require('events');
const crypto = require('crypto');
// API提供商配置
const API_CONFIGS = {
openai: {
baseURL: 'https://api.openai.com/v1',
headers: (apiKey) => ({
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
}),
models: {
'gpt-4': { maxTokens: 8192, costPer1K: 0.03 },
'gpt-3.5-turbo': { maxTokens: 4096, costPer1K: 0.002 },
'dall-e-3': { type: 'image', costPerImage: 0.04 }
}
},
anthropic: {
baseURL: 'https://api.anthropic.com/v1',
headers: (apiKey) => ({
'x-api-key': apiKey,
'Content-Type': 'application/json',
'anthropic-version': '2023-06-01'
}),
models: {
'claude-3-opus-20240229': { maxTokens: 200000, costPer1K: 0.015 },
'claude-3-sonnet-20240229': { maxTokens: 200000, costPer1K: 0.003 }
}
},
google: {
baseURL: 'https://generativelanguage.googleapis.com/v1beta',
headers: (apiKey) => ({
'Content-Type': 'application/json'
}),
models: {
'gemini-pro': { maxTokens: 30720, costPer1K: 0.0005 },
'gemini-pro-vision': { maxTokens: 16384, costPer1K: 0.0025 }
}
},
baidu: {
baseURL: 'https://aip.baidubce.com/rpc/2.0/ai_custom/v1',
headers: (accessToken) => ({
'Content-Type': 'application/json'
}),
models: {
'ernie-bot': { maxTokens: 2048, costPer1K: 0.008 },
'ernie-bot-turbo': { maxTokens: 2048, costPer1K: 0.003 }
}
}
};
class UniversalAIClient extends EventEmitter {
constructor(config = {}) {
super();
this.config = {
timeout: 30000,
maxRetries: 3,
retryDelay: 1000,
enableMetrics: true,
enableCache: true,
cacheExpiry: 3600000, // 1小时
rateLimits: {
openai: { rpm: 3500, tpm: 90000 },
anthropic: { rpm: 1000, tpm: 100000 },
google: { rpm: 60, tpm: 32000 }
},
...config
};
this.clients = new Map();
this.cache = new Map();
this.metrics = {
requests: 0,
successes: 0,
errors: 0,
totalCost: 0,
cacheHits: 0,
responseTime: []
};
this.rateLimiters = new Map();
this.initializeClients();
this.setupRateLimiting();
}
initializeClients() {
console.log('🔧 初始化AI客户端...');
// 清理旧告警
const originalAlerts = this.alerts.length;
this.alerts = this.alerts.filter(alert => alert.timestamp > cutoff);
const cleanedAlerts = originalAlerts - this.alerts.length;
if (cleanedAlerts > 0) {
console.log(`🧹 清理了 ${cleanedAlerts} 条历史告警`);
}
}
getActiveAlerts() {
return this.alerts.filter(alert => !alert.acknowledged);
}
getDashboardData() {
const now = Date.now();
const oneHour = 60 * 60 * 1000;
const recentRequests = this.metrics.requests.filter(
r => now - r.timestamp < oneHour
);
return {
realtime: {
activeRequests: recentRequests.length,
activeAlerts: this.getActiveAlerts().length,
avgResponseTime: this.calculateAverage(
recentRequests.map(r => r.responseTime)
),
successRate: recentRequests.length > 0 ?
(recentRequests.filter(r => r.success).length / recentRequests.length) : 1
},
trends: {
responseTime: this.metrics.responseTime.slice(-60), // 最近60个数据点
throughput: this.metrics.throughput.slice(-60),
errorRate: this.calculateErrorRateTrend()
},
providers: this.getProviderBreakdown(recentRequests)
};
}
calculateErrorRateTrend() {
const now = Date.now();
const interval = 5 * 60 * 1000; // 5分钟间隔
const points = [];
for (let i = 11; i >= 0; i--) {
const endTime = now - (i * interval);
const startTime = endTime - interval;
const requests = this.metrics.requests.filter(
r => r.timestamp >= startTime && r.timestamp < endTime
);
const errorRate = requests.length > 0 ?
requests.filter(r => !r.success).length / requests.length : 0;
points.push({
timestamp: endTime,
value: errorRate
});
}
return points;
}
stop() {
if (this.metricsTimer) {
clearInterval(this.metricsTimer);
this.metricsTimer = null;
}
console.log('📊 性能监控已停止');
}
}
// 使用示例
const monitor = new APIPerformanceMonitor({
metricsInterval: 30000, // 30秒
alertThresholds: {
responseTime: 3000,
errorRate: 0.05,
costPerHour: 5
}
});
// 监听事件
monitor.on('alert', (alert) => {
console.log(`🚨 收到告警: ${alert.type}`);
// 这里可以发送通知
});
monitor.on('metricsCollected', (metrics) => {
// 可以将指标发送到监控系统
console.log(`📊 指标已收集: ${metrics.totalRequests} 请求`);
});
// 集成到AI客户端
class MonitoredAIClient extends UniversalAIClient {
constructor(config = {}) {
super(config);
this.monitor = new APIPerformanceMonitor(config.monitoring || {});
this.setupMonitoring();
}
setupMonitoring() {
// 监听API调用事件
this.on('apiCall', (data) => {
this.monitor.recordRequest({
...data,
success: true
});
});
this.on('apiError', (data) => {
this.monitor.recordRequest({
...data,
success: false
});
});
}
async generateReport(timeRange = '24h') {
return this.monitor.generateReport(timeRange);
}
getDashboard() {
return this.monitor.getDashboardData();
}
cleanup() {
super.cleanup();
this.monitor.stop();
}
}
module.exports = { APIPerformanceMonitor, MonitoredAIClient };
🔄 错误处理与重试策略
智能重试管理器
class SmartRetryManager {
constructor(options = {}) {
this.options = {
maxRetries: 3,
baseDelay: 1000,
maxDelay: 30000,
backoffMultiplier: 2,
jitterRange: 0.1,
retryableErrors: [
'ECONNRESET',
'ETIMEDOUT',
'ENOTFOUND',
'rate_limit_exceeded',
'server_error',
'service_unavailable'
],
circuitBreakerThreshold: 5,
circuitBreakerTimeout: 60000,
...options
};
this.circuitBreakers = new Map();
this.retryStats = new Map();
}
async executeWithRetry(operation, context = {}) {
const {
provider = 'default',
operationId = 'unknown',
maxRetries = this.options.maxRetries
} = context;
// 检查熔断器状态
if (this.isCircuitOpen(provider)) {
throw new Error(`${provider} 服务熔断中,请稍后重试`);
}
let lastError;
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
console.log(`🔄 执行操作 ${operationId} (尝试 ${attempt + 1}/${maxRetries + 1})`);
const result = await operation();
// 成功时重置熔断器
this.recordSuccess(provider);
if (attempt > 0) {
console.log(`✅ 操作在第 ${attempt + 1} 次尝试后成功`);
}
return result;
} catch (error) {
lastError = error;
console.log(`❌ 操作失败 (尝试 ${attempt + 1}): ${error.message}`);
// 记录失败
this.recordFailure(provider, error);
// 检查是否应该重试
if (attempt === maxRetries || !this.shouldRetry(error)) {
console.log(`🛑 不再重试: ${this.getRetryReason(error, attempt, maxRetries)}`);
break;
}
// 计算延迟时间
const delay = this.calculateDelay(attempt);
console.log(`⏳ 等待 ${delay}ms 后重试...`);
await this.sleep(delay);
}
}
throw lastError;
}
shouldRetry(error) {
// 检查错误类型是否可重试
const errorMessage = error.message.toLowerCase();
const isRetryable = this.options.retryableErrors.some(retryableError =>
errorMessage.includes(retryableError.toLowerCase())
);
// 检查HTTP状态码
if (error.response) {
const status = error.response.status;
// 4xx错误通常不应重试(除了429)
if (status >= 400 && status < 500 && status !== 429) {
return false;
}
// 5xx错误应该重试
if (status >= 500) {
return true;
}
}
return isRetryable;
}
getRetryReason(error, attempt, maxRetries) {
if (attempt >= maxRetries) {
return '已达最大重试次数';
}
if (!this.shouldRetry(error)) {
return '错误类型不可重试';
}
return '未知原因';
}
calculateDelay(attempt) {
// 指数退避算法
let delay = this.options.baseDelay * Math.pow(this.options.backoffMultiplier, attempt);
// 添加抖动
const jitter = delay * this.options.jitterRange * (Math.random() * 2 - 1);
delay += jitter;
// 限制最大延迟
return Math.min(delay, this.options.maxDelay);
}
recordSuccess(provider) {
// 重置熔断器
if (this.circuitBreakers.has(provider)) {
const breaker = this.circuitBreakers.get(provider);
breaker.failures = 0;
breaker.state = 'closed';
breaker.nextAttempt = null;
}
// 更新统计
if (!this.retryStats.has(provider)) {
this.retryStats.set(provider, {
successes: 0,
failures: 0,
totalRetries: 0
});
}
this.retryStats.get(provider).successes++;
}
recordFailure(provider, error) {
// 更新熔断器
if (!this.circuitBreakers.has(provider)) {
this.circuitBreakers.set(provider, {
failures: 0,
state: 'closed', // closed, open, half-open
nextAttempt: null
});
}
const breaker = this.circuitBreakers.get(provider);
breaker.failures++;
// 检查是否需要打开熔断器
if (breaker.failures >= this.options.circuitBreakerThreshold) {
breaker.state = 'open';
breaker.nextAttempt = Date.now() + this.options.circuitBreakerTimeout;
console.log(`🔥 ${provider} 熔断器已打开,${this.options.circuitBreakerTimeout / 1000}秒后尝试恢复`);
}
// 更新统计
if (!this.retryStats.has(provider)) {
this.retryStats.set(provider, {
successes: 0,
failures: 0,
totalRetries: 0
});
}
this.retryStats.get(provider).failures++;
}
isCircuitOpen(provider) {
const breaker = this.circuitBreakers.get(provider);
if (!breaker) return false;
if (breaker.state === 'closed') {
return false;
}
if (breaker.state === 'open') {
if (Date.now() >= breaker.nextAttempt) {
// 转换到半开状态
breaker.state = 'half-open';
console.log(`🔄 ${provider} 熔断器转为半开状态`);
return false;
}
return true;
}
// half-open状态允许一次尝试
return false;
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
getStats() {
const stats = {
circuitBreakers: {},
retryStats: {}
};
this.circuitBreakers.forEach((breaker, provider) => {
stats.circuitBreakers[provider] = {
state: breaker.state,
failures: breaker.failures,
nextAttempt: breaker.nextAttempt
};
});
this.retryStats.forEach((stat, provider) => {
stats.retryStats[provider] = { ...stat };
});
return stats;
}
reset(provider = null) {
if (provider) {
this.circuitBreakers.delete(provider);
this.retryStats.delete(provider);
console.log(`🔄 ${provider} 重试状态已重置`);
} else {
this.circuitBreakers.clear();
this.retryStats.clear();
console.log('🔄 所有重试状态已重置');
}
}
}
// 使用示例
const retryManager = new SmartRetryManager({
maxRetries: 3,
baseDelay: 1000,
circuitBreakerThreshold: 3
});
// 集成到AI客户端
class ResilientAIClient extends MonitoredAIClient {
constructor(config = {}) {
super(config);
this.retryManager = new SmartRetryManager(config.retry || {});
}
async callAPI(provider, endpoint, data, options = {}) {
return this.retryManager.executeWithRetry(
() => super.callAPI(provider, endpoint, data, options),
{
provider,
operationId: `${provider}:${endpoint}`,
maxRetries: options.maxRetries
}
);
}
getRetryStats() {
return this.retryManager.getStats();
}
resetRetryState(provider = null) {
this.retryManager.reset(provider);
}
}
module.exports = { SmartRetryManager, ResilientAIClient };
🎯 学习检验
理论理解检验
- API对比分析:能否分析不同AI服务的特点和适用场景?
- 集成策略:能否设计统一的API调用框架?
- 安全管理:能否理解API密钥的安全管理策略?
- 性能优化:能否掌握缓存、重试、监控等优化技术?
实践能力检验
- 客户端开发:能否开发统一的AI API客户端?
- 错误处理:能否实现智能的重试和熔断机制?
- 性能监控:能否构建完整的API性能监控系统?
- 安全实践:能否实现安全的密钥管理和配置加密?
🚀 实践项目建议
基础实战项目
- 多模型对话系统:集成多个AI服务的对话应用
- API性能测试工具:AI API的性能测试和对比工具
- 智能重试代理:带有智能重试的API代理服务
- 成本监控仪表板:AI API使用成本的监控面板
高级综合项目
- 企业AI网关:企业级的AI API统一网关
- 多云AI平台:支持多个云服务商的AI平台
- AI服务编排器:复杂AI工作流的编排和执行引擎
- 智能负载均衡器:AI服务的智能负载均衡和故障转移
📚 延伸阅读
技术文档
- "API Integration Best Practices" - API集成最佳实践
- "Microservices Patterns" - 微服务架构模式
- "Building Resilient Systems" - 构建弹性系统
- "API Security Guide" - API安全指南
开源项目
- LangChain - AI应用开发框架
- LiteLLM - 统一LLM API接口
- OpenAI Node.js - OpenAI官方Node.js库
- Anthropic SDK - Anthropic官方SDK
💡 学习提示:AI API集成需要考虑多个维度:功能对比、性能优化、成本控制、安全管理等。建议从简单的单一API集成开始,逐步构建统一的调用框架。重视错误处理和监控告警,关注API的使用成本和性能指标。实践中要注意不同服务商的API差异,合理设计抽象层来屏蔽这些差异。
// 初始化各个提供商的客户端
Object.keys(API_CONFIGS).forEach(provider => {
const config = API_CONFIGS[provider];
const apiKey = this.getApiKey(provider);
if (apiKey) {
this.clients.set(provider, {
config,
apiKey,
httpClient: axios.create({
baseURL: config.baseURL,
timeout: this.config.timeout,
headers: config.headers(apiKey)
})
});
console.log(`[成功] ${provider} 客户端初始化成功`);
} else {
console.log(`[警告] ${provider} API密钥未配置`);
}
});
}
getApiKey(provider) {
const keyMap = {
openai: process.env.OPENAI_API_KEY,
anthropic: process.env.ANTHROPIC_API_KEY,
google: process.env.GOOGLE_AI_API_KEY,
baidu: process.env.BAIDU_API_KEY
};
return keyMap[provider];
}
setupRateLimiting() {
// 简单的令牌桶算法实现
Object.entries(this.config.rateLimits).forEach(([provider, limits]) => {
this.rateLimiters.set(provider, {
rpm: {
tokens: limits.rpm,
maxTokens: limits.rpm,
refillRate: limits.rpm / 60, // 每秒补充的令牌数
lastRefill: Date.now()
},
tpm: {
tokens: limits.tpm,
maxTokens: limits.tpm,
refillRate: limits.tpm / 60,
lastRefill: Date.now()
}
});
});
// 定期补充令牌
setInterval(() => {
this.refillTokens();
}, 1000);
}
refillTokens() {
const now = Date.now();
this.rateLimiters.forEach((limiter, provider) => {
['rpm', 'tpm'].forEach(type => {
const bucket = limiter[type];
const timePassed = (now - bucket.lastRefill) / 1000;
const tokensToAdd = timePassed * bucket.refillRate;
bucket.tokens = Math.min(bucket.maxTokens, bucket.tokens + tokensToAdd);
bucket.lastRefill = now;
});
});
}
async checkRateLimit(provider, estimatedTokens = 1) {
const limiter = this.rateLimiters.get(provider);
if (!limiter) return true;
// 检查RPM限制
if (limiter.rpm.tokens < 1) {
throw new Error(`${provider} RPM限制已达到,请稍后重试`);
}
// 检查TPM限制
if (limiter.tpm.tokens < estimatedTokens) {
throw new Error(`${provider} TPM限制已达到,请稍后重试`);
}
// 消耗令牌
limiter.rpm.tokens -= 1;
limiter.tpm.tokens -= estimatedTokens;
return true;
}
async callAPI(provider, endpoint, data, options = {}) {
const startTime = Date.now();
this.metrics.requests++;
try {
const client = this.clients.get(provider);
if (!client) {
throw new Error(`未找到 ${provider} 客户端`);
}
// 检查缓存
const cacheKey = this.generateCacheKey(provider, endpoint, data);
if (this.config.enableCache && this.cache.has(cacheKey)) {
const cached = this.cache.get(cacheKey);
if (Date.now() - cached.timestamp < this.config.cacheExpiry) {
this.metrics.cacheHits++;
return { ...cached.data, fromCache: true };
} else {
this.cache.delete(cacheKey);
}
}
// 估算Token数量
const estimatedTokens = this.estimateTokens(data);
// 检查速率限制
await this.checkRateLimit(provider, estimatedTokens);
console.log(`\n🚀 调用 ${provider} API: ${endpoint}`);
console.log(`估算Token数: ${estimatedTokens}`);
// 发送请求
const response = await this.makeRequest(client, endpoint, data, options);
// 缓存结果
if (this.config.enableCache && !options.noCache) {
this.cache.set(cacheKey, {
data: response.data,
timestamp: Date.now()
});
}
// 更新指标
this.metrics.successes++;
const responseTime = Date.now() - startTime;
this.metrics.responseTime.push(responseTime);
// 计算成本
const cost = this.calculateCost(provider, response.data);
this.metrics.totalCost += cost;
console.log(`✅ API调用成功 - 响应时间: ${responseTime}ms, 成本: $${cost.toFixed(4)}`);
this.emit('apiCall', {
provider,
endpoint,
success: true,
responseTime,
cost,
tokens: response.data.usage
});
return {
...response.data,
provider,
responseTime,
cost,
fromCache: false
};
} catch (error) {
this.metrics.errors++;
console.error(`❌ ${provider} API调用失败:`, error.message);
this.emit('apiError', {
provider,
endpoint,
error: error.message,
responseTime: Date.now() - startTime
});
// 重试逻辑
if (options.retry !== false && this.shouldRetry(error)) {
return this.retryRequest(provider, endpoint, data, options);
}
throw error;
}
}
async makeRequest(client, endpoint, data, options) {
const { method = 'POST', params = {} } = options;
const requestConfig = {
method,
url: endpoint,
data: method === 'GET' ? undefined : data,
params: method === 'GET' ? { ...data, ...params } : params
};
return await client.httpClient.request(requestConfig);
}
shouldRetry(error) {
// 可重试的错误类型
const retryableErrors = [
'ECONNRESET',
'ETIMEDOUT',
'ENOTFOUND',
'rate_limit_exceeded',
'server_error'
];
return retryableErrors.some(errorType =>
error.message.toLowerCase().includes(errorType.toLowerCase())
) || (error.response && error.response.status >= 500);
}
async retryRequest(provider, endpoint, data, options, attempt = 1) {
if (attempt > this.config.maxRetries) {
throw new Error(`${provider} API重试次数已达上限`);
}
const delay = this.config.retryDelay * Math.pow(2, attempt - 1); // 指数退避
console.log(`🔄 第${attempt}次重试 ${provider} API,${delay}ms后执行...`);
await new Promise(resolve => setTimeout(resolve, delay));
try {
return await this.callAPI(provider, endpoint, data, {
...options,
retry: false // 避免无限重试
});
} catch (error) {
return this.retryRequest(provider, endpoint, data, options, attempt + 1);
}
}
estimateTokens(data) {
// 简单的Token估算(实际应用中可以使用更精确的方法)
let text = '';
if (typeof data === 'string') {
text = data;
} else if (data.messages) {
text = data.messages.map(m => m.content).join(' ');
} else if (data.prompt) {
text = data.prompt;
}
// 粗略估算:1个Token约等于4个字符
return Math.ceil(text.length / 4);
}
calculateCost(provider, response) {
const config = API_CONFIGS[provider];
if (!config || !response.usage) return 0;
const usage = response.usage;
let cost = 0;
// 根据不同提供商计算成本
if (usage.prompt_tokens && usage.completion_tokens) {
const model = response.model || Object.keys(config.models)[0];
const modelConfig = config.models[model];
if (modelConfig && modelConfig.costPer1K) {
cost = ((usage.prompt_tokens + usage.completion_tokens) / 1000) * modelConfig.costPer1K;
}
}
return cost;
}
generateCacheKey(provider, endpoint, data) {
const keyData = {
provider,
endpoint,
data: typeof data === 'object' ? JSON.stringify(data) : data
};
return crypto.createHash('md5').update(JSON.stringify(keyData)).digest('hex');
}
// 统一的文本生成接口
async generateText(prompt, options = {}) {
const {
provider = 'openai',
model = 'gpt-3.5-turbo',
maxTokens = 1000,
temperature = 0.7,
stream = false
} = options;
switch (provider) {
case 'openai':
return this.callOpenAI(prompt, { model, maxTokens, temperature, stream });
case 'anthropic':
return this.callAnthropic(prompt, { model, maxTokens, temperature });
case 'google':
return this.callGoogle(prompt, { model, maxTokens, temperature });
case 'baidu':
return this.callBaidu(prompt, { model, maxTokens, temperature });
default:
throw new Error(`不支持的提供商: ${provider}`);
}
}
async callOpenAI(prompt, options) {
const { model, maxTokens, temperature, stream } = options;
const data = {
model,
messages: [{ role: 'user', content: prompt }],
max_tokens: maxTokens,
temperature,
stream
};
return this.callAPI('openai', '/chat/completions', data);
}
async callAnthropic(prompt, options) {
const { model, maxTokens, temperature } = options;
const data = {
model,
max_tokens: maxTokens,
temperature,
messages: [{ role: 'user', content: prompt }]
};
return this.callAPI('anthropic', '/messages', data);
}
async callGoogle(prompt, options) {
const { model, maxTokens, temperature } = options;
const data = {
contents: [{
parts: [{ text: prompt }]
}],
generationConfig: {
temperature,
maxOutputTokens: maxTokens
}
};
return this.callAPI('google', `/models/${model}:generateContent`, data, {
params: { key: this.getApiKey('google') }
});
}
async callBaidu(prompt, options) {
const { model, maxTokens, temperature } = options;
// 百度需要先获取access_token
const accessToken = await this.getBaiduAccessToken();
const data = {
messages: [{ role: 'user', content: prompt }],
max_output_tokens: maxTokens,
temperature
};
return this.callAPI('baidu', `/wenxinworkshop/chat/${model}`, data, {
params: { access_token: accessToken }
});
}
async getBaiduAccessToken() {
// 实现百度access_token获取逻辑
const clientId = process.env.BAIDU_CLIENT_ID;
const clientSecret = process.env.BAIDU_CLIENT_SECRET;
if (!clientId || !clientSecret) {
throw new Error('百度API凭证未配置');
}
// 这里应该实现实际的token获取逻辑
return 'mock_access_token';
}
// 批量处理
async batchProcess(requests, options = {}) {
const {
concurrency = 3,
delayBetweenBatches = 1000,
failFast = false
} = options;
console.log(`\n📦 开始批量处理 ${requests.length} 个请求`);
console.log(`并发数: ${concurrency}`);
const results = [];
const errors = [];
for (let i = 0; i < requests.length; i += concurrency) {
const batch = requests.slice(i, i + concurrency);
console.log(`\n处理批次 ${Math.floor(i / concurrency) + 1}/${Math.ceil(requests.length / concurrency)}`);
const batchPromises = batch.map(async (request, index) => {
try {
const result = await this.generateText(request.prompt, request.options);
return { index: i + index, success: true, result };
} catch (error) {
const errorResult = { index: i + index, success: false, error: error.message };
if (failFast) {
throw error;
}
return errorResult;
}
});
try {
const batchResults = await Promise.all(batchPromises);
batchResults.forEach(result => {
if (result.success) {
results.push(result);
} else {
errors.push(result);
}
});
console.log(`批次完成: 成功 ${batchResults.filter(r => r.success).length}, 失败 ${batchResults.filter(r => !r.success).length}`);
// 批次间延迟
if (i + concurrency < requests.length) {
await new Promise(resolve => setTimeout(resolve, delayBetweenBatches));
}
} catch (error) {
if (failFast) {
throw error;
}
console.error(`批次处理失败:`, error.message);
}
}
console.log(`\n✅ 批量处理完成`);
console.log(`总成功: ${results.length}`);
console.log(`总失败: ${errors.length}`);
return {
total: requests.length,
successes: results.length,
errors: errors.length,
results,
errorDetails: errors
};
}
// 获取指标统计
getMetrics() {
const avgResponseTime = this.metrics.responseTime.length > 0 ?
this.metrics.responseTime.reduce((a, b) => a + b, 0) / this.metrics.responseTime.length : 0;
return {
...this.metrics,
avgResponseTime: Math.round(avgResponseTime),
successRate: this.metrics.requests > 0 ?
(this.metrics.successes / this.metrics.requests * 100).toFixed(2) + '%' : '0%',
cacheHitRate: this.metrics.requests > 0 ?
(this.metrics.cacheHits / this.metrics.requests * 100).toFixed(2) + '%' : '0%',
availableProviders: Array.from(this.clients.keys()),
cacheSize: this.cache.size
};
}
// 健康检查
async healthCheck() {
console.log('\n执行健康检查...');
const results = {};
for (const [provider] of this.clients) {
try {
const startTime = Date.now();
await this.generateText('Hello', {
provider,
maxTokens: 10,
noCache: true
});
results[provider] = {
status: 'healthy',
responseTime: Date.now() - startTime
};
console.log(`[健康] ${provider}`);
} catch (error) {
results[provider] = {
status: 'unhealthy',
error: error.message
};
console.log(`[不健康] ${provider}: ${error.message}`);
}
}
return results;
}
// 清理资源
cleanup() {
this.cache.clear();
this.metrics.responseTime = [];
console.log('资源清理完成');
}
}
// 使用示例
const aiClient = new UniversalAIClient({
enableCache: true,
enableMetrics: true,
timeout: 30000
});
// 监听事件
aiClient.on('apiCall', (data) => {
console.log(`API调用: ${data.provider} - ${data.responseTime}ms - $${data.cost.toFixed(4)}`);
});
aiClient.on('apiError', (data) => {
console.log(`API错误: ${data.provider} - ${data.error}`);
});
// 文本生成演示已移除
// 健康检查演示
async function healthCheckDemo() {
const healthStatus = await aiClient.healthCheck();
console.log('\n健康检查结果:');
Object.entries(healthStatus).forEach(([provider, status]) => {
console.log(`${provider}: ${status.status}`);
if (status.responseTime) {
console.log(` 响应时间: ${status.responseTime}ms`);
}
});
}
// 运行演示
if (require.main === module) {
(async () => {
await textGenerationDemo();
await healthCheckDemo();
// 清理资源
aiClient.cleanup();
})().catch(console.error);
}
module.exports = { UniversalAIClient, API_CONFIGS };
🔐 API密钥管理与安全
安全配置管理器
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
class SecureConfigManager {
constructor(options = {}) {
this.options = {
encryptionKey: process.env.CONFIG_ENCRYPTION_KEY || this.generateKey(),
configPath: options.configPath || './config/secure.json',
backupPath: options.backupPath || './config/backup',
rotationInterval: options.rotationInterval || 30 * 24 * 60 * 60 * 1000, // 30天
...options
};
this.algorithm = 'aes-256-gcm';
this.configs = new Map();
this.loadConfigs();
this.setupRotation();
}
generateKey() {
return crypto.randomBytes(32).toString('hex');
}
encrypt(text) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipher(this.algorithm, this.options.encryptionKey);
cipher.setAAD(Buffer.from('config-data'));
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
const authTag = cipher.getAuthTag();
return {
encrypted,
iv: iv.toString('hex'),
authTag: authTag.toString('hex')
};
}
decrypt(encryptedData) {
const decipher = crypto.createDecipher(this.algorithm, this.options.encryptionKey);
decipher.setAAD(Buffer.from('config-data'));
decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
setApiKey(provider, apiKey, metadata = {}) {
console.log(`🔐 设置 ${provider} API密钥`);
const config = {
apiKey,
provider,
createdAt: new Date().toISOString(),
lastUsed: null,
usageCount: 0,
metadata: {
environment: process.env.NODE_ENV || 'development',
...metadata
}
};
this.configs.set(provider, config);
this.saveConfigs();
console.log(`✅ ${provider} API密钥已安全存储`);
}
getApiKey(provider) {
const config = this.configs.get(provider);
if (!config) {
throw new Error(`未找到 ${provider} 的API密钥`);
}
// 更新使用统计
config.lastUsed = new Date().toISOString();
config.usageCount++;
return config.apiKey;
}
rotateApiKey(provider, newApiKey) {
console.log(`🔄 轮换 ${provider} API密钥`);
const oldConfig = this.configs.get(provider);
if (oldConfig) {
// 备份旧密钥
this.backupConfig(provider, oldConfig);
}
this.setApiKey(provider, newApiKey, {
rotatedFrom: oldConfig?.apiKey?.substring(0, 8) + '...',
rotatedAt: new Date().toISOString()
});
console.log(`✅ ${provider} API密钥轮换完成`);
}
validateApiKey(provider, apiKey) {
// API密钥格式验证
const patterns = {
openai: /^sk-[a-zA-Z0-9]{48}$/,
anthropic: /^sk-ant-[a-zA-Z0-9\-_]{95}$/,
google: /^[a-zA-Z0-9\-_]{39}$/,
baidu: /^[a-zA-Z0-9]{24}$/
};
const pattern = patterns[provider];
if (pattern && !pattern.test(apiKey)) {
throw new Error(`${provider} API密钥格式无效`);
}
return true;
}
async testApiKey(provider, apiKey) {
console.log(`🧪 测试 ${provider} API密钥`);
try {
// 这里应该实现实际的API测试逻辑
const testClient = new UniversalAIClient();
// 临时设置密钥进行测试
const originalKey = process.env[`${provider.toUpperCase()}_API_KEY`];
process.env[`${provider.toUpperCase()}_API_KEY`] = apiKey;
await testClient.generateText('Hello', {
provider,
maxTokens: 5
});
// 恢复原密钥
if (originalKey) {
process.env[`${provider.toUpperCase()}_API_KEY`] = originalKey;
}
console.log(`✅ ${provider} API密钥测试通过`);
return true;
} catch (error) {
console.error(`❌ ${provider} API密钥测试失败:`, error.message);
return false;
}
}
loadConfigs() {
try {
if (fs.existsSync(this.options.configPath)) {
const encryptedData = JSON.parse(fs.readFileSync(this.options.configPath, 'utf8'));
const decryptedData = this.decrypt(encryptedData);
const configs = JSON.parse(decryptedData);
Object.entries(configs).forEach(([provider, config]) => {
this.configs.set(provider, config);
});
console.log(`📖 已加载 ${this.configs.size} 个API配置`);
}
} catch (error) {
console.error('配置加载失败:', error.message);
}
}
saveConfigs() {
try {
const configsObj = Object.fromEntries(this.configs);
const configData = JSON.stringify(configsObj, null, 2);
const encryptedData = this.encrypt(configData);
// 确保目录存在
const configDir = path.dirname(this.options.configPath);
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true });
}
fs.writeFileSync(this.options.configPath, JSON.stringify(encryptedData, null, 2));
console.log('💾 配置已安全保存');
} catch (error) {
console.error('配置保存失败:', error.message);
}
}
backupConfig(provider, config) {
try {
const backupDir = this.options.backupPath;
if (!fs.existsSync(backupDir)) {
fs.mkdirSync(backupDir, { recursive: true });
}
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const backupFile = path.join(backupDir, `${provider}_${timestamp}.json`);
const encryptedConfig = this.encrypt(JSON.stringify(config, null, 2));
fs.writeFileSync(backupFile, JSON.stringify(encryptedConfig, null, 2));
console.log(`📦 ${provider} 配置已备份到: ${backupFile}`);
} catch (error) {
console.error('配置备份失败:', error.message);
}
}
setupRotation() {
// 定期检查密钥是否需要轮换
setInterval(() => {
this.checkRotationNeeded();
}, 24 * 60 * 60 * 1000); // 每天检查一次
}
checkRotationNeeded() {
const now = Date.now();
this.configs.forEach((config, provider) => {
const createdAt = new Date(config.createdAt).getTime();
const age = now - createdAt;
if (age > this.options.rotationInterval) {
console.log(`⚠️ ${provider} API密钥需要轮换 (已使用 ${Math.floor(age / (24 * 60 * 60 * 1000))} 天)`);
// 这里可以发送通知或自动轮换
this.emit('rotationNeeded', { provider, age });
}
});
}
getUsageStats() {
const stats = {};
this.configs.forEach((config, provider) => {
stats[provider] = {
usageCount: config.usageCount,
lastUsed: config.lastUsed,
createdAt: config.createdAt,
age: Date.now() - new Date(config.createdAt).getTime()
};
});
return stats;
}
exportConfigs(outputPath, includeKeys = false) {
const exportData = {
timestamp: new Date().toISOString(),
configs: {}
};
this.configs.forEach((config, provider) => {
exportData.configs[provider] = {
provider: config.provider,
createdAt: config.createdAt,
lastUsed: config.lastUsed,
usageCount: config.usageCount,
metadata: config.metadata
};
if (includeKeys) {
exportData.configs[provider].apiKey = config.apiKey;
}
});
if (includeKeys) {
// 如果包含密钥,需要加密
const encryptedData = this.encrypt(JSON.stringify(exportData, null, 2));
fs.writeFileSync(outputPath, JSON.stringify(encryptedData, null, 2));
} else {
fs.writeFileSync(outputPath, JSON.stringify(exportData, null, 2));
}
console.log(`📤 配置已导出到: ${outputPath}`);
}
cleanup() {
this.configs.clear();
console.log('🧹 配置管理器已清理');
}
}
// 使用示例
const configManager = new SecureConfigManager({
configPath: './config/api_keys.json',
rotationInterval: 30 * 24 * 60 * 60 * 1000 // 30天
});
// 设置API密钥
async function setupApiKeys() {
console.log('🔐 API密钥管理演示\n');
try {
// 设置各个提供商的API密钥
const apiKeys = {
openai: process.env.OPENAI_API_KEY,
anthropic: process.env.ANTHROPIC_API_KEY,
google: process.env.GOOGLE_AI_API_KEY
};
for (const [provider, apiKey] of Object.entries(apiKeys)) {
if (apiKey) {
// 验证密钥格式
try {
configManager.validateApiKey(provider, apiKey);
console.log(`✅ ${provider} 密钥格式验证通过`);
} catch (error) {
console.log(`⚠️ ${provider} 密钥格式验证失败: ${error.message}`);
continue;
}
// 测试密钥有效性
const isValid = await configManager.testApiKey(provider, apiKey);
if (isValid) {
configManager.setApiKey(provider, apiKey, {
environment: 'production',
description: `${provider} API密钥`
});
}
}
}
// 显示使用统计
const stats = configManager.getUsageStats();
console.log('\n📊 API密钥使用统计:');
Object.entries(stats).forEach(([provider, stat]) => {
console.log(`${provider}:`);
console.log(` 使用次数: ${stat.usageCount}`);
console.log(` 最后使用: ${stat.lastUsed || '未使用'}`);
console.log(` 创建时间: ${stat.createdAt}`);
});
// 导出配置(不包含密钥)
configManager.exportConfigs('./config/api_stats.json', false);
} catch (error) {
console.error('API密钥设置失败:', error.message);
}
}
module.exports = { SecureConfigManager };
📈 性能监控与优化
API性能监控器
const EventEmitter = require('events');
const fs = require('fs');
class APIPerformanceMonitor extends EventEmitter {
constructor(options = {}) {
super();
this.options = {
metricsInterval: 60000, // 1分钟
alertThresholds: {
responseTime: 5000, // 5秒
errorRate: 0.1, // 10%
costPerHour: 10 // $10/小时
},
retentionPeriod: 7 * 24 * 60 * 60 * 1000, // 7天
...options
};
this.metrics = {
requests: [],
errors: [],
costs: [],
responseTime: [],
throughput: []
};
this.alerts = [];
this.startMonitoring();
}
startMonitoring() {
console.log('📊 启动API性能监控...');
// 定期收集指标
this.metricsTimer = setInterval(() => {
this.collectMetrics();
this.checkAlerts();
this.cleanupOldData();
}, this.options.metricsInterval);
console.log(`✅ 性能监控已启动,间隔: ${this.options.metricsInterval / 1000}秒`);
}
recordRequest(data) {
const record = {
timestamp: Date.now(),
provider: data.provider,
endpoint: data.endpoint,
responseTime: data.responseTime,
success: data.success,
cost: data.cost || 0,
tokens: data.tokens || 0,
error: data.error || null
};
this.metrics.requests.push(record);
if (!data.success) {
this.metrics.errors.push(record);
}
if (data.cost > 0) {
this.metrics.costs.push(record);
}
this.metrics.responseTime.push({
timestamp: record.timestamp,
value: data.responseTime,
provider: data.provider
});
// 触发实时事件
this.emit('requestRecorded', record);
}
collectMetrics() {
const now = Date.now();
const oneHour = 60 * 60 * 1000;
const recentRequests = this.metrics.requests.filter(
r => now - r.timestamp < oneHour
);
if (recentRequests.length === 0) return;
const metrics = {
timestamp: now,
totalRequests: recentRequests.length,
successfulRequests: recentRequests.filter(r => r.success).length,
failedRequests: recentRequests.filter(r => !r.success).length,
avgResponseTime: this.calculateAverage(
recentRequests.map(r => r.responseTime)
),
totalCost: recentRequests.reduce((sum, r) => sum + r.cost, 0),
totalTokens: recentRequests.reduce((sum, r) => sum + r.tokens, 0),
errorRate: recentRequests.filter(r => !r.success).length / recentRequests.length,
throughput: recentRequests.length / (oneHour / 1000), // 请求/秒
providerBreakdown: this.getProviderBreakdown(recentRequests)
};
this.metrics.throughput.push({
timestamp: now,
value: metrics.throughput
});
this.emit('metricsCollected', metrics);
console.log(`\n📊 性能指标 (过去1小时):`);
console.log(`总请求: ${metrics.totalRequests}`);
console.log(`成功率: ${((1 - metrics.errorRate) * 100).toFixed(2)}%`);
console.log(`平均响应时间: ${metrics.avgResponseTime.toFixed(0)}ms`);
console.log(`总成本: $${metrics.totalCost.toFixed(4)}`);
console.log(`吞吐量: ${metrics.throughput.toFixed(2)} 请求/秒`);
return metrics;
}
checkAlerts() {
const now = Date.now();
const oneHour = 60 * 60 * 1000;
const recentRequests = this.metrics.requests.filter(
r => now - r.timestamp < oneHour
);
if (recentRequests.length === 0) return;
const currentMetrics = {
avgResponseTime: this.calculateAverage(
recentRequests.map(r => r.responseTime)
),
errorRate: recentRequests.filter(r => !r.success).length / recentRequests.length,
costPerHour: recentRequests.reduce((sum, r) => sum + r.cost, 0)
};
// 检查响应时间告警
if (currentMetrics.avgResponseTime > this.options.alertThresholds.responseTime) {
this.triggerAlert('HIGH_RESPONSE_TIME', {
current: currentMetrics.avgResponseTime,
threshold: this.options.alertThresholds.responseTime,
message: `平均响应时间过高: ${currentMetrics.avgResponseTime.toFixed(0)}ms`
});
}
// 检查错误率告警
if (currentMetrics.errorRate > this.options.alertThresholds.errorRate) {
this.triggerAlert('HIGH_ERROR_RATE', {
current: currentMetrics.errorRate,
threshold: this.options.alertThresholds.errorRate,
message: `错误率过高: ${(currentMetrics.errorRate * 100).toFixed(2)}%`
});
}
// 检查成本告警
if (currentMetrics.costPerHour > this.options.alertThresholds.costPerHour) {
this.triggerAlert('HIGH_COST', {
current: currentMetrics.costPerHour,
threshold: this.options.alertThresholds.costPerHour,
message: `每小时成本过高: $${currentMetrics.costPerHour.toFixed(4)}`
});
}
}
triggerAlert(type, data) {
const alert = {
id: crypto.randomUUID(),
type,
timestamp: Date.now(),
data,
acknowledged: false
};
this.alerts.push(alert);
console.log(`\n🚨 告警触发: ${type}`);
console.log(`详情: ${data.message}`);
console.log(`当前值: ${data.current}`);
console.log(`阈值: ${data.threshold}`);
this.emit('alert', alert);
// 可以在这里添加邮件、短信等通知逻辑
this.sendNotification(alert);
}
sendNotification(alert) {
// 这里可以集成邮件、Slack、钉钉等通知服务
console.log(`📧 发送告警通知: ${alert.type}`);
}
acknowledgeAlert(alertId) {
const alert = this.alerts.find(a => a.id === alertId);
if (alert) {
alert.acknowledged = true;
alert.acknowledgedAt = Date.now();
console.log(`✅ 告警已确认: ${alert.type}`);
}
}
getProviderBreakdown(requests) {
const breakdown = {};
requests.forEach(request => {
if (!breakdown[request.provider]) {
breakdown[request.provider] = {
requests: 0,
successes: 0,
errors: 0,
totalCost: 0,
avgResponseTime: 0,
responseTimes: []
};
}
const provider = breakdown[request.provider];
provider.requests++;
if (request.success) {
provider.successes++;
} else {
provider.errors++;
}
provider.totalCost += request.cost;
provider.responseTimes.push(request.responseTime);
});
// 计算平均响应时间
Object.values(breakdown).forEach(provider => {
provider.avgResponseTime = this.calculateAverage(provider.responseTimes);
provider.successRate = provider.successes / provider.requests;
delete provider.responseTimes; // 清理临时数据
});
return breakdown;
}
calculateAverage(numbers) {
if (numbers.length === 0) return 0;
return numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
}
calculatePercentile(numbers, percentile) {
if (numbers.length === 0) return 0;
const sorted = numbers.slice().sort((a, b) => a - b);
const index = Math.ceil((percentile / 100) * sorted.length) - 1;
return sorted[index];
}
generateReport(timeRange = '1h') {
const now = Date.now();
const ranges = {
'1h': 60 * 60 * 1000,
'24h': 24 * 60 * 60 * 1000,
'7d': 7 * 24 * 60 * 60 * 1000
};
const range = ranges[timeRange] || ranges['1h'];
const requests = this.metrics.requests.filter(
r => now - r.timestamp < range
);
if (requests.length === 0) {
return { error: '指定时间范围内无数据' };
}
const responseTimes = requests.map(r => r.responseTime);
const costs = requests.map(r => r.cost);
const report = {
timeRange,
generatedAt: new Date().toISOString(),
summary: {
totalRequests: requests.length,
successfulRequests: requests.filter(r => r.success).length,
failedRequests: requests.filter(r => !r.success).length,
successRate: (requests.filter(r => r.success).length / requests.length * 100).toFixed(2) + '%',
totalCost: costs.reduce((sum, cost) => sum + cost, 0),
avgCostPerRequest: this.calculateAverage(costs)
},
performance: {
avgResponseTime: this.calculateAverage(responseTimes),
p50ResponseTime: this.calculatePercentile(responseTimes, 50),
p95ResponseTime: this.calculatePercentile(responseTimes, 95),
p99ResponseTime: this.calculatePercentile(responseTimes, 99),
maxResponseTime: Math.max(...responseTimes),
minResponseTime: Math.min(...responseTimes)
},
providers: this.getProviderBreakdown(requests),
errors: this.getErrorBreakdown(requests.filter(r => !r.success)),
alerts: this.alerts.filter(a => now - a.timestamp < range)
};
return report;
}
getErrorBreakdown(errorRequests) {
const breakdown = {};
errorRequests.forEach(request => {
const errorType = request.error || 'Unknown Error';
if (!breakdown[errorType]) {
breakdown[errorType] = {
count: 0,
providers: {},
firstOccurrence: request.timestamp,
lastOccurrence: request.timestamp
};
}
breakdown[errorType].count++;
breakdown[errorType].lastOccurrence = Math.max(
breakdown[errorType].lastOccurrence,
request.timestamp
);
if (!breakdown[errorType].providers[request.provider]) {
breakdown[errorType].providers[request.provider] = 0;
}
breakdown[errorType].providers[request.provider]++;
});
return breakdown;
}
exportReport(timeRange = '24h', format = 'json') {
const report = this.generateReport(timeRange);
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const filename = `api_performance_report_${timeRange}_${timestamp}.${format}`;
if (format === 'json') {
fs.writeFileSync(filename, JSON.stringify(report, null, 2));
} else if (format === 'csv') {
// 实现CSV导出逻辑
const csv = this.convertToCSV(report);
fs.writeFileSync(filename, csv);
}
console.log(`📊 性能报告已导出: ${filename}`);
return filename;
}
convertToCSV(report) {
// 简单的CSV转换实现
const lines = [];
lines.push('Metric,Value');
lines.push(`Total Requests,${report.summary.totalRequests}`);
lines.push(`Success Rate,${report.summary.successRate}`);
lines.push(`Total Cost,$${report.summary.totalCost.toFixed(4)}`);
lines.push(`Avg Response Time,${report.performance.avgResponseTime.toFixed(0)}ms`);
return lines.join('\n');
}
cleanupOldData() {
const cutoff = Date.now() - this.options.retentionPeriod;
['requests', 'errors', 'costs', 'responseTime', 'throughput'].forEach(metric => {
const originalLength = this.metrics[metric].length;
this.metrics[metric] = this.metrics[metric].filter(
item => item.timestamp > cutoff
);
const cleaned = originalLength - this.metrics[metric].length;
if (cleaned > 0) {
console.log(`🧹 清理了 ${cleaned} 条 ${metric} 历史数据`);
}
});
//