From 8f71e65f8cb5456182e292774370d2f1eca52568 Mon Sep 17 00:00:00 2001 From: Qihang Zhang Date: Mon, 21 Apr 2025 11:36:22 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=91=20fix(llm=5Fmanager):=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0API=E8=AF=B7=E6=B1=82=E9=87=8D=E8=AF=95=E6=9C=BA?= =?UTF-8?q?=E5=88=B6=EF=BC=8C=E4=BC=98=E5=8C=96=E7=BD=91=E7=BB=9C=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llm_manager.py | 103 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/llm_manager.py b/llm_manager.py index 256eddd..4a8f82d 100644 --- a/llm_manager.py +++ b/llm_manager.py @@ -1,7 +1,6 @@ from typing import Optional - import requests - +import time from config_manager import get_config_manager from logger_manager import get_logger @@ -11,7 +10,6 @@ logger = get_logger() class LLMManager: """LLM管理器,负责加载API配置并提供与LLM交互的功能""" - _instance = None # 单例实例 def __init__(self): @@ -19,6 +17,7 @@ class LLMManager: self._api_base = None self._model = None self._temperature = None + self._config = None def __new__(cls): """实现单例模式""" @@ -34,23 +33,23 @@ class LLMManager: def initialize(self): """初始化LLM配置""" llm_config = config_manager.get('llm', {}) - # 加载LLM配置 self._api_key = llm_config.get('api_key', '') self._api_base = llm_config.get('api_base', 'https://api.openai.com/v1') self._model = llm_config.get('model', 'gpt-3.5-turbo') self._temperature = llm_config.get('temperature', 0.7) - + self._config = llm_config if not self._api_key: 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: content: 用户输入内容 prompt: 可选的系统提示词 + max_retries: 最大重试次数,默认为5 Returns: LLM的回复内容 @@ -67,7 +66,6 @@ class LLMManager: # 添加系统提示(如果有) if prompt: messages.append({"role": "system", "content": prompt}) - # 添加用户消息 messages.append({"role": "user", "content": content}) @@ -79,17 +77,88 @@ class LLMManager: logger.debug(f"请求数据: {payload}") - response = requests.post( - f"{self._api_base}/chat/completions", - headers=headers, - json=payload - ) + # 实现重试机制 + attempts = 0 + last_exception = None - if response.status_code != 200: - logger.info(f"请求失败: {response.status_code}, {response.text}") - return "请求失败,请稍后再试。" + while attempts < max_retries: + try: + # 尝试直接不使用代理 + if attempts > 0: + logger.info(f"尝试不使用代理进行请求 (尝试 {attempts + 1}/{max_retries})") + response = requests.post( + f"{self._api_base}/chat/completions", + headers=headers, + json=payload, + proxies=None, # 明确不使用代理 + timeout=30 # 设置超时时间 + ) + else: + # 第一次尝试使用默认设置 + response = requests.post( + f"{self._api_base}/chat/completions", + headers=headers, + json=payload, + timeout=30 # 设置超时时间 + ) - return response.json()["choices"][0]["message"]["content"] + if response.status_code == 200: + 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)}" # 提供简单的访问函数