硅基流动API中转服务实战:如何用FastAPI添加监控和缓存功能

硅基流动API中转服务实战:如何用FastAPI添加监控和缓存功能

在构建面向生产环境的AI应用时,一个稳定、高效且可观测的API服务层往往是决定项目成败的关键。许多开发者在使用硅基流动这类大模型服务时,会直接调用其官方SDK,这在原型验证阶段无可厚非。然而,当应用规模扩大,面临复杂的流量管理、成本控制、性能优化和故障排查需求时,一个简单的客户端调用就显得捉襟见肘了。这时,一个自定义的API中转服务就成了架构中的“瑞士军刀”。

这个中转服务不仅仅是请求的“二传手”。它的核心价值在于,在你和上游AI服务商之间,建立了一个完全可控的中间层。你可以在这里植入业务逻辑,比如统一的鉴权、请求的审计与计费、响应内容的过滤与格式化。更重要的是,你可以深度集成监控缓存这两大生产级系统的支柱功能。监控让你对服务的健康状态、性能瓶颈和异常情况了如指掌;缓存则能直接降低延迟、节省成本,并提升系统在高并发下的韧性。

本文面向的是已经熟悉FastAPI基础,并希望将服务推向更高可用性、可维护性阶段的中级开发者。我们将抛开简单的代理转发,聚焦于如何为你的硅基流动API中转服务,系统地注入监控与缓存能力。我会分享从日志结构化、指标收集到多级缓存策略的实战代码与设计思路,这些方案都经过真实项目的检验,你可以直接借鉴并应用到自己的系统中。

1. 构建可观测的监控体系:从日志到指标

一个没有监控的服务,就像在黑夜中驾驶没有仪表的汽车。对于API中转服务,监控的首要目标是清晰地回答:谁、在什么时候、调用了什么、结果如何、花了多长时间。我们将从基础的日志增强开始,逐步构建一个完整的监控仪表盘。

1.1 结构化日志与请求追踪

FastAPI默认的访问日志信息有限。我们需要一个中间件来捕获每个请求的完整上下文。关键在于为每个请求生成一个唯一的追踪ID(request_id),并将其贯穿整个请求生命周期,包括对上游硅基流动服务的调用。

首先,安装必要的依赖:

pip install python-json-logger httpx

接下来,我们创建一个增强的日志配置和追踪中间件。在 app.py 或新建的 middleware.py 中:

import logging
import uuid
import time
from contextvars import ContextVar
from typing import Callable
import json_log_formatter
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware

# 创建用于存储请求上下文的ContextVar
_request_id_ctx_var: ContextVar[str] = ContextVar("request_id", default="")

def get_request_id() -> str:
    """获取当前请求的ID"""
    return _request_id_ctx_var.get()

class StructuredFormatter(json_log_formatter.JSONFormatter):
    """JSON结构化日志格式化器"""
    def json_record(self, message: str, extra: dict, record: logging.LogRecord):
        extra["message"] = message
        extra["level"] = record.levelname
        extra["module"] = record.module
        extra["funcName"] = record.funcName
        
        # 注入请求ID
        request_id = get_request_id()
        if request_id:
            extra["request_id"] = request_id
            
        # 添加时间戳
        extra["timestamp"] = record.created
        return extra

# 配置日志
def setup_logging():
    formatter = StructuredFormatter()
    
    json_handler = logging.StreamHandler()
    json_handler.setFormatter(formatter)
    
    logger = logging.getLogger("api_proxy")
    logger.setLevel(logging.INFO)
    logger.addHandler(json_handler)
    
    # 避免uvicorn等库的日志干扰
    logging.getLogger("uvicorn.access").handlers = []
    logging.getLogger("uvicorn").handlers = []
    
    return logger

logger = setup_logging()

