model_handler.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. AI模型处理器
  5. 用于管理生成、与嵌入模型的创建和配置
  6. 支持的模型类型:
  7. - doubao: 豆包模型
  8. - qwen: 通义千问模型
  9. - deepseek: DeepSeek模型
  10. - lq_qwen3_8b: 本地Qwen3-8B模型
  11. - lq_qwen3_8b_lq_lora: 本地Qwen3-8B-lq-lora模型
  12. - lq_qwen3_4b: 本地Qwen3-4B模型
  13. - qwen_local_14b: 本地Qwen3-14B模型
  14. - lq_qwen3_8b_emd: 本地Qwen3-Embedding-8B嵌入模型
  15. - siliconflow_embed: 硅基流动Qwen3-Embedding-8B嵌入模型
  16. - lq_bge_reranker_v2_m3: 本地BGE-reranker-v2-m3重排序模型
  17. - qwen3_5_35b_a3b: DashScope Qwen3.5-35B-A3B模型(默认兜底模型)
  18. - qwen3_5_27b: DashScope Qwen3.5-27B模型
  19. - qwen3_5_122b_a10b: DashScope Qwen3.5-122B-A10B模型
  20. - shutian_qwen3_5_122b: 蜀天Qwen3.5-122B-A10B模型(183.220.37.46:25423)
  21. - shutian_qwen3_8b: 蜀天Qwen3-8B模型(183.220.37.46:25424)
  22. - shutian_qwen3_5_35b: 蜀天Qwen3.5-35B模型(183.220.37.46:25427)
  23. - shutian_qwen3_embed: 蜀天Qwen3-Embedding-8B模型(183.220.37.46:25425)
  24. - shutian_qwen3_reranker: 蜀天Qwen3-Reranker-8B模型(183.220.37.46:25426)
  25. """
  26. # 禁用 transformers 的深度学习框架检测,避免启动时耗时扫描
  27. import os
  28. os.environ["TRANSFORMERS_VERBOSITY"] = "error"
  29. os.environ["HF_HUB_DISABLE_TELEMETRY"] = "1"
  30. import requests
  31. from langchain_openai import ChatOpenAI, OpenAIEmbeddings
  32. from foundation.infrastructure.config.config import config_handler
  33. from foundation.observability.logger.loggering import review_logger as logger
  34. class ModelConnectionError(Exception):
  35. """模型连接错误"""
  36. pass
  37. class ModelConfigError(Exception):
  38. """模型配置错误"""
  39. pass
  40. class ModelAPIError(Exception):
  41. """模型API调用错误"""
  42. pass
  43. class ModelHandler:
  44. """
  45. AI模型处理器类,用于管理多种AI模型的创建和配置
  46. """
  47. # 模型连接超时时间配置(秒)
  48. CONNECTION_TIMEOUT = 30
  49. REQUEST_TIMEOUT = 120
  50. MAX_RETRIES = 2
  51. def __init__(self):
  52. """
  53. 初始化模型处理器
  54. 加载配置处理器,用于后续读取各种模型的配置信息
  55. """
  56. self.config = config_handler
  57. self._model_cache = {} # 模型实例缓存
  58. def _check_connection(self, base_url: str, api_key: str = None, timeout: int = 5) -> bool:
  59. """
  60. 检查模型服务连接是否可用
  61. 支持两种检查方式:
  62. 1. GET /models - 标准 OpenAI 兼容接口
  63. 2. POST /chat/completions - 直接测试 chat 接口(部分服务只支持此接口)
  64. Args:
  65. base_url: 模型服务地址
  66. api_key: API密钥(可选)
  67. timeout: 超时时间(秒)
  68. Returns:
  69. bool: 连接是否可用
  70. """
  71. headers = {}
  72. if api_key and api_key != "dummy":
  73. headers["Authorization"] = f"Bearer {api_key}"
  74. # 方法1: 尝试 /models 端点
  75. try:
  76. health_url = f"{base_url.rstrip('/')}/models"
  77. response = requests.get(
  78. health_url,
  79. headers=headers,
  80. timeout=timeout
  81. )
  82. if 200 <= response.status_code < 300:
  83. logger.debug(f"连接检查通过 (/models): {base_url}")
  84. return True
  85. except requests.exceptions.Timeout:
  86. logger.debug(f"连接检查超时 (/models): {base_url}")
  87. except Exception as e:
  88. logger.debug(f"连接检查失败 (/models): {base_url}, {e}")
  89. # 方法2: 尝试 /chat/completions 端点(发送一个简单请求)
  90. try:
  91. chat_url = f"{base_url.rstrip('/')}/chat/completions"
  92. test_payload = {
  93. "model": "test",
  94. "messages": [{"role": "user", "content": "test"}],
  95. "max_tokens": 1
  96. }
  97. response = requests.post(
  98. chat_url,
  99. headers={**headers, "Content-Type": "application/json"},
  100. json=test_payload,
  101. timeout=timeout
  102. )
  103. # 即使返回 400/401/404 也说明服务是通的
  104. # 只有连接错误/超时才是真的连不上
  105. if response.status_code != 503: # 503 表示服务不可用
  106. logger.debug(f"连接检查通过 (/chat/completions): {base_url}, 状态码: {response.status_code}")
  107. return True
  108. except requests.exceptions.Timeout:
  109. logger.warning(f"连接检查超时: {base_url}")
  110. except requests.exceptions.ConnectionError as e:
  111. logger.warning(f"连接检查错误: {base_url}, {e}")
  112. except Exception as e:
  113. logger.warning(f"连接检查异常: {base_url}, {e}")
  114. return False
  115. def _handle_model_error(self, model_name: str, error: Exception, fallback_model=None):
  116. """
  117. 统一处理模型错误
  118. Args:
  119. model_name: 模型名称
  120. error: 异常对象
  121. fallback_model: 降级模型实例(可选)
  122. Returns:
  123. 降级模型实例,如果不可用则返回None
  124. """
  125. error_type = type(error).__name__
  126. error_msg = str(error)
  127. logger.error(f"模型初始化失败 [{model_name}]: {error_type} - {error_msg}")
  128. # 如果提供了降级模型,记录日志并返回
  129. if fallback_model:
  130. logger.warning(f"使用降级模型: {fallback_model.__class__.__name__}")
  131. return fallback_model
  132. # 如果没有降级模型,返回None让调用方处理
  133. return None
  134. def get_models(self):
  135. """
  136. 获取AI模型实例
  137. Returns:
  138. ChatOpenAI: 配置好的AI模型实例
  139. Note:
  140. 优先从 model_setting.yaml 读取默认模型配置,如果不存在则回退到 config.ini 的 MODEL_TYPE
  141. 支持的模型类型:doubao, qwen, deepseek, lq_qwen3_8b, lq_qwen3_8b_lora, lq_qwen3_4b, qwen_local_14b
  142. """
  143. # 优先从 model_setting.yaml 读取默认模型配置
  144. try:
  145. from foundation.ai.models.model_config_loader import get_model_for_function
  146. model_type = get_model_for_function("default")
  147. if model_type:
  148. logger.debug(f"从 model_setting.yaml 读取默认模型: {model_type}")
  149. else:
  150. model_type = self.config.get("model", "MODEL_TYPE")
  151. except Exception as e:
  152. logger.debug(f"从 model_setting.yaml 读取默认模型失败: {e},回退到 config.ini")
  153. model_type = self.config.get("model", "MODEL_TYPE")
  154. logger.info(f"正在初始化AI模型,模型类型: {model_type}")
  155. # 检查缓存
  156. cache_key = f"chat_{model_type}"
  157. if cache_key in self._model_cache:
  158. logger.info(f"使用缓存的模型: {model_type}")
  159. return self._model_cache[cache_key]
  160. model = None
  161. try:
  162. if model_type == "doubao":
  163. model = self._get_doubao_model()
  164. elif model_type == "qwen":
  165. model = self._get_qwen_model()
  166. elif model_type == "qwen3_30b":
  167. model = self._get_qwen3_30b_model()
  168. elif model_type == "deepseek":
  169. model = self._get_deepseek_model()
  170. elif model_type == "lq_qwen3_8b":
  171. model = self._get_lq_qwen3_8b_model()
  172. elif model_type == "lq_qwen3_8b_lq_lora":
  173. model = self._get_lq_qwen3_8b_lora_model()
  174. elif model_type == "lq_qwen3_4b":
  175. model = self._get_lq_qwen3_4b_model()
  176. elif model_type == "qwen_local_14b":
  177. model = self._get_qwen_local_14b_model()
  178. elif model_type == "qwen3_5_35b_a3b":
  179. model = self._get_qwen3_5_35b_a3b_model()
  180. elif model_type == "qwen3_5_27b":
  181. model = self._get_qwen3_5_27b_model()
  182. elif model_type == "qwen3_5_122b_a10b":
  183. model = self._get_qwen3_5_122b_a10b_model()
  184. elif model_type == "shutian_qwen3_5_122b":
  185. model = self._get_shutian_qwen3_5_122b_model()
  186. elif model_type == "shutian_qwen3_8b":
  187. model = self._get_shutian_qwen3_8b_model()
  188. elif model_type == "shutian_qwen3_5_35b":
  189. model = self._get_shutian_qwen3_5_35b_model()
  190. else:
  191. logger.warning(f"未知的模型类型 '{model_type}',使用默认 qwen3_5_35b_a3b 模型")
  192. model = self._get_qwen3_5_35b_a3b_model()
  193. if model:
  194. self._model_cache[cache_key] = model
  195. logger.info(f"AI模型初始化完成: {model_type}")
  196. return model
  197. else:
  198. raise ModelAPIError(f"模型初始化返回None: {model_type}")
  199. except Exception as e:
  200. logger.error(f"获取模型失败 [{model_type}]: {e}")
  201. # 使用 qwen3_5_35b_a3b 作为兜底降级方案
  202. if model_type != "qwen3_5_35b_a3b":
  203. logger.info("尝试使用 qwen3_5_35b_a3b 模型作为降级方案")
  204. try:
  205. fallback_model = self._get_qwen3_5_35b_a3b_model()
  206. if fallback_model:
  207. self._model_cache[cache_key] = fallback_model
  208. logger.warning("已切换到 qwen3_5_35b_a3b 降级模型")
  209. return fallback_model
  210. except Exception as fallback_error:
  211. logger.error(f"降级模型也失败: {fallback_error}")
  212. # 如果所有模型都失败,抛出异常
  213. raise ModelConnectionError(f"无法初始化任何模型服务: {e}")
  214. def get_model_by_name(self, model_type: str = None):
  215. """
  216. 根据模型名称动态获取指定的AI模型实例
  217. Args:
  218. model_type: 模型类型名称,如果为None则使用配置文件中的默认模型
  219. 支持的模型类型:doubao, qwen, qwen3_30b, deepseek, gemini,
  220. lq_qwen3_8b, lq_qwen3_8b_lq_lora,
  221. lq_qwen3_4b, qwen_local_14b
  222. Returns:
  223. ChatOpenAI: 配置好的AI模型实例
  224. Note:
  225. 该方法支持动态切换模型,不受配置文件中的默认MODEL_TYPE限制
  226. 如果model_type为None,则使用配置文件中的默认模型
  227. 如果model_type无效,则使用gemini作为降级模型
  228. """
  229. # 如果未指定模型类型,使用配置文件中的默认模型
  230. if model_type is None:
  231. model_type = self.config.get("model", "MODEL_TYPE")
  232. logger.info(f"动态获取AI模型,模型类型: {model_type}")
  233. # 检查缓存
  234. cache_key = f"chat_{model_type}"
  235. if cache_key in self._model_cache:
  236. logger.info(f"使用缓存的模型: {model_type}")
  237. return self._model_cache[cache_key]
  238. model = None
  239. try:
  240. if model_type == "doubao":
  241. model = self._get_doubao_model()
  242. elif model_type == "qwen":
  243. model = self._get_qwen_model()
  244. elif model_type == "qwen3_30b":
  245. model = self._get_qwen3_30b_model()
  246. elif model_type == "deepseek":
  247. model = self._get_deepseek_model()
  248. elif model_type == "lq_qwen3_8b":
  249. model = self._get_lq_qwen3_8b_model()
  250. elif model_type == "lq_qwen3_8b_lq_lora":
  251. model = self._get_lq_qwen3_8b_lora_model()
  252. elif model_type == "lq_qwen3_4b":
  253. model = self._get_lq_qwen3_4b_model()
  254. elif model_type == "qwen_local_14b":
  255. model = self._get_qwen_local_14b_model()
  256. elif model_type == "qwen3_5_35b_a3b":
  257. model = self._get_qwen3_5_35b_a3b_model()
  258. elif model_type == "qwen3_5_27b":
  259. model = self._get_qwen3_5_27b_model()
  260. elif model_type == "qwen3_5_122b_a10b":
  261. model = self._get_qwen3_5_122b_a10b_model()
  262. elif model_type == "shutian_qwen3_5_122b":
  263. model = self._get_shutian_qwen3_5_122b_model()
  264. elif model_type == "shutian_qwen3_8b":
  265. model = self._get_shutian_qwen3_8b_model()
  266. elif model_type == "shutian_qwen3_5_35b":
  267. model = self._get_shutian_qwen3_5_35b_model()
  268. else:
  269. logger.warning(f"未知的模型类型 '{model_type}',使用默认 qwen3_5_35b_a3b 模型")
  270. model = self._get_qwen3_5_35b_a3b_model()
  271. if model:
  272. self._model_cache[cache_key] = model
  273. logger.info(f"AI模型动态初始化完成: {model_type}")
  274. return model
  275. else:
  276. raise ModelAPIError(f"模型初始化返回None: {model_type}")
  277. except Exception as e:
  278. logger.error(f"动态获取模型失败 [{model_type}]: {e}")
  279. # 使用 qwen3_5_35b_a3b 作为兜底降级方案
  280. if model_type != "qwen3_5_35b_a3b":
  281. logger.info("尝试使用 qwen3_5_35b_a3b 模型作为降级方案")
  282. try:
  283. fallback_model = self._get_qwen3_5_35b_a3b_model()
  284. if fallback_model:
  285. # 注意:不要把降级模型存入原模型的缓存,避免后续调用都使用错误的模型
  286. fallback_cache_key = "chat_qwen3_5_35b_a3b"
  287. self._model_cache[fallback_cache_key] = fallback_model
  288. logger.warning(f"已切换到 qwen3_5_35b_a3b 降级模型(不会缓存为 {model_type})")
  289. return fallback_model
  290. except Exception as fallback_error:
  291. logger.error(f"降级模型也失败: {fallback_error}")
  292. # 如果所有模型都失败,抛出异常
  293. raise ModelConnectionError(f"无法初始化任何模型服务: {e}")
  294. def get_model_by_function(self, function_name: str):
  295. """
  296. 根据功能名称获取对应的AI模型实例
  297. 从 config/model_setting.yaml 加载功能对应的模型配置
  298. Args:
  299. function_name: 功能名称,如:
  300. - doc_classification_secondary: 文档二级分类
  301. - doc_classification_tertiary: 文档三级分类
  302. - completeness_review_generate: 完整性审查生成
  303. - completeness_review_classify: 完整性审查分类
  304. - rag_query_understand: RAG查询理解
  305. - rag_answer_generate: RAG答案生成
  306. - sensitive_check: 敏感信息检查
  307. - grammar_check: 语法检查
  308. Returns:
  309. ChatOpenAI: 配置好的AI模型实例
  310. Example:
  311. model = model_handler.get_model_by_function("doc_classification_tertiary")
  312. """
  313. try:
  314. from foundation.ai.models.model_config_loader import get_model_for_function
  315. model_type = get_model_for_function(function_name)
  316. logger.info(f"根据功能 '{function_name}' 获取模型: {model_type}")
  317. return self.get_model_by_name(model_type)
  318. except Exception as e:
  319. logger.warning(f"根据功能获取模型失败 [{function_name}]: {e},使用默认模型")
  320. return self.get_model_by_name("qwen3_5_35b_a3b")
  321. def get_embedding_model(self):
  322. """
  323. 获取Embedding模型实例
  324. Returns:
  325. OpenAIEmbeddings: 配置好的Embedding模型实例
  326. Note:
  327. 根据配置文件中的EMBEDDING_MODEL_TYPE参数选择对应模型
  328. 支持的模型类型:lq_qwen3_8b_emd, siliconflow_embed
  329. 默认返回本地 lq_qwen3_8b_emd 模型
  330. """
  331. # 优先从 model_setting.yaml 读取embedding配置
  332. embedding_model_type = None
  333. try:
  334. from .model_config_loader import model_config_loader
  335. settings = model_config_loader._config.get("model_settings", {})
  336. embedding_config = settings.get("embedding", {})
  337. if embedding_config and "model" in embedding_config:
  338. embedding_model_type = embedding_config["model"]
  339. logger.debug(f"从 model_setting.yaml 读取embedding模型: {embedding_model_type}")
  340. except Exception as e:
  341. logger.debug(f"从 model_setting.yaml 读取embedding配置失败: {e}")
  342. # 回退到 config.ini
  343. if not embedding_model_type:
  344. embedding_model_type = self.config.get("model", "EMBEDDING_MODEL_TYPE", "lq_qwen3_8b_emd")
  345. logger.info(f"正在初始化Embedding模型,模型类型: {embedding_model_type}")
  346. # 检查缓存
  347. cache_key = f"embed_{embedding_model_type}"
  348. if cache_key in self._model_cache:
  349. logger.info(f"使用缓存的Embedding模型: {embedding_model_type}")
  350. return self._model_cache[cache_key]
  351. model = None
  352. try:
  353. if embedding_model_type == "siliconflow_embed":
  354. model = self._get_siliconflow_embedding_model()
  355. elif embedding_model_type == "lq_qwen3_8b_emd":
  356. model = self._get_lq_qwen3_8b_emd()
  357. elif embedding_model_type == "shutian_qwen3_embed":
  358. model = self._get_shutian_qwen3_embed()
  359. else:
  360. # 默认返回本地模型
  361. logger.warning(f"未知的Embedding模型类型 '{embedding_model_type}',使用默认本地模型")
  362. model = self._get_lq_qwen3_8b_emd()
  363. if model:
  364. self._model_cache[cache_key] = model
  365. logger.info(f"Embedding模型初始化完成: {embedding_model_type}")
  366. return model
  367. else:
  368. raise ModelAPIError(f"Embedding模型初始化返回None: {embedding_model_type}")
  369. except (ModelConnectionError, Exception) as e:
  370. # 如果配置的模型是本地模型且连接失败,自动回退到蜀天Embedding
  371. if embedding_model_type == "lq_qwen3_8b_emd":
  372. logger.warning(f"本地Embedding模型连接失败,自动回退到蜀天Embedding: {e}")
  373. try:
  374. model = self._get_shutian_qwen3_embed()
  375. if model:
  376. self._model_cache["embed_shutian_qwen3_embed"] = model
  377. logger.info("Embedding模型回退成功: shutian_qwen3_embed")
  378. return model
  379. except Exception as fallback_e:
  380. logger.error(f"回退到蜀天Embedding也失败: {fallback_e}")
  381. logger.error(f"获取Embedding模型失败 [{embedding_model_type}]: {e}")
  382. raise ModelConnectionError(f"无法初始化Embedding模型服务: {e}")
  383. def _get_doubao_model(self):
  384. """
  385. 获取豆包模型
  386. Returns:
  387. ChatOpenAI: 配置好的豆包模型实例
  388. """
  389. try:
  390. doubao_url = self.config.get("doubao", "DOUBAO_SERVER_URL")
  391. doubao_model_id = self.config.get("doubao", "DOUBAO_MODEL_ID")
  392. doubao_api_key = self.config.get("doubao", "DOUBAO_API_KEY")
  393. # 验证配置完整性
  394. if not all([doubao_url, doubao_model_id, doubao_api_key]):
  395. missing = []
  396. if not doubao_url:
  397. missing.append("DOUBAO_SERVER_URL")
  398. if not doubao_model_id:
  399. missing.append("DOUBAO_MODEL_ID")
  400. if not doubao_api_key:
  401. missing.append("DOUBAO_API_KEY")
  402. raise ModelConfigError(f"豆包模型配置不完整,缺少: {', '.join(missing)}")
  403. # 检查连接
  404. if not self._check_connection(doubao_url, doubao_api_key):
  405. logger.warning(f"豆包模型服务连接失败: {doubao_url}")
  406. raise ModelConnectionError(f"无法连接到豆包模型服务: {doubao_url}")
  407. llm = ChatOpenAI(
  408. base_url=doubao_url,
  409. model=doubao_model_id,
  410. api_key=doubao_api_key,
  411. temperature=0.7,
  412. timeout=self.REQUEST_TIMEOUT,
  413. extra_body={
  414. "enable_thinking": False,
  415. })
  416. logger.info(f"豆包模型初始化成功: {doubao_model_id}")
  417. return llm
  418. except ModelConfigError:
  419. raise
  420. except ModelConnectionError:
  421. raise
  422. except Exception as e:
  423. error = ModelAPIError(f"豆包模型初始化异常: {e}")
  424. return self._handle_model_error("doubao", error)
  425. def _get_qwen_model(self):
  426. """
  427. 获取通义千问模型
  428. Returns:
  429. ChatOpenAI: 配置好的通义千问模型实例
  430. """
  431. try:
  432. qwen_url = self.config.get("qwen", "QWEN_SERVER_URL")
  433. qwen_model_id = self.config.get("qwen", "QWEN_MODEL_ID")
  434. qwen_api_key = self.config.get("qwen", "QWEN_API_KEY")
  435. # 验证配置完整性
  436. if not all([qwen_url, qwen_model_id, qwen_api_key]):
  437. missing = []
  438. if not qwen_url:
  439. missing.append("QWEN_SERVER_URL")
  440. if not qwen_model_id:
  441. missing.append("QWEN_MODEL_ID")
  442. if not qwen_api_key:
  443. missing.append("QWEN_API_KEY")
  444. raise ModelConfigError(f"通义千问模型配置不完整,缺少: {', '.join(missing)}")
  445. # 检查连接
  446. if not self._check_connection(qwen_url, qwen_api_key):
  447. logger.warning(f"通义千问模型服务连接失败: {qwen_url}")
  448. raise ModelConnectionError(f"无法连接到通义千问模型服务: {qwen_url}")
  449. llm = ChatOpenAI(
  450. base_url=qwen_url,
  451. model=qwen_model_id,
  452. api_key=qwen_api_key,
  453. temperature=0.7,
  454. timeout=self.REQUEST_TIMEOUT,
  455. extra_body={
  456. "enable_thinking": False,
  457. })
  458. logger.info(f"通义千问模型初始化成功: {qwen_model_id}")
  459. return llm
  460. except ModelConfigError:
  461. raise
  462. except ModelConnectionError:
  463. raise
  464. except Exception as e:
  465. error = ModelAPIError(f"通义千问模型初始化异常: {e}")
  466. return self._handle_model_error("qwen", error)
  467. def _get_qwen3_30b_model(self):
  468. """
  469. 获取Qwen3-30B模型
  470. Returns:
  471. ChatOpenAI: 配置好的Qwen3-30B模型实例
  472. """
  473. try:
  474. qwen3_30b_url = self.config.get("qwen3_30b", "QWEN3_30B_SERVER_URL")
  475. qwen3_30b_model_id = self.config.get("qwen3_30b", "QWEN3_30B_MODEL_ID")
  476. qwen3_30b_api_key = self.config.get("qwen3_30b", "QWEN3_30B_API_KEY")
  477. # 验证配置完整性
  478. if not all([qwen3_30b_url, qwen3_30b_model_id, qwen3_30b_api_key]):
  479. missing = []
  480. if not qwen3_30b_url:
  481. missing.append("QWEN3_30B_SERVER_URL")
  482. if not qwen3_30b_model_id:
  483. missing.append("QWEN3_30B_MODEL_ID")
  484. if not qwen3_30b_api_key:
  485. missing.append("QWEN3_30B_API_KEY")
  486. raise ModelConfigError(f"Qwen3-30B模型配置不完整,缺少: {', '.join(missing)}")
  487. # 检查连接
  488. if not self._check_connection(qwen3_30b_url, qwen3_30b_api_key):
  489. logger.warning(f"Qwen3-30B模型服务连接失败: {qwen3_30b_url}")
  490. raise ModelConnectionError(f"无法连接到Qwen3-30B模型服务: {qwen3_30b_url}")
  491. llm = ChatOpenAI(
  492. base_url=qwen3_30b_url,
  493. model=qwen3_30b_model_id,
  494. api_key=qwen3_30b_api_key,
  495. temperature=0.7,
  496. timeout=self.REQUEST_TIMEOUT,
  497. extra_body={
  498. "enable_thinking": False,
  499. })
  500. logger.info(f"Qwen3-30B模型初始化成功: {qwen3_30b_model_id}")
  501. return llm
  502. except ModelConfigError:
  503. raise
  504. except ModelConnectionError:
  505. raise
  506. except Exception as e:
  507. error = ModelAPIError(f"Qwen3-30B模型初始化异常: {e}")
  508. return self._handle_model_error("qwen3_30b", error)
  509. def _get_deepseek_model(self):
  510. """
  511. 获取DeepSeek模型
  512. Returns:
  513. ChatOpenAI: 配置好的DeepSeek模型实例
  514. """
  515. try:
  516. deepseek_url = self.config.get("deepseek", "DEEPSEEK_SERVER_URL")
  517. deepseek_model_id = self.config.get("deepseek", "DEEPSEEK_MODEL_ID")
  518. deepseek_api_key = self.config.get("deepseek", "DEEPSEEK_API_KEY")
  519. # 验证配置完整性
  520. if not all([deepseek_url, deepseek_model_id, deepseek_api_key]):
  521. missing = []
  522. if not deepseek_url:
  523. missing.append("DEEPSEEK_SERVER_URL")
  524. if not deepseek_model_id:
  525. missing.append("DEEPSEEK_MODEL_ID")
  526. if not deepseek_api_key:
  527. missing.append("DEEPSEEK_API_KEY")
  528. raise ModelConfigError(f"DeepSeek模型配置不完整,缺少: {', '.join(missing)}")
  529. # 检查连接
  530. if not self._check_connection(deepseek_url, deepseek_api_key):
  531. logger.warning(f"DeepSeek模型服务连接失败: {deepseek_url}")
  532. raise ModelConnectionError(f"无法连接到DeepSeek模型服务: {deepseek_url}")
  533. llm = ChatOpenAI(
  534. base_url=deepseek_url,
  535. model=deepseek_model_id,
  536. api_key=deepseek_api_key,
  537. temperature=0.7,
  538. timeout=self.REQUEST_TIMEOUT,
  539. extra_body={
  540. "enable_thinking": False,
  541. })
  542. logger.info(f"DeepSeek模型初始化成功: {deepseek_model_id}")
  543. return llm
  544. except ModelConfigError:
  545. raise
  546. except ModelConnectionError:
  547. raise
  548. except Exception as e:
  549. error = ModelAPIError(f"DeepSeek模型初始化异常: {e}")
  550. return self._handle_model_error("deepseek", error)
  551. def _get_lq_qwen3_8b_model(self):
  552. """
  553. 获取本地Qwen3-8B-Instruct模型
  554. Returns:
  555. ChatOpenAI: 配置好的本地Qwen3-8B模型实例
  556. """
  557. try:
  558. server_url = "http://192.168.91.253:9002/v1"
  559. model_id = "Qwen3-8B"
  560. # 检查本地服务连接
  561. if not self._check_connection(server_url, "dummy", timeout=3):
  562. logger.warning(f"本地Qwen3-8B模型服务连接失败: {server_url}")
  563. raise ModelConnectionError(f"无法连接到本地Qwen3-8B模型服务: {server_url}")
  564. llm = ChatOpenAI(
  565. base_url=server_url,
  566. model=model_id,
  567. api_key="dummy",
  568. temperature=0.7,
  569. timeout=self.REQUEST_TIMEOUT,
  570. )
  571. logger.info(f"本地Qwen3-8B模型初始化成功: {model_id}")
  572. return llm
  573. except ModelConnectionError:
  574. raise
  575. except Exception as e:
  576. error = ModelAPIError(f"本地Qwen3-8B模型初始化异常: {e}")
  577. return self._handle_model_error("lq_qwen3_8b", error)
  578. def _get_lq_qwen3_8b_lora_model(self):
  579. """
  580. 获取本地Qwen3-8B-lq-lora模型
  581. Returns:
  582. ChatOpenAI: 配置好的本地Qwen3-8B-lq-lora模型实例
  583. """
  584. try:
  585. server_url = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  586. model_id = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  587. api_key = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_API_KEY", "dummy")
  588. # 验证配置完整性
  589. if not all([server_url, model_id]):
  590. missing = []
  591. if not server_url:
  592. missing.append("LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  593. if not model_id:
  594. missing.append("LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  595. raise ModelConfigError(f"本地Qwen3-8B-lq-lora模型配置不完整,缺少: {', '.join(missing)}")
  596. # 检查本地服务连接
  597. if not self._check_connection(server_url, api_key, timeout=3):
  598. logger.warning(f"本地Qwen3-8B-lq-lora模型服务连接失败: {server_url}")
  599. raise ModelConnectionError(f"无法连接到本地Qwen3-8B-lq-lora模型服务: {server_url}")
  600. llm = ChatOpenAI(
  601. base_url=server_url,
  602. model=model_id,
  603. api_key=api_key,
  604. temperature=0.7,
  605. timeout=self.REQUEST_TIMEOUT,
  606. )
  607. logger.info(f"本地Qwen3-8B-lq-lora模型初始化成功: {model_id}")
  608. return llm
  609. except ModelConfigError:
  610. raise
  611. except ModelConnectionError:
  612. raise
  613. except Exception as e:
  614. error = ModelAPIError(f"本地Qwen3-8B-lq-lora模型初始化异常: {e}")
  615. return self._handle_model_error("lq_qwen3_8b_lora", error)
  616. def _get_lq_qwen3_4b_model(self):
  617. """
  618. 获取本地Qwen3-4B-Instruct模型
  619. Returns:
  620. ChatOpenAI: 配置好的本地Qwen3-4B模型实例
  621. """
  622. try:
  623. server_url = "http://192.168.91.253:9001/v1"
  624. model_id = "Qwen3-4B"
  625. # 检查本地服务连接
  626. if not self._check_connection(server_url, "dummy", timeout=3):
  627. logger.warning(f"本地Qwen3-4B模型服务连接失败: {server_url}")
  628. raise ModelConnectionError(f"无法连接到本地Qwen3-4B模型服务: {server_url}")
  629. llm = ChatOpenAI(
  630. base_url=server_url,
  631. model=model_id,
  632. api_key="dummy",
  633. temperature=0.7,
  634. timeout=self.REQUEST_TIMEOUT,
  635. )
  636. logger.info(f"本地Qwen3-4B模型初始化成功: {model_id}")
  637. return llm
  638. except ModelConnectionError:
  639. raise
  640. except Exception as e:
  641. error = ModelAPIError(f"本地Qwen3-4B模型初始化异常: {e}")
  642. return self._handle_model_error("lq_qwen3_4b", error)
  643. def _get_qwen_local_14b_model(self):
  644. """
  645. 获取本地Qwen3-14B-Instruct模型
  646. Returns:
  647. ChatOpenAI: 配置好的本地Qwen3-14B模型实例
  648. """
  649. try:
  650. server_url = "http://192.168.91.253:9003/v1"
  651. model_id = "Qwen3-14B"
  652. # 检查本地服务连接
  653. if not self._check_connection(server_url, "dummy", timeout=3):
  654. logger.warning(f"本地Qwen3-14B模型服务连接失败: {server_url}")
  655. raise ModelConnectionError(f"无法连接到本地Qwen3-14B模型服务: {server_url}")
  656. llm = ChatOpenAI(
  657. base_url=server_url,
  658. model=model_id,
  659. api_key="dummy",
  660. temperature=0.7,
  661. timeout=self.REQUEST_TIMEOUT,
  662. )
  663. logger.info(f"本地Qwen3-14B模型初始化成功: {model_id}")
  664. return llm
  665. except ModelConnectionError:
  666. raise
  667. except Exception as e:
  668. error = ModelAPIError(f"本地Qwen3-14B模型初始化异常: {e}")
  669. return self._handle_model_error("qwen_local_14b", error)
  670. def _get_qwen3_5_35b_a3b_model(self):
  671. """
  672. 获取 DashScope Qwen3.5-35B-A3B 模型
  673. Returns:
  674. ChatOpenAI: 配置好的 DashScope Qwen3.5-35B-A3B 模型实例
  675. """
  676. try:
  677. url = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_SERVER_URL")
  678. model_id = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_MODEL_ID")
  679. api_key = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_API_KEY")
  680. # 验证配置完整性
  681. if not all([url, model_id, api_key]):
  682. missing = []
  683. if not url:
  684. missing.append("DASHSCOPE_SERVER_URL")
  685. if not model_id:
  686. missing.append("DASHSCOPE_MODEL_ID")
  687. if not api_key:
  688. missing.append("DASHSCOPE_API_KEY")
  689. raise ModelConfigError(f"DashScope Qwen3.5-35B 模型配置不完整,缺少: {', '.join(missing)}")
  690. llm = ChatOpenAI(
  691. base_url=url,
  692. model=model_id,
  693. api_key=api_key,
  694. temperature=0.7,
  695. timeout=self.REQUEST_TIMEOUT,
  696. extra_body={
  697. "chat_template_kwargs": {"enable_thinking": False}
  698. }
  699. )
  700. logger.info(f"DashScope Qwen3.5-35B 模型初始化成功: {model_id} (思考模式: 关闭)")
  701. return llm
  702. except ModelConfigError:
  703. raise
  704. except Exception as e:
  705. return self._handle_model_error("qwen3_5_35b_a3b", ModelAPIError(str(e)))
  706. def _get_qwen3_5_27b_model(self):
  707. """
  708. 获取 DashScope Qwen3.5-27B 模型
  709. Returns:
  710. ChatOpenAI: 配置好的 DashScope Qwen3.5-27B 模型实例
  711. """
  712. try:
  713. url = self.config.get("qwen3_5_27b", "DASHSCOPE_SERVER_URL")
  714. model_id = self.config.get("qwen3_5_27b", "DASHSCOPE_MODEL_ID")
  715. api_key = self.config.get("qwen3_5_27b", "DASHSCOPE_API_KEY")
  716. # 验证配置完整性
  717. if not all([url, model_id, api_key]):
  718. missing = []
  719. if not url:
  720. missing.append("DASHSCOPE_SERVER_URL")
  721. if not model_id:
  722. missing.append("DASHSCOPE_MODEL_ID")
  723. if not api_key:
  724. missing.append("DASHSCOPE_API_KEY")
  725. raise ModelConfigError(f"DashScope Qwen3.5-27B 模型配置不完整,缺少: {', '.join(missing)}")
  726. llm = ChatOpenAI(
  727. base_url=url,
  728. model=model_id,
  729. api_key=api_key,
  730. temperature=0.7,
  731. timeout=self.REQUEST_TIMEOUT,
  732. extra_body={
  733. "chat_template_kwargs": {"enable_thinking": False}
  734. }
  735. )
  736. logger.info(f"DashScope Qwen3.5-27B 模型初始化成功: {model_id} (思考模式: 关闭)")
  737. return llm
  738. except ModelConfigError:
  739. raise
  740. except Exception as e:
  741. return self._handle_model_error("qwen3_5_27b", ModelAPIError(str(e)))
  742. def _get_qwen3_5_122b_a10b_model(self):
  743. """
  744. 获取 DashScope Qwen3.5-122B-A10B 模型
  745. Returns:
  746. ChatOpenAI: 配置好的 DashScope Qwen3.5-122B-A10B 模型实例
  747. """
  748. try:
  749. url = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_SERVER_URL")
  750. model_id = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_MODEL_ID")
  751. api_key = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_API_KEY")
  752. # 验证配置完整性
  753. if not all([url, model_id, api_key]):
  754. missing = []
  755. if not url:
  756. missing.append("DASHSCOPE_SERVER_URL")
  757. if not model_id:
  758. missing.append("DASHSCOPE_MODEL_ID")
  759. if not api_key:
  760. missing.append("DASHSCOPE_API_KEY")
  761. raise ModelConfigError(f"DashScope Qwen3.5-122B 模型配置不完整,缺少: {', '.join(missing)}")
  762. llm = ChatOpenAI(
  763. base_url=url,
  764. model=model_id,
  765. api_key=api_key,
  766. temperature=0.7,
  767. timeout=self.REQUEST_TIMEOUT,
  768. extra_body={
  769. "chat_template_kwargs": {"enable_thinking": False}
  770. }
  771. )
  772. logger.info(f"DashScope Qwen3.5-122B 模型初始化成功: {model_id} (思考模式: 关闭)")
  773. return llm
  774. except ModelConfigError:
  775. raise
  776. except Exception as e:
  777. return self._handle_model_error("qwen3_5_122b_a10b", ModelAPIError(str(e)))
  778. def _get_lq_qwen3_8b_emd(self):
  779. """
  780. 获取本地Qwen3-Embedding-8B嵌入模型
  781. Returns:
  782. OpenAIEmbeddings: 配置好的本地Qwen3-Embedding-8B嵌入模型实例
  783. """
  784. try:
  785. server_url = "http://192.168.91.253:9003/v1"
  786. model_id = "Qwen3-Embedding-8B"
  787. # 检查本地服务连接
  788. if not self._check_connection(server_url, "dummy", timeout=3):
  789. logger.warning(f"本地Qwen3-Embedding-8B模型服务连接失败: {server_url}")
  790. raise ModelConnectionError(f"无法连接到本地Qwen3-Embedding-8B模型服务: {server_url}")
  791. # 使用 langchain_openai 的 OpenAIEmbeddings
  792. embeddings = OpenAIEmbeddings(
  793. base_url=server_url,
  794. model=model_id,
  795. api_key="dummy", # 本地模型使用虚拟API key
  796. timeout=self.REQUEST_TIMEOUT,
  797. )
  798. logger.info(f"本地Qwen3-Embedding-8B模型初始化成功: {model_id}")
  799. return embeddings
  800. except ModelConnectionError:
  801. raise
  802. except Exception as e:
  803. error = ModelAPIError(f"本地Qwen3-Embedding-8B模型初始化异常: {e}")
  804. return self._handle_model_error("lq_qwen3_8b_emd", error)
  805. def _get_siliconflow_embedding_model(self):
  806. """
  807. 获取硅基流动Qwen3-Embedding-8B嵌入模型
  808. Returns:
  809. OpenAIEmbeddings: 配置好的硅基流动Qwen3-Embedding-8B嵌入模型实例
  810. """
  811. try:
  812. server_url = self.config.get("siliconflow_embed", "SLCF_EMBED_SERVER_URL")
  813. api_key = self.config.get("siliconflow_embed", "SLCF_EMBED_API_KEY")
  814. model_id = self.config.get("siliconflow_embed", "SLCF_EMBED_MODEL_ID", "Qwen/Qwen3-Embedding-8B")
  815. dimensions = self.config.get("siliconflow_embed", "SLCF_EMBED_DIMENSIONS", "4096")
  816. # 验证配置完整性
  817. if not all([server_url, api_key, model_id]):
  818. missing = []
  819. if not server_url:
  820. missing.append("SLCF_EMBED_SERVER_URL")
  821. if not api_key:
  822. missing.append("SLCF_EMBED_API_KEY")
  823. if not model_id:
  824. missing.append("SLCF_EMBED_MODEL_ID")
  825. raise ModelConfigError(f"硅基流动Embedding模型配置不完整,缺少: {', '.join(missing)}")
  826. # 检查连接
  827. if not self._check_connection(server_url, api_key):
  828. logger.warning(f"硅基流动Embedding模型服务连接失败: {server_url}")
  829. raise ModelConnectionError(f"无法连接到硅基流动Embedding模型服务: {server_url}")
  830. # 使用 langchain_openai 的 OpenAIEmbeddings
  831. embeddings = OpenAIEmbeddings(
  832. base_url=server_url,
  833. model=model_id,
  834. api_key=api_key,
  835. timeout=self.REQUEST_TIMEOUT,
  836. )
  837. logger.info(f"硅基流动Embedding模型初始化成功: {model_id} (dimensions: {dimensions})")
  838. return embeddings
  839. except ModelConfigError:
  840. raise
  841. except ModelConnectionError:
  842. raise
  843. except Exception as e:
  844. error = ModelAPIError(f"硅基流动Embedding模型初始化异常: {e}")
  845. return self._handle_model_error("siliconflow_embed", error)
  846. def _get_shutian_qwen3_5_122b_model(self):
  847. """
  848. 获取蜀天Qwen3.5-122B-A10B模型
  849. Returns:
  850. ChatOpenAI: 配置好的蜀天Qwen3.5-122B模型实例
  851. """
  852. try:
  853. server_url = self.config.get("shutian", "SHUTIAN_122B_SERVER_URL", "http://183.220.37.46:25423/v1")
  854. model_id = self.config.get("shutian", "SHUTIAN_122B_MODEL_ID", "/model/Qwen3.5-122B-A10B")
  855. api_key = self.config.get("shutian", "SHUTIAN_122B_API_KEY", "lq123456")
  856. # 检查服务连接
  857. if not self._check_connection(server_url, api_key, timeout=3):
  858. logger.warning(f"蜀天Qwen3.5-122B模型服务连接失败: {server_url}")
  859. raise ModelConnectionError(f"无法连接到蜀天Qwen3.5-122B模型服务: {server_url}")
  860. llm = ChatOpenAI(
  861. base_url=server_url,
  862. model=model_id,
  863. api_key=api_key,
  864. temperature=0.7,
  865. timeout=self.REQUEST_TIMEOUT,
  866. )
  867. logger.info(f"蜀天Qwen3.5-122B模型初始化成功: {model_id}")
  868. return llm
  869. except ModelConnectionError:
  870. raise
  871. except Exception as e:
  872. error = ModelAPIError(f"蜀天Qwen3.5-122B模型初始化异常: {e}")
  873. return self._handle_model_error("shutian_qwen3_5_122b", error)
  874. def _get_shutian_qwen3_8b_model(self):
  875. """
  876. 获取蜀天Qwen3-8B模型
  877. Returns:
  878. ChatOpenAI: 配置好的蜀天Qwen3-8B模型实例
  879. """
  880. try:
  881. server_url = self.config.get("shutian", "SHUTIAN_8B_SERVER_URL", "http://183.220.37.46:25424/v1")
  882. model_id = self.config.get("shutian", "SHUTIAN_8B_MODEL_ID", "/model/Qwen3-8B")
  883. api_key = self.config.get("shutian", "SHUTIAN_8B_API_KEY", "lq123456")
  884. # 检查服务连接
  885. if not self._check_connection(server_url, api_key, timeout=3):
  886. logger.warning(f"蜀天Qwen3-8B模型服务连接失败: {server_url}")
  887. raise ModelConnectionError(f"无法连接到蜀天Qwen3-8B模型服务: {server_url}")
  888. llm = ChatOpenAI(
  889. base_url=server_url,
  890. model=model_id,
  891. api_key=api_key,
  892. temperature=0.7,
  893. timeout=self.REQUEST_TIMEOUT,
  894. )
  895. logger.info(f"蜀天Qwen3-8B模型初始化成功: {model_id}")
  896. return llm
  897. except ModelConnectionError:
  898. raise
  899. except Exception as e:
  900. error = ModelAPIError(f"蜀天Qwen3-8B模型初始化异常: {e}")
  901. return self._handle_model_error("shutian_qwen3_8b", error)
  902. def _get_shutian_qwen3_5_35b_model(self):
  903. """
  904. 获取蜀天Qwen3.5-35B模型
  905. Returns:
  906. ChatOpenAI: 配置好的蜀天Qwen3.5-35B模型实例
  907. """
  908. try:
  909. server_url = self.config.get("shutian", "SHUTIAN_35B_SERVER_URL", "http://183.220.37.46:25427/v1")
  910. model_id = self.config.get("shutian", "SHUTIAN_35B_MODEL_ID", "/model/Qwen3.5-35B")
  911. api_key = self.config.get("shutian", "SHUTIAN_35B_API_KEY", "lq123456")
  912. logger.info(f"正在初始化蜀天Qwen3.5-35B模型,服务器地址: {server_url}")
  913. # 检查服务连接(可通过配置禁用)
  914. skip_check = self.config.get("shutian", "SKIP_CONNECTION_CHECK", "false").lower() == "true"
  915. if not skip_check:
  916. connection_ok = self._check_connection(server_url, api_key, timeout=5)
  917. if not connection_ok:
  918. # 连接检查失败时记录警告,但不阻止初始化(实际调用时如果失败会报错)
  919. logger.warning(f"蜀天Qwen3.5-35B模型服务连接检查失败: {server_url},但仍尝试初始化")
  920. else:
  921. logger.info(f"蜀天Qwen3.5-35B模型服务连接检查通过: {server_url}")
  922. else:
  923. logger.info(f"跳过蜀天Qwen3.5-35B模型连接检查(SKIP_CONNECTION_CHECK=true)")
  924. llm = ChatOpenAI(
  925. base_url=server_url,
  926. model=model_id,
  927. api_key=api_key,
  928. temperature=0.7,
  929. timeout=self.REQUEST_TIMEOUT,
  930. )
  931. # 记录模型实例的详细信息用于调试
  932. logger.info(f"蜀天Qwen3.5-35B模型初始化成功: model_id={model_id}, base_url={llm.base_url if hasattr(llm, 'base_url') else server_url}")
  933. return llm
  934. except ModelConnectionError:
  935. raise
  936. except Exception as e:
  937. error = ModelAPIError(f"蜀天Qwen3.5-35B模型初始化异常: {e}")
  938. return self._handle_model_error("shutian_qwen3_5_35b", error)
  939. def _get_shutian_qwen3_embed(self):
  940. """
  941. 获取蜀天Qwen3-Embedding-8B嵌入模型
  942. Returns:
  943. OpenAIEmbeddings: 配置好的蜀天Embedding模型实例
  944. """
  945. try:
  946. server_url = self.config.get("shutian", "SHUTIAN_EMBED_SERVER_URL", "http://183.220.37.46:25425/v1")
  947. model_id = self.config.get("shutian", "SHUTIAN_EMBED_MODEL_ID", "/model/Qwen3-Embedding-8B")
  948. api_key = self.config.get("shutian", "SHUTIAN_EMBED_API_KEY", "lq123456")
  949. # 检查服务连接
  950. if not self._check_connection(server_url, api_key, timeout=3):
  951. logger.warning(f"蜀天Qwen3-Embedding模型服务连接失败: {server_url}")
  952. raise ModelConnectionError(f"无法连接到蜀天Qwen3-Embedding模型服务: {server_url}")
  953. embeddings = OpenAIEmbeddings(
  954. base_url=server_url,
  955. model=model_id,
  956. api_key=api_key,
  957. timeout=self.REQUEST_TIMEOUT,
  958. )
  959. logger.info(f"蜀天Qwen3-Embedding-8B模型初始化成功: {model_id}")
  960. return embeddings
  961. except ModelConnectionError:
  962. raise
  963. except Exception as e:
  964. error = ModelAPIError(f"蜀天Qwen3-Embedding模型初始化异常: {e}")
  965. return self._handle_model_error("shutian_qwen3_embed", error)
  966. # 创建全局实例
  967. model_handler = ModelHandler()
  968. def get_models():
  969. """
  970. 获取模型的全局函数
  971. Returns:
  972. tuple: (llm, chat, embed) - LLM模型、聊天模型和嵌入模型实例
  973. 注意:当前llm和chat使用相同模型实例,embed暂时返回None
  974. Note:
  975. 这是一个便捷函数,直接使用全局model_handler实例获取模型
  976. """
  977. try:
  978. llm = model_handler.get_models()
  979. # 暂时返回相同的模型作为chat和embed
  980. return llm, llm, None
  981. except Exception as e:
  982. logger.error(f"获取模型失败: {e}")
  983. raise ModelConnectionError(f"无法获取模型服务: {e}")