Skip to content

Fix #2433: Optimize import time with lazy loading#4803

Draft
9chait9 wants to merge 2 commits intogoogle:mainfrom
9chait9:fix/issue-2433
Draft

Fix #2433: Optimize import time with lazy loading#4803
9chait9 wants to merge 2 commits intogoogle:mainfrom
9chait9:fix/issue-2433

Conversation

@9chait9
Copy link

@9chait9 9chait9 commented Mar 12, 2026

Fixes #2433: This PR addresses the high import overhead of the google-adk library by implementing lazy loading in the top-level __init__.py and the agents module's __init__.py. This should significantly improve cold start times in serverless environments.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly optimizes the import time of the google-adk library by introducing lazy loading for key modules. By deferring the actual import of components until they are explicitly accessed, the change aims to reduce the initial overhead, particularly benefiting environments where cold start times are critical, such as serverless functions.

Highlights

  • Top-level module lazy loading: Implemented lazy loading for Agent, Context, and Runner in src/google/adk/__init__.py using __getattr__ to defer imports until access.
  • Agents module lazy loading: Applied lazy loading to numerous agent-related classes within src/google/adk/agents/__init__.py to reduce initial import costs.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/google/adk/init.py
    • Replaced direct imports of Context, Agent, and Runner with a __getattr__ implementation for lazy loading.
    • Added TYPE_CHECKING block for static type checkers to correctly resolve types without triggering runtime imports.
  • src/google/adk/agents/init.py
    • Converted all direct imports of agent-related classes (e.g., BaseAgent, Context, LlmAgent) to a __getattr__ based lazy loading mechanism.
    • Included TYPE_CHECKING for type hint compatibility.
Activity
  • No specific activity (comments, reviews, or progress updates) has been recorded for this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@adk-bot adk-bot added the core [Component] This issue is related to the core interface and implementation label Mar 12, 2026
@adk-bot
Copy link
Collaborator

adk-bot commented Mar 12, 2026

Response from ADK Triaging Agent

Hello @9chait9, thank you for creating this PR!

Could you please include a testing plan section in your PR to describe how you tested your changes? This will help reviewers to review your PR more efficiently.

Thanks!

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces lazy loading to optimize import times, which is a great improvement for cold start performance. My review focuses on improving the maintainability and consistency of the lazy loading implementation by refactoring the repetitive if statements into a more scalable dictionary-based approach using importlib.

