2026-04-26 12:00:57 +08:00
|
|
|
|
"""
|
|
|
|
|
|
生成式大模型服务模块
|
|
|
|
|
|
|
|
|
|
|
|
本模块提供统一的生成式大模型服务获取接口,支持多种模型:
|
|
|
|
|
|
1. Local VLLM 服务:本地 gemma-4-E4B-it 模型
|
2026-05-01 02:56:09 +08:00
|
|
|
|
2. Zhipu AI:智谱 glm-5.1 模型
|
|
|
|
|
|
3. DeepSeek:deepseek-v4-pro 模型
|
2026-05-07 00:48:17 +08:00
|
|
|
|
4. Baosi API:ops4.7 模型
|
2026-04-26 12:00:57 +08:00
|
|
|
|
|
|
|
|
|
|
主要功能:
|
|
|
|
|
|
- LocalVLLMChatProvider:本地 VLLM 服务提供者
|
|
|
|
|
|
- ZhipuChatProvider:智谱 API 服务提供者
|
|
|
|
|
|
- DeepSeekChatProvider:DeepSeek API 服务提供者
|
2026-05-07 00:48:17 +08:00
|
|
|
|
- BaosiChatProvider:Baosi API 服务提供者
|
2026-04-26 12:00:57 +08:00
|
|
|
|
- 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
|
|
|
|
|
|
)
|
2026-05-06 01:15:52 +08:00
|
|
|
|
from backend.app.config import (
|
2026-04-26 12:00:57 +08:00
|
|
|
|
VLLM_BASE_URL,
|
|
|
|
|
|
LLM_API_KEY,
|
|
|
|
|
|
ZHIPUAI_API_KEY,
|
2026-05-04 03:26:19 +08:00
|
|
|
|
DEEPSEEK_API_KEY,
|
2026-05-07 00:48:17 +08:00
|
|
|
|
BAOSI_API_KEY,
|
|
|
|
|
|
BAOSI_API_BASE,
|
|
|
|
|
|
BAOSI_MODEL,
|
2026-05-04 03:26:19 +08:00
|
|
|
|
LOCAL_MODEL_NAME
|
2026-04-26 12:00:57 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
2026-05-05 17:30:55 +08:00
|
|
|
|
# 缓存已初始化的模型字典
|
|
|
|
|
|
_cached_services: Dict[str, BaseChatModel] | None = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _check_http_service_available(base_url: str, api_key: str = "", timeout: float = 2.0) -> bool:
|
|
|
|
|
|
"""通过探测 /models 端点检查 HTTP API 是否可用(内部工具函数)"""
|
|
|
|
|
|
try:
|
|
|
|
|
|
import httpx
|
|
|
|
|
|
client = httpx.Client(base_url=base_url.rstrip('/'), timeout=timeout)
|
|
|
|
|
|
headers = {"Authorization": f"Bearer {api_key}"} if api_key else {}
|
|
|
|
|
|
resp = client.get("/models", headers=headers)
|
|
|
|
|
|
return resp.status_code == 200
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
2026-04-26 12:00:57 +08:00
|
|
|
|
|
|
|
|
|
|
class LocalVLLMChatProvider(BaseServiceProvider[BaseChatModel]):
|
|
|
|
|
|
"""
|
|
|
|
|
|
本地 VLLM 生成式大模型服务提供者
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
2026-05-04 03:26:19 +08:00
|
|
|
|
def __init__(self, model: str = None):
|
2026-04-26 12:00:57 +08:00
|
|
|
|
super().__init__("local_vllm_chat")
|
2026-05-04 03:26:19 +08:00
|
|
|
|
self._model = model or LOCAL_MODEL_NAME
|
2026-04-26 12:00:57 +08:00
|
|
|
|
|
|
|
|
|
|
def is_available(self) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
检查本地 VLLM 服务是否可用
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
bool: 服务是否可用
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not VLLM_BASE_URL:
|
|
|
|
|
|
logger.warning("VLLM_BASE_URL 未配置")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
2026-05-05 17:30:55 +08:00
|
|
|
|
# 使用统一的 HTTP 探测方法
|
|
|
|
|
|
return _check_http_service_available(VLLM_BASE_URL, LLM_API_KEY, timeout=2.0)
|
2026-04-26 12:00:57 +08:00
|
|
|
|
|
|
|
|
|
|
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 生成式大模型服务提供者
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
2026-05-01 02:56:09 +08:00
|
|
|
|
def __init__(self, model: str = "glm-5.1"):
|
2026-04-26 12:00:57 +08:00
|
|
|
|
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 生成式大模型服务提供者
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
2026-05-01 02:56:09 +08:00
|
|
|
|
def __init__(self, model: str = "deepseek-v4-pro"):
|
2026-04-26 12:00:57 +08:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-07 00:48:17 +08:00
|
|
|
|
class BaosiChatProvider(BaseServiceProvider[BaseChatModel]):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Baosi API 生成式大模型服务提供者
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, model: str = None):
|
|
|
|
|
|
super().__init__("baosi_chat")
|
|
|
|
|
|
self._model = model or BAOSI_MODEL
|
|
|
|
|
|
self._base_url = BAOSI_API_BASE
|
|
|
|
|
|
self._api_key = BAOSI_API_KEY
|
|
|
|
|
|
|
|
|
|
|
|
def is_available(self) -> bool:
|
|
|
|
|
|
"""
|
|
|
|
|
|
检查 Baosi API 服务是否可用
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
bool: 服务是否可用
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not self._api_key:
|
|
|
|
|
|
logger.warning("BAOSI_API_KEY 未配置")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
logger.info(f"Baosi API 服务配置正确,准备使用: {self._model}")
|
|
|
|
|
|
return True
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.warning(f"Baosi API 服务不可用: {e}")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def get_service(self) -> BaseChatModel:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取 Baosi API 服务
|
|
|
|
|
|
|
|
|
|
|
|
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=self._base_url,
|
|
|
|
|
|
api_key=SecretStr(self._api_key) if self._api_key else SecretStr(""),
|
|
|
|
|
|
model=self._model,
|
|
|
|
|
|
temperature=0.1,
|
|
|
|
|
|
max_tokens=4096,
|
|
|
|
|
|
timeout=120.0,
|
|
|
|
|
|
max_retries=2,
|
|
|
|
|
|
streaming=False, # Baosi API 可能不兼容 streaming,设置为 False
|
|
|
|
|
|
)
|
|
|
|
|
|
return self._service_instance
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-03 16:45:46 +08:00
|
|
|
|
# ========== 轻量级模型 Provider ==========
|
|
|
|
|
|
|
2026-05-04 17:58:10 +08:00
|
|
|
|
class LocalSmallModelProvider(BaseServiceProvider[BaseChatModel]):
|
2026-05-03 16:45:46 +08:00
|
|
|
|
"""
|
2026-05-04 17:58:10 +08:00
|
|
|
|
本地轻量级模型服务提供者(用于查询改写、意图分类等简单任务)
|
|
|
|
|
|
使用小模型独立配置
|
2026-05-03 16:45:46 +08:00
|
|
|
|
"""
|
|
|
|
|
|
|
2026-05-04 17:58:10 +08:00
|
|
|
|
def __init__(self, model: str = None):
|
2026-05-06 01:15:52 +08:00
|
|
|
|
from backend.app.config import SMALL_LOCAL_MODEL_NAME, SMALL_VLLM_BASE_URL, SMALL_LLM_API_KEY
|
2026-05-04 17:58:10 +08:00
|
|
|
|
super().__init__("local_small")
|
|
|
|
|
|
self._model = model or SMALL_LOCAL_MODEL_NAME
|
|
|
|
|
|
self._base_url = SMALL_VLLM_BASE_URL
|
|
|
|
|
|
self._api_key = SMALL_LLM_API_KEY
|
2026-05-03 16:45:46 +08:00
|
|
|
|
|
|
|
|
|
|
def is_available(self) -> bool:
|
2026-05-04 17:58:10 +08:00
|
|
|
|
"""检查本地小模型服务是否可用"""
|
|
|
|
|
|
if not self._base_url:
|
|
|
|
|
|
logger.warning("SMALL_VLLM_BASE_URL 未配置,本地小模型不可用")
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
2026-05-05 17:30:55 +08:00
|
|
|
|
# 使用统一的 HTTP 探测方法
|
|
|
|
|
|
return _check_http_service_available(self._base_url, self._api_key, timeout=2.0)
|
2026-05-03 16:45:46 +08:00
|
|
|
|
|
|
|
|
|
|
def get_service(self) -> BaseChatModel:
|
2026-05-04 17:58:10 +08:00
|
|
|
|
"""获取本地小模型服务"""
|
2026-05-03 16:45:46 +08:00
|
|
|
|
if self._service_instance is None:
|
2026-05-04 17:58:10 +08:00
|
|
|
|
from langchain_openai import ChatOpenAI
|
|
|
|
|
|
from pydantic import SecretStr
|
|
|
|
|
|
|
|
|
|
|
|
self._service_instance = ChatOpenAI(
|
|
|
|
|
|
base_url=self._base_url,
|
|
|
|
|
|
api_key=SecretStr(self._api_key) if self._api_key else SecretStr(""),
|
2026-05-03 16:45:46 +08:00
|
|
|
|
model=self._model,
|
|
|
|
|
|
timeout=30.0,
|
|
|
|
|
|
max_retries=2,
|
2026-05-04 17:58:10 +08:00
|
|
|
|
streaming=False,
|
2026-05-03 16:45:46 +08:00
|
|
|
|
)
|
|
|
|
|
|
return self._service_instance
|
|
|
|
|
|
|
2026-05-04 17:58:10 +08:00
|
|
|
|
|
2026-05-03 16:45:46 +08:00
|
|
|
|
class DeepSeekSmallModelProvider(BaseServiceProvider[BaseChatModel]):
|
|
|
|
|
|
"""
|
2026-05-04 17:58:10 +08:00
|
|
|
|
DeepSeek 轻量级模型服务提供者(用于查询改写、意图分类等简单任务)
|
|
|
|
|
|
使用小模型独立配置
|
2026-05-03 16:45:46 +08:00
|
|
|
|
"""
|
|
|
|
|
|
|
2026-05-04 17:58:10 +08:00
|
|
|
|
def __init__(self, model: str = None):
|
2026-05-06 01:15:52 +08:00
|
|
|
|
from backend.app.config import SMALL_DEEPSEEK_MODEL, SMALL_DEEPSEEK_API_KEY, SMALL_DEEPSEEK_API_BASE
|
2026-05-03 16:45:46 +08:00
|
|
|
|
super().__init__("deepseek_small")
|
2026-05-04 17:58:10 +08:00
|
|
|
|
self._model = model or SMALL_DEEPSEEK_MODEL
|
|
|
|
|
|
self._api_key = SMALL_DEEPSEEK_API_KEY
|
|
|
|
|
|
self._api_base = SMALL_DEEPSEEK_API_BASE
|
2026-05-03 16:45:46 +08:00
|
|
|
|
|
|
|
|
|
|
def is_available(self) -> bool:
|
2026-05-04 17:58:10 +08:00
|
|
|
|
if not self._api_key:
|
|
|
|
|
|
logger.warning("SMALL_DEEPSEEK_API_KEY 未配置")
|
2026-05-03 16:45:46 +08:00
|
|
|
|
return False
|
|
|
|
|
|
logger.info(f"DeepSeek 轻量模型配置正确: {self._model}")
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
def get_service(self) -> BaseChatModel:
|
|
|
|
|
|
if self._service_instance is None:
|
|
|
|
|
|
from langchain_openai import ChatOpenAI
|
|
|
|
|
|
from pydantic import SecretStr
|
|
|
|
|
|
|
|
|
|
|
|
self._service_instance = ChatOpenAI(
|
2026-05-04 17:58:10 +08:00
|
|
|
|
base_url=self._api_base,
|
|
|
|
|
|
api_key=SecretStr(self._api_key),
|
2026-05-03 16:45:46 +08:00
|
|
|
|
model=self._model,
|
|
|
|
|
|
temperature=0.1,
|
|
|
|
|
|
max_tokens=2048,
|
|
|
|
|
|
timeout=30.0,
|
|
|
|
|
|
max_retries=2,
|
|
|
|
|
|
streaming=False,
|
|
|
|
|
|
)
|
|
|
|
|
|
return self._service_instance
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-26 12:00:57 +08:00
|
|
|
|
# 全局服务映射表 - 名称 -> Provider
|
|
|
|
|
|
CHAT_PROVIDERS: Dict[str, Callable[[], BaseServiceProvider[BaseChatModel]]] = {
|
|
|
|
|
|
"local": lambda: LocalVLLMChatProvider(),
|
2026-05-07 00:48:17 +08:00
|
|
|
|
"baosi": lambda: BaosiChatProvider(),
|
2026-04-26 12:00:57 +08:00
|
|
|
|
"zhipu": lambda: ZhipuChatProvider(),
|
|
|
|
|
|
"deepseek": lambda: DeepSeekChatProvider(),
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_chat_service() -> BaseChatModel:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取默认的生成式大模型服务(带自动降级)
|
2026-05-07 00:48:17 +08:00
|
|
|
|
优先顺序: local → baosi → zhipu → deepseek
|
2026-04-26 12:00:57 +08:00
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
BaseChatModel: LangChain 兼容的 ChatModel 实例
|
|
|
|
|
|
"""
|
|
|
|
|
|
def _create_chain():
|
|
|
|
|
|
primary = LocalVLLMChatProvider()
|
2026-05-07 00:48:17 +08:00
|
|
|
|
fallbacks = [BaosiChatProvider(), ZhipuChatProvider(), DeepSeekChatProvider()]
|
2026-04-26 12:00:57 +08:00
|
|
|
|
return FallbackServiceChain(primary, fallbacks)
|
|
|
|
|
|
|
|
|
|
|
|
chain = SingletonServiceManager.get_or_create("chat_service_chain", _create_chain)
|
|
|
|
|
|
return chain.get_available_service()
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-05 17:30:55 +08:00
|
|
|
|
def _init_chat_services() -> Dict[str, BaseChatModel]:
|
|
|
|
|
|
"""实际初始化所有可用模型(仅在首次调用)"""
|
2026-04-26 12:00:57 +08:00
|
|
|
|
services = {}
|
|
|
|
|
|
|
|
|
|
|
|
for name, provider_factory in CHAT_PROVIDERS.items():
|
|
|
|
|
|
try:
|
|
|
|
|
|
provider = provider_factory()
|
|
|
|
|
|
if provider.is_available():
|
|
|
|
|
|
services[name] = provider.get_service()
|
2026-05-05 17:30:55 +08:00
|
|
|
|
logger.info(f"已加载模型: {name}")
|
2026-04-26 12:00:57 +08:00
|
|
|
|
except Exception as e:
|
2026-05-05 17:30:55 +08:00
|
|
|
|
logger.warning(f"模型 {name} 初始化失败: {e}")
|
2026-04-26 12:00:57 +08:00
|
|
|
|
|
|
|
|
|
|
if not services:
|
|
|
|
|
|
raise RuntimeError(f"没有可用的生成式大模型,尝试了: {list(CHAT_PROVIDERS.keys())}")
|
|
|
|
|
|
|
|
|
|
|
|
return services
|
2026-05-03 16:45:46 +08:00
|
|
|
|
|
|
|
|
|
|
|
2026-05-05 17:30:55 +08:00
|
|
|
|
def get_cached_chat_services() -> Dict[str, BaseChatModel]:
|
|
|
|
|
|
"""获取缓存的可用模型字典(用于单图动态注入)"""
|
|
|
|
|
|
global _cached_services
|
|
|
|
|
|
if _cached_services is None:
|
|
|
|
|
|
_cached_services = _init_chat_services()
|
|
|
|
|
|
return _cached_services
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_all_chat_services() -> Dict[str, BaseChatModel]:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取所有可用的生成式大模型服务(用于多模型切换,保留兼容性)
|
|
|
|
|
|
新代码请使用 get_cached_chat_services() 获取缓存版本
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
Dict[str, BaseChatModel]: 模型名称 -> ChatModel 实例 的字典
|
|
|
|
|
|
"""
|
|
|
|
|
|
return get_cached_chat_services()
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-03 16:45:46 +08:00
|
|
|
|
def get_small_llm_service() -> BaseChatModel:
|
|
|
|
|
|
"""
|
2026-05-04 17:58:10 +08:00
|
|
|
|
获取轻量级大模型服务(用于查询改写、意图分类等简单任务)
|
|
|
|
|
|
优先顺序: 本地模型 -> DeepSeek 小模型
|
|
|
|
|
|
⚠️ 注意:小模型任务不降级到大模型,避免不必要的 token 消耗!
|
2026-05-03 16:45:46 +08:00
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
BaseChatModel: LangChain 兼容的 ChatModel 实例
|
|
|
|
|
|
"""
|
|
|
|
|
|
def _create_small_chain():
|
2026-05-04 17:58:10 +08:00
|
|
|
|
primary = LocalSmallModelProvider()
|
2026-05-03 16:45:46 +08:00
|
|
|
|
fallbacks = [DeepSeekSmallModelProvider()]
|
|
|
|
|
|
return FallbackServiceChain(primary, fallbacks)
|
|
|
|
|
|
|
2026-05-04 17:58:10 +08:00
|
|
|
|
chain = SingletonServiceManager.get_or_create("small_llm_chain", _create_small_chain)
|
|
|
|
|
|
return chain.get_available_service()
|