model_handler.py 49 KB

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