""" 生成式大模型服务模块 本模块提供统一的生成式大模型服务获取接口,支持多种模型: 1. Local VLLM 服务:本地 gemma-4-E4B-it 模型 2. Zhipu AI:智谱 glm-4.7-flash 模型 3. DeepSeek:deepseek-reasoner 模型 主要功能: - LocalVLLMChatProvider:本地 VLLM 服务提供者 - ZhipuChatProvider:智谱 API 服务提供者 - DeepSeekChatProvider:DeepSeek API 服务提供者 - get_chat_service():获取默认服务(带自动降级) - get_all_chat_services():获取所有可用模型服务(用于多模型切换) """ import logging from typing import Dict, Callable from langchain_core.language_models import BaseChatModel from .base import ( BaseServiceProvider, FallbackServiceChain, SingletonServiceManager ) from ..config import ( VLLM_BASE_URL, LLM_API_KEY, ZHIPUAI_API_KEY, DEEPSEEK_API_KEY ) logger = logging.getLogger(__name__) class LocalVLLMChatProvider(BaseServiceProvider[BaseChatModel]): """ 本地 VLLM 生成式大模型服务提供者 """ def __init__(self, model: str = "gemma-4-E4B-it"): super().__init__("local_vllm_chat") self._model = model def is_available(self) -> bool: """ 检查本地 VLLM 服务是否可用 Returns: bool: 服务是否可用 """ if not VLLM_BASE_URL: logger.warning("VLLM_BASE_URL 未配置") return False try: # 尝试创建一个简单的测试调用 from langchain_openai import ChatOpenAI from pydantic import SecretStr llm = ChatOpenAI( base_url=VLLM_BASE_URL, api_key=SecretStr(LLM_API_KEY) if LLM_API_KEY else SecretStr("dummy"), model=self._model, timeout=10.0, max_retries=1, ) # 简单的 ping 测试(不实际调用模型) logger.info(f"本地 VLLM 服务配置正确,准备使用: {self._model}") return True except Exception as e: logger.warning(f"本地 VLLM 服务不可用: {e}") return False def get_service(self) -> BaseChatModel: """ 获取本地 VLLM 服务 Returns: BaseChatModel: LangChain 兼容的 ChatModel 实例 """ if self._service_instance is None: from langchain_openai import ChatOpenAI from pydantic import SecretStr self._service_instance = ChatOpenAI( base_url=VLLM_BASE_URL, api_key=SecretStr(LLM_API_KEY) if LLM_API_KEY else SecretStr(""), model=self._model, timeout=60.0, max_retries=2, streaming=True, ) return self._service_instance class ZhipuChatProvider(BaseServiceProvider[BaseChatModel]): """ 智谱 AI 生成式大模型服务提供者 """ def __init__(self, model: str = "glm-4.7-flash"): super().__init__("zhipu_chat") self._model = model def is_available(self) -> bool: """ 检查智谱 AI 服务是否可用 Returns: bool: 服务是否可用 """ if not ZHIPUAI_API_KEY: logger.warning("ZHIPUAI_API_KEY 未配置") return False try: logger.info(f"智谱 AI 服务配置正确,准备使用: {self._model}") return True except Exception as e: logger.warning(f"智谱 AI 服务不可用: {e}") return False def get_service(self) -> BaseChatModel: """ 获取智谱 AI 服务 Returns: BaseChatModel: LangChain 兼容的 ChatModel 实例 """ if self._service_instance is None: from langchain_community.chat_models import ChatZhipuAI self._service_instance = ChatZhipuAI( model=self._model, api_key=ZHIPUAI_API_KEY, temperature=0.1, max_tokens=4096, timeout=120.0, max_retries=3, streaming=True, ) return self._service_instance class DeepSeekChatProvider(BaseServiceProvider[BaseChatModel]): """ DeepSeek 生成式大模型服务提供者 """ def __init__(self, model: str = "deepseek-reasoner"): super().__init__("deepseek_chat") self._model = model def is_available(self) -> bool: """ 检查 DeepSeek 服务是否可用 Returns: bool: 服务是否可用 """ if not DEEPSEEK_API_KEY: logger.warning("DEEPSEEK_API_KEY 未配置") return False try: logger.info(f"DeepSeek 服务配置正确,准备使用: {self._model}") return True except Exception as e: logger.warning(f"DeepSeek 服务不可用: {e}") return False def get_service(self) -> BaseChatModel: """ 获取 DeepSeek 服务 Returns: BaseChatModel: LangChain 兼容的 ChatModel 实例 """ if self._service_instance is None: from langchain_openai import ChatOpenAI from pydantic import SecretStr self._service_instance = ChatOpenAI( base_url="https://api.deepseek.com", api_key=SecretStr(DEEPSEEK_API_KEY), model=self._model, temperature=0.1, max_tokens=4096, timeout=60.0, max_retries=2, streaming=True, ) return self._service_instance # 全局服务映射表 - 名称 -> Provider CHAT_PROVIDERS: Dict[str, Callable[[], BaseServiceProvider[BaseChatModel]]] = { "local": lambda: LocalVLLMChatProvider(), "zhipu": lambda: ZhipuChatProvider(), "deepseek": lambda: DeepSeekChatProvider(), } def get_chat_service() -> BaseChatModel: """ 获取默认的生成式大模型服务(带自动降级) 优先顺序: local -> zhipu -> deepseek Returns: BaseChatModel: LangChain 兼容的 ChatModel 实例 """ def _create_chain(): primary = LocalVLLMChatProvider() fallbacks = [ZhipuChatProvider(), DeepSeekChatProvider()] return FallbackServiceChain(primary, fallbacks) chain = SingletonServiceManager.get_or_create("chat_service_chain", _create_chain) return chain.get_available_service() def get_all_chat_services() -> Dict[str, BaseChatModel]: """ 获取所有可用的生成式大模型服务(用于多模型切换) Returns: Dict[str, BaseChatModel]: 模型名称 -> ChatModel 实例 的字典 """ services = {} for name, provider_factory in CHAT_PROVIDERS.items(): try: provider = provider_factory() if provider.is_available(): logger.info(f"模型 '{name}' 可用") services[name] = provider.get_service() else: logger.warning(f"模型 '{name}' 不可用,跳过") except Exception as e: logger.warning(f"初始化模型 '{name}' 失败: {e}") if not services: raise RuntimeError(f"没有可用的生成式大模型,尝试了: {list(CHAT_PROVIDERS.keys())}") return services