API集成最佳实践:专业的接入之道
正确的API集成方式不仅能提升应用性能,还能降低成本、提高可靠性。 本指南将分享经过实践验证的集成模式和技巧。
集成架构设计
分层架构模式
// 1. API抽象层
interface LLMProvider {
chat(messages: Message[]): Promise<Response>;
complete(prompt: string): Promise<string>;
embed(text: string): Promise<number[]>;
}
// 2. 提供商实现
class OpenAIProvider implements LLMProvider {
private client: OpenAI;
private config: ProviderConfig;
constructor(config: ProviderConfig) {
this.config = config;
this.client = new OpenAI({
apiKey: config.apiKey,
maxRetries: config.maxRetries || 3,
});
}
async chat(messages: Message[]): Promise<Response> {
try {
const response = await this.client.chat.completions.create({
model: this.config.model || 'gpt-3.5-turbo',
messages: messages,
temperature: this.config.temperature || 0.7,
stream: this.config.stream || false,
});
return this.formatResponse(response);
} catch (error) {
throw this.handleError(error);
}
}
private handleError(error: any): Error {
if (error.status === 429) {
return new RateLimitError('Rate limit exceeded', error);
}
if (error.status === 401) {
return new AuthenticationError('Invalid API key', error);
}
return new APIError('API request failed', error);
}
}
// 3. 服务层
class LLMService {
private providers: Map<string, LLMProvider>;
private cache: CacheManager;
private metrics: MetricsCollector;
constructor() {
this.providers = new Map();
this.cache = new CacheManager();
this.metrics = new MetricsCollector();
}
addProvider(name: string, provider: LLMProvider) {
this.providers.set(name, provider);
}
async chat(
providerName: string,
messages: Message[],
options?: ChatOptions
): Promise<Response> {
const provider = this.providers.get(providerName);
if (!provider) {
throw new Error(`Provider ${providerName} not found`);
}
// 缓存检查
const cacheKey = this.generateCacheKey(messages);
const cached = await this.cache.get(cacheKey);
if (cached && options?.useCache) {
this.metrics.recordCacheHit();
return cached;
}
// 调用API
const startTime = Date.now();
try {
const response = await provider.chat(messages);
// 记录指标
this.metrics.recordLatency(Date.now() - startTime);
this.metrics.recordTokenUsage(response.usage);
// 缓存结果
if (options?.useCache) {
await this.cache.set(cacheKey, response, options.cacheTTL);
}
return response;
} catch (error) {
this.metrics.recordError(error);
throw error;
}
}
}错误处理策略
健壮的错误处理
错误分类处理
class ErrorHandler {
static handle(error: any): ErrorResponse {
// 1. API错误
if (error.response) {
switch (error.response.status) {
case 429:
return {
retry: true,
delay: this.getRetryDelay(error),
message: 'Rate limited'
};
case 401:
return {
retry: false,
message: 'Authentication failed'
};
case 500:
case 502:
case 503:
return {
retry: true,
delay: 1000,
message: 'Server error'
};
}
}
// 2. 网络错误
if (error.code === 'ECONNREFUSED') {
return {
retry: true,
delay: 5000,
message: 'Connection failed'
};
}
// 3. 超时错误
if (error.code === 'ETIMEDOUT') {
return {
retry: true,
delay: 2000,
message: 'Request timeout'
};
}
// 默认处理
return {
retry: false,
message: error.message
};
}
static getRetryDelay(error: any): number {
// 从响应头获取重试时间
const retryAfter =
error.response?.headers['retry-after'];
if (retryAfter) {
return parseInt(retryAfter) * 1000;
}
// 指数退避
const attempt = error.attempt || 1;
return Math.min(
Math.pow(2, attempt) * 1000,
30000
);
}
}智能重试机制
class RetryManager {
async execute<T>(
operation: () => Promise<T>,
options: RetryOptions = {}
): Promise<T> {
const {
maxAttempts = 3,
initialDelay = 1000,
maxDelay = 30000,
factor = 2,
jitter = true
} = options;
let lastError: any;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await operation();
} catch (error: any) {
lastError = error;
error.attempt = attempt;
const errorResponse =
ErrorHandler.handle(error);
if (!errorResponse.retry ||
attempt === maxAttempts) {
throw error;
}
// 计算延迟
let delay = errorResponse.delay ||
Math.min(
initialDelay * Math.pow(factor, attempt - 1),
maxDelay
);
// 添加抖动
if (jitter) {
delay *= 0.5 + Math.random();
}
console.log(
`Retry ${attempt}/${maxAttempts} after ${delay}ms`
);
await this.sleep(delay);
}
}
throw lastError;
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve =>
setTimeout(resolve, ms)
);
}
}流式响应处理
高效的流处理
// 流式响应处理器
class StreamHandler {
async *handleStream(
stream: ReadableStream,
options: StreamOptions = {}
): AsyncGenerator<StreamChunk> {
const reader = stream.getReader();
const decoder = new TextDecoder();
let buffer = '';
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
// 处理剩余数据
if (buffer) {
yield this.parseChunk(buffer);
}
break;
}
// 解码数据
buffer += decoder.decode(value, { stream: true });
// 按行分割
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (line.trim() === '') continue;
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') {
return;
}
try {
const chunk = JSON.parse(data);
// 处理数据
const processed = await this.processChunk(chunk);
// 发送处理后的数据
yield processed;
// 回调处理
if (options.onChunk) {
options.onChunk(processed);
}
} catch (error) {
console.error('Failed to parse chunk:', error);
if (options.onError) {
options.onError(error);
}
}
}
}
}
} finally {
reader.releaseLock();
}
}
private processChunk(chunk: any): StreamChunk {
return {
id: chunk.id,
content: chunk.choices?.[0]?.delta?.content || '',
role: chunk.choices?.[0]?.delta?.role,
finishReason: chunk.choices?.[0]?.finish_reason,
usage: chunk.usage
};
}
// 流聚合器
async aggregateStream(
stream: AsyncGenerator<StreamChunk>
): Promise<CompleteResponse> {
let content = '';
let role = '';
let usage = null;
for await (const chunk of stream) {
if (chunk.content) {
content += chunk.content;
}
if (chunk.role) {
role = chunk.role;
}
if (chunk.usage) {
usage = chunk.usage;
}
}
return {
content,
role,
usage
};
}
}
// 使用示例
const streamHandler = new StreamHandler();
// React组件中使用
function ChatComponent() {
const [response, setResponse] = useState('');
const handleStream = async (prompt: string) => {
const stream = await api.createChatStream(prompt);
for await (const chunk of streamHandler.handleStream(stream, {
onChunk: (chunk) => {
setResponse(prev => prev + chunk.content);
},
onError: (error) => {
console.error('Stream error:', error);
}
})) {
// 可以在这里做额外处理
}
};
}性能优化技巧
提升API调用性能
🚀 连接池优化
// HTTP Agent配置
const https = require('https');
const http = require('http');
const httpsAgent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000,
scheduling: 'lifo'
});
const httpAgent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 1000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 60000
});
// Axios配置
const apiClient = axios.create({
httpsAgent,
httpAgent,
timeout: 30000,
maxRedirects: 0,
decompress: true,
responseType: 'stream'
});
// 请求拦截器
apiClient.interceptors.request.use(
config => {
config.headers['Connection'] = 'keep-alive';
config.headers['Accept-Encoding'] = 'gzip, deflate';
return config;
}
);💾 智能缓存策略
class SmartCache {
private cache: Map<string, CacheEntry>;
private lru: string[];
private maxSize: number;
constructor(maxSize = 1000) {
this.cache = new Map();
this.lru = [];
this.maxSize = maxSize;
}
async get(
key: string,
factory: () => Promise<any>,
options: CacheOptions = {}
): Promise<any> {
// 检查缓存
const entry = this.cache.get(key);
if (entry && !this.isExpired(entry)) {
this.updateLRU(key);
return entry.value;
}
// 生成新值
const value = await factory();
// 存储到缓存
this.set(key, value, options.ttl || 3600000);
return value;
}
private set(key: string, value: any, ttl: number) {
// 检查容量
if (this.cache.size >= this.maxSize) {
this.evict();
}
this.cache.set(key, {
value,
expiry: Date.now() + ttl
});
this.updateLRU(key);
}
private evict() {
// LRU淘汰
const leastUsed = this.lru.shift();
if (leastUsed) {
this.cache.delete(leastUsed);
}
}
private updateLRU(key: string) {
const index = this.lru.indexOf(key);
if (index > -1) {
this.lru.splice(index, 1);
}
this.lru.push(key);
}
private isExpired(entry: CacheEntry): boolean {
return Date.now() > entry.expiry;
}
}成本控制策略
精细化成本管理
Token优化
class TokenOptimizer {
// 压缩Prompt
compressPrompt(text: string): string {
return text
// 移除多余空白
.replace(/\s+/g, ' ')
// 移除重复标点
.replace(/([.!?])\1+/g, '$1')
// 精简格式
.trim();
}
// 智能截断
truncateToLimit(
text: string,
maxTokens: number,
model: string = 'gpt-3.5-turbo'
): string {
const encoder = this.getEncoder(model);
const tokens = encoder.encode(text);
if (tokens.length <= maxTokens) {
return text;
}
// 保留重要部分
const importance = this.calculateImportance(text);
const truncated = this.smartTruncate(
text,
maxTokens,
importance
);
return truncated;
}
// 批量优化
optimizeBatch(messages: Message[]): Message[] {
// 去重
const unique = this.deduplicateMessages(messages);
// 合并相似
const merged = this.mergeSimilar(unique);
// 压缩内容
return merged.map(msg => ({
...msg,
content: this.compressPrompt(msg.content)
}));
}
}使用量监控
class UsageMonitor {
private usage: Map<string, UserUsage>;
private limits: Map<string, UsageLimit>;
async trackUsage(
userId: string,
tokens: number,
cost: number
): Promise<void> {
const usage = this.getOrCreateUsage(userId);
// 更新使用量
usage.tokens += tokens;
usage.cost += cost;
usage.requests += 1;
// 检查限制
await this.checkLimits(userId, usage);
// 发送告警
if (usage.cost > usage.budget * 0.8) {
await this.sendBudgetAlert(userId, usage);
}
}
async checkLimits(
userId: string,
usage: UserUsage
): Promise<void> {
const limits = this.limits.get(userId);
if (!limits) return;
if (usage.tokens > limits.maxTokens) {
throw new Error('Token limit exceeded');
}
if (usage.cost > limits.maxCost) {
throw new Error('Cost limit exceeded');
}
if (usage.requests > limits.maxRequests) {
throw new Error('Request limit exceeded');
}
}
generateReport(userId: string): UsageReport {
const usage = this.usage.get(userId);
if (!usage) return null;
return {
period: this.getCurrentPeriod(),
totalTokens: usage.tokens,
totalCost: usage.cost,
totalRequests: usage.requests,
avgTokensPerRequest: usage.tokens / usage.requests,
avgCostPerRequest: usage.cost / usage.requests,
topModels: this.getTopModels(usage),
recommendations: this.getRecommendations(usage)
};
}
}安全最佳实践
API安全防护
🔐 密钥管理
// 安全的密钥管理
class SecureKeyManager {
private keys: Map<string, EncryptedKey>;
private vault: KeyVault;
constructor() {
this.keys = new Map();
this.vault = new KeyVault(process.env.VAULT_URL);
}
async getKey(keyName: string): Promise<string> {
// 1. 检查内存缓存
const cached = this.keys.get(keyName);
if (cached && !this.isExpired(cached)) {
return this.decrypt(cached);
}
// 2. 从密钥库获取
const key = await this.vault.getSecret(keyName);
// 3. 缓存加密的密钥
this.keys.set(keyName, {
value: this.encrypt(key),
expiry: Date.now() + 3600000 // 1小时
});
return key;
}
// 密钥轮换
async rotateKey(keyName: string): Promise<void> {
// 生成新密钥
const newKey = this.generateKey();
// 更新密钥库
await this.vault.updateSecret(keyName, newKey);
// 清除缓存
this.keys.delete(keyName);
// 通知相关服务
await this.notifyKeyRotation(keyName);
}
// 审计日志
async logKeyAccess(keyName: string, userId: string) {
await this.vault.audit({
action: 'KEY_ACCESS',
keyName,
userId,
timestamp: new Date(),
ip: this.getClientIP()
});
}
}🛡️ 输入验证
class InputValidator {
static validateChatInput(input: ChatInput): void {
// 1. 长度检查
if (input.message.length > 4000) {
throw new ValidationError('Message too long');
}
// 2. 内容过滤
if (this.containsMalicious(input.message)) {
throw new ValidationError('Malicious content detected');
}
// 3. 注入检测
if (this.detectInjection(input.message)) {
throw new ValidationError('Injection attempt detected');
}
// 4. 编码检查
if (!this.isValidUTF8(input.message)) {
throw new ValidationError('Invalid encoding');
}
}
private static containsMalicious(text: string): boolean {
const patterns = [
/system\s*:/i,
/ignore\s+previous/i,
/<script[^>]*>/i,
/\x00/
];
return patterns.some(pattern => pattern.test(text));
}
private static detectInjection(text: string): boolean {
// Prompt注入检测
const injectionPatterns = [
'forget all previous',
'disregard instructions',
'new system prompt'
];
const lowercased = text.toLowerCase();
return injectionPatterns.some(pattern =>
lowercased.includes(pattern)
);
}
}监控与可观测性
全方位监控体系
// 集成监控系统
class ObservabilitySystem {
private metrics: MetricsClient;
private traces: TracingClient;
private logs: LoggingClient;
constructor() {
this.metrics = new PrometheusClient();
this.traces = new JaegerClient();
this.logs = new ElasticsearchClient();
}
// 请求追踪
async traceRequest(
operation: string,
fn: () => Promise<any>
): Promise<any> {
const span = this.traces.startSpan(operation);
const requestId = generateRequestId();
try {
// 设置追踪上下文
span.setTag('request.id', requestId);
span.setTag('user.id', getCurrentUserId());
// 记录开始
this.logs.info('Request started', {
requestId,
operation,
timestamp: new Date()
});
// 执行操作
const startTime = Date.now();
const result = await fn();
const duration = Date.now() - startTime;
// 记录指标
this.metrics.histogram('api_request_duration', duration, {
operation,
status: 'success'
});
// 记录成功
span.setTag('response.status', 'success');
span.finish();
return result;
} catch (error) {
// 记录错误
span.setTag('error', true);
span.log({
event: 'error',
message: error.message,
stack: error.stack
});
// 错误指标
this.metrics.increment('api_request_errors', {
operation,
error_type: error.constructor.name
});
// 错误日志
this.logs.error('Request failed', {
requestId,
operation,
error: {
message: error.message,
stack: error.stack
}
});
span.finish();
throw error;
}
}
// 自定义指标
recordCustomMetric(name: string, value: number, tags?: any) {
this.metrics.gauge(name, value, tags);
}
// 健康检查
async healthCheck(): Promise<HealthStatus> {
const checks = await Promise.all([
this.checkAPIHealth(),
this.checkDatabaseHealth(),
this.checkCacheHealth()
]);
const allHealthy = checks.every(c => c.healthy);
return {
status: allHealthy ? 'healthy' : 'unhealthy',
checks,
timestamp: new Date()
};
}
}