model_handler.py 30 KB

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