Documentation Index
Fetch the complete documentation index at: https://mintlify.com/firebase/genkit/llms.txt
Use this file to discover all available pages before exploring further.
Tools give AI models the ability to call functions, enabling them to interact with external systems, access real-time data, and perform complex operations beyond text generation.
A tool is a function that an AI model can choose to call during generation. The model:
- Analyzes the user’s request
- Decides which tool(s) to use
- Calls the tool(s) with appropriate arguments
- Incorporates the tool results into its response
This enables agentic workflows where the model acts autonomously to solve problems.
import { genkit, z } from 'genkit';
import { googleAI } from '@genkit-ai/google-genai';
const ai = genkit({ plugins: [googleAI()] });
const getWeatherTool = ai.defineTool(
{
name: 'getWeather',
description: 'Get current weather for a city. Use this when users ask about weather conditions.',
inputSchema: z.object({
city: z.string().describe('City name, e.g., "Paris" or "New York"'),
}),
outputSchema: z.object({
temperature: z.number(),
conditions: z.string(),
humidity: z.number(),
}),
},
async ({ city }) => {
// Call weather API...
return {
temperature: 72,
conditions: 'Sunny',
humidity: 65,
};
}
);
// Use in generation
const { text } = await ai.generate({
model: googleAI.model('gemini-2.0-flash'),
prompt: 'What is the weather in Paris?',
tools: [getWeatherTool],
});
console.log(text);
// "The weather in Paris is currently sunny with a temperature of 72°F and 65% humidity."
The tool execution flow:
┌─────────────────────────────────────────────────────────────────────┐
│ Tool Execution Flow │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Model │ ───► │ Tool │ ───► │ Execute │ ───► │ Model │ │
│ │ Request │ │ Request │ │ Function │ │ Continue │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │ │
│ ▼ (if interrupt=True) │
│ ┌──────────┐ │
│ │ Pause │ ────► User confirms ────► Resume │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────────────┘
- User sends prompt: “What’s the weather in Paris?”
- Model analyzes prompt and available tools
- Model decides to call
getWeather with {city: "Paris"}
- Genkit executes the tool function
- Tool returns
{temperature: 72, conditions: "Sunny", humidity: 65}
- Model incorporates result into its response
- Model returns: “The weather in Paris is currently sunny…”
Provide multiple tools for the model to choose from:
@ai.tool()
def get_weather(city: str) -> dict:
"""Get current weather for a city."""
return {'temperature': 72, 'conditions': 'Sunny'}
@ai.tool()
def search_restaurants(city: str, cuisine: str) -> list[dict]:
"""Search for restaurants in a city."""
return [
{'name': 'Le Bistro', 'rating': 4.5},
{'name': 'Chez Pierre', 'rating': 4.8},
]
@ai.tool()
def book_reservation(restaurant: str, time: str, party_size: int) -> dict:
"""Book a restaurant reservation."""
return {'confirmation': 'ABC123', 'restaurant': restaurant}
response = await ai.generate(
prompt='Plan dinner in Paris tonight for 4 people. I like Italian food.',
tools=['get_weather', 'search_restaurants', 'book_reservation'],
)
print(response.text)
# Model may call multiple tools:
# 1. get_weather("Paris") to check conditions
# 2. search_restaurants("Paris", "Italian") to find options
# 3. book_reservation("Le Bistro", "7:00 PM", 4) to book
Control how the model uses tools:
// Auto: Model decides when to use tools (default)
const { text } = await ai.generate({
prompt: 'What is the weather?',
tools: [getWeatherTool],
toolChoice: 'auto',
});
// Required: Model MUST use at least one tool
const { text } = await ai.generate({
prompt: 'Get me some data',
tools: [getWeatherTool, searchTool],
toolChoice: 'required',
});
// None: Model cannot use tools
const { text } = await ai.generate({
prompt: 'Tell me about weather',
tools: [getWeatherTool],
toolChoice: 'none',
});
Interrupts let you pause tool execution for human approval - perfect for sensitive operations like financial transactions or data deletion.
const deleteUserTool = ai.defineTool(
{
name: 'deleteUser',
description: 'Delete a user account (requires confirmation)',
inputSchema: z.object({ userId: z.string() }),
interrupt: true, // Pause execution for approval
},
async ({ userId }) => {
// This won't execute automatically
return `User ${userId} deleted`;
}
);
// First generate - tool is NOT executed
const response = await ai.generate({
prompt: 'Delete user account 12345',
tools: [deleteUserTool],
});
// Check for interrupts
if (response.interrupts && response.interrupts.length > 0) {
const interrupt = response.interrupts[0];
console.log('Tool call pending approval:', interrupt.toolRequest.name);
console.log('Arguments:', interrupt.toolRequest.input);
// Show to user: "Confirm delete user 12345? [Yes/No]"
const userApproved = await getUserConfirmation();
if (userApproved) {
// Resume with approval
const resumedResponse = await ai.generate({
prompt: 'Delete user account 12345',
tools: [deleteUserTool],
messages: response.messages,
resume: {
respond: deleteUserTool.respond(interrupt, 'User confirmed deletion'),
},
});
}
}
Interrupt Flow
┌─────────────────────────────────────────────────────────────────────┐
│ 1. Model decides to call deleteUser(userId="12345") │
├─────────────────────────────────────────────────────────────────────┤
│ 2. Genkit sees interrupt=true, PAUSES execution │
├─────────────────────────────────────────────────────────────────────┤
│ 3. Response includes tool call in response.interrupts │
├─────────────────────────────────────────────────────────────────────┤
│ 4. Your app shows confirmation dialog to user │
├─────────────────────────────────────────────────────────────────────┤
│ 5. User approves/rejects │
├─────────────────────────────────────────────────────────────────────┤
│ 6. Resume with tool response (approved or rejected) │
├─────────────────────────────────────────────────────────────────────┤
│ 7. Model incorporates response and continues │
└─────────────────────────────────────────────────────────────────────┘
Prevent infinite tool calling loops:
const { text } = await ai.generate({
prompt: 'Research quantum computing',
tools: [searchTool, analyzeTool],
maxTurns: 5, // Stop after 5 model-tool interactions
});
Default is typically 5 turns. Each turn = model call + tool execution(s).
Inspect what tools the model wants to call without executing them:
const { text, toolRequests } = await ai.generate({
prompt: 'What is the weather in Tokyo?',
tools: [getWeatherTool],
returnToolRequests: true, // Don't auto-execute
});
console.log(toolRequests);
// [{ name: 'getWeather', input: { city: 'Tokyo' } }]
// Manually execute
const result = await getWeatherTool({ city: 'Tokyo' });
Useful for:
- Debugging tool selection
- Custom tool execution logic
- Rate limiting
- Logging/auditing
1. Write Clear Descriptions
The model uses descriptions to decide when to call tools:
@ai.tool()
def get_weather(city: str) -> dict:
"""Get current weather for a city.
Use this tool when:
- User asks about weather conditions
- User mentions temperature, rain, or forecast
- Planning outdoor activities
Args:
city: Full city name (e.g., "San Francisco", not "SF")
Returns:
Weather data including temperature (Fahrenheit), conditions, humidity
"""
...
2. Use Detailed Schema Descriptions
const searchTool = ai.defineTool(
{
name: 'search',
description: 'Search the web for information',
inputSchema: z.object({
query: z.string()
.describe('Search query. Be specific and include relevant keywords.'),
maxResults: z.number()
.optional()
.describe('Maximum number of results to return (default: 5, max: 20)'),
}),
},
async (input) => { /* ... */ }
);
3. Handle Errors Gracefully
Tools should return user-friendly error messages:
@ai.tool()
def get_stock_price(symbol: str) -> dict:
"""Get current stock price."""
try:
# API call...
return {'symbol': symbol, 'price': 150.25}
except APIError as e:
# Return error as data, not exception
return {'error': f'Could not fetch price for {symbol}: {str(e)}'}
4. Use Interrupts for Sensitive Actions
Always use interrupt=True for:
- Financial transactions
- Data deletion
- Sending emails/messages
- Modifying user data
- External API calls with side effects
Each tool should do one thing well:
# Good: Focused tools
@ai.tool()
def get_weather(city: str) -> dict: ...
@ai.tool()
def get_forecast(city: str, days: int) -> dict: ...
# Bad: Tool does too much
@ai.tool()
def weather_everything(city: str, action: str, days: int) -> dict: ...
Real-World Example: Travel Agent
from genkit import Genkit
from genkit.plugins.google_genai import GoogleGenAI, gemini_2_0_flash
ai = Genkit(plugins=[GoogleGenAI()], model=gemini_2_0_flash)
@ai.tool()
def get_weather(city: str) -> dict:
"""Get current weather for a city."""
# Call weather API
return {'temperature': 72, 'conditions': 'Sunny'}
@ai.tool()
def search_flights(origin: str, destination: str, date: str) -> list[dict]:
"""Search for flights between cities."""
# Call flight API
return [
{'airline': 'United', 'price': 350, 'departure': '10:00 AM'},
{'airline': 'Delta', 'price': 380, 'departure': '2:00 PM'},
]
@ai.tool()
def search_hotels(city: str, checkin: str, checkout: str) -> list[dict]:
"""Search for hotels in a city."""
# Call hotel API
return [
{'name': 'Grand Hotel', 'price': 200, 'rating': 4.5},
{'name': 'City Inn', 'price': 150, 'rating': 4.0},
]
@ai.tool(interrupt=True)
def book_flight(flight_id: str, passenger: dict) -> dict:
"""Book a flight (requires confirmation)."""
# This will pause for user confirmation
return {'confirmation': 'ABC123', 'flight': flight_id}
@ai.flow()
async def travel_planner(request: str) -> str:
"""Plan a trip with weather, flights, and hotels."""
response = await ai.generate(
prompt=f"Help plan this trip: {request}",
tools=['get_weather', 'search_flights', 'search_hotels', 'book_flight'],
)
# Check for interrupts
if response.interrupts:
# Return to user for confirmation
return f"Pending confirmation: {response.interrupts[0].tool_request.input}"
return response.text
# Usage
result = await travel_planner(
"I want to go to Paris next Friday for 3 days. Book the cheapest flight."
)
# Model will:
# 1. get_weather("Paris") - check conditions
# 2. search_flights("San Francisco", "Paris", "2024-03-15") - find options
# 3. search_hotels("Paris", "2024-03-15", "2024-03-18") - find hotels
# 4. book_flight(...) - PAUSES for user confirmation
Next Steps
- Learn about Flows - building multi-step workflows with tools
- Explore Prompts - using tools in prompt templates
- See Observability - tracing tool executions