mirror of
https://github.com/linyqh/NarratoAI.git
synced 2025-12-10 18:02:51 +00:00
309 lines
11 KiB
Python
309 lines
11 KiB
Python
"""
|
||
LLM服务配置验证器
|
||
|
||
验证大模型服务的配置是否正确,并提供配置建议
|
||
"""
|
||
|
||
from typing import Dict, List, Any, Optional
|
||
from loguru import logger
|
||
|
||
from app.config import config
|
||
from .manager import LLMServiceManager
|
||
from .exceptions import ConfigurationError
|
||
|
||
|
||
class LLMConfigValidator:
|
||
"""LLM服务配置验证器"""
|
||
|
||
@staticmethod
|
||
def validate_all_configs() -> Dict[str, Any]:
|
||
"""
|
||
验证所有LLM服务配置
|
||
|
||
Returns:
|
||
验证结果字典
|
||
"""
|
||
results = {
|
||
"vision_providers": {},
|
||
"text_providers": {},
|
||
"summary": {
|
||
"total_vision_providers": 0,
|
||
"valid_vision_providers": 0,
|
||
"total_text_providers": 0,
|
||
"valid_text_providers": 0,
|
||
"errors": [],
|
||
"warnings": []
|
||
}
|
||
}
|
||
|
||
# 验证视觉模型提供商
|
||
vision_providers = LLMServiceManager.list_vision_providers()
|
||
results["summary"]["total_vision_providers"] = len(vision_providers)
|
||
|
||
for provider in vision_providers:
|
||
try:
|
||
validation_result = LLMConfigValidator.validate_vision_provider(provider)
|
||
results["vision_providers"][provider] = validation_result
|
||
|
||
if validation_result["is_valid"]:
|
||
results["summary"]["valid_vision_providers"] += 1
|
||
else:
|
||
results["summary"]["errors"].extend(validation_result["errors"])
|
||
|
||
except Exception as e:
|
||
error_msg = f"验证视觉模型提供商 {provider} 时发生错误: {str(e)}"
|
||
results["vision_providers"][provider] = {
|
||
"is_valid": False,
|
||
"errors": [error_msg],
|
||
"warnings": []
|
||
}
|
||
results["summary"]["errors"].append(error_msg)
|
||
|
||
# 验证文本模型提供商
|
||
text_providers = LLMServiceManager.list_text_providers()
|
||
results["summary"]["total_text_providers"] = len(text_providers)
|
||
|
||
for provider in text_providers:
|
||
try:
|
||
validation_result = LLMConfigValidator.validate_text_provider(provider)
|
||
results["text_providers"][provider] = validation_result
|
||
|
||
if validation_result["is_valid"]:
|
||
results["summary"]["valid_text_providers"] += 1
|
||
else:
|
||
results["summary"]["errors"].extend(validation_result["errors"])
|
||
|
||
except Exception as e:
|
||
error_msg = f"验证文本模型提供商 {provider} 时发生错误: {str(e)}"
|
||
results["text_providers"][provider] = {
|
||
"is_valid": False,
|
||
"errors": [error_msg],
|
||
"warnings": []
|
||
}
|
||
results["summary"]["errors"].append(error_msg)
|
||
|
||
return results
|
||
|
||
@staticmethod
|
||
def validate_vision_provider(provider_name: str) -> Dict[str, Any]:
|
||
"""
|
||
验证视觉模型提供商配置
|
||
|
||
Args:
|
||
provider_name: 提供商名称
|
||
|
||
Returns:
|
||
验证结果字典
|
||
"""
|
||
result = {
|
||
"is_valid": False,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"config": {}
|
||
}
|
||
|
||
try:
|
||
# 获取配置
|
||
config_prefix = f"vision_{provider_name}"
|
||
api_key = config.app.get(f'{config_prefix}_api_key')
|
||
model_name = config.app.get(f'{config_prefix}_model_name')
|
||
base_url = config.app.get(f'{config_prefix}_base_url')
|
||
|
||
result["config"] = {
|
||
"api_key": "***" if api_key else None,
|
||
"model_name": model_name,
|
||
"base_url": base_url
|
||
}
|
||
|
||
# 验证必需配置
|
||
if not api_key:
|
||
result["errors"].append(f"缺少API密钥配置: {config_prefix}_api_key")
|
||
|
||
if not model_name:
|
||
result["errors"].append(f"缺少模型名称配置: {config_prefix}_model_name")
|
||
|
||
# 尝试创建提供商实例
|
||
if api_key and model_name:
|
||
try:
|
||
provider_instance = LLMServiceManager.get_vision_provider(provider_name)
|
||
result["is_valid"] = True
|
||
logger.debug(f"视觉模型提供商 {provider_name} 配置验证成功")
|
||
|
||
except Exception as e:
|
||
result["errors"].append(f"创建提供商实例失败: {str(e)}")
|
||
|
||
# 添加警告
|
||
if not base_url:
|
||
result["warnings"].append(f"未配置base_url,将使用默认值")
|
||
|
||
except Exception as e:
|
||
result["errors"].append(f"配置验证过程中发生错误: {str(e)}")
|
||
|
||
return result
|
||
|
||
@staticmethod
|
||
def validate_text_provider(provider_name: str) -> Dict[str, Any]:
|
||
"""
|
||
验证文本模型提供商配置
|
||
|
||
Args:
|
||
provider_name: 提供商名称
|
||
|
||
Returns:
|
||
验证结果字典
|
||
"""
|
||
result = {
|
||
"is_valid": False,
|
||
"errors": [],
|
||
"warnings": [],
|
||
"config": {}
|
||
}
|
||
|
||
try:
|
||
# 获取配置
|
||
config_prefix = f"text_{provider_name}"
|
||
api_key = config.app.get(f'{config_prefix}_api_key')
|
||
model_name = config.app.get(f'{config_prefix}_model_name')
|
||
base_url = config.app.get(f'{config_prefix}_base_url')
|
||
|
||
result["config"] = {
|
||
"api_key": "***" if api_key else None,
|
||
"model_name": model_name,
|
||
"base_url": base_url
|
||
}
|
||
|
||
# 验证必需配置
|
||
if not api_key:
|
||
result["errors"].append(f"缺少API密钥配置: {config_prefix}_api_key")
|
||
|
||
if not model_name:
|
||
result["errors"].append(f"缺少模型名称配置: {config_prefix}_model_name")
|
||
|
||
# 尝试创建提供商实例
|
||
if api_key and model_name:
|
||
try:
|
||
provider_instance = LLMServiceManager.get_text_provider(provider_name)
|
||
result["is_valid"] = True
|
||
logger.debug(f"文本模型提供商 {provider_name} 配置验证成功")
|
||
|
||
except Exception as e:
|
||
result["errors"].append(f"创建提供商实例失败: {str(e)}")
|
||
|
||
# 添加警告
|
||
if not base_url:
|
||
result["warnings"].append(f"未配置base_url,将使用默认值")
|
||
|
||
except Exception as e:
|
||
result["errors"].append(f"配置验证过程中发生错误: {str(e)}")
|
||
|
||
return result
|
||
|
||
@staticmethod
|
||
def get_config_suggestions() -> Dict[str, Any]:
|
||
"""
|
||
获取配置建议
|
||
|
||
Returns:
|
||
配置建议字典
|
||
"""
|
||
suggestions = {
|
||
"vision_providers": {},
|
||
"text_providers": {},
|
||
"general_tips": [
|
||
"确保所有API密钥都已正确配置",
|
||
"建议为每个提供商配置base_url以提高稳定性",
|
||
"定期检查模型名称是否为最新版本",
|
||
"建议配置多个提供商作为备用方案",
|
||
"推荐使用 LiteLLM 作为统一接口,支持 100+ providers"
|
||
]
|
||
}
|
||
|
||
# 为每个视觉模型提供商提供建议
|
||
vision_providers = LLMServiceManager.list_vision_providers()
|
||
for provider in vision_providers:
|
||
suggestions["vision_providers"][provider] = {
|
||
"required_configs": [
|
||
f"vision_{provider}_api_key",
|
||
f"vision_{provider}_model_name"
|
||
],
|
||
"optional_configs": [
|
||
f"vision_{provider}_base_url"
|
||
],
|
||
"example_models": LLMConfigValidator._get_example_models(provider, "vision")
|
||
}
|
||
|
||
# 为每个文本模型提供商提供建议
|
||
text_providers = LLMServiceManager.list_text_providers()
|
||
for provider in text_providers:
|
||
suggestions["text_providers"][provider] = {
|
||
"required_configs": [
|
||
f"text_{provider}_api_key",
|
||
f"text_{provider}_model_name"
|
||
],
|
||
"optional_configs": [
|
||
f"text_{provider}_base_url"
|
||
],
|
||
"example_models": LLMConfigValidator._get_example_models(provider, "text")
|
||
}
|
||
|
||
return suggestions
|
||
|
||
@staticmethod
|
||
def _get_example_models(provider_name: str, model_type: str) -> List[str]:
|
||
"""获取示例模型名称"""
|
||
examples = {
|
||
"gemini": {
|
||
"vision": ["gemini-2.5-flash", "gemini-2.0-flash-lite", "gemini-2.0-flash"],
|
||
"text": ["gemini-2.5-flash", "gemini-2.0-flash", "gemini-1.5-pro"]
|
||
},
|
||
"openai": {
|
||
"vision": [],
|
||
"text": ["gpt-4o", "gpt-4o-mini", "gpt-4-turbo"]
|
||
},
|
||
"qwen": {
|
||
"vision": ["qwen2.5-vl-32b-instruct"],
|
||
"text": ["qwen-plus-1127", "qwen-turbo"]
|
||
},
|
||
"deepseek": {
|
||
"vision": [],
|
||
"text": ["deepseek-chat", "deepseek-reasoner"]
|
||
},
|
||
"siliconflow": {
|
||
"vision": ["Qwen/Qwen2.5-VL-32B-Instruct"],
|
||
"text": ["deepseek-ai/DeepSeek-R1", "Qwen/Qwen2.5-72B-Instruct"]
|
||
}
|
||
}
|
||
|
||
return examples.get(provider_name, {}).get(model_type, [])
|
||
|
||
@staticmethod
|
||
def print_validation_report(validation_results: Dict[str, Any]):
|
||
"""
|
||
打印验证报告
|
||
|
||
Args:
|
||
validation_results: 验证结果
|
||
"""
|
||
summary = validation_results["summary"]
|
||
|
||
print("\n" + "="*60)
|
||
print("LLM服务配置验证报告")
|
||
print("="*60)
|
||
|
||
print(f"\n📊 总体统计:")
|
||
print(f" 视觉模型提供商: {summary['valid_vision_providers']}/{summary['total_vision_providers']} 有效")
|
||
print(f" 文本模型提供商: {summary['valid_text_providers']}/{summary['total_text_providers']} 有效")
|
||
|
||
if summary["errors"]:
|
||
print(f"\n❌ 错误 ({len(summary['errors'])}):")
|
||
for error in summary["errors"]:
|
||
print(f" - {error}")
|
||
|
||
if summary["warnings"]:
|
||
print(f"\n⚠️ 警告 ({len(summary['warnings'])}):")
|
||
for warning in summary["warnings"]:
|
||
print(f" - {warning}")
|
||
|
||
print(f"\n✅ 配置验证完成")
|
||
print("="*60)
|