model_handler.py 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. AI模型处理器
  5. 用于管理生成、与嵌入模型的创建和配置
  6. 支持的模型类型:
  7. - doubao: 豆包模型
  8. - qwen: 通义千问模型
  9. - deepseek: DeepSeek模型
  10. - gemini: Gemini模型
  11. - lq_qwen3_8b: 本地Qwen3-8B模型
  12. - lq_qwen3_8b_lq_lora: 本地Qwen3-8B-lq-lora模型
  13. - lq_qwen3_4b: 本地Qwen3-4B模型
  14. - qwen_local_14b: 本地Qwen3-14B模型
  15. - lq_qwen3_8b_emd: 本地Qwen3-Embedding-8B嵌入模型
  16. - siliconflow_embed: 硅基流动Qwen3-Embedding-8B嵌入模型
  17. - lq_bge_reranker_v2_m3: 本地BGE-reranker-v2-m3重排序模型
  18. - qwen3_5_35b_a3b: DashScope Qwen3.5-35B-A3B模型
  19. - qwen3_5_27b: DashScope Qwen3.5-27B模型
  20. - qwen3_5_122b_a10b: DashScope Qwen3.5-122B-A10B模型
  21. """
  22. # 禁用 transformers 的深度学习框架检测,避免启动时耗时扫描
  23. import os
  24. os.environ["TRANSFORMERS_VERBOSITY"] = "error"
  25. os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1"
  26. import requests
  27. from langchain_openai import ChatOpenAI, OpenAIEmbeddings
  28. from foundation.infrastructure.config.config import config_handler
  29. from foundation.observability.logger.loggering import review_logger as logger
  30. class ModelConnectionError(Exception):
  31. """模型连接错误"""
  32. pass
  33. class ModelConfigError(Exception):
  34. """模型配置错误"""
  35. pass
  36. class ModelAPIError(Exception):
  37. """模型API调用错误"""
  38. pass
  39. class ModelHandler:
  40. """
  41. AI模型处理器类,用于管理多种AI模型的创建和配置
  42. """
  43. # 模型连接超时时间配置(秒)
  44. CONNECTION_TIMEOUT = 30
  45. REQUEST_TIMEOUT = 120
  46. MAX_RETRIES = 2
  47. def __init__(self):
  48. """
  49. 初始化模型处理器
  50. 加载配置处理器,用于后续读取各种模型的配置信息
  51. """
  52. self.config = config_handler
  53. self._model_cache = {} # 模型实例缓存
  54. def _check_connection(self, base_url: str, api_key: str = None, timeout: int = 5) -> bool:
  55. """
  56. 检查模型服务连接是否可用
  57. Args:
  58. base_url: 模型服务地址
  59. api_key: API密钥(可选)
  60. timeout: 超时时间(秒)
  61. Returns:
  62. bool: 连接是否可用
  63. """
  64. try:
  65. # 构造健康检查URL
  66. health_url = f"{base_url.rstrip('/')}/models"
  67. headers = {}
  68. if api_key and api_key != "dummy":
  69. headers["Authorization"] = f"Bearer {api_key}"
  70. response = requests.get(
  71. health_url,
  72. headers=headers,
  73. timeout=timeout
  74. )
  75. # 200-299 都认为可用
  76. return 200 <= response.status_code < 300
  77. except requests.exceptions.Timeout:
  78. logger.warning(f"连接超时: {base_url}")
  79. return False
  80. except requests.exceptions.ConnectionError as e:
  81. logger.warning(f"连接错误: {base_url}, 错误: {e}")
  82. return False
  83. except Exception as e:
  84. logger.warning(f"连接检查异常: {base_url}, 错误: {e}")
  85. return False
  86. def _handle_model_error(self, model_name: str, error: Exception, fallback_model=None):
  87. """
  88. 统一处理模型错误
  89. Args:
  90. model_name: 模型名称
  91. error: 异常对象
  92. fallback_model: 降级模型实例(可选)
  93. Returns:
  94. 降级模型实例,如果不可用则返回None
  95. """
  96. error_type = type(error).__name__
  97. error_msg = str(error)
  98. logger.error(f"模型初始化失败 [{model_name}]: {error_type} - {error_msg}")
  99. # 如果提供了降级模型,记录日志并返回
  100. if fallback_model:
  101. logger.warning(f"使用降级模型: {fallback_model.__class__.__name__}")
  102. return fallback_model
  103. # 如果没有降级模型,返回None让调用方处理
  104. return None
  105. def get_models(self):
  106. """
  107. 获取AI模型实例
  108. Returns:
  109. ChatOpenAI: 配置好的AI模型实例
  110. Note:
  111. 根据配置文件中的MODEL_TYPE参数选择对应模型
  112. 支持的模型类型:doubao, qwen, deepseek, lq_qwen3_8b, lq_qwen3_8b_lora, lq_qwen3_4b, qwen_local_14b
  113. 默认返回豆包模型
  114. """
  115. model_type = self.config.get("model", "MODEL_TYPE")
  116. logger.info(f"正在初始化AI模型,模型类型: {model_type}")
  117. # 检查缓存
  118. cache_key = f"chat_{model_type}"
  119. if cache_key in self._model_cache:
  120. logger.info(f"使用缓存的模型: {model_type}")
  121. return self._model_cache[cache_key]
  122. model = None
  123. try:
  124. if model_type == "doubao":
  125. model = self._get_doubao_model()
  126. elif model_type == "gemini":
  127. model = self._get_gemini_model()
  128. elif model_type == "qwen":
  129. model = self._get_qwen_model()
  130. elif model_type == "qwen3_30b":
  131. model = self._get_qwen3_30b_model()
  132. elif model_type == "deepseek":
  133. model = self._get_deepseek_model()
  134. elif model_type == "lq_qwen3_8b":
  135. model = self._get_lq_qwen3_8b_model()
  136. elif model_type == "lq_qwen3_8b_lq_lora":
  137. model = self._get_lq_qwen3_8b_lora_model()
  138. elif model_type == "lq_qwen3_4b":
  139. model = self._get_lq_qwen3_4b_model()
  140. elif model_type == "qwen_local_14b":
  141. model = self._get_qwen_local_14b_model()
  142. elif model_type == "qwen3_5_35b_a3b":
  143. model = self._get_qwen3_5_35b_a3b_model()
  144. elif model_type == "qwen3_5_27b":
  145. model = self._get_qwen3_5_27b_model()
  146. elif model_type == "qwen3_5_122b_a10b":
  147. model = self._get_qwen3_5_122b_a10b_model()
  148. else:
  149. # 默认返回gemini
  150. logger.warning(f"未知的模型类型 '{model_type}',使用默认gemini模型")
  151. model = self._get_gemini_model()
  152. if model:
  153. self._model_cache[cache_key] = model
  154. logger.info(f"AI模型初始化完成: {model_type}")
  155. return model
  156. else:
  157. raise ModelAPIError(f"模型初始化返回None: {model_type}")
  158. except Exception as e:
  159. logger.error(f"获取模型失败 [{model_type}]: {e}")
  160. # 尝试使用gemini作为降级方案
  161. if model_type != "gemini":
  162. logger.info("尝试使用Gemini模型作为降级方案")
  163. try:
  164. fallback_model = self._get_gemini_model()
  165. if fallback_model:
  166. self._model_cache[cache_key] = fallback_model
  167. logger.warning(f"已切换到Gemini降级模型")
  168. return fallback_model
  169. except Exception as fallback_error:
  170. logger.error(f"降级模型也失败: {fallback_error}")
  171. # 如果所有模型都失败,抛出异常
  172. raise ModelConnectionError(f"无法初始化任何模型服务: {e}")
  173. def get_model_by_name(self, model_type: str = None):
  174. """
  175. 根据模型名称动态获取指定的AI模型实例
  176. Args:
  177. model_type: 模型类型名称,如果为None则使用配置文件中的默认模型
  178. 支持的模型类型:doubao, qwen, qwen3_30b, deepseek, gemini,
  179. lq_qwen3_8b, lq_qwen3_8b_lq_lora,
  180. lq_qwen3_4b, qwen_local_14b
  181. Returns:
  182. ChatOpenAI: 配置好的AI模型实例
  183. Note:
  184. 该方法支持动态切换模型,不受配置文件中的默认MODEL_TYPE限制
  185. 如果model_type为None,则使用配置文件中的默认模型
  186. 如果model_type无效,则使用gemini作为降级模型
  187. """
  188. # 如果未指定模型类型,使用配置文件中的默认模型
  189. if model_type is None:
  190. model_type = self.config.get("model", "MODEL_TYPE")
  191. logger.info(f"动态获取AI模型,模型类型: {model_type}")
  192. # 检查缓存
  193. cache_key = f"chat_{model_type}"
  194. if cache_key in self._model_cache:
  195. logger.info(f"使用缓存的模型: {model_type}")
  196. return self._model_cache[cache_key]
  197. model = None
  198. try:
  199. if model_type == "doubao":
  200. model = self._get_doubao_model()
  201. elif model_type == "gemini":
  202. model = self._get_gemini_model()
  203. elif model_type == "qwen":
  204. model = self._get_qwen_model()
  205. elif model_type == "qwen3_30b":
  206. model = self._get_qwen3_30b_model()
  207. elif model_type == "deepseek":
  208. model = self._get_deepseek_model()
  209. elif model_type == "lq_qwen3_8b":
  210. model = self._get_lq_qwen3_8b_model()
  211. elif model_type == "lq_qwen3_8b_lq_lora":
  212. model = self._get_lq_qwen3_8b_lora_model()
  213. elif model_type == "lq_qwen3_4b":
  214. model = self._get_lq_qwen3_4b_model()
  215. elif model_type == "qwen_local_14b":
  216. model = self._get_qwen_local_14b_model()
  217. elif model_type == "qwen3_5_35b_a3b":
  218. model = self._get_qwen3_5_35b_a3b_model()
  219. elif model_type == "qwen3_5_27b":
  220. model = self._get_qwen3_5_27b_model()
  221. elif model_type == "qwen3_5_122b_a10b":
  222. model = self._get_qwen3_5_122b_a10b_model()
  223. else:
  224. # 默认返回gemini
  225. logger.warning(f"未知的模型类型 '{model_type}',使用默认gemini模型")
  226. model = self._get_gemini_model()
  227. if model:
  228. self._model_cache[cache_key] = model
  229. logger.info(f"AI模型动态初始化完成: {model_type}")
  230. return model
  231. else:
  232. raise ModelAPIError(f"模型初始化返回None: {model_type}")
  233. except Exception as e:
  234. logger.error(f"动态获取模型失败 [{model_type}]: {e}")
  235. # 尝试使用gemini作为降级方案
  236. if model_type != "gemini":
  237. logger.info("尝试使用Gemini模型作为降级方案")
  238. try:
  239. fallback_model = self._get_gemini_model()
  240. if fallback_model:
  241. self._model_cache[cache_key] = fallback_model
  242. logger.warning(f"已切换到Gemini降级模型")
  243. return fallback_model
  244. except Exception as fallback_error:
  245. logger.error(f"降级模型也失败: {fallback_error}")
  246. # 如果所有模型都失败,抛出异常
  247. raise ModelConnectionError(f"无法初始化任何模型服务: {e}")
  248. def get_embedding_model(self):
  249. """
  250. 获取Embedding模型实例
  251. Returns:
  252. OpenAIEmbeddings: 配置好的Embedding模型实例
  253. Note:
  254. 根据配置文件中的EMBEDDING_MODEL_TYPE参数选择对应模型
  255. 支持的模型类型:lq_qwen3_8b_emd, siliconflow_embed
  256. 默认返回本地 lq_qwen3_8b_emd 模型
  257. """
  258. embedding_model_type = self.config.get("model", "EMBEDDING_MODEL_TYPE", "lq_qwen3_8b_emd")
  259. logger.info(f"正在初始化Embedding模型,模型类型: {embedding_model_type}")
  260. # 检查缓存
  261. cache_key = f"embed_{embedding_model_type}"
  262. if cache_key in self._model_cache:
  263. logger.info(f"使用缓存的Embedding模型: {embedding_model_type}")
  264. return self._model_cache[cache_key]
  265. model = None
  266. try:
  267. if embedding_model_type == "siliconflow_embed":
  268. model = self._get_siliconflow_embedding_model()
  269. elif embedding_model_type == "lq_qwen3_8b_emd":
  270. model = self._get_lq_qwen3_8b_emd()
  271. else:
  272. # 默认返回本地模型
  273. logger.warning(f"未知的Embedding模型类型 '{embedding_model_type}',使用默认本地模型")
  274. model = self._get_lq_qwen3_8b_emd()
  275. if model:
  276. self._model_cache[cache_key] = model
  277. logger.info(f"Embedding模型初始化完成: {embedding_model_type}")
  278. return model
  279. else:
  280. raise ModelAPIError(f"Embedding模型初始化返回None: {embedding_model_type}")
  281. except Exception as e:
  282. logger.error(f"获取Embedding模型失败 [{embedding_model_type}]: {e}")
  283. raise ModelConnectionError(f"无法初始化Embedding模型服务: {e}")
  284. def _get_doubao_model(self):
  285. """
  286. 获取豆包模型
  287. Returns:
  288. ChatOpenAI: 配置好的豆包模型实例
  289. """
  290. try:
  291. doubao_url = self.config.get("doubao", "DOUBAO_SERVER_URL")
  292. doubao_model_id = self.config.get("doubao", "DOUBAO_MODEL_ID")
  293. doubao_api_key = self.config.get("doubao", "DOUBAO_API_KEY")
  294. # 验证配置完整性
  295. if not all([doubao_url, doubao_model_id, doubao_api_key]):
  296. missing = []
  297. if not doubao_url:
  298. missing.append("DOUBAO_SERVER_URL")
  299. if not doubao_model_id:
  300. missing.append("DOUBAO_MODEL_ID")
  301. if not doubao_api_key:
  302. missing.append("DOUBAO_API_KEY")
  303. raise ModelConfigError(f"豆包模型配置不完整,缺少: {', '.join(missing)}")
  304. # 检查连接
  305. if not self._check_connection(doubao_url, doubao_api_key):
  306. logger.warning(f"豆包模型服务连接失败: {doubao_url}")
  307. raise ModelConnectionError(f"无法连接到豆包模型服务: {doubao_url}")
  308. llm = ChatOpenAI(
  309. base_url=doubao_url,
  310. model=doubao_model_id,
  311. api_key=doubao_api_key,
  312. temperature=0.7,
  313. timeout=self.REQUEST_TIMEOUT,
  314. extra_body={
  315. "enable_thinking": False,
  316. })
  317. logger.info(f"豆包模型初始化成功: {doubao_model_id}")
  318. return llm
  319. except ModelConfigError:
  320. raise
  321. except ModelConnectionError:
  322. raise
  323. except Exception as e:
  324. error = ModelAPIError(f"豆包模型初始化异常: {e}")
  325. return self._handle_model_error("doubao", error)
  326. def _get_qwen_model(self):
  327. """
  328. 获取通义千问模型
  329. Returns:
  330. ChatOpenAI: 配置好的通义千问模型实例
  331. """
  332. try:
  333. qwen_url = self.config.get("qwen", "QWEN_SERVER_URL")
  334. qwen_model_id = self.config.get("qwen", "QWEN_MODEL_ID")
  335. qwen_api_key = self.config.get("qwen", "QWEN_API_KEY")
  336. # 验证配置完整性
  337. if not all([qwen_url, qwen_model_id, qwen_api_key]):
  338. missing = []
  339. if not qwen_url:
  340. missing.append("QWEN_SERVER_URL")
  341. if not qwen_model_id:
  342. missing.append("QWEN_MODEL_ID")
  343. if not qwen_api_key:
  344. missing.append("QWEN_API_KEY")
  345. raise ModelConfigError(f"通义千问模型配置不完整,缺少: {', '.join(missing)}")
  346. # 检查连接
  347. if not self._check_connection(qwen_url, qwen_api_key):
  348. logger.warning(f"通义千问模型服务连接失败: {qwen_url}")
  349. raise ModelConnectionError(f"无法连接到通义千问模型服务: {qwen_url}")
  350. llm = ChatOpenAI(
  351. base_url=qwen_url,
  352. model=qwen_model_id,
  353. api_key=qwen_api_key,
  354. temperature=0.7,
  355. timeout=self.REQUEST_TIMEOUT,
  356. extra_body={
  357. "enable_thinking": False,
  358. })
  359. logger.info(f"通义千问模型初始化成功: {qwen_model_id}")
  360. return llm
  361. except ModelConfigError:
  362. raise
  363. except ModelConnectionError:
  364. raise
  365. except Exception as e:
  366. error = ModelAPIError(f"通义千问模型初始化异常: {e}")
  367. return self._handle_model_error("qwen", error)
  368. def _get_qwen3_30b_model(self):
  369. """
  370. 获取Qwen3-30B模型
  371. Returns:
  372. ChatOpenAI: 配置好的Qwen3-30B模型实例
  373. """
  374. try:
  375. qwen3_30b_url = self.config.get("qwen3_30b", "QWEN3_30B_SERVER_URL")
  376. qwen3_30b_model_id = self.config.get("qwen3_30b", "QWEN3_30B_MODEL_ID")
  377. qwen3_30b_api_key = self.config.get("qwen3_30b", "QWEN3_30B_API_KEY")
  378. # 验证配置完整性
  379. if not all([qwen3_30b_url, qwen3_30b_model_id, qwen3_30b_api_key]):
  380. missing = []
  381. if not qwen3_30b_url:
  382. missing.append("QWEN3_30B_SERVER_URL")
  383. if not qwen3_30b_model_id:
  384. missing.append("QWEN3_30B_MODEL_ID")
  385. if not qwen3_30b_api_key:
  386. missing.append("QWEN3_30B_API_KEY")
  387. raise ModelConfigError(f"Qwen3-30B模型配置不完整,缺少: {', '.join(missing)}")
  388. # 检查连接
  389. if not self._check_connection(qwen3_30b_url, qwen3_30b_api_key):
  390. logger.warning(f"Qwen3-30B模型服务连接失败: {qwen3_30b_url}")
  391. raise ModelConnectionError(f"无法连接到Qwen3-30B模型服务: {qwen3_30b_url}")
  392. llm = ChatOpenAI(
  393. base_url=qwen3_30b_url,
  394. model=qwen3_30b_model_id,
  395. api_key=qwen3_30b_api_key,
  396. temperature=0.7,
  397. timeout=self.REQUEST_TIMEOUT,
  398. extra_body={
  399. "enable_thinking": False,
  400. })
  401. logger.info(f"Qwen3-30B模型初始化成功: {qwen3_30b_model_id}")
  402. return llm
  403. except ModelConfigError:
  404. raise
  405. except ModelConnectionError:
  406. raise
  407. except Exception as e:
  408. error = ModelAPIError(f"Qwen3-30B模型初始化异常: {e}")
  409. return self._handle_model_error("qwen3_30b", error)
  410. def _get_deepseek_model(self):
  411. """
  412. 获取DeepSeek模型
  413. Returns:
  414. ChatOpenAI: 配置好的DeepSeek模型实例
  415. """
  416. try:
  417. deepseek_url = self.config.get("deepseek", "DEEPSEEK_SERVER_URL")
  418. deepseek_model_id = self.config.get("deepseek", "DEEPSEEK_MODEL_ID")
  419. deepseek_api_key = self.config.get("deepseek", "DEEPSEEK_API_KEY")
  420. # 验证配置完整性
  421. if not all([deepseek_url, deepseek_model_id, deepseek_api_key]):
  422. missing = []
  423. if not deepseek_url:
  424. missing.append("DEEPSEEK_SERVER_URL")
  425. if not deepseek_model_id:
  426. missing.append("DEEPSEEK_MODEL_ID")
  427. if not deepseek_api_key:
  428. missing.append("DEEPSEEK_API_KEY")
  429. raise ModelConfigError(f"DeepSeek模型配置不完整,缺少: {', '.join(missing)}")
  430. # 检查连接
  431. if not self._check_connection(deepseek_url, deepseek_api_key):
  432. logger.warning(f"DeepSeek模型服务连接失败: {deepseek_url}")
  433. raise ModelConnectionError(f"无法连接到DeepSeek模型服务: {deepseek_url}")
  434. llm = ChatOpenAI(
  435. base_url=deepseek_url,
  436. model=deepseek_model_id,
  437. api_key=deepseek_api_key,
  438. temperature=0.7,
  439. timeout=self.REQUEST_TIMEOUT,
  440. extra_body={
  441. "enable_thinking": False,
  442. })
  443. logger.info(f"DeepSeek模型初始化成功: {deepseek_model_id}")
  444. return llm
  445. except ModelConfigError:
  446. raise
  447. except ModelConnectionError:
  448. raise
  449. except Exception as e:
  450. error = ModelAPIError(f"DeepSeek模型初始化异常: {e}")
  451. return self._handle_model_error("deepseek", error)
  452. def _get_gemini_model(self):
  453. """
  454. 获取Gemini模型
  455. Returns:
  456. ChatOpenAI: 配置好的Gemini模型实例
  457. """
  458. try:
  459. gemini_url = self.config.get("gemini", "GEMINI_SERVER_URL")
  460. gemini_model_id = self.config.get("gemini", "GEMINI_MODEL_ID")
  461. gemini_api_key = self.config.get("gemini", "GEMINI_API_KEY")
  462. # 验证配置完整性
  463. if not all([gemini_url, gemini_model_id, gemini_api_key]):
  464. missing = []
  465. if not gemini_url:
  466. missing.append("GEMINI_SERVER_URL")
  467. if not gemini_model_id:
  468. missing.append("GEMINI_MODEL_ID")
  469. if not gemini_api_key:
  470. missing.append("GEMINI_API_KEY")
  471. raise ModelConfigError(f"Gemini模型配置不完整,缺少: {', '.join(missing)}")
  472. # 检查连接
  473. if not self._check_connection(gemini_url, gemini_api_key):
  474. logger.warning(f"Gemini模型服务连接失败: {gemini_url}")
  475. raise ModelConnectionError(f"无法连接到Gemini模型服务: {gemini_url}")
  476. llm = ChatOpenAI(
  477. base_url=gemini_url,
  478. model=gemini_model_id,
  479. api_key=gemini_api_key,
  480. temperature=0.7,
  481. timeout=self.REQUEST_TIMEOUT,
  482. )
  483. logger.info(f"Gemini模型初始化成功: {gemini_model_id}")
  484. return llm
  485. except ModelConfigError:
  486. raise
  487. except ModelConnectionError:
  488. raise
  489. except Exception as e:
  490. error = ModelAPIError(f"Gemini模型初始化异常: {e}")
  491. return self._handle_model_error("gemini", error)
  492. def _get_lq_qwen3_8b_model(self):
  493. """
  494. 获取本地Qwen3-8B-Instruct模型
  495. Returns:
  496. ChatOpenAI: 配置好的本地Qwen3-8B模型实例
  497. """
  498. try:
  499. server_url = "http://192.168.91.253:9002/v1"
  500. model_id = "Qwen3-8B"
  501. # 检查本地服务连接
  502. if not self._check_connection(server_url, "dummy", timeout=3):
  503. logger.warning(f"本地Qwen3-8B模型服务连接失败: {server_url}")
  504. raise ModelConnectionError(f"无法连接到本地Qwen3-8B模型服务: {server_url}")
  505. llm = ChatOpenAI(
  506. base_url=server_url,
  507. model=model_id,
  508. api_key="dummy",
  509. temperature=0.7,
  510. timeout=self.REQUEST_TIMEOUT,
  511. )
  512. logger.info(f"本地Qwen3-8B模型初始化成功: {model_id}")
  513. return llm
  514. except ModelConnectionError:
  515. raise
  516. except Exception as e:
  517. error = ModelAPIError(f"本地Qwen3-8B模型初始化异常: {e}")
  518. return self._handle_model_error("lq_qwen3_8b", error)
  519. def _get_lq_qwen3_8b_lora_model(self):
  520. """
  521. 获取本地Qwen3-8B-lq-lora模型
  522. Returns:
  523. ChatOpenAI: 配置好的本地Qwen3-8B-lq-lora模型实例
  524. """
  525. try:
  526. server_url = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  527. model_id = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  528. api_key = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_API_KEY", "dummy")
  529. # 验证配置完整性
  530. if not all([server_url, model_id]):
  531. missing = []
  532. if not server_url:
  533. missing.append("LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  534. if not model_id:
  535. missing.append("LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  536. raise ModelConfigError(f"本地Qwen3-8B-lq-lora模型配置不完整,缺少: {', '.join(missing)}")
  537. # 检查本地服务连接
  538. if not self._check_connection(server_url, api_key, timeout=3):
  539. logger.warning(f"本地Qwen3-8B-lq-lora模型服务连接失败: {server_url}")
  540. raise ModelConnectionError(f"无法连接到本地Qwen3-8B-lq-lora模型服务: {server_url}")
  541. llm = ChatOpenAI(
  542. base_url=server_url,
  543. model=model_id,
  544. api_key=api_key,
  545. temperature=0.7,
  546. timeout=self.REQUEST_TIMEOUT,
  547. )
  548. logger.info(f"本地Qwen3-8B-lq-lora模型初始化成功: {model_id}")
  549. return llm
  550. except ModelConfigError:
  551. raise
  552. except ModelConnectionError:
  553. raise
  554. except Exception as e:
  555. error = ModelAPIError(f"本地Qwen3-8B-lq-lora模型初始化异常: {e}")
  556. return self._handle_model_error("lq_qwen3_8b_lora", error)
  557. def _get_lq_qwen3_4b_model(self):
  558. """
  559. 获取本地Qwen3-4B-Instruct模型
  560. Returns:
  561. ChatOpenAI: 配置好的本地Qwen3-4B模型实例
  562. """
  563. try:
  564. server_url = "http://192.168.91.253:9001/v1"
  565. model_id = "Qwen3-4B"
  566. # 检查本地服务连接
  567. if not self._check_connection(server_url, "dummy", timeout=3):
  568. logger.warning(f"本地Qwen3-4B模型服务连接失败: {server_url}")
  569. raise ModelConnectionError(f"无法连接到本地Qwen3-4B模型服务: {server_url}")
  570. llm = ChatOpenAI(
  571. base_url=server_url,
  572. model=model_id,
  573. api_key="dummy",
  574. temperature=0.7,
  575. timeout=self.REQUEST_TIMEOUT,
  576. )
  577. logger.info(f"本地Qwen3-4B模型初始化成功: {model_id}")
  578. return llm
  579. except ModelConnectionError:
  580. raise
  581. except Exception as e:
  582. error = ModelAPIError(f"本地Qwen3-4B模型初始化异常: {e}")
  583. return self._handle_model_error("lq_qwen3_4b", error)
  584. def _get_qwen_local_14b_model(self):
  585. """
  586. 获取本地Qwen3-14B-Instruct模型
  587. Returns:
  588. ChatOpenAI: 配置好的本地Qwen3-14B模型实例
  589. """
  590. try:
  591. server_url = "http://192.168.91.253:9003/v1"
  592. model_id = "Qwen3-14B"
  593. # 检查本地服务连接
  594. if not self._check_connection(server_url, "dummy", timeout=3):
  595. logger.warning(f"本地Qwen3-14B模型服务连接失败: {server_url}")
  596. raise ModelConnectionError(f"无法连接到本地Qwen3-14B模型服务: {server_url}")
  597. llm = ChatOpenAI(
  598. base_url=server_url,
  599. model=model_id,
  600. api_key="dummy",
  601. temperature=0.7,
  602. timeout=self.REQUEST_TIMEOUT,
  603. )
  604. logger.info(f"本地Qwen3-14B模型初始化成功: {model_id}")
  605. return llm
  606. except ModelConnectionError:
  607. raise
  608. except Exception as e:
  609. error = ModelAPIError(f"本地Qwen3-14B模型初始化异常: {e}")
  610. return self._handle_model_error("qwen_local_14b", error)
  611. def _get_qwen3_5_35b_a3b_model(self):
  612. """
  613. 获取 DashScope Qwen3.5-35B-A3B 模型
  614. Returns:
  615. ChatOpenAI: 配置好的 DashScope Qwen3.5-35B-A3B 模型实例
  616. """
  617. try:
  618. url = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_SERVER_URL")
  619. model_id = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_MODEL_ID")
  620. api_key = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_API_KEY")
  621. # 验证配置完整性
  622. if not all([url, model_id, api_key]):
  623. missing = []
  624. if not url:
  625. missing.append("DASHSCOPE_SERVER_URL")
  626. if not model_id:
  627. missing.append("DASHSCOPE_MODEL_ID")
  628. if not api_key:
  629. missing.append("DASHSCOPE_API_KEY")
  630. raise ModelConfigError(f"DashScope Qwen3.5-35B 模型配置不完整,缺少: {', '.join(missing)}")
  631. llm = ChatOpenAI(
  632. base_url=url,
  633. model=model_id,
  634. api_key=api_key,
  635. temperature=0.7,
  636. timeout=self.REQUEST_TIMEOUT,
  637. )
  638. logger.info(f"DashScope Qwen3.5-35B 模型初始化成功: {model_id}")
  639. return llm
  640. except ModelConfigError:
  641. raise
  642. except Exception as e:
  643. return self._handle_model_error("qwen3_5_35b_a3b", ModelAPIError(str(e)))
  644. def _get_qwen3_5_27b_model(self):
  645. """
  646. 获取 DashScope Qwen3.5-27B 模型
  647. Returns:
  648. ChatOpenAI: 配置好的 DashScope Qwen3.5-27B 模型实例
  649. """
  650. try:
  651. url = self.config.get("qwen3_5_27b", "DASHSCOPE_SERVER_URL")
  652. model_id = self.config.get("qwen3_5_27b", "DASHSCOPE_MODEL_ID")
  653. api_key = self.config.get("qwen3_5_27b", "DASHSCOPE_API_KEY")
  654. # 验证配置完整性
  655. if not all([url, model_id, api_key]):
  656. missing = []
  657. if not url:
  658. missing.append("DASHSCOPE_SERVER_URL")
  659. if not model_id:
  660. missing.append("DASHSCOPE_MODEL_ID")
  661. if not api_key:
  662. missing.append("DASHSCOPE_API_KEY")
  663. raise ModelConfigError(f"DashScope Qwen3.5-27B 模型配置不完整,缺少: {', '.join(missing)}")
  664. llm = ChatOpenAI(
  665. base_url=url,
  666. model=model_id,
  667. api_key=api_key,
  668. temperature=0.7,
  669. timeout=self.REQUEST_TIMEOUT,
  670. )
  671. logger.info(f"DashScope Qwen3.5-27B 模型初始化成功: {model_id}")
  672. return llm
  673. except ModelConfigError:
  674. raise
  675. except Exception as e:
  676. return self._handle_model_error("qwen3_5_27b", ModelAPIError(str(e)))
  677. def _get_qwen3_5_122b_a10b_model(self):
  678. """
  679. 获取 DashScope Qwen3.5-122B-A10B 模型
  680. Returns:
  681. ChatOpenAI: 配置好的 DashScope Qwen3.5-122B-A10B 模型实例
  682. """
  683. try:
  684. url = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_SERVER_URL")
  685. model_id = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_MODEL_ID")
  686. api_key = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_API_KEY")
  687. # 验证配置完整性
  688. if not all([url, model_id, api_key]):
  689. missing = []
  690. if not url:
  691. missing.append("DASHSCOPE_SERVER_URL")
  692. if not model_id:
  693. missing.append("DASHSCOPE_MODEL_ID")
  694. if not api_key:
  695. missing.append("DASHSCOPE_API_KEY")
  696. raise ModelConfigError(f"DashScope Qwen3.5-122B 模型配置不完整,缺少: {', '.join(missing)}")
  697. llm = ChatOpenAI(
  698. base_url=url,
  699. model=model_id,
  700. api_key=api_key,
  701. temperature=0.7,
  702. timeout=self.REQUEST_TIMEOUT,
  703. )
  704. logger.info(f"DashScope Qwen3.5-122B 模型初始化成功: {model_id}")
  705. return llm
  706. except ModelConfigError:
  707. raise
  708. except Exception as e:
  709. return self._handle_model_error("qwen3_5_122b_a10b", ModelAPIError(str(e)))
  710. def _get_lq_qwen3_8b_emd(self):
  711. """
  712. 获取本地Qwen3-Embedding-8B嵌入模型
  713. Returns:
  714. OpenAIEmbeddings: 配置好的本地Qwen3-Embedding-8B嵌入模型实例
  715. """
  716. try:
  717. server_url = "http://192.168.91.253:9003/v1"
  718. model_id = "Qwen3-Embedding-8B"
  719. # 检查本地服务连接
  720. if not self._check_connection(server_url, "dummy", timeout=3):
  721. logger.warning(f"本地Qwen3-Embedding-8B模型服务连接失败: {server_url}")
  722. raise ModelConnectionError(f"无法连接到本地Qwen3-Embedding-8B模型服务: {server_url}")
  723. # 使用 langchain_openai 的 OpenAIEmbeddings
  724. embeddings = OpenAIEmbeddings(
  725. base_url=server_url,
  726. model=model_id,
  727. api_key="dummy", # 本地模型使用虚拟API key
  728. timeout=self.REQUEST_TIMEOUT,
  729. )
  730. logger.info(f"本地Qwen3-Embedding-8B模型初始化成功: {model_id}")
  731. return embeddings
  732. except ModelConnectionError:
  733. raise
  734. except Exception as e:
  735. error = ModelAPIError(f"本地Qwen3-Embedding-8B模型初始化异常: {e}")
  736. return self._handle_model_error("lq_qwen3_8b_emd", error)
  737. def _get_siliconflow_embedding_model(self):
  738. """
  739. 获取硅基流动Qwen3-Embedding-8B嵌入模型
  740. Returns:
  741. OpenAIEmbeddings: 配置好的硅基流动Qwen3-Embedding-8B嵌入模型实例
  742. """
  743. try:
  744. server_url = self.config.get("siliconflow_embed", "SLCF_EMBED_SERVER_URL")
  745. api_key = self.config.get("siliconflow_embed", "SLCF_EMBED_API_KEY")
  746. model_id = self.config.get("siliconflow_embed", "SLCF_EMBED_MODEL_ID", "Qwen/Qwen3-Embedding-8B")
  747. dimensions = self.config.get("siliconflow_embed", "SLCF_EMBED_DIMENSIONS", "4096")
  748. # 验证配置完整性
  749. if not all([server_url, api_key, model_id]):
  750. missing = []
  751. if not server_url:
  752. missing.append("SLCF_EMBED_SERVER_URL")
  753. if not api_key:
  754. missing.append("SLCF_EMBED_API_KEY")
  755. if not model_id:
  756. missing.append("SLCF_EMBED_MODEL_ID")
  757. raise ModelConfigError(f"硅基流动Embedding模型配置不完整,缺少: {', '.join(missing)}")
  758. # 检查连接
  759. if not self._check_connection(server_url, api_key):
  760. logger.warning(f"硅基流动Embedding模型服务连接失败: {server_url}")
  761. raise ModelConnectionError(f"无法连接到硅基流动Embedding模型服务: {server_url}")
  762. # 使用 langchain_openai 的 OpenAIEmbeddings
  763. embeddings = OpenAIEmbeddings(
  764. base_url=server_url,
  765. model=model_id,
  766. api_key=api_key,
  767. timeout=self.REQUEST_TIMEOUT,
  768. )
  769. logger.info(f"硅基流动Embedding模型初始化成功: {model_id} (dimensions: {dimensions})")
  770. return embeddings
  771. except ModelConfigError:
  772. raise
  773. except ModelConnectionError:
  774. raise
  775. except Exception as e:
  776. error = ModelAPIError(f"硅基流动Embedding模型初始化异常: {e}")
  777. return self._handle_model_error("siliconflow_embed", error)
  778. # 创建全局实例
  779. model_handler = ModelHandler()
  780. def get_models():
  781. """
  782. 获取模型的全局函数
  783. Returns:
  784. tuple: (llm, chat, embed) - LLM模型、聊天模型和嵌入模型实例
  785. 注意:当前llm和chat使用相同模型实例,embed暂时返回None
  786. Note:
  787. 这是一个便捷函数,直接使用全局model_handler实例获取模型
  788. """
  789. try:
  790. llm = model_handler.get_models()
  791. # 暂时返回相同的模型作为chat和embed
  792. return llm, llm, None
  793. except Exception as e:
  794. logger.error(f"获取模型失败: {e}")
  795. raise ModelConnectionError(f"无法获取模型服务: {e}")