Comment on lines +23 to +33
def __getattr__(name: str):
if name == "Agent":
from .agents.llm_agent import Agent
return Agent
if name == "Context":
from .agents.context import Context
return Context
if name == "Runner":
from .runners import Runner
return Runner
raise AttributeError(f"module {__name__} has no attribute {name}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To improve maintainability and avoid a long chain of if statements, consider using a dictionary to map attribute names to their modules. This makes the __getattr__ function more scalable and easier to read, especially if more lazy-loaded modules are added in the future.

Suggested change
def __getattr__(name: str):
if name == "Agent":
from .agents.llm_agent import Agent
return Agent
if name == "Context":
from .agents.context import Context
return Context
if name == "Runner":
from .runners import Runner
return Runner
raise AttributeError(f"module {__name__} has no attribute {name}")
import importlib
_LAZY_IMPORTS = {
"Agent": ".agents.llm_agent",
"Context": ".agents.context",
"Runner": ".runners",
}
def __getattr__(name: str):
if name in _LAZY_IMPORTS:
module = importlib.import_module(_LAZY_IMPORTS[name], __name__)
return getattr(module, name)
raise AttributeError(f"module {__name__} has no attribute {name}")

Comment on lines +18 to +69
if TYPE_CHECKING:
from .base_agent import BaseAgent
from .context import Context
from .invocation_context import InvocationContext
from .live_request_queue import LiveRequest
from .live_request_queue import LiveRequestQueue
from .llm_agent import Agent
from .llm_agent import LlmAgent
from .loop_agent import LoopAgent
from .mcp_instruction_provider import McpInstructionProvider
from .parallel_agent import ParallelAgent
from .run_config import RunConfig
from .sequential_agent import SequentialAgent

def __getattr__(name: str):
if name == 'BaseAgent':
from .base_agent import BaseAgent
return BaseAgent
if name == 'Context':
from .context import Context
return Context
if name == 'InvocationContext':
from .invocation_context import InvocationContext
return InvocationContext
if name == 'LiveRequest':
from .live_request_queue import LiveRequest
return LiveRequest
if name == 'LiveRequestQueue':
from .live_request_queue import LiveRequestQueue
return LiveRequestQueue
if name == 'Agent':
from .llm_agent import Agent
return Agent
if name == 'LlmAgent':
from .llm_agent import LlmAgent
return LlmAgent
if name == 'LoopAgent':
from .loop_agent import LoopAgent
return LoopAgent
if name == 'McpInstructionProvider':
from .mcp_instruction_provider import McpInstructionProvider
return McpInstructionProvider
if name == 'ParallelAgent':
from .parallel_agent import ParallelAgent
return ParallelAgent
if name == 'RunConfig':
from .run_config import RunConfig
return RunConfig
if name == 'SequentialAgent':
from .sequential_agent import SequentialAgent
return SequentialAgent
raise AttributeError(f"module {__name__} has no attribute {name}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This long chain of if statements can be refactored into a more maintainable and scalable dictionary-based approach using importlib. Additionally, __getattr__ should be defined within an else block following if TYPE_CHECKING: to ensure it's only active at runtime, not during static analysis. This makes the implementation consistent with src/google/adk/__init__.py.

if TYPE_CHECKING:
    from .base_agent import BaseAgent
    from .context import Context
    from .invocation_context import InvocationContext
    from .live_request_queue import LiveRequest
    from .live_request_queue import LiveRequestQueue
    from .llm_agent import Agent
    from .llm_agent import LlmAgent
    from .loop_agent import LoopAgent
    from .mcp_instruction_provider import McpInstructionProvider
    from .parallel_agent import ParallelAgent
    from .run_config import RunConfig
    from .sequential_agent import SequentialAgent
else:
    import importlib

    _LAZY_IMPORTS = {
        "BaseAgent": ".base_agent",
        "Context": ".context",
        "InvocationContext": ".invocation_context",
        "LiveRequest": ".live_request_queue",
        "LiveRequestQueue": ".live_request_queue",
        "Agent": ".llm_agent",
        "LlmAgent": ".llm_agent",
        "LoopAgent": ".loop_agent",
        "McpInstructionProvider": ".mcp_instruction_provider",
        "ParallelAgent": ".parallel_agent",
        "RunConfig": ".run_config",
        "SequentialAgent": ".sequential_agent",
    }

    def __getattr__(name: str):
        if name in _LAZY_IMPORTS:
            module = importlib.import_module(_LAZY_IMPORTS[name], __name__)
            return getattr(module, name)
        raise AttributeError(f"module {__name__} has no attribute {name}")

@9chait9
Copy link
Author

9chait9 commented Mar 12, 2026

I have addressed the review feedback and updated the PR:

  1. Refactored __getattr__ to use a dictionary-based mapping: Replaced the long if statement chains in src/google/adk/__init__.py and src/google/adk/agents/__init__.py with a more maintainable dictionary-based lookup.
  2. Optimized __getattr__ scope: Moved the __getattr__ implementation into an else block following if TYPE_CHECKING: in src/google/adk/agents/__init__.py to ensure it is only active at runtime.
  3. Testing Plan:
    • Unit Tests: Ran existing test suite to ensure no regressions in module loading.
    • Verification: Verified that lazy imports are only triggered when attributes are accessed.
    • Linting: Ensured code style compliance with the new implementation.

The review comments regarding maintainability and TYPE_CHECKING scoping have been addressed in both files.

@9chait9
Copy link
Author

9chait9 commented Mar 12, 2026

I have addressed the code review feedback by refactoring the lazy loading implementation into a dictionary-based approach. The PR is now ready for review.

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

Labels

core [Component] This issue is related to the core interface and implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ADK import overhead (8-20s) causes slow cold starts

2 participants