class RequestLoggingMiddleware(BaseHTTPMiddleware):
    """请求日志与追踪中间件"""
    
    async def dispatch(self, request: Request, call_next: Callable) -> Response:
        # 生成或获取请求ID
        request_id = request.headers.get("X-Request-ID", str(uuid.uuid4()))
        _request_id_ctx_var.set(request_id)
        
        # 记录请求开始
        start_time = time.time()
        logger.info("Request started", extra={
            "method": request.method,
            "url": str(request.url),
            "client_host": request.client.host if request.client else None,
            "user_agent": request.headers.get("user-agent"),
            "request_id": request_id
        })
        
        # 处理请求
        response = await call_next(request)
        
        # 计算处理时间
        process_time = time.time() - start_time
        response.headers["X-Request-ID"] = request_id
        response.headers["X-Process-Time"] = str(process_time)
        
        # 记录请求完成
        logger.info("Request completed", extra={
            "method": request.method,
            "url": str(request.url),
            "status_code": response.status_code,
            "process_time_sec": round(process_time, 4),
            "request_id": request_id
        })
        
        return response

将这个中间件添加到你的FastAPI应用中:

from fastapi import FastAPI

app = FastAPI()
app.add_middleware(RequestLoggingMiddleware)

现在,你的日志不再是杂乱的文本行,而是结构化的JSON对象。每一条日志都包含了 request_id,使得你能够轻松地将分散的日志条目串联成一个完整的请求故事线。这种格式非常适合被日志收集系统(如ELK Stack、Loki)摄取和分析。

1.2 关键性能指标(KPM)收集

除了日志,我们还需要量化的指标来评估系统健康度。我们将使用 prometheus-client 来暴露符合Prometheus格式的指标。这些指标可以被Prometheus抓取,并在Grafana中可视化。

安装依赖:

pip install prometheus-client

创建一个 metrics.py 文件来定义和收集指标:

from prometheus_client import Counter, Histogram, Gauge, generate_latest, REGISTRY
from typing import Optional

# 定义指标
REQUEST_COUNT = Counter(
    'api_proxy_requests_total',
    'Total number of API requests',
    ['method', 'endpoint', 'status_code']
)

REQUEST_LATENCY = Histogram(
    'api_proxy_request_duration_seconds',
    'Request latency in seconds',
    ['method', 'endpoint'],
    buckets=(0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0)
)

UPSTREAM_LATENCY = Histogram(
    'api_proxy_upstream_duration_seconds',
    'Upstream (SiliconFlow) API latency in seconds',
    ['upstream_service', 'model'],
    buckets=(0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 30.0)
)

ACTIVE_REQUESTS = Gauge(
    'api_proxy_requests_in_progress',
    'Number of requests currently being processed',
    ['endpoint']
)

TOKEN_USAGE = Counter(
    'api_proxy_tokens_total',
    'Total tokens consumed',
    ['model', 'type']  # type: 'prompt' or 'completion'
)

# 指标收集工具类
class MetricsCollector:
    @staticmethod
    def record_request(method: str, endpoint: str, status_code: int, duration: float):
        """记录一次请求"""
        REQUEST_COUNT.labels(method=method, endpoint=endpoint, status_code=str(status_code)).inc()
        REQUEST_LATENCY.labels(method=method, endpoint=endpoint).observe(duration)
    
    @staticmethod
    def record_upstream_call(service: str, model: str, duration: float):
        """记录一次上游API调用"""
        UPSTREAM_LATENCY.labels(upstream_service=service, model=model).observe(duration)
    
    @staticmethod
    def record_token_usage(model: str, token_type: str, count: int):
        """记录Token使用量"""
        TOKEN_USAGE.labels(model=model, type=token_type).inc(count)
    
    @staticmethod
    def track_active_request(endpoint: str):
        """追踪活跃请求(用于上下文管理器)"""
        return ActiveRequestTracker(endpoint)

class ActiveRequestTracker:
    def __init__(self, endpoint: str):
        self.endpoint = endpoint
        ACTIVE_REQUESTS.labels(endpoint=endpoint).inc()
    
    def __enter__(self):
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        ACTIVE_REQUESTS.label
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值