mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
feat: Add bypass_multi_tools_limit option to GoogleSearchTool and VertexAiSearchTool
PiperOrigin-RevId: 817493869
This commit is contained in:
committed by
Copybara-Service
parent
64646e0002
commit
9a6b8507f0
@@ -118,17 +118,19 @@ async def _convert_tool_union_to_tools(
|
|||||||
model: Union[str, BaseLlm],
|
model: Union[str, BaseLlm],
|
||||||
multiple_tools: bool = False,
|
multiple_tools: bool = False,
|
||||||
) -> list[BaseTool]:
|
) -> list[BaseTool]:
|
||||||
from ..tools.google_search_tool import google_search
|
from ..tools.google_search_tool import GoogleSearchTool
|
||||||
from ..tools.vertex_ai_search_tool import VertexAiSearchTool
|
from ..tools.vertex_ai_search_tool import VertexAiSearchTool
|
||||||
|
|
||||||
# Wrap google_search tool with AgentTool if there are multiple tools because
|
# Wrap google_search tool with AgentTool if there are multiple tools because
|
||||||
# the built-in tools cannot be used together with other tools.
|
# the built-in tools cannot be used together with other tools.
|
||||||
# TODO(b/448114567): Remove once the workaround is no longer needed.
|
# TODO(b/448114567): Remove once the workaround is no longer needed.
|
||||||
if multiple_tools and tool_union is google_search:
|
if multiple_tools and isinstance(tool_union, GoogleSearchTool):
|
||||||
from ..tools.google_search_agent_tool import create_google_search_agent
|
from ..tools.google_search_agent_tool import create_google_search_agent
|
||||||
from ..tools.google_search_agent_tool import GoogleSearchAgentTool
|
from ..tools.google_search_agent_tool import GoogleSearchAgentTool
|
||||||
|
|
||||||
return [GoogleSearchAgentTool(create_google_search_agent(model))]
|
search_tool = cast(GoogleSearchTool, tool_union)
|
||||||
|
if search_tool.bypass_multi_tools_limit:
|
||||||
|
return [GoogleSearchAgentTool(create_google_search_agent(model))]
|
||||||
|
|
||||||
# Replace VertexAiSearchTool with DiscoveryEngineSearchTool if there are
|
# Replace VertexAiSearchTool with DiscoveryEngineSearchTool if there are
|
||||||
# multiple tools because the built-in tools cannot be used together with
|
# multiple tools because the built-in tools cannot be used together with
|
||||||
@@ -138,15 +140,16 @@ async def _convert_tool_union_to_tools(
|
|||||||
from ..tools.discovery_engine_search_tool import DiscoveryEngineSearchTool
|
from ..tools.discovery_engine_search_tool import DiscoveryEngineSearchTool
|
||||||
|
|
||||||
vais_tool = cast(VertexAiSearchTool, tool_union)
|
vais_tool = cast(VertexAiSearchTool, tool_union)
|
||||||
return [
|
if vais_tool.bypass_multi_tools_limit:
|
||||||
DiscoveryEngineSearchTool(
|
return [
|
||||||
data_store_id=vais_tool.data_store_id,
|
DiscoveryEngineSearchTool(
|
||||||
data_store_specs=vais_tool.data_store_specs,
|
data_store_id=vais_tool.data_store_id,
|
||||||
search_engine_id=vais_tool.search_engine_id,
|
data_store_specs=vais_tool.data_store_specs,
|
||||||
filter=vais_tool.filter,
|
search_engine_id=vais_tool.search_engine_id,
|
||||||
max_results=vais_tool.max_results,
|
filter=vais_tool.filter,
|
||||||
)
|
max_results=vais_tool.max_results,
|
||||||
]
|
)
|
||||||
|
]
|
||||||
|
|
||||||
if isinstance(tool_union, BaseTool):
|
if isinstance(tool_union, BaseTool):
|
||||||
return [tool_union]
|
return [tool_union]
|
||||||
|
|||||||
@@ -35,9 +35,17 @@ class GoogleSearchTool(BaseTool):
|
|||||||
local code execution.
|
local code execution.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, *, bypass_multi_tools_limit: bool = True):
|
||||||
|
"""Initializes the Google search tool.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bypass_multi_tools_limit: Whether to bypass the multi tools limitation,
|
||||||
|
so that the tool can be used with other tools in the same agent.
|
||||||
|
"""
|
||||||
|
|
||||||
# Name and description are not used because this is a model built-in tool.
|
# Name and description are not used because this is a model built-in tool.
|
||||||
super().__init__(name='google_search', description='google_search')
|
super().__init__(name='google_search', description='google_search')
|
||||||
|
self.bypass_multi_tools_limit = bypass_multi_tools_limit
|
||||||
|
|
||||||
@override
|
@override
|
||||||
async def process_llm_request(
|
async def process_llm_request(
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ class VertexAiSearchTool(BaseTool):
|
|||||||
search_engine_id: Optional[str] = None,
|
search_engine_id: Optional[str] = None,
|
||||||
filter: Optional[str] = None,
|
filter: Optional[str] = None,
|
||||||
max_results: Optional[int] = None,
|
max_results: Optional[int] = None,
|
||||||
|
bypass_multi_tools_limit: bool = True,
|
||||||
):
|
):
|
||||||
"""Initializes the Vertex AI Search tool.
|
"""Initializes the Vertex AI Search tool.
|
||||||
|
|
||||||
@@ -58,6 +59,10 @@ class VertexAiSearchTool(BaseTool):
|
|||||||
searched. It should only be set if engine is used.
|
searched. It should only be set if engine is used.
|
||||||
search_engine_id: The Vertex AI search engine resource ID in the format of
|
search_engine_id: The Vertex AI search engine resource ID in the format of
|
||||||
"projects/{project}/locations/{location}/collections/{collection}/engines/{engine}".
|
"projects/{project}/locations/{location}/collections/{collection}/engines/{engine}".
|
||||||
|
filter: The filter to apply to the search results.
|
||||||
|
max_results: The maximum number of results to return.
|
||||||
|
bypass_multi_tools_limit: Whether to bypass the multi tools limitation,
|
||||||
|
so that the tool can be used with other tools in the same agent.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If both data_store_id and search_engine_id are not specified
|
ValueError: If both data_store_id and search_engine_id are not specified
|
||||||
@@ -80,6 +85,7 @@ class VertexAiSearchTool(BaseTool):
|
|||||||
self.search_engine_id = search_engine_id
|
self.search_engine_id = search_engine_id
|
||||||
self.filter = filter
|
self.filter = filter
|
||||||
self.max_results = max_results
|
self.max_results = max_results
|
||||||
|
self.bypass_multi_tools_limit = bypass_multi_tools_limit
|
||||||
|
|
||||||
@override
|
@override
|
||||||
async def process_llm_request(
|
async def process_llm_request(
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from google.adk.models.llm_request import LlmRequest
|
|||||||
from google.adk.models.registry import LLMRegistry
|
from google.adk.models.registry import LLMRegistry
|
||||||
from google.adk.sessions.in_memory_session_service import InMemorySessionService
|
from google.adk.sessions.in_memory_session_service import InMemorySessionService
|
||||||
from google.adk.tools.google_search_tool import google_search
|
from google.adk.tools.google_search_tool import google_search
|
||||||
|
from google.adk.tools.google_search_tool import GoogleSearchTool
|
||||||
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
|
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
|
||||||
from google.genai import types
|
from google.genai import types
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
@@ -310,6 +311,25 @@ class TestCanonicalTools:
|
|||||||
assert tools[1].name == 'google_search_agent'
|
assert tools[1].name == 'google_search_agent'
|
||||||
assert tools[1].__class__.__name__ == 'GoogleSearchAgentTool'
|
assert tools[1].__class__.__name__ == 'GoogleSearchAgentTool'
|
||||||
|
|
||||||
|
async def test_handle_google_search_with_other_tools_no_bypass(self):
|
||||||
|
"""Test that google_search is not wrapped into an agent."""
|
||||||
|
agent = LlmAgent(
|
||||||
|
name='test_agent',
|
||||||
|
model='gemini-pro',
|
||||||
|
tools=[
|
||||||
|
self._my_tool,
|
||||||
|
GoogleSearchTool(bypass_multi_tools_limit=False),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
ctx = await _create_readonly_context(agent)
|
||||||
|
tools = await agent.canonical_tools(ctx)
|
||||||
|
|
||||||
|
assert len(tools) == 2
|
||||||
|
assert tools[0].name == '_my_tool'
|
||||||
|
assert tools[0].__class__.__name__ == 'FunctionTool'
|
||||||
|
assert tools[1].name == 'google_search'
|
||||||
|
assert tools[1].__class__.__name__ == 'GoogleSearchTool'
|
||||||
|
|
||||||
async def test_handle_google_search_only(self):
|
async def test_handle_google_search_only(self):
|
||||||
"""Test that google_search is not wrapped into an agent."""
|
"""Test that google_search is not wrapped into an agent."""
|
||||||
agent = LlmAgent(
|
agent = LlmAgent(
|
||||||
@@ -346,8 +366,8 @@ class TestCanonicalTools:
|
|||||||
'google.auth.default',
|
'google.auth.default',
|
||||||
mock.MagicMock(return_value=('credentials', 'project')),
|
mock.MagicMock(return_value=('credentials', 'project')),
|
||||||
)
|
)
|
||||||
async def test_handle_google_vais_with_other_tools(self):
|
async def test_handle_vais_with_other_tools(self):
|
||||||
"""Test that VertexAiSearchTool is wrapped into an agent."""
|
"""Test that VertexAiSearchTool is replaced with Discovery Engine Search."""
|
||||||
agent = LlmAgent(
|
agent = LlmAgent(
|
||||||
name='test_agent',
|
name='test_agent',
|
||||||
model='gemini-pro',
|
model='gemini-pro',
|
||||||
@@ -365,6 +385,28 @@ class TestCanonicalTools:
|
|||||||
assert tools[1].name == 'discovery_engine_search'
|
assert tools[1].name == 'discovery_engine_search'
|
||||||
assert tools[1].__class__.__name__ == 'DiscoveryEngineSearchTool'
|
assert tools[1].__class__.__name__ == 'DiscoveryEngineSearchTool'
|
||||||
|
|
||||||
|
async def test_handle_vais_with_other_tools_no_bypass(self):
|
||||||
|
"""Test that VertexAiSearchTool is not replaced."""
|
||||||
|
agent = LlmAgent(
|
||||||
|
name='test_agent',
|
||||||
|
model='gemini-pro',
|
||||||
|
tools=[
|
||||||
|
self._my_tool,
|
||||||
|
VertexAiSearchTool(
|
||||||
|
data_store_id='test_data_store_id',
|
||||||
|
bypass_multi_tools_limit=False,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
ctx = await _create_readonly_context(agent)
|
||||||
|
tools = await agent.canonical_tools(ctx)
|
||||||
|
|
||||||
|
assert len(tools) == 2
|
||||||
|
assert tools[0].name == '_my_tool'
|
||||||
|
assert tools[0].__class__.__name__ == 'FunctionTool'
|
||||||
|
assert tools[1].name == 'vertex_ai_search'
|
||||||
|
assert tools[1].__class__.__name__ == 'VertexAiSearchTool'
|
||||||
|
|
||||||
async def test_handle_vais_only(self):
|
async def test_handle_vais_only(self):
|
||||||
"""Test that VertexAiSearchTool is not wrapped into an agent."""
|
"""Test that VertexAiSearchTool is not wrapped into an agent."""
|
||||||
agent = LlmAgent(
|
agent = LlmAgent(
|
||||||
|
|||||||
Reference in New Issue
Block a user