本节将系统讲解企业级大模型API接入系统的完整构建过程,从架构设计到实际部署,帮助读者掌握从零开始搭建稳定、高效、安全的企业级API接入能力。
企业级API接入系统是一个复杂的分布式系统,需要处理高并发、保证稳定性、确保安全性,同时提供完善的监控和管理能力。其核心架构通常包括:
首先构建API网关作为系统的统一入口点:
# api_gateway.py from fastapi import FastAPI, HTTPException, Depends, Request from fastapi.security import APIKeyHeader from fastapi.middleware.cors import CORSMiddleware from typing import Optional, Dict, Any import time import hashlib import redis import logging from prometheus_client import Counter, Histogram, generate_latest import uvicorn app = FastAPI(title="企业级API网关") # 中间件配置 app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Redis连接 redis_client = redis.Redis(host='localhost', port=6379, db=0) # Prometheus监控 REQUEST_COUNT = Counter('api_requests_total', 'Total API requests', ['method', 'endpoint']) REQUEST_DURATION = Histogram('api_request_duration_seconds', 'API request duration') # API密钥验证 API_KEY_HEADER = APIKeyHeader(name="X-API-Key", auto_error=False) async def get_api_key(api_key: Optional[str] = Depends(API_KEY_HEADER)) -> str: if api_key is None: raise HTTPException(status_code=403, detail="API密钥缺失") # 验证API密钥 if not await validate_api_key(api_key): raise HTTPException(status_code=403, detail="无效的API密钥") return api_key async def validate_api_key(api_key: str) -> bool: # 检查API密钥是否存在且有效 key_hash = hashlib.sha256(api_key.encode()).hexdigest() stored_key = redis_client.get(f"api_key:{key_hash}") if stored_key: key_data = eval(stored_key.decode()) if key_data['active'] and key_data['expires'] > time.time(): return True return False # 限流装饰器 def rate_limit(limit: int, window: int): def decorator(func): async def wrapper(*args, **kwargs): api_key = kwargs.get('api_key') or args[0] if args else None if api_key: key_hash = hashlib.sha256(api_key.encode()).hexdigest() current = redis_client.get(f"rate_limit:{key_hash}") if current is None: redis_client.setex(f"rate_limit:{key_hash}", window, 1) return await func(*args, **kwargs) elif int(current.decode()) < limit: redis_client.incr(f"rate_limit:{key_hash}") return await func(*args, **kwargs) else: raise HTTPException(status_code=429, detail="请求过于频繁") return await func(*args, **kwargs) return wrapper return decorator # API端点 @app.post("/api/chat") @REQUEST_COUNT.count() @REQUEST_DURATION.time() @rate_limit(limit=100, window=60) # 每分钟最多100次请求 async def chat_completion( request: Dict[str, Any], api_key: str = Depends(get_api_key) ): """ 聊天完成API端点 """ start_time = time.time() try: # 验证请求数据格式 if 'messages' not in request: raise HTTPException(status_code=400, detail="缺少messages字段") # 调用大模型API response = await call_large_language_model(request) # 记录请求日志 await log_request(api_key, request, response) return response except Exception as e: # 错误处理 error_response = { "error": str(e), "timestamp": time.time(), "api_key": api_key[:8] + "*" * 8 # 脱敏处理 } # 记录错误日志 await log_error(api_key, str(e)) raise HTTPException(status_code=500, detail="服务器内部错误") async def call_large_language_model(request: Dict[str, Any]) -> Dict[str, Any]: """ 调用大模型API """ # 这里集成具体的大模型API,如OpenAI、Azure OpenAI、百度文心等 # 示例代码结构,实际需要根据具体API调整 # 模拟API调用 import time time.sleep(0.1) # 模拟网络延迟 return { "id": f"chat-{int(time.time())}", "object": "chat.completion", "created": int(time.time()), "model": "gpt-4", "choices": [ { "index": 0, "message": { "role": "assistant", "content": f"这是对用户问题的回复:{request['messages'][-1]['content'][:100]}..." }, "finish_reason": "stop" } ] } async def log_request(api_key: str, request: Dict[str, Any], response: Dict[str, Any]): """ 记录请求日志 """ log_data = { "timestamp": time.time(), "api_key": api_key[:8] + "*" * 8, "request": str(request)[:200], # 截取前200字符 "response": str(response)[:200], "status": "success" } # 存储到Redis redis_client.lpush("api_logs", str(log_data)) redis_client.ltrim("api_logs", 0, 9999) # 保留最新10000条日志 async def log_error(api_key: str, error: str): """ 记录错误日志 """ error_data = { "timestamp": time.time(), "api_key": api_key[:8] + "*" * 8, "error": error, "status": "error" } redis_client.lpush("error_logs", str(error_data)) redis_client.ltrim("error_logs", 0, 9999) @app.get("/health") async def health_check(): """健康检查端点""" return {"status": "healthy", "timestamp": time.time()} @app.get("/metrics") async def metrics(): """监控指标端点""" return generate_latest() if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000, workers=4)
创建统一的SDK,简化客户端调用:
# llm_client_sdk.py import asyncio import aiohttp import time from typing import Dict, List, Optional, Any, Union import json import hashlib from dataclasses import dataclass from enum import Enum @dataclass class LLMConfig: """大模型配置类""" api_endpoint: str api_key: str model_name: str = "gpt-4" timeout: int = 30 max_retries: int = 3 retry_delay: float = 1.0 @dataclass class Message: """消息数据类""" role: str content: str name: Optional[str] = None @dataclass class ChatCompletionRequest: """聊天完成请求类""" messages: List[Message] model: str = "gpt-4" temperature: float = 0.7 max_tokens: Optional[int] = None top_p: float = 1.0 frequency_penalty: float = 0.0 presence_penalty: float = 0.0 @dataclass class ChatCompletionResponse: """聊天完成响应类""" id: str object: str created: int model: str choices: List[Dict] usage: Dict[str, int] class LLMClient: """大模型客户端""" def __init__(self, config: LLMConfig): self.config = config self.session = None self.request_stats = { "total_requests": 0, "successful_requests": 0, "failed_requests": 0, "total_tokens": 0, "total_time": 0.0 } async def __aenter__(self): self.session = aiohttp.ClientSession() return self async def __aexit__(self, exc_type, exc_val, exc_tb): if self.session: await self.session.close() async def chat_completion( self, messages: List[Union[Message, Dict]], **kwargs ) -> ChatCompletionResponse: """ 聊天完成API Args: messages: 消息列表,可以是Message对象或字典 **kwargs: 其他参数 Returns: ChatCompletionResponse: 聊天完成响应 """ start_time = time.time() # 转换消息格式 processed_messages = [] for msg in messages: if isinstance(msg, dict): processed_messages.append(Message(**msg)) else: processed_messages.append(msg) # 构建请求 request = ChatCompletionRequest( messages=processed_messages, model=kwargs.get('model', self.config.model_name), temperature=kwargs.get('temperature', 0.7), max_tokens=kwargs.get('max_tokens'), top_p=kwargs.get('top_p', 1.0), frequency_penalty=kwargs.get('frequency_penalty', 0.0), presence_penalty=kwargs.get('presence_penalty', 0.0) ) # 执行请求 response = await self._make_request(request) # 更新统计信息 self.request_stats["total_requests"] += 1 self.request_stats["total_time"] += time.time() - start_time self.request_stats["total_tokens"] += response.usage.get("total_tokens", 0) return response async def _make_request(self, request: ChatCompletionRequest) -> ChatCompletionResponse: """ 发送HTTP请求 """ headers = { "Authorization": f"Bearer {self.config.api_key}", "Content-Type": "application/json" } data = { "model": request.model, "messages": [{"role": msg.role, "content": msg.content} for msg in request.messages], "temperature": request.temperature, "top_p": request.top_p, "frequency_penalty": request.frequency_penalty, "presence_penalty": request.presence_penalty } if request.max_tokens: data["max_tokens"] = request.max_tokens # 重试机制 for attempt in range(self.config.max_retries): try: async with self.session.post( f"{self.config.api_endpoint}/chat/completions", headers=headers, json=data, timeout=aiohttp.ClientTimeout(total=self.config.timeout) ) as response: if response.status == 200: response_data = await response.json() self.request_stats["successful_requests"] += 1 return ChatCompletionResponse( id=response_data["id"], object=response_data["object"], created=response_data["created"], model=response_data["model"], choices=response_data["choices"], usage=response_data.get("usage", {}) ) else: error_text = await response.text() if attempt == self.config.max_retries - 1: raise Exception(f"API请求失败: {response.status} - {error_text}") await asyncio.sleep(self.config.retry_delay * (2 ** attempt)) except Exception as e: if attempt == self.config.max_retries - 1: self.request_stats["failed_requests"] += 1 raise await asyncio.sleep(self.config.retry_delay * (2 ** attempt)) def get_stats(self) -> Dict[str, Any]: """ 获取请求统计信息 """ stats = self.request_stats.copy() if stats["total_requests"] > 0: stats["success_rate"] = stats["successful_requests"] / stats["total_requests"] stats["avg_time_per_request"] = stats["total_time"] / stats["total_requests"] stats["avg_tokens_per_request"] = stats["total_tokens"] / stats["total_requests"] return stats # 使用示例 async def example_usage(): """SDK使用示例""" config = LLMConfig( api_endpoint="https://api.openai.com/v1", api_key="your-api-key-here" ) async with LLMClient(config) as client: # 准备消息 messages = [ {"role": "system", "content": "你是一个专业的助手"}, {"role": "user", "content": "什么是机器学习?"} ] try: # 调用API response = await client.chat_completion(messages) print(f"响应ID: {response.id}") print(f"模型: {response.model}") print(f"回复: {response.choices[0]['message']['content']}") print(f"Token使用: {response.usage}") # 获取统计信息 stats = client.get_stats() print(f"请求统计: {stats}") except Exception as e: print(f"请求失败: {e}") if __name__ == "__main__": asyncio.run(example_usage())
构建完整的监控和日志系统:
# monitoring_system.py import asyncio import time import json import logging from typing import Dict, Any, Optional from dataclasses import dataclass from collections import defaultdict, deque import aiohttp import redis from prometheus_client import Counter, Histogram, Gauge, generate_latest @dataclass class MetricData: """指标数据类""" name: str value: float labels: Dict[str, str] timestamp: float class APIMonitor: """API监控系统""" def __init__(self, redis_host: str = "localhost", redis_port: int = 6379):