model_handler.py 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  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 config.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 config.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. embedding_model_type = self.config.get("model", "EMBEDDING_MODEL_TYPE", "lq_qwen3_8b_emd")
  332. logger.info(f"正在初始化Embedding模型,模型类型: {embedding_model_type}")
  333. # 检查缓存
  334. cache_key = f"embed_{embedding_model_type}"
  335. if cache_key in self._model_cache:
  336. logger.info(f"使用缓存的Embedding模型: {embedding_model_type}")
  337. return self._model_cache[cache_key]
  338. model = None
  339. try:
  340. if embedding_model_type == "siliconflow_embed":
  341. model = self._get_siliconflow_embedding_model()
  342. elif embedding_model_type == "lq_qwen3_8b_emd":
  343. model = self._get_lq_qwen3_8b_emd()
  344. elif embedding_model_type == "shutian_qwen3_embed":
  345. model = self._get_shutian_qwen3_embed()
  346. else:
  347. # 默认返回本地模型
  348. logger.warning(f"未知的Embedding模型类型 '{embedding_model_type}',使用默认本地模型")
  349. model = self._get_lq_qwen3_8b_emd()
  350. if model:
  351. self._model_cache[cache_key] = model
  352. logger.info(f"Embedding模型初始化完成: {embedding_model_type}")
  353. return model
  354. else:
  355. raise ModelAPIError(f"Embedding模型初始化返回None: {embedding_model_type}")
  356. except Exception as e:
  357. logger.error(f"获取Embedding模型失败 [{embedding_model_type}]: {e}")
  358. raise ModelConnectionError(f"无法初始化Embedding模型服务: {e}")
  359. def _get_doubao_model(self):
  360. """
  361. 获取豆包模型
  362. Returns:
  363. ChatOpenAI: 配置好的豆包模型实例
  364. """
  365. try:
  366. doubao_url = self.config.get("doubao", "DOUBAO_SERVER_URL")
  367. doubao_model_id = self.config.get("doubao", "DOUBAO_MODEL_ID")
  368. doubao_api_key = self.config.get("doubao", "DOUBAO_API_KEY")
  369. # 验证配置完整性
  370. if not all([doubao_url, doubao_model_id, doubao_api_key]):
  371. missing = []
  372. if not doubao_url:
  373. missing.append("DOUBAO_SERVER_URL")
  374. if not doubao_model_id:
  375. missing.append("DOUBAO_MODEL_ID")
  376. if not doubao_api_key:
  377. missing.append("DOUBAO_API_KEY")
  378. raise ModelConfigError(f"豆包模型配置不完整,缺少: {', '.join(missing)}")
  379. # 检查连接
  380. if not self._check_connection(doubao_url, doubao_api_key):
  381. logger.warning(f"豆包模型服务连接失败: {doubao_url}")
  382. raise ModelConnectionError(f"无法连接到豆包模型服务: {doubao_url}")
  383. llm = ChatOpenAI(
  384. base_url=doubao_url,
  385. model=doubao_model_id,
  386. api_key=doubao_api_key,
  387. temperature=0.7,
  388. timeout=self.REQUEST_TIMEOUT,
  389. extra_body={
  390. "enable_thinking": False,
  391. })
  392. logger.info(f"豆包模型初始化成功: {doubao_model_id}")
  393. return llm
  394. except ModelConfigError:
  395. raise
  396. except ModelConnectionError:
  397. raise
  398. except Exception as e:
  399. error = ModelAPIError(f"豆包模型初始化异常: {e}")
  400. return self._handle_model_error("doubao", error)
  401. def _get_qwen_model(self):
  402. """
  403. 获取通义千问模型
  404. Returns:
  405. ChatOpenAI: 配置好的通义千问模型实例
  406. """
  407. try:
  408. qwen_url = self.config.get("qwen", "QWEN_SERVER_URL")
  409. qwen_model_id = self.config.get("qwen", "QWEN_MODEL_ID")
  410. qwen_api_key = self.config.get("qwen", "QWEN_API_KEY")
  411. # 验证配置完整性
  412. if not all([qwen_url, qwen_model_id, qwen_api_key]):
  413. missing = []
  414. if not qwen_url:
  415. missing.append("QWEN_SERVER_URL")
  416. if not qwen_model_id:
  417. missing.append("QWEN_MODEL_ID")
  418. if not qwen_api_key:
  419. missing.append("QWEN_API_KEY")
  420. raise ModelConfigError(f"通义千问模型配置不完整,缺少: {', '.join(missing)}")
  421. # 检查连接
  422. if not self._check_connection(qwen_url, qwen_api_key):
  423. logger.warning(f"通义千问模型服务连接失败: {qwen_url}")
  424. raise ModelConnectionError(f"无法连接到通义千问模型服务: {qwen_url}")
  425. llm = ChatOpenAI(
  426. base_url=qwen_url,
  427. model=qwen_model_id,
  428. api_key=qwen_api_key,
  429. temperature=0.7,
  430. timeout=self.REQUEST_TIMEOUT,
  431. extra_body={
  432. "enable_thinking": False,
  433. })
  434. logger.info(f"通义千问模型初始化成功: {qwen_model_id}")
  435. return llm
  436. except ModelConfigError:
  437. raise
  438. except ModelConnectionError:
  439. raise
  440. except Exception as e:
  441. error = ModelAPIError(f"通义千问模型初始化异常: {e}")
  442. return self._handle_model_error("qwen", error)
  443. def _get_qwen3_30b_model(self):
  444. """
  445. 获取Qwen3-30B模型
  446. Returns:
  447. ChatOpenAI: 配置好的Qwen3-30B模型实例
  448. """
  449. try:
  450. qwen3_30b_url = self.config.get("qwen3_30b", "QWEN3_30B_SERVER_URL")
  451. qwen3_30b_model_id = self.config.get("qwen3_30b", "QWEN3_30B_MODEL_ID")
  452. qwen3_30b_api_key = self.config.get("qwen3_30b", "QWEN3_30B_API_KEY")
  453. # 验证配置完整性
  454. if not all([qwen3_30b_url, qwen3_30b_model_id, qwen3_30b_api_key]):
  455. missing = []
  456. if not qwen3_30b_url:
  457. missing.append("QWEN3_30B_SERVER_URL")
  458. if not qwen3_30b_model_id:
  459. missing.append("QWEN3_30B_MODEL_ID")
  460. if not qwen3_30b_api_key:
  461. missing.append("QWEN3_30B_API_KEY")
  462. raise ModelConfigError(f"Qwen3-30B模型配置不完整,缺少: {', '.join(missing)}")
  463. # 检查连接
  464. if not self._check_connection(qwen3_30b_url, qwen3_30b_api_key):
  465. logger.warning(f"Qwen3-30B模型服务连接失败: {qwen3_30b_url}")
  466. raise ModelConnectionError(f"无法连接到Qwen3-30B模型服务: {qwen3_30b_url}")
  467. llm = ChatOpenAI(
  468. base_url=qwen3_30b_url,
  469. model=qwen3_30b_model_id,
  470. api_key=qwen3_30b_api_key,
  471. temperature=0.7,
  472. timeout=self.REQUEST_TIMEOUT,
  473. extra_body={
  474. "enable_thinking": False,
  475. })
  476. logger.info(f"Qwen3-30B模型初始化成功: {qwen3_30b_model_id}")
  477. return llm
  478. except ModelConfigError:
  479. raise
  480. except ModelConnectionError:
  481. raise
  482. except Exception as e:
  483. error = ModelAPIError(f"Qwen3-30B模型初始化异常: {e}")
  484. return self._handle_model_error("qwen3_30b", error)
  485. def _get_deepseek_model(self):
  486. """
  487. 获取DeepSeek模型
  488. Returns:
  489. ChatOpenAI: 配置好的DeepSeek模型实例
  490. """
  491. try:
  492. deepseek_url = self.config.get("deepseek", "DEEPSEEK_SERVER_URL")
  493. deepseek_model_id = self.config.get("deepseek", "DEEPSEEK_MODEL_ID")
  494. deepseek_api_key = self.config.get("deepseek", "DEEPSEEK_API_KEY")
  495. # 验证配置完整性
  496. if not all([deepseek_url, deepseek_model_id, deepseek_api_key]):
  497. missing = []
  498. if not deepseek_url:
  499. missing.append("DEEPSEEK_SERVER_URL")
  500. if not deepseek_model_id:
  501. missing.append("DEEPSEEK_MODEL_ID")
  502. if not deepseek_api_key:
  503. missing.append("DEEPSEEK_API_KEY")
  504. raise ModelConfigError(f"DeepSeek模型配置不完整,缺少: {', '.join(missing)}")
  505. # 检查连接
  506. if not self._check_connection(deepseek_url, deepseek_api_key):
  507. logger.warning(f"DeepSeek模型服务连接失败: {deepseek_url}")
  508. raise ModelConnectionError(f"无法连接到DeepSeek模型服务: {deepseek_url}")
  509. llm = ChatOpenAI(
  510. base_url=deepseek_url,
  511. model=deepseek_model_id,
  512. api_key=deepseek_api_key,
  513. temperature=0.7,
  514. timeout=self.REQUEST_TIMEOUT,
  515. extra_body={
  516. "enable_thinking": False,
  517. })
  518. logger.info(f"DeepSeek模型初始化成功: {deepseek_model_id}")
  519. return llm
  520. except ModelConfigError:
  521. raise
  522. except ModelConnectionError:
  523. raise
  524. except Exception as e:
  525. error = ModelAPIError(f"DeepSeek模型初始化异常: {e}")
  526. return self._handle_model_error("deepseek", error)
  527. def _get_lq_qwen3_8b_model(self):
  528. """
  529. 获取本地Qwen3-8B-Instruct模型
  530. Returns:
  531. ChatOpenAI: 配置好的本地Qwen3-8B模型实例
  532. """
  533. try:
  534. server_url = "http://192.168.91.253:9002/v1"
  535. model_id = "Qwen3-8B"
  536. # 检查本地服务连接
  537. if not self._check_connection(server_url, "dummy", timeout=3):
  538. logger.warning(f"本地Qwen3-8B模型服务连接失败: {server_url}")
  539. raise ModelConnectionError(f"无法连接到本地Qwen3-8B模型服务: {server_url}")
  540. llm = ChatOpenAI(
  541. base_url=server_url,
  542. model=model_id,
  543. api_key="dummy",
  544. temperature=0.7,
  545. timeout=self.REQUEST_TIMEOUT,
  546. )
  547. logger.info(f"本地Qwen3-8B模型初始化成功: {model_id}")
  548. return llm
  549. except ModelConnectionError:
  550. raise
  551. except Exception as e:
  552. error = ModelAPIError(f"本地Qwen3-8B模型初始化异常: {e}")
  553. return self._handle_model_error("lq_qwen3_8b", error)
  554. def _get_lq_qwen3_8b_lora_model(self):
  555. """
  556. 获取本地Qwen3-8B-lq-lora模型
  557. Returns:
  558. ChatOpenAI: 配置好的本地Qwen3-8B-lq-lora模型实例
  559. """
  560. try:
  561. server_url = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  562. model_id = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  563. api_key = self.config.get("lq_qwen3_8B_lora", "LQ_QWEN3_8B_LQ_LORA_API_KEY", "dummy")
  564. # 验证配置完整性
  565. if not all([server_url, model_id]):
  566. missing = []
  567. if not server_url:
  568. missing.append("LQ_QWEN3_8B_LQ_LORA_SERVER_URL")
  569. if not model_id:
  570. missing.append("LQ_QWEN3_8B_LQ_LORA_MODEL_ID")
  571. raise ModelConfigError(f"本地Qwen3-8B-lq-lora模型配置不完整,缺少: {', '.join(missing)}")
  572. # 检查本地服务连接
  573. if not self._check_connection(server_url, api_key, timeout=3):
  574. logger.warning(f"本地Qwen3-8B-lq-lora模型服务连接失败: {server_url}")
  575. raise ModelConnectionError(f"无法连接到本地Qwen3-8B-lq-lora模型服务: {server_url}")
  576. llm = ChatOpenAI(
  577. base_url=server_url,
  578. model=model_id,
  579. api_key=api_key,
  580. temperature=0.7,
  581. timeout=self.REQUEST_TIMEOUT,
  582. )
  583. logger.info(f"本地Qwen3-8B-lq-lora模型初始化成功: {model_id}")
  584. return llm
  585. except ModelConfigError:
  586. raise
  587. except ModelConnectionError:
  588. raise
  589. except Exception as e:
  590. error = ModelAPIError(f"本地Qwen3-8B-lq-lora模型初始化异常: {e}")
  591. return self._handle_model_error("lq_qwen3_8b_lora", error)
  592. def _get_lq_qwen3_4b_model(self):
  593. """
  594. 获取本地Qwen3-4B-Instruct模型
  595. Returns:
  596. ChatOpenAI: 配置好的本地Qwen3-4B模型实例
  597. """
  598. try:
  599. server_url = "http://192.168.91.253:9001/v1"
  600. model_id = "Qwen3-4B"
  601. # 检查本地服务连接
  602. if not self._check_connection(server_url, "dummy", timeout=3):
  603. logger.warning(f"本地Qwen3-4B模型服务连接失败: {server_url}")
  604. raise ModelConnectionError(f"无法连接到本地Qwen3-4B模型服务: {server_url}")
  605. llm = ChatOpenAI(
  606. base_url=server_url,
  607. model=model_id,
  608. api_key="dummy",
  609. temperature=0.7,
  610. timeout=self.REQUEST_TIMEOUT,
  611. )
  612. logger.info(f"本地Qwen3-4B模型初始化成功: {model_id}")
  613. return llm
  614. except ModelConnectionError:
  615. raise
  616. except Exception as e:
  617. error = ModelAPIError(f"本地Qwen3-4B模型初始化异常: {e}")
  618. return self._handle_model_error("lq_qwen3_4b", error)
  619. def _get_qwen_local_14b_model(self):
  620. """
  621. 获取本地Qwen3-14B-Instruct模型
  622. Returns:
  623. ChatOpenAI: 配置好的本地Qwen3-14B模型实例
  624. """
  625. try:
  626. server_url = "http://192.168.91.253:9003/v1"
  627. model_id = "Qwen3-14B"
  628. # 检查本地服务连接
  629. if not self._check_connection(server_url, "dummy", timeout=3):
  630. logger.warning(f"本地Qwen3-14B模型服务连接失败: {server_url}")
  631. raise ModelConnectionError(f"无法连接到本地Qwen3-14B模型服务: {server_url}")
  632. llm = ChatOpenAI(
  633. base_url=server_url,
  634. model=model_id,
  635. api_key="dummy",
  636. temperature=0.7,
  637. timeout=self.REQUEST_TIMEOUT,
  638. )
  639. logger.info(f"本地Qwen3-14B模型初始化成功: {model_id}")
  640. return llm
  641. except ModelConnectionError:
  642. raise
  643. except Exception as e:
  644. error = ModelAPIError(f"本地Qwen3-14B模型初始化异常: {e}")
  645. return self._handle_model_error("qwen_local_14b", error)
  646. def _get_qwen3_5_35b_a3b_model(self):
  647. """
  648. 获取 DashScope Qwen3.5-35B-A3B 模型
  649. Returns:
  650. ChatOpenAI: 配置好的 DashScope Qwen3.5-35B-A3B 模型实例
  651. """
  652. try:
  653. url = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_SERVER_URL")
  654. model_id = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_MODEL_ID")
  655. api_key = self.config.get("qwen3_5_35b_a3b", "DASHSCOPE_API_KEY")
  656. # 验证配置完整性
  657. if not all([url, model_id, api_key]):
  658. missing = []
  659. if not url:
  660. missing.append("DASHSCOPE_SERVER_URL")
  661. if not model_id:
  662. missing.append("DASHSCOPE_MODEL_ID")
  663. if not api_key:
  664. missing.append("DASHSCOPE_API_KEY")
  665. raise ModelConfigError(f"DashScope Qwen3.5-35B 模型配置不完整,缺少: {', '.join(missing)}")
  666. llm = ChatOpenAI(
  667. base_url=url,
  668. model=model_id,
  669. api_key=api_key,
  670. temperature=0.7,
  671. timeout=self.REQUEST_TIMEOUT,
  672. extra_body={
  673. "chat_template_kwargs": {"enable_thinking": False}
  674. }
  675. )
  676. logger.info(f"DashScope Qwen3.5-35B 模型初始化成功: {model_id} (思考模式: 关闭)")
  677. return llm
  678. except ModelConfigError:
  679. raise
  680. except Exception as e:
  681. return self._handle_model_error("qwen3_5_35b_a3b", ModelAPIError(str(e)))
  682. def _get_qwen3_5_27b_model(self):
  683. """
  684. 获取 DashScope Qwen3.5-27B 模型
  685. Returns:
  686. ChatOpenAI: 配置好的 DashScope Qwen3.5-27B 模型实例
  687. """
  688. try:
  689. url = self.config.get("qwen3_5_27b", "DASHSCOPE_SERVER_URL")
  690. model_id = self.config.get("qwen3_5_27b", "DASHSCOPE_MODEL_ID")
  691. api_key = self.config.get("qwen3_5_27b", "DASHSCOPE_API_KEY")
  692. # 验证配置完整性
  693. if not all([url, model_id, api_key]):
  694. missing = []
  695. if not url:
  696. missing.append("DASHSCOPE_SERVER_URL")
  697. if not model_id:
  698. missing.append("DASHSCOPE_MODEL_ID")
  699. if not api_key:
  700. missing.append("DASHSCOPE_API_KEY")
  701. raise ModelConfigError(f"DashScope Qwen3.5-27B 模型配置不完整,缺少: {', '.join(missing)}")
  702. llm = ChatOpenAI(
  703. base_url=url,
  704. model=model_id,
  705. api_key=api_key,
  706. temperature=0.7,
  707. timeout=self.REQUEST_TIMEOUT,
  708. extra_body={
  709. "chat_template_kwargs": {"enable_thinking": False}
  710. }
  711. )
  712. logger.info(f"DashScope Qwen3.5-27B 模型初始化成功: {model_id} (思考模式: 关闭)")
  713. return llm
  714. except ModelConfigError:
  715. raise
  716. except Exception as e:
  717. return self._handle_model_error("qwen3_5_27b", ModelAPIError(str(e)))
  718. def _get_qwen3_5_122b_a10b_model(self):
  719. """
  720. 获取 DashScope Qwen3.5-122B-A10B 模型
  721. Returns:
  722. ChatOpenAI: 配置好的 DashScope Qwen3.5-122B-A10B 模型实例
  723. """
  724. try:
  725. url = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_SERVER_URL")
  726. model_id = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_MODEL_ID")
  727. api_key = self.config.get("qwen3_5_122b_a10b", "DASHSCOPE_API_KEY")
  728. # 验证配置完整性
  729. if not all([url, model_id, api_key]):
  730. missing = []
  731. if not url:
  732. missing.append("DASHSCOPE_SERVER_URL")
  733. if not model_id:
  734. missing.append("DASHSCOPE_MODEL_ID")
  735. if not api_key:
  736. missing.append("DASHSCOPE_API_KEY")
  737. raise ModelConfigError(f"DashScope Qwen3.5-122B 模型配置不完整,缺少: {', '.join(missing)}")
  738. llm = ChatOpenAI(
  739. base_url=url,
  740. model=model_id,
  741. api_key=api_key,
  742. temperature=0.7,
  743. timeout=self.REQUEST_TIMEOUT,
  744. extra_body={
  745. "chat_template_kwargs": {"enable_thinking": False}
  746. }
  747. )
  748. logger.info(f"DashScope Qwen3.5-122B 模型初始化成功: {model_id} (思考模式: 关闭)")
  749. return llm
  750. except ModelConfigError:
  751. raise
  752. except Exception as e:
  753. return self._handle_model_error("qwen3_5_122b_a10b", ModelAPIError(str(e)))
  754. def _get_lq_qwen3_8b_emd(self):
  755. """
  756. 获取本地Qwen3-Embedding-8B嵌入模型
  757. Returns:
  758. OpenAIEmbeddings: 配置好的本地Qwen3-Embedding-8B嵌入模型实例
  759. """
  760. try:
  761. server_url = "http://192.168.91.253:9003/v1"
  762. model_id = "Qwen3-Embedding-8B"
  763. # 检查本地服务连接
  764. if not self._check_connection(server_url, "dummy", timeout=3):
  765. logger.warning(f"本地Qwen3-Embedding-8B模型服务连接失败: {server_url}")
  766. raise ModelConnectionError(f"无法连接到本地Qwen3-Embedding-8B模型服务: {server_url}")
  767. # 使用 langchain_openai 的 OpenAIEmbeddings
  768. embeddings = OpenAIEmbeddings(
  769. base_url=server_url,
  770. model=model_id,
  771. api_key="dummy", # 本地模型使用虚拟API key
  772. timeout=self.REQUEST_TIMEOUT,
  773. )
  774. logger.info(f"本地Qwen3-Embedding-8B模型初始化成功: {model_id}")
  775. return embeddings
  776. except ModelConnectionError:
  777. raise
  778. except Exception as e:
  779. error = ModelAPIError(f"本地Qwen3-Embedding-8B模型初始化异常: {e}")
  780. return self._handle_model_error("lq_qwen3_8b_emd", error)
  781. def _get_siliconflow_embedding_model(self):
  782. """
  783. 获取硅基流动Qwen3-Embedding-8B嵌入模型
  784. Returns:
  785. OpenAIEmbeddings: 配置好的硅基流动Qwen3-Embedding-8B嵌入模型实例
  786. """
  787. try:
  788. server_url = self.config.get("siliconflow_embed", "SLCF_EMBED_SERVER_URL")
  789. api_key = self.config.get("siliconflow_embed", "SLCF_EMBED_API_KEY")
  790. model_id = self.config.get("siliconflow_embed", "SLCF_EMBED_MODEL_ID", "Qwen/Qwen3-Embedding-8B")
  791. dimensions = self.config.get("siliconflow_embed", "SLCF_EMBED_DIMENSIONS", "4096")
  792. # 验证配置完整性
  793. if not all([server_url, api_key, model_id]):
  794. missing = []
  795. if not server_url:
  796. missing.append("SLCF_EMBED_SERVER_URL")
  797. if not api_key:
  798. missing.append("SLCF_EMBED_API_KEY")
  799. if not model_id:
  800. missing.append("SLCF_EMBED_MODEL_ID")
  801. raise ModelConfigError(f"硅基流动Embedding模型配置不完整,缺少: {', '.join(missing)}")
  802. # 检查连接
  803. if not self._check_connection(server_url, api_key):
  804. logger.warning(f"硅基流动Embedding模型服务连接失败: {server_url}")
  805. raise ModelConnectionError(f"无法连接到硅基流动Embedding模型服务: {server_url}")
  806. # 使用 langchain_openai 的 OpenAIEmbeddings
  807. embeddings = OpenAIEmbeddings(
  808. base_url=server_url,
  809. model=model_id,
  810. api_key=api_key,
  811. timeout=self.REQUEST_TIMEOUT,
  812. )
  813. logger.info(f"硅基流动Embedding模型初始化成功: {model_id} (dimensions: {dimensions})")
  814. return embeddings
  815. except ModelConfigError:
  816. raise
  817. except ModelConnectionError:
  818. raise
  819. except Exception as e:
  820. error = ModelAPIError(f"硅基流动Embedding模型初始化异常: {e}")
  821. return self._handle_model_error("siliconflow_embed", error)
  822. def _get_shutian_qwen3_5_122b_model(self):
  823. """
  824. 获取蜀天Qwen3.5-122B-A10B模型
  825. Returns:
  826. ChatOpenAI: 配置好的蜀天Qwen3.5-122B模型实例
  827. """
  828. try:
  829. server_url = self.config.get("shutian", "SHUTIAN_122B_SERVER_URL", "http://183.220.37.46:25423/v1")
  830. model_id = self.config.get("shutian", "SHUTIAN_122B_MODEL_ID", "/model/Qwen3.5-122B-A10B")
  831. api_key = self.config.get("shutian", "SHUTIAN_122B_API_KEY", "lq123456")
  832. # 检查服务连接
  833. if not self._check_connection(server_url, api_key, timeout=3):
  834. logger.warning(f"蜀天Qwen3.5-122B模型服务连接失败: {server_url}")
  835. raise ModelConnectionError(f"无法连接到蜀天Qwen3.5-122B模型服务: {server_url}")
  836. llm = ChatOpenAI(
  837. base_url=server_url,
  838. model=model_id,
  839. api_key=api_key,
  840. temperature=0.7,
  841. timeout=self.REQUEST_TIMEOUT,
  842. )
  843. logger.info(f"蜀天Qwen3.5-122B模型初始化成功: {model_id}")
  844. return llm
  845. except ModelConnectionError:
  846. raise
  847. except Exception as e:
  848. error = ModelAPIError(f"蜀天Qwen3.5-122B模型初始化异常: {e}")
  849. return self._handle_model_error("shutian_qwen3_5_122b", error)
  850. def _get_shutian_qwen3_8b_model(self):
  851. """
  852. 获取蜀天Qwen3-8B模型
  853. Returns:
  854. ChatOpenAI: 配置好的蜀天Qwen3-8B模型实例
  855. """
  856. try:
  857. server_url = self.config.get("shutian", "SHUTIAN_8B_SERVER_URL", "http://183.220.37.46:25424/v1")
  858. model_id = self.config.get("shutian", "SHUTIAN_8B_MODEL_ID", "/model/Qwen3-8B")
  859. api_key = self.config.get("shutian", "SHUTIAN_8B_API_KEY", "lq123456")
  860. # 检查服务连接
  861. if not self._check_connection(server_url, api_key, timeout=3):
  862. logger.warning(f"蜀天Qwen3-8B模型服务连接失败: {server_url}")
  863. raise ModelConnectionError(f"无法连接到蜀天Qwen3-8B模型服务: {server_url}")
  864. llm = ChatOpenAI(
  865. base_url=server_url,
  866. model=model_id,
  867. api_key=api_key,
  868. temperature=0.7,
  869. timeout=self.REQUEST_TIMEOUT,
  870. )
  871. logger.info(f"蜀天Qwen3-8B模型初始化成功: {model_id}")
  872. return llm
  873. except ModelConnectionError:
  874. raise
  875. except Exception as e:
  876. error = ModelAPIError(f"蜀天Qwen3-8B模型初始化异常: {e}")
  877. return self._handle_model_error("shutian_qwen3_8b", error)
  878. def _get_shutian_qwen3_5_35b_model(self):
  879. """
  880. 获取蜀天Qwen3.5-35B模型
  881. Returns:
  882. ChatOpenAI: 配置好的蜀天Qwen3.5-35B模型实例
  883. """
  884. try:
  885. server_url = self.config.get("shutian", "SHUTIAN_35B_SERVER_URL", "http://183.220.37.46:25427/v1")
  886. model_id = self.config.get("shutian", "SHUTIAN_35B_MODEL_ID", "/model/Qwen3.5-35B")
  887. api_key = self.config.get("shutian", "SHUTIAN_35B_API_KEY", "lq123456")
  888. logger.info(f"正在初始化蜀天Qwen3.5-35B模型,服务器地址: {server_url}")
  889. # 检查服务连接(可通过配置禁用)
  890. skip_check = self.config.get("shutian", "SKIP_CONNECTION_CHECK", "false").lower() == "true"
  891. if not skip_check:
  892. connection_ok = self._check_connection(server_url, api_key, timeout=5)
  893. if not connection_ok:
  894. # 连接检查失败时记录警告,但不阻止初始化(实际调用时如果失败会报错)
  895. logger.warning(f"蜀天Qwen3.5-35B模型服务连接检查失败: {server_url},但仍尝试初始化")
  896. else:
  897. logger.info(f"蜀天Qwen3.5-35B模型服务连接检查通过: {server_url}")
  898. else:
  899. logger.info(f"跳过蜀天Qwen3.5-35B模型连接检查(SKIP_CONNECTION_CHECK=true)")
  900. llm = ChatOpenAI(
  901. base_url=server_url,
  902. model=model_id,
  903. api_key=api_key,
  904. temperature=0.7,
  905. timeout=self.REQUEST_TIMEOUT,
  906. )
  907. # 记录模型实例的详细信息用于调试
  908. logger.info(f"蜀天Qwen3.5-35B模型初始化成功: model_id={model_id}, base_url={llm.base_url if hasattr(llm, 'base_url') else server_url}")
  909. return llm
  910. except ModelConnectionError:
  911. raise
  912. except Exception as e:
  913. error = ModelAPIError(f"蜀天Qwen3.5-35B模型初始化异常: {e}")
  914. return self._handle_model_error("shutian_qwen3_5_35b", error)
  915. def _get_shutian_qwen3_embed(self):
  916. """
  917. 获取蜀天Qwen3-Embedding-8B嵌入模型
  918. Returns:
  919. OpenAIEmbeddings: 配置好的蜀天Embedding模型实例
  920. """
  921. try:
  922. server_url = self.config.get("shutian", "SHUTIAN_EMBED_SERVER_URL", "http://183.220.37.46:25425/v1")
  923. model_id = self.config.get("shutian", "SHUTIAN_EMBED_MODEL_ID", "/model/Qwen3-Embedding-8B")
  924. api_key = self.config.get("shutian", "SHUTIAN_EMBED_API_KEY", "lq123456")
  925. # 检查服务连接
  926. if not self._check_connection(server_url, api_key, timeout=3):
  927. logger.warning(f"蜀天Qwen3-Embedding模型服务连接失败: {server_url}")
  928. raise ModelConnectionError(f"无法连接到蜀天Qwen3-Embedding模型服务: {server_url}")
  929. embeddings = OpenAIEmbeddings(
  930. base_url=server_url,
  931. model=model_id,
  932. api_key=api_key,
  933. timeout=self.REQUEST_TIMEOUT,
  934. )
  935. logger.info(f"蜀天Qwen3-Embedding-8B模型初始化成功: {model_id}")
  936. return embeddings
  937. except ModelConnectionError:
  938. raise
  939. except Exception as e:
  940. error = ModelAPIError(f"蜀天Qwen3-Embedding模型初始化异常: {e}")
  941. return self._handle_model_error("shutian_qwen3_embed", error)
  942. # 创建全局实例
  943. model_handler = ModelHandler()
  944. def get_models():
  945. """
  946. 获取模型的全局函数
  947. Returns:
  948. tuple: (llm, chat, embed) - LLM模型、聊天模型和嵌入模型实例
  949. 注意:当前llm和chat使用相同模型实例,embed暂时返回None
  950. Note:
  951. 这是一个便捷函数,直接使用全局model_handler实例获取模型
  952. """
  953. try:
  954. llm = model_handler.get_models()
  955. # 暂时返回相同的模型作为chat和embed
  956. return llm, llm, None
  957. except Exception as e:
  958. logger.error(f"获取模型失败: {e}")
  959. raise ModelConnectionError(f"无法获取模型服务: {e}")