Skip to content

Commit 69627b6

Browse files
wuliang229copybara-github
authored andcommitted
chore: Implement lazy loading for modules within google.adk.tools
This is ~27% of the current cold start latency after previous changes are submitted. This change refactors `google.adk.tools/__init__.py` to use `__getattr__` for lazy loading of all tools and related classes. Previously, all modules were imported directly upon `google.adk.tools` import, leading to potentially long initial import times. With lazy loading, modules are only imported when they are first accessed, improving the initial startup performance. Co-authored-by: Liang Wu <wuliang@google.com> PiperOrigin-RevId: 831537187
1 parent 0ab79b9 commit 69627b6

File tree

1 file changed

+84
-55
lines changed

1 file changed

+84
-55
lines changed

src/google/adk/tools/__init__.py

Lines changed: 84 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,65 +11,94 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
import importlib
1415
import logging
1516
import sys
17+
from typing import Any
18+
from typing import TYPE_CHECKING
1619

17-
from ..auth.auth_tool import AuthToolArguments
18-
from .agent_tool import AgentTool
19-
from .apihub_tool.apihub_toolset import APIHubToolset
20-
from .base_tool import BaseTool
21-
from .discovery_engine_search_tool import DiscoveryEngineSearchTool
22-
from .enterprise_search_tool import enterprise_web_search_tool as enterprise_web_search
23-
from .example_tool import ExampleTool
24-
from .exit_loop_tool import exit_loop
25-
from .function_tool import FunctionTool
26-
from .get_user_choice_tool import get_user_choice_tool as get_user_choice
27-
from .google_maps_grounding_tool import google_maps_grounding
28-
from .google_search_tool import google_search
29-
from .load_artifacts_tool import load_artifacts_tool as load_artifacts
30-
from .load_memory_tool import load_memory_tool as load_memory
31-
from .long_running_tool import LongRunningFunctionTool
32-
from .preload_memory_tool import preload_memory_tool as preload_memory
33-
from .tool_context import ToolContext
34-
from .transfer_to_agent_tool import transfer_to_agent
35-
from .url_context_tool import url_context
36-
from .vertex_ai_search_tool import VertexAiSearchTool
20+
# The TYPE_CHECKING block is needed for autocomplete to work.
21+
if TYPE_CHECKING:
22+
from ..auth.auth_tool import AuthToolArguments
23+
from .agent_tool import AgentTool
24+
from .apihub_tool.apihub_toolset import APIHubToolset
25+
from .base_tool import BaseTool
26+
from .discovery_engine_search_tool import DiscoveryEngineSearchTool
27+
from .enterprise_search_tool import enterprise_web_search_tool as enterprise_web_search
28+
from .example_tool import ExampleTool
29+
from .exit_loop_tool import exit_loop
30+
from .function_tool import FunctionTool
31+
from .get_user_choice_tool import get_user_choice_tool as get_user_choice
32+
from .google_maps_grounding_tool import google_maps_grounding
33+
from .google_search_tool import google_search
34+
from .load_artifacts_tool import load_artifacts_tool as load_artifacts
35+
from .load_memory_tool import load_memory_tool as load_memory
36+
from .long_running_tool import LongRunningFunctionTool
37+
from .preload_memory_tool import preload_memory_tool as preload_memory
38+
from .tool_context import ToolContext
39+
from .transfer_to_agent_tool import transfer_to_agent
40+
from .url_context_tool import url_context
41+
from .vertex_ai_search_tool import VertexAiSearchTool
3742

