Merge pull request #286 from 4Crusaders:fix/gemini-structured-output-tools-conflict

fix: 修复Gemini模型不支持同时使用tools和结构化输出的问题
This commit is contained in:
snaily
2025-08-16 01:13:18 +08:00
committed by GitHub
2 changed files with 53 additions and 25 deletions
+14
View File
@@ -119,6 +119,14 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]:
record[k] = v record[k] = v
return record 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() tool = dict()
if payload and isinstance(payload, dict) and "tools" in payload: if payload and isinstance(payload, dict) and "tools" in payload:
if payload.get("tools") and isinstance(payload.get("tools"), dict): if payload.get("tools") and isinstance(payload.get("tools"), dict):
@@ -127,12 +135,18 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]:
if items and isinstance(items, list): if items and isinstance(items, list):
tool.update(_merge_tools(items)) tool.update(_merge_tools(items))
# "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 ( if (
settings.TOOLS_CODE_EXECUTION_ENABLED settings.TOOLS_CODE_EXECUTION_ENABLED
and not (model.endswith("-search") or "-thinking" in model) and not (model.endswith("-search") or "-thinking" in model)
and not _has_image_parts(payload.get("contents", [])) and not _has_image_parts(payload.get("contents", []))
): ):
tool["codeExecution"] = {} tool["codeExecution"] = {}
if model.endswith("-search"): if model.endswith("-search"):
tool["googleSearch"] = {} tool["googleSearch"] = {}
@@ -97,6 +97,14 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]:
record[k] = v record[k] = v
return record 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() tool = dict()
if payload and isinstance(payload, dict) and "tools" in payload: if payload and isinstance(payload, dict) and "tools" in payload:
if payload.get("tools") and isinstance(payload.get("tools"), dict): if payload.get("tools") and isinstance(payload.get("tools"), dict):
@@ -105,12 +113,18 @@ def _build_tools(model: str, payload: Dict[str, Any]) -> List[Dict[str, Any]]:
if items and isinstance(items, list): if items and isinstance(items, list):
tool.update(_merge_tools(items)) tool.update(_merge_tools(items))
# "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 ( if (
settings.TOOLS_CODE_EXECUTION_ENABLED settings.TOOLS_CODE_EXECUTION_ENABLED
and not (model.endswith("-search") or "-thinking" in model) and not (model.endswith("-search") or "-thinking" in model)
and not _has_image_parts(payload.get("contents", [])) and not _has_image_parts(payload.get("contents", []))
): ):
tool["codeExecution"] = {} tool["codeExecution"] = {}
if model.endswith("-search"): if model.endswith("-search"):
tool["googleSearch"] = {} tool["googleSearch"] = {}