From f51a4d20adee5e938b11d1ffa1154791366b9d41 Mon Sep 17 00:00:00 2001 From: 4Crusaders <1595081195@qq.com> Date: Wed, 6 Aug 2025 14:07:33 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DGemini=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E4=B8=8D=E6=94=AF=E6=8C=81=E5=90=8C=E6=97=B6=E4=BD=BF?= =?UTF-8?q?=E7=94=A8tools=E5=92=8C=E7=BB=93=E6=9E=84=E5=8C=96=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加_is_structured_output_request函数检测是否为结构化JSON输出请求 - 当检测到请求指定responseMimeType为application/json时,跳过gemini-balance主动添加的所有工具 - 仅在非结构化输出场景下,gemini-balance才会自动添加codeExecution、googleSearch、urlContext等工具 - 解决"Tool use with a response mime type: 'application/json' is unsupported"错误 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- app/service/chat/gemini_chat_service.py | 40 +++++++++++++------ .../chat/vertex_express_chat_service.py | 38 ++++++++++++------ 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/app/service/chat/gemini_chat_service.py b/app/service/chat/gemini_chat_service.py index 0845b57..c8276ea 100644 --- a/app/service/chat/gemini_chat_service.py +++ b/app/service/chat/gemini_chat_service.py @@ -119,6 +119,14 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]: record[k] = v return record + def _is_structured_output_request(payload: Dict[str, Any]) -> bool: + """检查请求是否要求结构化JSON输出""" + try: + generation_config = payload.get("generationConfig", {}) + return generation_config.get("responseMimeType") == "application/json" + except (AttributeError, TypeError): + return False + tool = dict() if payload and isinstance(payload, dict) and "tools" in payload: if payload.get("tools") and isinstance(payload.get("tools"), dict): @@ -127,19 +135,25 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]: if items and isinstance(items, list): tool.update(_merge_tools(items)) - if ( - settings.TOOLS_CODE_EXECUTION_ENABLED - and not (model.endswith("-search") or "-thinking" in model) - and not _has_image_parts(payload.get("contents", [])) - ): - tool["codeExecution"] = {} - if model.endswith("-search"): - tool["googleSearch"] = {} - - real_model = _get_real_model(model) - if real_model in settings.URL_CONTEXT_MODELS and settings.URL_CONTEXT_ENABLED: - tool["urlContext"] = {} - + # "Tool use with a response mime type: 'application/json' is unsupported" + # Gemini API限制:不支持同时使用tools和结构化输出(response_mime_type='application/json') + # 当请求指定了JSON响应格式时,跳过所有工具的添加以避免API错误 + has_structured_output = _is_structured_output_request(payload) + if not has_structured_output: + if ( + settings.TOOLS_CODE_EXECUTION_ENABLED + and not (model.endswith("-search") or "-thinking" in model) + and not _has_image_parts(payload.get("contents", [])) + ): + tool["codeExecution"] = {} + + if model.endswith("-search"): + tool["googleSearch"] = {} + + real_model = _get_real_model(model) + if real_model in settings.URL_CONTEXT_MODELS and settings.URL_CONTEXT_ENABLED: + tool["urlContext"] = {} + # 解决 "Tool use with function calling is unsupported" 问题 if tool.get("functionDeclarations") or _has_function_call(payload.get("contents", [])): tool.pop("googleSearch", None) diff --git a/app/service/chat/vertex_express_chat_service.py b/app/service/chat/vertex_express_chat_service.py index 6885ac0..e8371a6 100644 --- a/app/service/chat/vertex_express_chat_service.py +++ b/app/service/chat/vertex_express_chat_service.py @@ -97,6 +97,14 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]: record[k] = v return record + def _is_structured_output_request(payload: Dict[str, Any]) -> bool: + """检查请求是否要求结构化JSON输出""" + try: + generation_config = payload.get("generationConfig", {}) + return generation_config.get("responseMimeType") == "application/json" + except (AttributeError, TypeError): + return False + tool = dict() if payload and isinstance(payload, dict) and "tools" in payload: if payload.get("tools") and isinstance(payload.get("tools"), dict): @@ -105,18 +113,24 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]: if items and isinstance(items, list): tool.update(_merge_tools(items)) - if ( - settings.TOOLS_CODE_EXECUTION_ENABLED - and not (model.endswith("-search") or "-thinking" in model) - and not _has_image_parts(payload.get("contents", [])) - ): - tool["codeExecution"] = {} - if model.endswith("-search"): - tool["googleSearch"] = {} - - real_model = _get_real_model(model) - if real_model in settings.URL_CONTEXT_MODELS and settings.URL_CONTEXT_ENABLED: - tool["urlContext"] = {} + # "Tool use with a response mime type: 'application/json' is unsupported" + # Gemini API限制:不支持同时使用tools和结构化输出(response_mime_type='application/json') + # 当请求指定了JSON响应格式时,跳过所有工具的添加以避免API错误 + has_structured_output = _is_structured_output_request(payload) + if not has_structured_output: + if ( + settings.TOOLS_CODE_EXECUTION_ENABLED + and not (model.endswith("-search") or "-thinking" in model) + and not _has_image_parts(payload.get("contents", [])) + ): + tool["codeExecution"] = {} + + if model.endswith("-search"): + tool["googleSearch"] = {} + + real_model = _get_real_model(model) + if real_model in settings.URL_CONTEXT_MODELS and settings.URL_CONTEXT_ENABLED: + tool["urlContext"] = {} # 解决 "Tool use with function calling is unsupported" 问题 if tool.get("functionDeclarations") or _has_function_call(payload.get("contents", [])):