model_handler.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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 server_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 == "deepseek":
  128. model = self._get_deepseek_model()
  129. elif model_type == "lq_qwen3_8b":
  130. model = self._get_lq_qwen3_8b_model()
  131. elif model_type == "lq_qwen3_8b_lq_lora":
  132. model = self._get_lq_qwen3_8b_lora_model()
  133. elif model_type == "lq_qwen3_4b":
  134. model = self._get_lq_qwen3_4b_model()
  135. elif model_type == "qwen_local_14b":
  136. model = self._get_qwen_local_14b_model()
  137. else:
  138. # 默认返回gemini
  139. logger.warning(f"未知的模型类型 '{model_type}',使用默认gemini模型")
  140. model = self._get_gemini_model()
  141. if model:
  142. self._model_cache[cache_key] = model
  143. logger.info(f"AI模型初始化完成: {model_type}")
  144. return model
  145. else:
  146. raise ModelAPIError(f"模型初始化返回None: {model_type}")
  147. except Exception as e:
  148. logger.error(f"获取模型失败 [{model_type}]: {e}")
  149. # 尝试使用gemini作为降级方案
  150. if model_type != "gemini":
  151. logger.info("尝试使用Gemini模型作为降级方案")
  152. try:
  153. fallback_model = self._get_gemini_model()
  154. if fallback_model:
  155. self._model_cache[cache_key] = fallback_model
  156. logger.warning(f"已切换到Gemini降级模型")
  157. return fallback_model
  158. except Exception as fallback_error:
  159. logger.error(f"降级模型也失败: {fallback_error}")
  160. # 如果所有模型都失败,抛出异常
  161. raise ModelConnectionError(f"无法初始化任何模型服务: {e}")
  162. def get_embedding_model(self):
  163. """
  164. 获取Embedding模型实例
  165. Returns:
  166. OpenAIEmbeddings: 配置好的Embedding模型实例
  167. Note:
  168. 根据配置文件中的EMBEDDING_MODEL_TYPE参数选择对应模型
  169. 支持的模型类型:lq_qwen3_8b_emd, siliconflow_embed
  170. 默认返回本地 lq_qwen3_8b_emd 模型
  171. """
  172. embedding_model_type = self.config.get("model", "EMBEDDING_MODEL_TYPE", "lq_qwen3_8b_emd")
  173. logger.info(f"正在初始化Embedding模型,模型类型: {embedding_model_type}")
  174. # 检查缓存
  175. cache_key = f"embed_{embedding_model_type}"
  176. if cache_key in self._model_cache:
  177. logger.info(f"使用缓存的Embedding模型: {embedding_model_type}")
  178. return self._model_cache[cache_key]
  179. model = None
  180. try:
  181. if embedding_model_type == "siliconflow_embed":
  182. model = self._get_siliconflow_embedding_model()
  183. elif embedding_model_type == "lq_qwen3_8b_emd":
  184. model = self._get_lq_qwen3_8b_emd()
  185. else:
  186. # 默认返回本地模型
  187. logger.warning(f"未知的Embedding模型类型 '{embedding_model_type}',使用默认本地模型")
  188. model = self._get_lq_qwen3_8b_emd()
  189. if model:
  190. self._model_cache[cache_key] = model
  191. logger.info(f"Embedding模型初始化完成: {embedding_model_type}")
  192. return model
  193. else:
  194. raise ModelAPIError(f"Embedding模型初始化返回None: {embedding_model_type}")
  195. except Exception as e:
  196. logger.error(f"获取Embedding模型失败 [{embedding_model_type}]: {e}")
  197. raise ModelConnectionError(f"无法初始化Embedding模型服务: {e}")
  198. def _get_doubao_model(self):
  199. """
  200. 获取豆包模型
  201. Returns:
  202. ChatOpenAI: 配置好的豆包模型实例
  203. """
  204. try:
  205. doubao_url = self.config.get("doubao", "DOUBAO_SERVER_URL")
  206. doubao_model_id = self.config.get("doubao", "DOUBAO_MODEL_ID")
  207. doubao_api_key = self.config.get("doubao", "DOUBAO_API_KEY")
  208. # 验证配置完整性
  209. if not all([doubao_url, doubao_model_id, doubao_api_key]):
  210. missing = []
  211. if not doubao_url:
  212. missing.append("DOUBAO_SERVER_URL")
  213. if not doubao_model_id:
  214. missing.append("DOUBAO_MODEL_ID")
  215. if not doubao_api_key:
  216. missing.append("DOUBAO_API_KEY")
  217. raise ModelConfigError(f"豆包模型配置不完整,缺少: {', '.join(missing)}")
  218. # 检查连接
  219. if not self._check_connection(doubao_url, doubao_api_key):
  220. logger.warning(f"豆包模型服务连接失败: {doubao_url}")
  221. raise ModelConnectionError(f"无法连接到豆包模型服务: {doubao_url}")
  222. llm = ChatOpenAI(
  223. base_url=doubao_url,
  224. model=doubao_model_id,
  225. api_key=doubao_api_key,
  226. temperature=0.7,
  227. timeout=self.REQUEST_TIMEOUT,
  228. extra_body={
  229. "enable_thinking": False,
  230. })
  231. logger.info(f"豆包模型初始化成功: {doubao_model_id}")
  232. return llm
  233. except ModelConfigError:
  234. raise
  235. except ModelConnectionError:
  236. raise
  237. except Exception as e:
  238. error = ModelAPIError(f"豆包模型初始化异常: {e}")
  239. return self._handle_model_error("doubao", error)
  240. def _get_qwen_model(self):
  241. """
  242. 获取通义千问模型
  243. Returns:
  244. ChatOpenAI: 配置好的通义千问模型实例
  245. """
  246. try:
  247. qwen_url = self.config.get("qwen", "QWEN_SERVER_URL")
  248. qwen_model_id = self.config.get("qwen", "QWEN_MODEL_ID")
  249. qwen_api_key = self.config.get("qwen", "QWEN_API_KEY")
  250. # 验证配置完整性
  251. if not all([qwen_url, qwen_model_id, qwen_api_key]):
  252. missing = []
  253. if not qwen_url:
  254. missing.append("QWEN_SERVER_URL")
  255. if not qwen_model_id:
  256. missing.append("QWEN_MODEL_ID")
  257. if not qwen_api_key:
  258. missing.append("QWEN_API_KEY")
  259. raise ModelConfigError(f"通义千问模型配置不完整,缺少: {', '.join(missing)}")
  260. # 检查连接
  261. if not self._check_connection(qwen_url, qwen_api_key):
  262. logger.warning(f"通义千问模型服务连接失败: {qwen_url}")
  263. raise ModelConnectionError(f"无法连接到通义千问模型服务: {qwen_url}")
  264. llm = ChatOpenAI(
  265. base_url=qwen_url,
  266. model=qwen_model_id,
  267. api_key=qwen_api_key,
  268. temperature=0.7,
  269. timeout=self.REQUEST_TIMEOUT,
  270. extra_body={
  271. "enable_thinking": False,
  272. })
  273. logger.info(f"通义千问模型初始化成功: {qwen_model_id}")
  274. return llm
  275. except ModelConfigError:
  276. raise
  277. except ModelConnectionError:
  278. raise
  279. except Exception as e:
  280. error = ModelAPIError(f"通义千问模型初始化异常: {e}")
  281. return self._handle_model_error("qwen", error)
  282. def _get_deepseek_model(self):
  283. """
  284. 获取DeepSeek模型
  285. Returns:
  286. ChatOpenAI: 配置好的DeepSeek模型实例
  287. """
  288. try:
  289. deepseek_url = self.config.get("deepseek", "DEEPSEEK_SERVER_URL")
  290. deepseek_model_id = self.config.get("deepseek", "DEEPSEEK_MODEL_ID")
  291. deepseek_api_key = self.config.get("deepseek", "DEEPSEEK_API_KEY")
  292. # 验证配置完整性
  293. if not all([deepseek_url, deepseek_model_id, deepseek_api_key]):
  294. missing = []
  295. if not deepseek_url:
  296. missing.append("DEEPSEEK_SERVER_URL")
  297. if not deepseek_model_id:
  298. missing.append("DEEPSEEK_MODEL_ID")
  299. if not deepseek_api_key:
  300. missing.append("DEEPSEEK_API_KEY")
  301. raise ModelConfigError(f"DeepSeek模型配置不完整,缺少: {', '.join(missing)}")
  302. # 检查连接
  303. if not self._check_connection(deepseek_url, deepseek_api_key):
  304. logger.warning(f"DeepSeek模型服务连接失败: {deepseek_url}")
  305. raise ModelConnectionError(f"无法连接到DeepSeek模型服务: {deepseek_url}")
  306. llm = ChatOpenAI(
  307. base_url=deepseek_url,
  308. model=deepseek_model_id,
  309. api_key=deepseek_api_key,
  310. temperature=0.7,
  311. timeout=self.REQUEST_TIMEOUT,
  312. extra_body={
  313. "enable_thinking": False,
  314. })
  315. logger.info(f"DeepSeek模型初始化成功: {deepseek_model_id}")
  316. return llm
  317. except ModelConfigError:
  318. raise
  319. except ModelConnectionError:
  320. raise
  321. except Exception as e:
  322. error = ModelAPIError(f"DeepSeek模型初始化异常: {e}")
  323. return self._handle_model_error("deepseek", error)
  324. def _get_gemini_model(self):
  325. """
  326. 获取Gemini模型
  327. Returns:
  328. ChatOpenAI: 配置好的Gemini模型实例
  329. """
  330. try:
  331. gemini_url = self.config.get("gemini", "GEMINI_SERVER_URL")
  332. gemini_model_id = self.config.get("gemini", "GEMINI_MODEL_ID")
  333. gemini_api_key = self.config.get("gemini", "GEMINI_API_KEY")
  334. # 验证配置完整性
  335. if not all([gemini_url, gemini_model_id, gemini_api_key]):
  336. missing = []
  337. if not gemini_url:
  338. missing.append("GEMINI_SERVER_URL")
  339. if not gemini_model_id:
  340. missing.append("GEMINI_MODEL_ID")
  341. if not gemini_api_key:
  342. missing.append("GEMINI_API_KEY")
  343. raise ModelConfigError(f"Gemini模型配置不完整,缺少: {', '.join(missing)}")
  344. # 检查连接
  345. if not self._check_connection(gemini_url, gemini_api_key):
  346. logger.warning(f"Gemini模型服务连接失败: {gemini_url}")
  347. raise ModelConnectionError(f"无法连接到Gemini模型服务: {gemini_url}")
  348. llm = ChatOpenAI(
  349. base_url=gemini_url,
  350. model=gemini_model_id,
  351. api_key=gemini_api_key,
  352. temperature=0.7,
  353. timeout=self.REQUEST_TIMEOUT,
  354. )
  355. logger.info(f"Gemini模型初始化成功: {gemini_model_id}")
  356. return llm
  357. except ModelConfigError:
  358. raise
  359. except ModelConnectionError:
  360. raise
  361. except Exception as e:
  362. error = ModelAPIError(f"Gemini模型初始化异常: {e}")
  363. return self._handle_model_error("gemini", error)
  364. def _get_lq_qwen3_8b_model(self):
  365. """
  366. 获取本地Qwen3-8B-Instruct模型
  367. Returns:
  368. ChatOpenAI: 配置好的本地Qwen3-8B模型实例
  369. """
  370. try:
  371. server_url = "http://192.168.91.253:9002/v1"
  372. model_id = "Qwen3-8B"
  373. # 检查本地服务连接
  374. if not self._check_connection(server_url, "dummy", timeout=3):
  375. logger.warning(f"本地Qwen3-8B模型服务连接失败: {server_url}")
  376. raise ModelConnectionError(f"无法连接到本地Qwen3-8B模型服务: {server_url}")
  377. llm = ChatOpenAI(
  378. base_url=server_url,
  379. model=model_id,
  380. api_key="dummy",
  381. temperature=0.7,
  382. timeout=self.REQUEST_TIMEOUT,
  383. )
  384. logger.info(f"本地Qwen3-8B模型初始化成功: {model_id}")
  385. return llm
  386. except ModelConnectionError:
  387. raise
  388. except Exception as e:
  389. error = ModelAPIError(f"本地Qwen3-8B模型初始化异常: {e}")
  390. return self._handle_model_error("lq_qwen3_8b", error)
  391. def _get_lq_qwen3_8b_lora_model(self):
  392. """
  393. 获取本地Qwen3-8B-lq-lora模型
  394. Returns:
  395. ChatOpenAI: 配置好的本地Qwen3-8B-lq-lora模型实例
  396. """
  397. try:
  398. server_url = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  399. model_id = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  400. api_key = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_API_KEY", "dummy")
  401. # 验证配置完整性
  402. if not all([server_url, model_id]):
  403. missing = []
  404. if not server_url:
  405. missing.append("LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  406. if not model_id:
  407. missing.append("LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  408. raise ModelConfigError(f"本地Qwen3-8B-lq-lora模型配置不完整,缺少: {', '.join(missing)}")
  409. # 检查本地服务连接
  410. if not self._check_connection(server_url, api_key, timeout=3):
  411. logger.warning(f"本地Qwen3-8B-lq-lora模型服务连接失败: {server_url}")
  412. raise ModelConnectionError(f"无法连接到本地Qwen3-8B-lq-lora模型服务: {server_url}")
  413. llm = ChatOpenAI(
  414. base_url=server_url,
  415. model=model_id,
  416. api_key=api_key,
  417. temperature=0.7,
  418. timeout=self.REQUEST_TIMEOUT,
  419. )
  420. logger.info(f"本地Qwen3-8B-lq-lora模型初始化成功: {model_id}")
  421. return llm
  422. except ModelConfigError:
  423. raise
  424. except ModelConnectionError:
  425. raise
  426. except Exception as e:
  427. error = ModelAPIError(f"本地Qwen3-8B-lq-lora模型初始化异常: {e}")
  428. return self._handle_model_error("lq_qwen3_8b_lora", error)
  429. def _get_lq_qwen3_4b_model(self):
  430. """
  431. 获取本地Qwen3-4B-Instruct模型
  432. Returns:
  433. ChatOpenAI: 配置好的本地Qwen3-4B模型实例
  434. """
  435. try:
  436. server_url = "http://192.168.91.253:9001/v1"
  437. model_id = "Qwen3-4B"
  438. # 检查本地服务连接
  439. if not self._check_connection(server_url, "dummy", timeout=3):
  440. logger.warning(f"本地Qwen3-4B模型服务连接失败: {server_url}")
  441. raise ModelConnectionError(f"无法连接到本地Qwen3-4B模型服务: {server_url}")
  442. llm = ChatOpenAI(
  443. base_url=server_url,
  444. model=model_id,
  445. api_key="dummy",
  446. temperature=0.7,
  447. timeout=self.REQUEST_TIMEOUT,
  448. )
  449. logger.info(f"本地Qwen3-4B模型初始化成功: {model_id}")
  450. return llm
  451. except ModelConnectionError:
  452. raise
  453. except Exception as e:
  454. error = ModelAPIError(f"本地Qwen3-4B模型初始化异常: {e}")
  455. return self._handle_model_error("lq_qwen3_4b", error)
  456. def _get_qwen_local_14b_model(self):
  457. """
  458. 获取本地Qwen3-14B-Instruct模型
  459. Returns:
  460. ChatOpenAI: 配置好的本地Qwen3-14B模型实例
  461. """
  462. try:
  463. server_url = "http://192.168.91.253:9003/v1"
  464. model_id = "Qwen3-14B"
  465. # 检查本地服务连接
  466. if not self._check_connection(server_url, "dummy", timeout=3):
  467. logger.warning(f"本地Qwen3-14B模型服务连接失败: {server_url}")
  468. raise ModelConnectionError(f"无法连接到本地Qwen3-14B模型服务: {server_url}")
  469. llm = ChatOpenAI(
  470. base_url=server_url,
  471. model=model_id,
  472. api_key="dummy",
  473. temperature=0.7,
  474. timeout=self.REQUEST_TIMEOUT,
  475. )
  476. logger.info(f"本地Qwen3-14B模型初始化成功: {model_id}")
  477. return llm
  478. except ModelConnectionError:
  479. raise
  480. except Exception as e:
  481. error = ModelAPIError(f"本地Qwen3-14B模型初始化异常: {e}")
  482. return self._handle_model_error("qwen_local_14b", error)
  483. def _get_lq_qwen3_8b_emd(self):
  484. """
  485. 获取本地Qwen3-Embedding-8B嵌入模型
  486. Returns:
  487. OpenAIEmbeddings: 配置好的本地Qwen3-Embedding-8B嵌入模型实例
  488. """
  489. try:
  490. server_url = "http://192.168.91.253:9003/v1"
  491. model_id = "Qwen3-Embedding-8B"
  492. # 检查本地服务连接
  493. if not self._check_connection(server_url, "dummy", timeout=3):
  494. logger.warning(f"本地Qwen3-Embedding-8B模型服务连接失败: {server_url}")
  495. raise ModelConnectionError(f"无法连接到本地Qwen3-Embedding-8B模型服务: {server_url}")
  496. # 使用 langchain_openai 的 OpenAIEmbeddings
  497. embeddings = OpenAIEmbeddings(
  498. base_url=server_url,
  499. model=model_id,
  500. api_key="dummy", # 本地模型使用虚拟API key
  501. timeout=self.REQUEST_TIMEOUT,
  502. )
  503. logger.info(f"本地Qwen3-Embedding-8B模型初始化成功: {model_id}")
  504. return embeddings
  505. except ModelConnectionError:
  506. raise
  507. except Exception as e:
  508. error = ModelAPIError(f"本地Qwen3-Embedding-8B模型初始化异常: {e}")
  509. return self._handle_model_error("lq_qwen3_8b_emd", error)
  510. def _get_siliconflow_embedding_model(self):
  511. """
  512. 获取硅基流动Qwen3-Embedding-8B嵌入模型
  513. Returns:
  514. OpenAIEmbeddings: 配置好的硅基流动Qwen3-Embedding-8B嵌入模型实例
  515. """
  516. try:
  517. server_url = self.config.get("siliconflow_embed", "SLCF_EMBED_SERVER_URL")
  518. api_key = self.config.get("siliconflow_embed", "SLCF_EMBED_API_KEY")
  519. model_id = self.config.get("siliconflow_embed", "SLCF_EMBED_MODEL_ID", "Qwen/Qwen3-Embedding-8B")
  520. dimensions = self.config.get("siliconflow_embed", "SLCF_EMBED_DIMENSIONS", "4096")
  521. # 验证配置完整性
  522. if not all([server_url, api_key, model_id]):
  523. missing = []
  524. if not server_url:
  525. missing.append("SLCF_EMBED_SERVER_URL")
  526. if not api_key:
  527. missing.append("SLCF_EMBED_API_KEY")
  528. if not model_id:
  529. missing.append("SLCF_EMBED_MODEL_ID")
  530. raise ModelConfigError(f"硅基流动Embedding模型配置不完整,缺少: {', '.join(missing)}")
  531. # 检查连接
  532. if not self._check_connection(server_url, api_key):
  533. logger.warning(f"硅基流动Embedding模型服务连接失败: {server_url}")
  534. raise ModelConnectionError(f"无法连接到硅基流动Embedding模型服务: {server_url}")
  535. # 使用 langchain_openai 的 OpenAIEmbeddings
  536. embeddings = OpenAIEmbeddings(
  537. base_url=server_url,
  538. model=model_id,
  539. api_key=api_key,
  540. timeout=self.REQUEST_TIMEOUT,
  541. )
  542. logger.info(f"硅基流动Embedding模型初始化成功: {model_id} (dimensions: {dimensions})")
  543. return embeddings
  544. except ModelConfigError:
  545. raise
  546. except ModelConnectionError:
  547. raise
  548. except Exception as e:
  549. error = ModelAPIError(f"硅基流动Embedding模型初始化异常: {e}")
  550. return self._handle_model_error("siliconflow_embed", error)
  551. # 创建全局实例
  552. model_handler = ModelHandler()
  553. def get_models():
  554. """
  555. 获取模型的全局函数
  556. Returns:
  557. tuple: (llm, chat, embed) - LLM模型、聊天模型和嵌入模型实例
  558. 注意:当前llm和chat使用相同模型实例,embed暂时返回None
  559. Note:
  560. 这是一个便捷函数,直接使用全局model_handler实例获取模型
  561. """
  562. try:
  563. llm = model_handler.get_models()
  564. # 暂时返回相同的模型作为chat和embed
  565. return llm, llm, None
  566. except Exception as e:
  567. logger.error(f"获取模型失败: {e}")
  568. raise ModelConnectionError(f"无法获取模型服务: {e}")