Skip to content

bypass_multi_tools_limit on VertexAiSearchTool is a leaky abstraction: unexpected dependencies, silent shift from inbuilt RAG to tool calling, and prompt fragility #7100

Description

@vadakattu

The bypass_multi_tools_limit=True flag on VertexAiSearchTool is presented as a convenient boolean toggle to allow using Vertex AI Search alongside other tools. In practice, this flag is implemented as a hidden class replacement (VertexAiSearchToolDiscoveryEngineSearchTool) that breaks the developer experience in three major ways:

  1. Unexpected runtime dependency: Silently requires google-cloud-discoveryengine (google-adk[gcp]), failing at runtime with a ModuleNotFoundError.
  2. Silent shift from inbuilt RAG to client tool calling: Transparent, citation-backed model retrieval is secretly replaced with an explicit client-side function call.
  3. Hardcoded tool naming and prompt fragility: The substituted tool is hardcoded as discovery_engine_search. Because developers write instructions for their domain (e.g., "use the knowledge base"), the model naturally hallucinates calling search(...) instead, causing runtime crashes (ValueError: Tool 'search' not found).

This breaks the illusion that setting bypass_multi_tools_limit=True is a clean, seamless configuration switch.


Minimal Reproduction

Consider a minimal agent combining a knowledge base search with a single custom helper function:

from google.adk.agents import Agent
from google.adk.tools import VertexAiSearchTool


def get_user_tier() -> str:
    """Returns the loyalty tier of the current user."""
    return "Platinum"


search_tool = VertexAiSearchTool(
    data_store_id="projects/my-project/locations/global/collections/default_collection/dataStores/my-store",
    max_results=10,
    bypass_multi_tools_limit=True,
)

agent = Agent(
    name="support_agent",
    model="gemini-flash-lite-latest",
    static_instruction="You are a helpful support assistant. Answer user questions using the knowledge base.",
    tools=[search_tool, get_user_tier],
)

The Issues

1. Undeclared Runtime Dependency (google-adk[gcp])

When bypass_multi_tools_limit=False (or when the agent has only one tool), VertexAiSearchTool works with the base google-adk package using the Gemini API's built-in grounding (types.Tool(retrieval=...)).

However, the moment a second tool is added and bypass_multi_tools_limit=True is set, ADK's internal resolver (llm_agent.py) silently swaps VertexAiSearchTool for DiscoveryEngineSearchTool. This class imports google.cloud.discoveryengine, immediately crashing with:

ModuleNotFoundError: No module named 'google.cloud.discoveryengine'

There is no warning at agent instantiation time indicating that setting this flag requires the [gcp] extra.

2. Silent Paradigm Shift: Inbuilt RAG Grounding → Tool Calling

Developers choose VertexAiSearchTool because it integrates natively with Gemini's retrieval capability:

  • Grounding happens transparently inside the model generation turn.
  • The model returns grounded responses with citations and groundingMetadata.
  • The model does not need to decide whether to execute a function call, construct JSON arguments, or wait for a second inference round-trip.

Flipping bypass_multi_tools_limit=True quietly transforms this into a client-side function calling tool:

  • The model must now generate a structured tool call.
  • A local API client executes an RPC to Discovery Engine.
  • The raw JSON results are piped back into the conversation context for a second LLM turn.

This fundamental architectural shift is completely hidden behind what appears to be a minor transport flag.

3. Leaky Tool Naming & Prompt Fragility (discovery_engine_search)

In discovery_engine_search_tool.py, the substituted tool inherits from FunctionTool and registers self.discovery_engine_search:

class DiscoveryEngineSearchTool(FunctionTool):
    def __init__(self, ...):
        super().__init__(self.discovery_engine_search)

This creates two critical problems:

  1. The name cannot be customized: The function name is hardcoded to "discovery_engine_search" with the docstring "Search through Vertex AI Search's discovery engine search API." Neither VertexAiSearchTool nor DiscoveryEngineSearchTool accepts a name or description parameter.
  2. The model fails to call it: Prompts written naturally (e.g. "Answer user questions using the knowledge base") give the model no reason to suspect the tool is called discovery_engine_search. LLMs (especially lightweight models like gemini-flash-lite) guess generic names like search(query=...), leading directly to:
    ValueError: Tool 'search' not found.
    Available tools: discovery_engine_search, get_user_tier
    

To make the agent work, developers are forced to leak internal Google Cloud plumbing into user-facing prompts:

"Answer user questions using the knowledge base by calling discovery_engine_search."

Suggested Improvements

  1. Allow Custom Tool Naming and Description:
    If VertexAiSearchTool is going to be transformed into a client FunctionTool, it must accept name and description parameters (e.g., name="knowledge_base_search"), forwarding them to DiscoveryEngineSearchTool so the tool declaration matches the domain instructions.

  2. Handle Common Name Aliases / Fuzzy Resolution:
    When DiscoveryEngineSearchTool is the only search tool present, ADK should either register search as an alias or allow flexible resolution rather than failing with a hard ValueError.

  3. Explicit Tooling over Magic Flags:
    Rather than hiding a completely different execution model and dependency set behind bypass_multi_tools_limit=True, consider deprecating the flag in favor of:

    • Providing DiscoveryEngineSearchTool directly as a first-class, documented tool when client-side search is desired.
    • Documenting the sub-agent pattern (AgentTool / sub_agents) as the recommended architectural pattern when combining native search retrieval grounding with function tools.
  4. Fail Fast with Clear Dependency Errors:
    If bypass_multi_tools_limit=True is used without google-cloud-discoveryengine installed, raise a clear error during Agent.__init__ instructing the user to install google-adk[gcp].

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions