Gemini: Fix For UNEXPECTED_TOOL_CALL With Automatic_function_calling
In the realm of AI development, particularly when leveraging powerful models like Gemini through the google-genai library, encountering unexpected behaviors can be a significant hurdle. One such issue arises with the automatic_function_calling configuration, which, under certain circumstances, persists across API requests, leading to the dreaded FinishReason.UNEXPECTED_TOOL_CALL error. This article delves into the root cause of this problem, provides a step-by-step guide to reproduce it, outlines the expected behavior, and offers a practical workaround to ensure your AI applications function as intended.
Understanding the Problem: Persistent automatic_function_calling
The core of the issue lies in how the automatic_function_calling setting within the GenerateContentConfig is handled across multiple API requests within the same client session. Specifically, if you initiate a request with tools enabled and automatic_function_calling active, subsequent requests with tools=None (i.e., no tools declared) do not automatically disable function calling. Instead, Gemini continues to attempt function calls based on the context from previous requests, resulting in the FinishReason.UNEXPECTED_TOOL_CALL error and, critically, a malformed response where candidate.content is set to None. This behavior deviates from the expected norm, where the absence of declared tools should implicitly disable function calling for that specific request.
Why This Matters
For developers building complex AI-driven applications, especially those utilizing frameworks like CrewAI (a multi-agent framework that orchestrates numerous LLM calls with varying tool configurations), this persistent behavior can introduce significant complications. Imagine a scenario where one agent requires access to specific tools while another operates independently without any tools. If automatic_function_calling remains active from the first agent's request, the second agent's request will inadvertently trigger function call attempts, leading to errors and unpredictable behavior. This necessitates a robust understanding of the underlying issue and a reliable workaround to maintain the integrity of your AI workflows.
Reproducing the Error: A Step-by-Step Guide
To fully grasp the problem, let's walk through the steps to reproduce it:
- Create a Gemini client: Begin by instantiating a Gemini client using the
google-genailibrary. Ensure you are using a model that supports function calling, such asgemini-2.5-pro. - Make a request with tools enabled: Construct a request with tools enabled and
automatic_function_callingset to active. This initial request establishes the context for subsequent calls. - Make a subsequent request with
tools=None: Following the first request, create a new request wheretoolsis explicitly set toNone. This simulates a scenario where you intend to disable function calling. - Observe the error: Execute the second request and carefully examine the response. You should observe the
FinishReasonbeing set toUNEXPECTED_TOOL_CALL, and theresponse.candidates[0].contentwill likely beNone. Additionally, you may encounter a log message indicating that "AFC is enabled with max remote calls: 10", further confirming that automatic function calling is still active despite the absence of declared tools.
By following these steps, you can directly witness the persistent behavior of automatic_function_calling and the resulting UNEXPECTED_TOOL_CALL error.
Expected vs. Actual Behavior: Discrepancies in Function Calling
The expected behavior is that when tools=None or the tools list is empty, automatic function calling (AFC) should be automatically disabled for that specific request. This expectation aligns with the principle of least surprise, where the absence of a feature's configuration should logically imply its deactivation. In other words, if no tools are declared, the model should not attempt to invoke any functions.
However, the actual behavior deviates from this expectation. AFC remains enabled from previous requests, causing Gemini to attempt function calls based on the conversation context, even when no tools are explicitly declared in the current request. This leads to several undesirable consequences:
FinishReason.UNEXPECTED_TOOL_CALL: The API returns an error indicating that a tool call was unexpected in the given context.response.candidates[0].content = None: The response content is empty, rendering the API call effectively useless.- Log message: `