Module 9: Creating Custom Function Tools
Theoryβ
Unlocking Unlimited Capabilitiesβ
While built-in tools like google_search are powerful, the true potential of your agent is realized when you give it custom capabilities tailored to your specific needs. This is done by creating Custom Function Tools.
A custom function tool is, at its core, a regular Python function that you write and then make available to your agent. This allows you to connect your agent to virtually anything you can program: a proprietary database, a third-party API, a complex business logic algorithm, or even another AI model.
How it Works: From Python to Agent Toolβ
When you add one of your Python functions to an agent's tools list, the ADK framework performs a clever transformation behind the scenes. It inspects your function's signature
βits name, parameters, type hints, and docstringβand automatically generates a detailed description, or schema.
This schema is what's provided to the Large Language Model. The LLM doesn't see your Python code. It only sees this schema, which tells it:
- The tool's name (from your function name).
- What the tool does (from your function's docstring).
- What parameters it needs (from your function's arguments).
- What data type each parameter should be (from your type hints).
Based on this information, the LLM can intelligently decide when to use your function and what arguments to pass to it.
The Anatomy of a Well-Defined Tool Functionβ
For the LLM to use your tool correctly and reliably, it's crucial to define your Python function in a structured way.
1. Descriptive Function Nameβ
The name should clearly indicate the action the function performs.
- Good:
get_weather,calculate_loan_payment,lookup_order_status - Bad:
process_data,run_logic,my_function
2. Clear Parameters with Type Hintsβ
Each argument your function takes must have a type hint. This is non-negotiable, as it tells the LLM what kind of data to provide.
# The LLM knows 'city' must be a string and 'is_forecast' must be a boolean.
def get_weather(city: str, is_forecast: bool):
...
3. The All-Important Docstringβ
The docstring is the most critical part. It serves as the tool's description for the LLM. A good docstring should explain:
- Purpose: What does the tool do?
- Usage: When should the agent use this tool? Provide context.
- Parameters: Describe what each parameter represents.
def get_weather(city: str, is_forecast: bool):
"""
Fetches the current weather or a 3-day forecast for a specific city.
Use this tool when a user asks about the weather.
Args:
city: The name of the city (e.g., "San Francisco").
is_forecast: Set to True for a 3-day forecast, False for current conditions.
"""
...
4. Structured Return Valueβ
In ADK 2.0, a tool function can return a dictionary or, ideally, a Pydantic model. The LLM will receive this structured data and use its contents to formulate the final response.
from pydantic import BaseModel
class WeatherReport(BaseModel):
status: str
temperature: float
conditions: str
def get_weather(city: str) -> WeatherReport:
"""Fetches the current weather."""
# ... logic ...
return WeatherReport(status="success", temperature=22.0, conditions="Sunny")
Advanced: The ToolContextβ
Sometimes your tool needs to know more than just its arguments. It might need to read from the session state or perform an action like transferring control to another agent. In ADK 2.0, you can add a tool_context: ToolContext argument to your function to gain access to these framework features.
from google.adk.tools import ToolContext
def my_advanced_tool(query: str, tool_context: ToolContext):
# Access session state!
user_name = tool_context.session.state.get("user_name")
...
Registering Tools with Your Agent Nodeβ
In ADK 2.0, registering your custom functions as tools is incredibly simple. You just import your functions and pass them directly into the Agent node's tools list. The ADK automatically wraps them.
# In agent.py
from google.adk import Agent
from .tools.calculator import add, subtract # Import your functions
root_agent = Agent(
# ... other params
tools=[
add, # The ADK automatically converts this Python function
subtract, # into an LLM-compatible Tool!
]
)
In the lab for this module, you will put all these principles into practice by building a set of calculator functions and integrating them into a new "Calculator" agent.
Key Takeawaysβ
- Custom Function Tools connect your agent node to any Python capability.
- Auto-Schema: ADK 2.0 generates the tool schema from your function's signature and docstring.
- Type Safety: Use type hints and Pydantic return models for robust tool execution.
- Context Awareness: Use
ToolContextfor advanced interaction with the ADK runtime. - Workflow Ready: Tools are nodes in your graph, allowing for modular and testable designs.
Limitations: Mixing Tool Typesβ
As you start building more complex agents, it's important to be aware of a current limitation regarding tool usage.
One Built-in Tool Per Agentβ
A single agent generally supports using only one type of tool at a time.
Specifically, you cannot mix a Built-in Tool (like google_search) with Custom Function Tools within the same agent definition β this isn't an arbitrary ADK restriction, it's the underlying Gemini API itself rejecting the request:
# This is NOT supported -- it constructs fine in Python, but the first real
# model call fails with:
# 400 INVALID_ARGUMENT: Multiple tools are supported only when they are
# all search tools.
root_agent = Agent(
name="MixedToolAgent",
model="gemini-3.5-flash",
tools=[google_search, custom_function],
)
The Workaround: Multi-Agent Systemsβ
So, how do you build a system that can search the web and use your custom calculator?
The solution is to use separate agents, each with its own single tool type, coordinated together:
- A "Search Specialist" agent with only the
google_searchtool. - A "Calculator Specialist" agent with only your custom function tools.
- Either a coordinating agent, or your own Python code, that calls each one in turn and combines their results.
You'll learn exactly how to build these multi-agent architectures in Module 15. Module 12 revisits this same constraint hands-on, once you've seen google_search and the other built-in tools in more depth.