🚑 fix(llm_manager): 添加API请求重试机制,优化网络错误处理
This commit is contained in:
parent
cf605ac5b8
commit
8f71e65f8c
@ -1,7 +1,6 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
import time
|
||||||
from config_manager import get_config_manager
|
from config_manager import get_config_manager
|
||||||
from logger_manager import get_logger
|
from logger_manager import get_logger
|
||||||
|
|
||||||
@ -11,7 +10,6 @@ logger = get_logger()
|
|||||||
|
|
||||||
class LLMManager:
|
class LLMManager:
|
||||||
"""LLM管理器,负责加载API配置并提供与LLM交互的功能"""
|
"""LLM管理器,负责加载API配置并提供与LLM交互的功能"""
|
||||||
|
|
||||||
_instance = None # 单例实例
|
_instance = None # 单例实例
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -19,6 +17,7 @@ class LLMManager:
|
|||||||
self._api_base = None
|
self._api_base = None
|
||||||
self._model = None
|
self._model = None
|
||||||
self._temperature = None
|
self._temperature = None
|
||||||
|
self._config = None
|
||||||
|
|
||||||
def __new__(cls):
|
def __new__(cls):
|
||||||
"""实现单例模式"""
|
"""实现单例模式"""
|
||||||
@ -34,23 +33,23 @@ class LLMManager:
|
|||||||
def initialize(self):
|
def initialize(self):
|
||||||
"""初始化LLM配置"""
|
"""初始化LLM配置"""
|
||||||
llm_config = config_manager.get('llm', {})
|
llm_config = config_manager.get('llm', {})
|
||||||
|
|
||||||
# 加载LLM配置
|
# 加载LLM配置
|
||||||
self._api_key = llm_config.get('api_key', '')
|
self._api_key = llm_config.get('api_key', '')
|
||||||
self._api_base = llm_config.get('api_base', 'https://api.openai.com/v1')
|
self._api_base = llm_config.get('api_base', 'https://api.openai.com/v1')
|
||||||
self._model = llm_config.get('model', 'gpt-3.5-turbo')
|
self._model = llm_config.get('model', 'gpt-3.5-turbo')
|
||||||
self._temperature = llm_config.get('temperature', 0.7)
|
self._temperature = llm_config.get('temperature', 0.7)
|
||||||
|
self._config = llm_config
|
||||||
if not self._api_key:
|
if not self._api_key:
|
||||||
logger.warning("警告: LLM API密钥未配置,请在config.yaml中设置。")
|
logger.warning("警告: LLM API密钥未配置,请在config.yaml中设置。")
|
||||||
|
|
||||||
def chat(self, content: str, prompt: Optional[str] = None) -> str:
|
def chat(self, content: str, prompt: Optional[str] = None, max_retries: int = 5) -> str:
|
||||||
"""
|
"""
|
||||||
与LLM进行对话
|
与LLM进行对话,包含自动重试机制
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
content: 用户输入内容
|
content: 用户输入内容
|
||||||
prompt: 可选的系统提示词
|
prompt: 可选的系统提示词
|
||||||
|
max_retries: 最大重试次数,默认为5
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
LLM的回复内容
|
LLM的回复内容
|
||||||
@ -67,7 +66,6 @@ class LLMManager:
|
|||||||
# 添加系统提示(如果有)
|
# 添加系统提示(如果有)
|
||||||
if prompt:
|
if prompt:
|
||||||
messages.append({"role": "system", "content": prompt})
|
messages.append({"role": "system", "content": prompt})
|
||||||
|
|
||||||
# 添加用户消息
|
# 添加用户消息
|
||||||
messages.append({"role": "user", "content": content})
|
messages.append({"role": "user", "content": content})
|
||||||
|
|
||||||
@ -79,17 +77,88 @@ class LLMManager:
|
|||||||
|
|
||||||
logger.debug(f"请求数据: {payload}")
|
logger.debug(f"请求数据: {payload}")
|
||||||
|
|
||||||
|
# 实现重试机制
|
||||||
|
attempts = 0
|
||||||
|
last_exception = None
|
||||||
|
|
||||||
|
while attempts < max_retries:
|
||||||
|
try:
|
||||||
|
# 尝试直接不使用代理
|
||||||
|
if attempts > 0:
|
||||||
|
logger.info(f"尝试不使用代理进行请求 (尝试 {attempts + 1}/{max_retries})")
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
f"{self._api_base}/chat/completions",
|
f"{self._api_base}/chat/completions",
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json=payload
|
json=payload,
|
||||||
|
proxies=None, # 明确不使用代理
|
||||||
|
timeout=30 # 设置超时时间
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# 第一次尝试使用默认设置
|
||||||
|
response = requests.post(
|
||||||
|
f"{self._api_base}/chat/completions",
|
||||||
|
headers=headers,
|
||||||
|
json=payload,
|
||||||
|
timeout=30 # 设置超时时间
|
||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code == 200:
|
||||||
logger.info(f"请求失败: {response.status_code}, {response.text}")
|
|
||||||
return "请求失败,请稍后再试。"
|
|
||||||
|
|
||||||
return response.json()["choices"][0]["message"]["content"]
|
return response.json()["choices"][0]["message"]["content"]
|
||||||
|
elif response.status_code == 429:
|
||||||
|
# 限流错误,需要等待更长时间
|
||||||
|
logger.warning(
|
||||||
|
f"API请求限流 (尝试 {attempts + 1}/{max_retries}): {response.status_code}, {response.text}")
|
||||||
|
attempts += 1
|
||||||
|
wait_time = 10 * (2 ** attempts) # 指数退避:10s, 20s, 40s...
|
||||||
|
logger.info(f"等待 {wait_time} 秒后重试...")
|
||||||
|
time.sleep(wait_time)
|
||||||
|
else:
|
||||||
|
# 其他服务器错误
|
||||||
|
logger.warning(
|
||||||
|
f"请求失败 (尝试 {attempts + 1}/{max_retries}): {response.status_code}, {response.text}")
|
||||||
|
attempts += 1
|
||||||
|
wait_time = 2 * (2 ** attempts) # 指数退避:4s, 8s, 16s...
|
||||||
|
logger.info(f"等待 {wait_time} 秒后重试...")
|
||||||
|
time.sleep(wait_time)
|
||||||
|
|
||||||
|
except requests.exceptions.ProxyError as e:
|
||||||
|
# 代理错误处理
|
||||||
|
last_exception = e
|
||||||
|
attempts += 1
|
||||||
|
logger.warning(f"代理连接错误 (尝试 {attempts}/{max_retries}): {str(e)}")
|
||||||
|
if attempts >= max_retries:
|
||||||
|
break
|
||||||
|
wait_time = 2 * attempts # 线性退避:2s, 4s, 6s...
|
||||||
|
logger.info(f"等待 {wait_time} 秒后尝试不使用代理重试...")
|
||||||
|
time.sleep(wait_time)
|
||||||
|
|
||||||
|
except (requests.exceptions.ConnectionError,
|
||||||
|
requests.exceptions.Timeout,
|
||||||
|
requests.exceptions.ReadTimeout) as e:
|
||||||
|
# 连接错误和超时
|
||||||
|
last_exception = e
|
||||||
|
attempts += 1
|
||||||
|
logger.warning(f"连接错误或超时 (尝试 {attempts}/{max_retries}): {str(e)}")
|
||||||
|
if attempts >= max_retries:
|
||||||
|
break
|
||||||
|
wait_time = 3 * (2 ** attempts) # 指数退避:6s, 12s, 24s...
|
||||||
|
logger.info(f"等待 {wait_time} 秒后重试...")
|
||||||
|
time.sleep(wait_time)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# 其他未预期的错误
|
||||||
|
last_exception = e
|
||||||
|
attempts += 1
|
||||||
|
logger.error(f"未预期的错误 (尝试 {attempts}/{max_retries}): {str(e)}")
|
||||||
|
if attempts >= max_retries:
|
||||||
|
break
|
||||||
|
wait_time = 2 * attempts # 线性退避
|
||||||
|
logger.info(f"等待 {wait_time} 秒后重试...")
|
||||||
|
time.sleep(wait_time)
|
||||||
|
|
||||||
|
# 所有重试都失败后
|
||||||
|
logger.error(f"达到最大重试次数 ({max_retries}),请求失败。最后错误: {str(last_exception)}")
|
||||||
|
return f"抱歉,请求遇到网络问题,无法获取分析结果。请检查网络设置或稍后再试。\n错误信息: {str(last_exception)}"
|
||||||
|
|
||||||
|
|
||||||
# 提供简单的访问函数
|
# 提供简单的访问函数
|
||||||
|
Loading…
Reference in New Issue
Block a user