From a125f5c90667a940f3e31621fca88468ecd042bd Mon Sep 17 00:00:00 2001 From: dw1161 Date: Sat, 21 Mar 2026 15:34:39 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=84=20Google=20client=20=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=20SSL/=E8=BF=9E=E6=8E=A5=E9=94=99=E8=AF=AF=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E9=87=8D=E8=AF=95=EF=BC=88=E6=8C=87=E6=95=B0=E9=80=80?= =?UTF-8?q?=E9=81=BF=EF=BC=8C=E6=9C=80=E5=A4=9A5=E6=AC=A1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tradingagents/llm_clients/google_client.py | 33 ++++++++++++++-------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/tradingagents/llm_clients/google_client.py b/tradingagents/llm_clients/google_client.py index 3dd85e3f..4b105ef6 100644 --- a/tradingagents/llm_clients/google_client.py +++ b/tradingagents/llm_clients/google_client.py @@ -1,3 +1,5 @@ +import time +import random from typing import Any, Optional from langchain_google_genai import ChatGoogleGenerativeAI @@ -7,11 +9,7 @@ from .validators import validate_model class NormalizedChatGoogleGenerativeAI(ChatGoogleGenerativeAI): - """ChatGoogleGenerativeAI with normalized content output. - - Gemini 3 models return content as list: [{'type': 'text', 'text': '...'}] - This normalizes to string for consistent downstream handling. - """ + """ChatGoogleGenerativeAI with normalized content output and auto-retry on SSL/connection errors.""" def _normalize_content(self, response): content = response.content @@ -25,7 +23,24 @@ class NormalizedChatGoogleGenerativeAI(ChatGoogleGenerativeAI): return response def invoke(self, input, config=None, **kwargs): - return self._normalize_content(super().invoke(input, config, **kwargs)) + max_retries = 5 + for attempt in range(1, max_retries + 1): + try: + return self._normalize_content(super().invoke(input, config, **kwargs)) + except Exception as e: + err = str(e) + # 判断是否为可重试的网络错误 + retryable = any(kw in err for kw in [ + "SSL", "EOF", "RemoteProtocolError", "ConnectError", + "Server disconnected", "ConnectionError", "timeout", + "503", "502", "500", + ]) + if retryable and attempt < max_retries: + wait = 2 ** attempt + random.uniform(0, 2) + print(f"\n⚠️ Gemini 连接失败(第 {attempt}/{max_retries} 次),{wait:.1f}s 后重试... [{type(e).__name__}]") + time.sleep(wait) + else: + raise class GoogleClient(BaseLLMClient): @@ -42,20 +57,14 @@ class GoogleClient(BaseLLMClient): if key in self.kwargs: llm_kwargs[key] = self.kwargs[key] - # Map thinking_level to appropriate API param based on model - # Gemini 3 Pro: low, high - # Gemini 3 Flash: minimal, low, medium, high - # Gemini 2.5: thinking_budget (0=disable, -1=dynamic) thinking_level = self.kwargs.get("thinking_level") if thinking_level: model_lower = self.model.lower() if "gemini-3" in model_lower: - # Gemini 3 Pro doesn't support "minimal", use "low" instead if "pro" in model_lower and thinking_level == "minimal": thinking_level = "low" llm_kwargs["thinking_level"] = thinking_level else: - # Gemini 2.5: map to thinking_budget llm_kwargs["thinking_budget"] = -1 if thinking_level == "high" else 0 return NormalizedChatGoogleGenerativeAI(**llm_kwargs)