38-
__all__ = [
39-
'AgentTool',
40-
'APIHubToolset',
41-
'AuthToolArguments',
42-
'BaseTool',
43-
'DiscoveryEngineSearchTool',
44-
'enterprise_web_search',
45-
'google_maps_grounding',
46-
'google_search',
47-
'url_context',
48-
'VertexAiSearchTool',
49-
'ExampleTool',
50-
'exit_loop',
51-
'FunctionTool',
52-
'get_user_choice',
53-
'load_artifacts',
54-
'load_memory',
55-
'LongRunningFunctionTool',
56-
'preload_memory',
57-
'ToolContext',
58-
'transfer_to_agent',
59-
]
43+
# If you are adding a new tool to this file, please make sure you add it to the
44+
# lazy mapping to avoid expensive imports. If the tool is not using any third
45+
# party dependencies, please feel free to import it eagerly at the top of this
46+
# file.
47+
_LAZY_MAPPING = {
48+
'AuthToolArguments': ('..auth.auth_tool', 'AuthToolArguments'),
49+
'AgentTool': ('.agent_tool', 'AgentTool'),
50+
'APIHubToolset': ('.apihub_tool.apihub_toolset', 'APIHubToolset'),
51+
'BaseTool': ('.base_tool', 'BaseTool'),
52+
'DiscoveryEngineSearchTool': (
53+
'.discovery_engine_search_tool',
54+
'DiscoveryEngineSearchTool',
55+
),
56+
'enterprise_web_search': (
57+
'.enterprise_search_tool',
58+
'enterprise_web_search_tool',
59+
),
60+
'ExampleTool': ('.example_tool', 'ExampleTool'),
61+
'exit_loop': ('.exit_loop_tool', 'exit_loop'),
62+
'FunctionTool': ('.function_tool', 'FunctionTool'),
63+
'get_user_choice': ('.get_user_choice_tool', 'get_user_choice_tool'),
64+
'google_maps_grounding': (
65+
'.google_maps_grounding_tool',
66+
'google_maps_grounding',
67+
),
68+
'google_search': ('.google_search_tool', 'google_search'),
69+
'load_artifacts': ('.load_artifacts_tool', 'load_artifacts_tool'),
70+
'load_memory': ('.load_memory_tool', 'load_memory_tool'),
71+
'LongRunningFunctionTool': (
72+
'.long_running_tool',
73+
'LongRunningFunctionTool',
74+
),
75+
'preload_memory': ('.preload_memory_tool', 'preload_memory_tool'),
76+
'ToolContext': ('.tool_context', 'ToolContext'),
77+
'transfer_to_agent': ('.transfer_to_agent_tool', 'transfer_to_agent'),
78+
'url_context': ('.url_context_tool', 'url_context'),
79+
'VertexAiSearchTool': ('.vertex_ai_search_tool', 'VertexAiSearchTool'),
80+
'MCPToolset': ('.mcp_tool.mcp_toolset', 'MCPToolset'),
81+
'McpToolset': ('.mcp_tool.mcp_toolset', 'McpToolset'),
82+
}
6083

84+
__all__ = list(_LAZY_MAPPING.keys())
6185

62-
if sys.version_info < (3, 10):
63-
logger = logging.getLogger('google_adk.' + __name__)
64-
logger.warning(
65-
'MCP requires Python 3.10 or above. Please upgrade your Python'
66-
' version in order to use it.'
67-
)
68-
else:
69-
from .mcp_tool.mcp_toolset import MCPToolset
70-
from .mcp_tool.mcp_toolset import McpToolset
7186

72-
__all__.extend([
73-
'MCPToolset',
74-
'McpToolset',
75-
])
87+
def __getattr__(name: str) -> Any:
88+
"""Lazy loads tools to avoid expensive imports."""
89+
if name not in _LAZY_MAPPING:
90+
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')
91+
92+
module_path, attr_name = _LAZY_MAPPING[name]
93+
# __name__ is `google.adk.tools` and we are doing a relative import
94+
# from there.
95+
module = importlib.import_module(module_path, __name__)
96+
attr = getattr(module, attr_name)
97+
globals()[name] = attr
98+
return attr
99+
100+
101+
# __dir__ is used to expose all public interfaces to keep mocking with autoscope
102+
# working.
103+
def __dir__() -> list[str]:
104+
return list(globals().keys()) + __all__

0 commit comments

Comments
 (0)