AIProviderConfig.md - AI 厂商动态配置架构设计
| 文档类型 |
Technical Design (技术设计文档) |
| 项目名称 |
SmartAudit (AI 营销内容合规审核平台) |
| 版本号 |
V1.0 |
| 日期 |
2026-02-02 |
| 侧重 |
AI 厂商动态配置、多租户隔离、运行时热更新 |
版本历史 (Version History)
| 版本 |
日期 |
作者 |
变更说明 |
| V1.0 |
2026-02-02 |
Claude |
初稿:AI 厂商动态配置架构设计 |
1. 设计背景与目标
1.1 问题陈述
传统方案将 AI 模型的 API Key 和 Base URL 写死在环境变量中,存在以下问题:
- 灵活性差: 切换 AI 厂商需要修改环境变量并重启服务
- 多租户困难: 无法支持不同品牌方使用不同的 AI 厂商
- 安全隐患: 环境变量容易泄露,难以细粒度管理
- 运维成本高: 密钥轮换需要重新部署
1.2 设计目标
实现商业 SaaS 级别的 AI 厂商动态配置系统:
| 目标 |
描述 |
| 动态配置 |
管理员在后台配置 AI 厂商,无需修改代码或重启服务 |
| 多厂商支持 |
支持 DeepSeek、OpenAI、阿里云、OneAPI 中转等多种厂商 |
| 多租户隔离 |
不同品牌方可配置独立的 AI 厂商和配额 |
| 热更新 |
配置变更即时生效,无需重启服务 |
| 安全存储 |
API Key 加密存储,支持密钥轮换 |
| 故障转移 |
主厂商不可用时自动切换到备用厂商 |
2. 系统架构
2.1 架构概览
┌─────────────────────────────────────────────────────────────────────────┐
│ 管理后台 (Admin Portal) │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ AI 厂商配置页面:添加/编辑/删除/测试连通性 │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ API 层 (FastAPI) │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ POST /admin/ai-providers - 创建 AI 厂商配置 │ │
│ │ GET /admin/ai-providers - 获取厂商列表 │ │
│ │ PUT /admin/ai-providers/{id} - 更新配置 │ │
│ │ POST /admin/ai-providers/{id}/test - 测试连通性 │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ AI 客户端工厂 (AIClientFactory) │
│ ┌──────────────────────────────────────────────────────────────────┐ │
│ │ • 根据配置动态创建 AI 客户端实例 │ │
│ │ • 支持连接池和客户端复用 │ │
│ │ • 配置变更时自动刷新客户端 │ │
│ └──────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ DeepSeek │ │ OpenAI │ │ OneAPI │
│ Client │ │ Client │ │ (中转) │
└─────────────┘ └─────────────┘ └─────────────┘
2.2 核心组件
| 组件 |
职责 |
| AIProviderConfig |
数据模型,存储厂商配置 |
| AIClientFactory |
工厂类,根据配置创建客户端 |
| AIClientRegistry |
注册表,缓存和管理客户端实例 |
| ConfigWatcher |
监听配置变更,触发客户端刷新 |
| SecretsManager |
加密存储和解密 API Key |
3. 数据模型设计
3.1 AI 厂商配置表 (ai_provider_configs)
CREATE TABLE ai_provider_configs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- 基础信息
name VARCHAR(100) NOT NULL, -- 配置名称,如 "生产环境 DeepSeek"
provider_type VARCHAR(50) NOT NULL, -- 厂商类型:deepseek/openai/oneapi/aliyun/...
description TEXT, -- 配置说明
-- 连接配置
base_url VARCHAR(500) NOT NULL, -- API Base URL
api_key_encrypted BYTEA NOT NULL, -- 加密后的 API Key
-- 模型配置
default_model VARCHAR(100), -- 默认模型,如 "deepseek-chat"
available_models JSONB DEFAULT '[]', -- 可用模型列表
-- 能力标签
capabilities JSONB DEFAULT '[]', -- 支持的能力:["chat", "vision", "embedding"]
-- 使用场景
use_cases JSONB DEFAULT '[]', -- 适用场景:["brief_parsing", "script_review", "video_audit"]
-- 租户隔离
tenant_id UUID, -- 所属租户(品牌方),NULL 表示全局配置
-- 优先级与状态
priority INT DEFAULT 100, -- 优先级,数字越小优先级越高
is_enabled BOOLEAN DEFAULT true, -- 是否启用
is_default BOOLEAN DEFAULT false, -- 是否为默认配置
-- 限流配置
rate_limit_rpm INT DEFAULT 60, -- 每分钟请求限制
rate_limit_tpm INT DEFAULT 100000, -- 每分钟 Token 限制
-- 故障转移
fallback_provider_id UUID, -- 备用厂商配置 ID
-- 扩展配置
extra_config JSONB DEFAULT '{}', -- 厂商特定配置
-- 元数据
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
created_by UUID,
-- 约束
CONSTRAINT uk_tenant_default UNIQUE (tenant_id, is_default)
WHERE is_default = true
);
-- 索引
CREATE INDEX idx_provider_tenant ON ai_provider_configs(tenant_id);
CREATE INDEX idx_provider_type ON ai_provider_configs(provider_type);
CREATE INDEX idx_provider_enabled ON ai_provider_configs(is_enabled);
CREATE INDEX idx_provider_use_cases ON ai_provider_configs USING GIN(use_cases);
3.2 厂商类型枚举
from enum import Enum
class AIProviderType(str, Enum):
"""支持的 AI 厂商类型"""
# 国内厂商
DEEPSEEK = "deepseek" # DeepSeek
QWEN = "qwen" # 阿里云通义千问
DOUBAO = "doubao" # 字节豆包
ZHIPU = "zhipu" # 智谱 GLM
BAICHUAN = "baichuan" # 百川
MOONSHOT = "moonshot" # Moonshot (Kimi)
# 海外厂商(需注意合规)
OPENAI = "openai" # OpenAI
ANTHROPIC = "anthropic" # Anthropic Claude
# 中转服务
ONEAPI = "oneapi" # OneAPI 中转
OPENROUTER = "openrouter" # OpenRouter
# 本地部署
OLLAMA = "ollama" # Ollama 本地
VLLM = "vllm" # vLLM 部署
# ASR/OCR 专用
ALIYUN_ASR = "aliyun_asr" # 阿里云 ASR
ALIYUN_OCR = "aliyun_ocr" # 阿里云 OCR
PADDLEOCR = "paddleocr" # PaddleOCR 本地
WHISPER = "whisper" # OpenAI Whisper
class AICapability(str, Enum):
"""AI 能力标签"""
CHAT = "chat" # 对话/文本生成
VISION = "vision" # 图像理解
EMBEDDING = "embedding" # 向量嵌入
ASR = "asr" # 语音识别
OCR = "ocr" # 文字识别
TTS = "tts" # 语音合成
class AIUseCase(str, Enum):
"""AI 使用场景"""
BRIEF_PARSING = "brief_parsing" # Brief 解析
SCRIPT_REVIEW = "script_review" # 脚本预审
VIDEO_AUDIT = "video_audit" # 视频审核
CONTEXT_CLASSIFICATION = "context_classification" # 语境分类
SENTIMENT_ANALYSIS = "sentiment_analysis" # 情感分析
LOGO_DETECTION = "logo_detection" # Logo 检测
ASR_TRANSCRIPTION = "asr_transcription" # 语音转写
OCR_EXTRACTION = "ocr_extraction" # 文字提取
3.3 使用日志表 (ai_usage_logs)
CREATE TABLE ai_usage_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
provider_id UUID NOT NULL REFERENCES ai_provider_configs(id),
tenant_id UUID,
-- 请求信息
use_case VARCHAR(50) NOT NULL,
model VARCHAR(100),
-- 用量统计
prompt_tokens INT DEFAULT 0,
completion_tokens INT DEFAULT 0,
total_tokens INT DEFAULT 0,
-- 性能指标
latency_ms INT,
status VARCHAR(20), -- success/error/timeout
error_message TEXT,
-- 时间
created_at TIMESTAMPTZ DEFAULT NOW(),
-- 分区键
created_date DATE DEFAULT CURRENT_DATE
) PARTITION BY RANGE (created_date);
-- 按月分区
CREATE TABLE ai_usage_logs_2026_02 PARTITION OF ai_usage_logs
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
4. 核心代码设计
4.1 配置模型 (Pydantic)
# app/models/ai_provider.py
from pydantic import BaseModel, Field, SecretStr
from typing import Optional, List
from uuid import UUID
from datetime import datetime
from enum import Enum
class AIProviderCreate(BaseModel):
"""创建 AI 厂商配置请求"""
name: str = Field(..., max_length=100)
provider_type: AIProviderType
description: Optional[str] = None
base_url: str
api_key: SecretStr # 接收时为明文,存储时加密
default_model: Optional[str] = None
available_models: List[str] = []
capabilities: List[AICapability] = []
use_cases: List[AIUseCase] = []
tenant_id: Optional[UUID] = None
priority: int = 100
is_enabled: bool = True
is_default: bool = False
rate_limit_rpm: int = 60
rate_limit_tpm: int = 100000
fallback_provider_id: Optional[UUID] = None
extra_config: dict = {}
class AIProviderResponse(BaseModel):
"""AI 厂商配置响应"""
id: UUID
name: str
provider_type: AIProviderType
description: Optional[str]
base_url: str
# 注意:不返回 api_key
default_model: Optional[str]
available_models: List[str]
capabilities: List[AICapability]
use_cases: List[AIUseCase]
tenant_id: Optional[UUID]
priority: int
is_enabled: bool
is_default: bool
rate_limit_rpm: int
rate_limit_tpm: int
fallback_provider_id: Optional[UUID]
extra_config: dict
created_at: datetime
updated_at: datetime
4.2 AI 客户端工厂
# app/services/ai/client_factory.py
from abc import ABC, abstractmethod
from typing import Dict, Optional, Type
from functools import lru_cache
import asyncio
from openai import AsyncOpenAI
from app.models.ai_provider import AIProviderType
from app.services.secrets_manager import SecretsManager
class BaseAIClient(ABC):
"""AI 客户端基类"""
def __init__(self, config: dict):
self.config = config
self.base_url = config["base_url"]
self.api_key = config["api_key"]
self.default_model = config.get("default_model")
@abstractmethod
async def chat(self, messages: list, model: str = None, **kwargs) -> dict:
"""对话接口"""
pass
@abstractmethod
async def health_check(self) -> bool:
"""健康检查"""
pass
class OpenAICompatibleClient(BaseAIClient):
"""OpenAI 兼容客户端 (适用于 DeepSeek, OneAPI, Moonshot 等)"""
def __init__(self, config: dict):
super().__init__(config)
self.client = AsyncOpenAI(
api_key=self.api_key,
base_url=self.base_url,
)
async def chat(self, messages: list, model: str = None, **kwargs) -> dict:
model = model or self.default_model
response = await self.client.chat.completions.create(
model=model,
messages=messages,
**kwargs
)
return {
"content": response.choices[0].message.content,
"usage": {
"prompt_tokens": response.usage.prompt_tokens,
"completion_tokens": response.usage.completion_tokens,
"total_tokens": response.usage.total_tokens,
},
"model": response.model,
}
async def health_check(self) -> bool:
try:
await self.client.models.list()
return True
except Exception:
return False
class AIClientFactory:
"""AI 客户端工厂"""
# 厂商类型到客户端类的映射
_client_classes: Dict[AIProviderType, Type[BaseAIClient]] = {
AIProviderType.DEEPSEEK: OpenAICompatibleClient,
AIProviderType.OPENAI: OpenAICompatibleClient,
AIProviderType.ONEAPI: OpenAICompatibleClient,
AIProviderType.QWEN: OpenAICompatibleClient,
AIProviderType.MOONSHOT: OpenAICompatibleClient,
AIProviderType.ZHIPU: OpenAICompatibleClient,
# 可扩展更多厂商...
}
def __init__(self, secrets_manager: SecretsManager):
self.secrets_manager = secrets_manager
self._client_cache: Dict[str, BaseAIClient] = {}
self._cache_lock = asyncio.Lock()
async def get_client(self, provider_config: dict) -> BaseAIClient:
"""获取或创建 AI 客户端"""
cache_key = f"{provider_config['id']}:{provider_config['updated_at']}"
if cache_key in self._client_cache:
return self._client_cache[cache_key]
async with self._cache_lock:
# 双重检查
if cache_key in self._client_cache:
return self._client_cache[cache_key]
# 解密 API Key
api_key = await self.secrets_manager.decrypt(
provider_config["api_key_encrypted"]
)
config = {
**provider_config,
"api_key": api_key,
}
# 创建客户端
provider_type = AIProviderType(provider_config["provider_type"])
client_class = self._client_classes.get(provider_type)
if not client_class:
raise ValueError(f"Unsupported provider type: {provider_type}")
client = client_class(config)
# 缓存客户端
self._client_cache[cache_key] = client
# 清理旧缓存
self._cleanup_old_cache(provider_config['id'])
return client
def _cleanup_old_cache(self, provider_id: str):
"""清理同一 provider 的旧缓存"""
keys_to_remove = [
k for k in self._client_cache.keys()
if k.startswith(f"{provider_id}:")
]
# 保留最新的一个
for key in keys_to_remove[:-1]:
del self._client_cache[key]
def invalidate_cache(self, provider_id: str = None):
"""使缓存失效"""
if provider_id:
keys_to_remove = [
k for k in self._client_cache.keys()
if k.startswith(f"{provider_id}:")
]
for key in keys_to_remove:
del self._client_cache[key]
else:
self._client_cache.clear()
4.3 AI 服务路由器
# app/services/ai/router.py
from typing import Optional, List
from uuid import UUID
from app.models.ai_provider import AIUseCase, AICapability
from app.repositories.ai_provider_repo import AIProviderRepository
from app.services.ai.client_factory import AIClientFactory, BaseAIClient
class AIServiceRouter:
"""AI 服务路由器 - 根据场景选择合适的 AI 厂商"""
def __init__(
self,
provider_repo: AIProviderRepository,
client_factory: AIClientFactory,
):
self.provider_repo = provider_repo
self.client_factory = client_factory
async def get_client_for_use_case(
self,
use_case: AIUseCase,
tenant_id: Optional[UUID] = None,
required_capabilities: List[AICapability] = None,
) -> BaseAIClient:
"""
根据使用场景获取合适的 AI 客户端
优先级:
1. 租户专属配置 (tenant_id 匹配)
2. 全局默认配置 (tenant_id = NULL)
3. 按 priority 排序
"""
# 查询符合条件的配置
configs = await self.provider_repo.find_by_use_case(
use_case=use_case,
tenant_id=tenant_id,
capabilities=required_capabilities,
enabled_only=True,
)
if not configs:
raise ValueError(
f"No AI provider configured for use case: {use_case}"
)
# 选择优先级最高的配置
selected_config = configs[0]
# 创建并返回客户端
client = await self.client_factory.get_client(selected_config)
# 健康检查,失败则尝试备用
if not await client.health_check():
if selected_config.get("fallback_provider_id"):
fallback_config = await self.provider_repo.get_by_id(
selected_config["fallback_provider_id"]
)
if fallback_config:
client = await self.client_factory.get_client(fallback_config)
return client
async def chat(
self,
messages: list,
use_case: AIUseCase,
tenant_id: Optional[UUID] = None,
model: str = None,
**kwargs
) -> dict:
"""统一的对话接口"""
client = await self.get_client_for_use_case(
use_case=use_case,
tenant_id=tenant_id,
required_capabilities=[AICapability.CHAT],
)
return await client.chat(messages, model=model, **kwargs)
4.4 管理后台 API
# app/api/v1/endpoints/admin/ai_providers.py
from fastapi import APIRouter, Depends, HTTPException, status
from typing import List, Optional
from uuid import UUID
from app.models.ai_provider import (
AIProviderCreate,
AIProviderUpdate,
AIProviderResponse,
)
from app.services.ai_provider_service import AIProviderService
from app.api.deps import get_current_admin_user
router = APIRouter()
@router.post("", response_model=AIProviderResponse, status_code=status.HTTP_201_CREATED)
async def create_ai_provider(
request: AIProviderCreate,
service: AIProviderService = Depends(),
current_user = Depends(get_current_admin_user),
):
"""创建 AI 厂商配置(仅管理员)"""
return await service.create(request, created_by=current_user.id)
@router.get("", response_model=List[AIProviderResponse])
async def list_ai_providers(
tenant_id: Optional[UUID] = None,
provider_type: Optional[str] = None,
service: AIProviderService = Depends(),
current_user = Depends(get_current_admin_user),
):
"""获取 AI 厂商配置列表"""
return await service.list(tenant_id=tenant_id, provider_type=provider_type)
@router.get("/{provider_id}", response_model=AIProviderResponse)
async def get_ai_provider(
provider_id: UUID,
service: AIProviderService = Depends(),
current_user = Depends(get_current_admin_user),
):
"""获取单个 AI 厂商配置"""
provider = await service.get_by_id(provider_id)
if not provider:
raise HTTPException(status_code=404, detail="Provider not found")
return provider
@router.put("/{provider_id}", response_model=AIProviderResponse)
async def update_ai_provider(
provider_id: UUID,
request: AIProviderUpdate,
service: AIProviderService = Depends(),
current_user = Depends(get_current_admin_user),
):
"""更新 AI 厂商配置"""
provider = await service.update(provider_id, request)
if not provider:
raise HTTPException(status_code=404, detail="Provider not found")
return provider
@router.delete("/{provider_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_ai_provider(
provider_id: UUID,
service: AIProviderService = Depends(),
current_user = Depends(get_current_admin_user),
):
"""删除 AI 厂商配置"""
success = await service.delete(provider_id)
if not success:
raise HTTPException(status_code=404, detail="Provider not found")
@router.post("/{provider_id}/test")
async def test_ai_provider(
provider_id: UUID,
service: AIProviderService = Depends(),
current_user = Depends(get_current_admin_user),
):
"""测试 AI 厂商连通性"""
result = await service.test_connection(provider_id)
return {
"success": result.success,
"latency_ms": result.latency_ms,
"error": result.error,
}
@router.post("/{provider_id}/rotate-key", response_model=AIProviderResponse)
async def rotate_api_key(
provider_id: UUID,
new_api_key: str,
service: AIProviderService = Depends(),
current_user = Depends(get_current_admin_user),
):
"""轮换 API Key"""
return await service.rotate_api_key(provider_id, new_api_key)
5. 安全设计
5.1 API Key 加密存储
# app/services/secrets_manager.py
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
import base64
import os
class SecretsManager:
"""密钥管理器 - 负责加密/解密敏感信息"""
def __init__(self, master_key: str):
"""
初始化密钥管理器
Args:
master_key: 主密钥,从安全存储(如 Vault、KMS)获取
"""
# 从主密钥派生加密密钥
salt = os.environ.get("ENCRYPTION_SALT", "smartaudit").encode()
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
)
key = base64.urlsafe_b64encode(kdf.derive(master_key.encode()))
self.fernet = Fernet(key)
async def encrypt(self, plaintext: str) -> bytes:
"""加密明文"""
return self.fernet.encrypt(plaintext.encode())
async def decrypt(self, ciphertext: bytes) -> str:
"""解密密文"""
return self.fernet.decrypt(ciphertext).decode()
5.2 权限控制
| 操作 |
系统管理员 |
品牌方管理员 |
代理商 |
达人 |
| 创建全局配置 |
✅ |
❌ |
❌ |
❌ |
| 创建租户配置 |
✅ |
✅ (仅自己租户) |
❌ |
❌ |
| 查看配置列表 |
✅ (全部) |
✅ (仅自己租户) |
❌ |
❌ |
| 修改配置 |
✅ |
✅ (仅自己租户) |
❌ |
❌ |
| 删除配置 |
✅ |
✅ (仅自己租户) |
❌ |
❌ |
| 查看 API Key |
❌ |
❌ |
❌ |
❌ |
| 轮换 API Key |
✅ |
✅ (仅自己租户) |
❌ |
❌ |
6. 配置热更新
6.1 更新机制
# app/services/ai/config_watcher.py
import asyncio
from datetime import datetime
from typing import Callable, List
from app.repositories.ai_provider_repo import AIProviderRepository
from app.services.ai.client_factory import AIClientFactory
class ConfigWatcher:
"""配置变更监听器"""
def __init__(
self,
provider_repo: AIProviderRepository,
client_factory: AIClientFactory,
poll_interval: int = 30, # 秒
):
self.provider_repo = provider_repo
self.client_factory = client_factory
self.poll_interval = poll_interval
self._last_check = datetime.min
self._running = False
self._callbacks: List[Callable] = []
def on_config_change(self, callback: Callable):
"""注册配置变更回调"""
self._callbacks.append(callback)
async def start(self):
"""启动监听"""
self._running = True
while self._running:
await self._check_for_changes()
await asyncio.sleep(self.poll_interval)
async def stop(self):
"""停止监听"""
self._running = False
async def _check_for_changes(self):
"""检查配置变更"""
changed_configs = await self.provider_repo.find_updated_since(
self._last_check
)
if changed_configs:
self._last_check = datetime.utcnow()
# 使相关缓存失效
for config in changed_configs:
self.client_factory.invalidate_cache(config["id"])
# 触发回调
for callback in self._callbacks:
await callback(changed_configs)
6.2 应用启动集成
# app/main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI
from app.services.ai.config_watcher import ConfigWatcher
@asynccontextmanager
async def lifespan(app: FastAPI):
# 启动时
config_watcher = ConfigWatcher(
provider_repo=app.state.provider_repo,
client_factory=app.state.client_factory,
)
asyncio.create_task(config_watcher.start())
yield
# 关闭时
await config_watcher.stop()
app = FastAPI(lifespan=lifespan)
7. 使用示例
7.1 在业务代码中使用
# app/services/brief_parser.py
from app.services.ai.router import AIServiceRouter
from app.models.ai_provider import AIUseCase
class BriefParserService:
"""Brief 解析服务"""
def __init__(self, ai_router: AIServiceRouter):
self.ai_router = ai_router
async def parse_brief(self, content: str, tenant_id: UUID = None) -> dict:
"""解析 Brief 文档"""
messages = [
{"role": "system", "content": "你是一个专业的 Brief 解析助手..."},
{"role": "user", "content": f"请解析以下 Brief 内容:\n{content}"},
]
# 自动选择合适的 AI 厂商
result = await self.ai_router.chat(
messages=messages,
use_case=AIUseCase.BRIEF_PARSING,
tenant_id=tenant_id,
)
return self._parse_response(result["content"])
7.2 管理员配置流程
1. 管理员登录后台
2. 进入「系统设置 → AI 厂商管理」
3. 点击「添加厂商」
4. 填写配置:
- 名称:生产环境 DeepSeek
- 厂商类型:DeepSeek
- Base URL:https://api.deepseek.com/v1
- API Key:sk-xxx
- 默认模型:deepseek-chat
- 适用场景:Brief 解析、脚本预审
- 优先级:10
5. 点击「测试连通性」
6. 保存配置
7. 配置立即生效,无需重启服务
8. 监控与告警
8.1 监控指标
| 指标 |
说明 |
告警阈值 |
ai_request_total |
AI 请求总数 |
- |
ai_request_latency_p99 |
P99 延迟 |
> 10s |
ai_request_error_rate |
错误率 |
> 5% |
ai_token_usage_total |
Token 使用量 |
接近配额 80% |
ai_provider_health |
厂商健康状态 |
连续失败 > 3 次 |
8.2 告警规则
# prometheus/alerts/ai_provider.yml
groups:
- name: ai_provider
rules:
- alert: AIProviderHighErrorRate
expr: rate(ai_request_errors_total[5m]) / rate(ai_request_total[5m]) > 0.05
for: 2m
labels:
severity: warning
annotations:
summary: "AI 厂商 {{ $labels.provider }} 错误率过高"
- alert: AIProviderDown
expr: ai_provider_health == 0
for: 1m
labels:
severity: critical
annotations:
summary: "AI 厂商 {{ $labels.provider }} 不可用"
9. 相关文档
| 文档 |
说明 |
| DevelopmentPlan.md |
开发计划(已更新 AI 配置章节) |
| RequirementsDoc.md |
需求文档 |
| FeatureSummary.md |
功能清单 |
| API 接口规范 |
待编写 |