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 (VertexAiSearchTool → DiscoveryEngineSearchTool) 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

  1. chelsealong commented on Sep 12, 2026

    @chelsealong
    Contributor

    Picking this one up now — opening a PR shortly. Flagging it here so nobody duplicates the work; if someone is already on it, say so and I will drop mine.

  2. llalitkumarrr commented on Sep 15, 2026

    @llalitkumarrr
    Collaborator

    Hello @vadakattu,

    VertexAiSearchTool is replaced with DiscoveryEngineSearchTool since built in tools cannot be used with other tools.
    Also PR #7121 should address the hardcoded tool naming and runtime dependency issues. Could you please review it and let me know your thoughts?

  3. added
    request clarification[Status] The maintainer need clarification or more information from the author
    on Sep 15, 2026
  4. added a commit that references this issue on Sep 15, 2026
    a25cde5
  5. adk-bot commented on Sep 23, 2026

    @adk-bot
    Collaborator

    This issue has been automatically marked as stale because it has not had recent activity for 7 days after a maintainer requested clarification. It will be closed if no further activity occurs within 7 days.

  6. added
    stale[Status] Issues which have been marked inactive since there is no user response
    on Sep 23, 2026
  7. chelsealong commented on Sep 23, 2026

    @chelsealong
    Contributor

    For the stale bot — recording what has shipped against the three parts of this report, so the state is visible before it auto-closes:

    1. Unexpected dependencies — fixed. fix: raise clear ImportError when VertexAiSearchTool bypass needs google-adk[gcp] #7101 landed as 4e73b7d: VertexAiSearchTool with bypass_multi_tools_limit now raises a clear ImportError naming the missing google-cloud-discoveryengine dependency instead of failing obscurely at call time.
    2. Hardcoded tool naming — @llalitkumarrr's allow custom name/description when VertexAiSearchTool is swapped #7121 is open for this.
    3. Silent shift from built-in RAG to tool calling, and prompt fragility — still open, and this is the part that needs @vadakattu's input. It is a design question about what the bypass should do, not a defect with an obvious fix.

    So the issue is not stale for lack of work; parts 1 and 2 have been acted on. Part 3 is the one waiting.

  8. removed
    stale[Status] Issues which have been marked inactive since there is no user response
    on Sep 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

request clarification[Status] The maintainer need clarification or more information from the authortools[Component] This issue is related to tools

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions