|
|
@@ -60,9 +60,9 @@ class AIService:
|
|
|
trust_env=False, # 不信任环境变量中的代理设置
|
|
|
# 连接池优化:复用 TCP 连接,但每次 API 调用都是独立请求
|
|
|
limits=httpx.Limits(
|
|
|
- max_keepalive_connections=20, # 增加keepalive连接数(默认10)
|
|
|
- max_connections=50, # 增加总连接数(默认20),支持并发请求
|
|
|
- keepalive_expiry=30.0, # keepalive过期时间30秒
|
|
|
+ max_keepalive_connections=settings.HTTPX_MAX_KEEPALIVE_CONNECTIONS, # 从配置读取
|
|
|
+ max_connections=settings.HTTPX_MAX_CONNECTIONS, # 从配置读取
|
|
|
+ keepalive_expiry=settings.HTTPX_KEEPALIVE_EXPIRY, # 从配置读取
|
|
|
),
|
|
|
# HTTP/2支持 - 多路复用,减少连接开销,支持并发请求
|
|
|
http2=True,
|
|
|
@@ -74,6 +74,10 @@ class AIService:
|
|
|
http_client=http_client, # 使用自定义 HTTP 客户端
|
|
|
)
|
|
|
|
|
|
+ # 🔥 连接健康检查标记
|
|
|
+ self._last_llm_healthcheck: float = 0.0
|
|
|
+ self._llm_healthcheck_interval = settings.LLM_HEALTHCHECK_INTERVAL # 从配置读取
|
|
|
+
|
|
|
# 🔥 TTS优化:预热TTS连接(后台执行,不阻塞启动)
|
|
|
import threading
|
|
|
|
|
|
@@ -149,6 +153,9 @@ class AIService:
|
|
|
import time
|
|
|
llm_api_start = time.time()
|
|
|
|
|
|
+ # 🔥 连接健康检查(长时间未使用时)
|
|
|
+ await self._ensure_llm_connection()
|
|
|
+
|
|
|
try:
|
|
|
response = self.openai_client.chat.completions.create(
|
|
|
model=settings.llm_model,
|
|
|
@@ -286,6 +293,9 @@ class AIService:
|
|
|
# 构建System Prompt
|
|
|
system_prompt = self._build_system_prompt()
|
|
|
|
|
|
+ # 🔥 连接健康检查(长时间未使用时)
|
|
|
+ await self._ensure_llm_connection()
|
|
|
+
|
|
|
# 调用LLM
|
|
|
response = self.openai_client.chat.completions.create(
|
|
|
model=settings.llm_model,
|
|
|
@@ -587,6 +597,66 @@ class AIService:
|
|
|
)
|
|
|
raise
|
|
|
|
|
|
+ async def _ensure_llm_connection(self):
|
|
|
+ """确保LLM连接可用(长时间未使用时进行健康检查)"""
|
|
|
+ import time
|
|
|
+ now = time.time()
|
|
|
+
|
|
|
+ # 如果距离上次检查超过间隔,执行健康检查
|
|
|
+ if now - self._last_llm_healthcheck < self._llm_healthcheck_interval:
|
|
|
+ return
|
|
|
+
|
|
|
+ try:
|
|
|
+ # 🔥 执行简单的健康检查:发送一个极短的测试请求
|
|
|
+ # 注意:使用asyncio.to_thread包装同步调用,避免阻塞事件循环
|
|
|
+ def health_check():
|
|
|
+ return self.openai_client.chat.completions.create(
|
|
|
+ model=settings.llm_model,
|
|
|
+ messages=[{"role": "user", "content": "Hi"}],
|
|
|
+ max_tokens=1,
|
|
|
+ timeout=5.0, # 5秒超时
|
|
|
+ )
|
|
|
+
|
|
|
+ test_response = await asyncio.to_thread(health_check)
|
|
|
+ self._last_llm_healthcheck = now
|
|
|
+ logger.debug("✅ LLM连接健康检查成功")
|
|
|
+ except Exception as e:
|
|
|
+ # 健康检查失败,重建HTTP客户端
|
|
|
+ logger.warning(f"⚠️ LLM连接健康检查失败,重建连接: {e}")
|
|
|
+ self._recreate_http_client()
|
|
|
+ self._last_llm_healthcheck = now
|
|
|
+
|
|
|
+ def _recreate_http_client(self):
|
|
|
+ """重建HTTP客户端(连接失效时)"""
|
|
|
+ import httpx
|
|
|
+ try:
|
|
|
+ # 关闭旧客户端
|
|
|
+ if hasattr(self, 'openai_client') and self.openai_client:
|
|
|
+ if hasattr(self.openai_client, '_client') and self.openai_client._client:
|
|
|
+ self.openai_client._client.close()
|
|
|
+ except:
|
|
|
+ pass
|
|
|
+
|
|
|
+ # 创建新客户端(使用配置值)
|
|
|
+ http_client = httpx.Client(
|
|
|
+ proxy=None,
|
|
|
+ timeout=60.0,
|
|
|
+ trust_env=False,
|
|
|
+ limits=httpx.Limits(
|
|
|
+ max_keepalive_connections=settings.HTTPX_MAX_KEEPALIVE_CONNECTIONS,
|
|
|
+ max_connections=settings.HTTPX_MAX_CONNECTIONS,
|
|
|
+ keepalive_expiry=settings.HTTPX_KEEPALIVE_EXPIRY,
|
|
|
+ ),
|
|
|
+ http2=True,
|
|
|
+ )
|
|
|
+
|
|
|
+ self.openai_client = OpenAI(
|
|
|
+ api_key=settings.active_dashscope_api_key,
|
|
|
+ base_url=get_dashscope_http_base_url(),
|
|
|
+ http_client=http_client,
|
|
|
+ )
|
|
|
+ logger.info("✅ HTTP客户端已重建")
|
|
|
+
|
|
|
def _get_voice_for_emotion(self, emotion: EmotionType) -> str:
|
|
|
"""根据情感选择音色"""
|
|
|
# 所有情感统一使用配置文件中的音色
|
|
|
@@ -745,6 +815,9 @@ Critical:
|
|
|
总结文本
|
|
|
"""
|
|
|
try:
|
|
|
+ # 🔥 连接健康检查(长时间未使用时)
|
|
|
+ await self._ensure_llm_connection()
|
|
|
+
|
|
|
response = self.openai_client.chat.completions.create(
|
|
|
model=settings.llm_model,
|
|
|
messages=[
|