Enhancing Agent Intelligence with Tools and Multi-Step Workflows
To build truly capable AI agents, mere conversational abilities are not enough. Agents must interact with the real world, access dynamic information, and perform actions beyond generating text. This is precisely where tools become indispensable. Tools are external functions or APIs that an agent can invoke to perform specific tasks, retrieve real-time data, or integrate with other systems. Imagine an agent that can not only chat about the weather but also fetch the current weather forecast for any city.
This chapter focuses on empowering our long-running ADK agent with such external tools and orchestrating these tools within multi-step workflows. We will design and implement a practical tool, integrate it into our agent, and demonstrate how the agent autonomously decides when and how to use it to achieve a goal. By the end of this chapter, your agent will exhibit more complex reasoning and action, leveraging its persistent state to manage intricate tasks over time, ensuring it never loses context.
Project Overview: From Stateful to Tool-Augmented
In previous chapters, we established a foundational ADK agent capable of maintaining conversational context across sessions using a durable state manager. While crucial, this agent was limited to its internal knowledge. This chapter marks a significant upgrade:
- Intelligence Boost: The agent gains the ability to “act” in the real world by calling external functions.
- Multi-Step Actions: We enable the agent to break down complex requests into a sequence of tool calls and reasoning steps.
- Enhanced Utility: The agent can now solve problems requiring up-to-date information or specific external functionalities.
The outcome is an agent that can intelligently interact with external systems, process their responses, and continue a coherent conversation, all while leveraging its persistent memory to manage the workflow’s state.
Tech Stack for Tool Integration
This chapter continues to build upon our core Python and Google Cloud stack, with specific emphasis on the google-generative-ai library for its function-calling capabilities.
- Python 3.12+: The primary language for our agent and tools.
google-generative-ai(v0.11.0 as of 2026-05-23): This library facilitates interaction with Google’s Gemini models, which provide the underlying large language model (LLM) and its function-calling feature—a key component of Google’s Agent Development Kit (ADK).- Google Cloud Firestore: Our chosen durable state store for persisting agent context and conversation history.
python-dotenv: For managing environment variables securely.
Milestones for This Chapter
To incrementally build this capability, we will follow these steps:
- Define a Tool Function: Create a standard Python function that simulates an external action (e.g., fetching weather). This function will serve as our “tool.”
- Register the Tool: Integrate this function with our
google-generative-aimodel, making it aware of the tool’s existence and capabilities. - Handle Tool Invocations: Modify the agent’s message processing loop to detect when the LLM requests a tool call, execute the tool, and feed its output back to the LLM.
- Verify Persistent Tool State: Ensure that tool calls and their outputs are correctly saved and loaded as part of the agent’s conversational history.
- Test Multi-Step Workflows: Validate that the agent can use the tool and reason effectively through a multi-turn interaction.
Planning & Design: Agent-Tool Interaction
An ADK agent equipped with tools operates on an advanced “Sense, Think, Act” loop. The agent receives a user prompt, reasons about the optimal course of action (which often involves using a tool), executes the tool, processes the tool’s output, and then formulates a response or continues the workflow.
The Role of Tools
Tools are essentially well-defined wrappers around external functions or APIs. When you define a tool for an ADK agent using Google’s generative AI models, you provide essential metadata:
- Name: A unique identifier for the tool, typically derived directly from the Python function name. The LLM uses this name to refer to the tool.
- Description: A clear explanation of what the tool does, its purpose, and when it should be used. This description, often extracted from the function’s docstring, is crucial for the underlying LLM to understand when to invoke the tool.
- Schema: A specification for the tool’s input parameters, inferred from Python type hints and parameter names. This helps the LLM generate correct arguments when calling the tool.
Multi-Step Workflows
A multi-step workflow involves the agent performing a sequence of actions, potentially using multiple tools, to achieve a complex goal. The agent’s persistent memory (established in previous chapters) is critical here, allowing it to remember the progress, results of previous tool calls, and overall conversational context across steps. This ensures continuity and avoids re-asking for information.
For this chapter, we’ll implement a simple get_current_weather tool. The agent will be able to:
- Receive a user request about weather in a specific city.
- Identify that it needs to use the
get_current_weathertool. - Extract the city name and desired unit from the user’s request.
- Call the tool with the correct arguments.
- Receive the weather data (mocked for now).
- Formulate a natural language response based on the weather data, integrating it into the conversation.
This flow, while simple, demonstrates the core principles of tool usage and lays the foundation for more complex, chained workflows.
Architecture of Agent-Tool Interaction
The following diagram illustrates how the agent interacts with a tool and leverages its internal reasoning capabilities.
Explanation:
- User Prompt: The initial input provided by the user.
- ADK Agent Core: Our Python application, responsible for orchestrating the overall interaction.
- LLM Decision: The core intelligence, powered by a large language model (e.g., Google’s Gemini), which analyzes the prompt and available tools to decide the next action.
- Tool Call Request: If the LLM determines a tool is needed, it generates a structured request specifying the tool’s name and arguments.
- Tool Registry: A component within our ADK setup that maps tool names to their actual Python functions.
- External Tool Function: The actual implementation of the tool, which might call an external service (like a weather API) or perform a local computation.
- Tool Output (JSON): The structured result returned by the external tool, typically in JSON format.
- LLM Response: The LLM processes the tool’s output, integrates it with the ongoing conversation, and generates a coherent response or determines the next step in a multi-turn workflow.
- User Output: The final response presented to the user.
Step-by-Step Implementation
We will continue building on our existing ADK agent structure, which includes the ADKAgent class and a StateManager. We need to define our tool, register it, and then modify the agent’s interaction loop to handle tool calls and their subsequent processing.
Prerequisites:
- Ensure you have a Python 3.12+ environment set up.
- Your Google Cloud project and credentials are configured (as per Chapter 1).
- The
google-generative-ailibrary is installed. As of 2026-05-23, the latest stable version ofgoogle-generative-aiis0.11.0. - The
google-cloud-firestorelibrary is installed for the state manager. - The ADK context here refers to using the Gemini API’s function calling capabilities, which is a core part of building agents with Google’s models.
1. Define a Simple Tool Function
First, let’s create a Python function that simulates fetching weather data. For a real-world scenario, this would involve making an HTTP request to a weather API.
Create a new file tools.py in your project root:
# project_root/tools.py
import json
def get_current_weather(location: str, unit: str = "celsius"):
"""
Fetches the current weather for a given location.
Args:
location (str): The city and state, e.g., "San Francisco, CA".
unit (str): The unit of temperature, either "celsius" or "fahrenheit". Defaults to "celsius".
Returns:
str: A JSON string containing weather information (temperature, description, unit, location).
"""
print(f"DEBUG: Calling get_current_weather for {location} in {unit}")
# In a real application, this would call an external weather API.
# For demonstration, we'll return mock data.
mock_weather_data = {
"San Francisco, CA": {"temperature": 15, "description": "Cloudy", "unit": "celsius"},
"New York, NY": {"temperature": 22, "description": "Sunny", "unit": "celsius"},
"London, UK": {"temperature": 10, "description": "Rainy", "unit": "celsius"},
}
if unit.lower() == "fahrenheit":
# Create a fahrenheit version of mock data for conversion
fahrenheit_data = {}
for loc, data in mock_weather_data.items():
temp_f = round(data["temperature"] * 9/5 + 32)
fahrenheit_data[loc] = {"temperature": temp_f, "description": data["description"], "unit": "fahrenheit"}
mock_weather_data = fahrenheit_data
weather = mock_weather_data.get(location, {
"temperature": "N/A",
"description": "Weather data not available",
"unit": unit
})
weather["location"] = location # Add location to the output for clarity
return json.dumps(weather) # Return as JSON string for consistency with tool outputsExplanation:
- The
get_current_weatherfunction takeslocationand an optionalunitas arguments. - Its docstring is crucial: the LLM uses this description to understand the tool’s purpose and how to use it.
- For simplicity, it returns mock data. In a production system, this would integrate with a service like OpenWeatherMap or a similar API.
- The output is returned as a JSON string. This structured format is ideal for the LLM to parse and interpret consistently.
2. Register the Tool and Handle Tool Calls
Now, we need to make this tool available to our agent and teach our agent how to execute it when the LLM decides. We’ll modify adk_agent.py to import this tool, register it with the model, and implement the logic for handling tool call requests and feeding their outputs back to the LLM.
Update adk_agent.py:
# project_root/adk_agent.py
import google.generativeai as genai
import os
from dotenv import load_dotenv
import json
import uuid
import time
import google.generativeai.types as glm # Import glm for explicit typing and FunctionResponse
from state_manager import StateManager # Assuming this is from Chapter 3/4
from tools import get_current_weather # Import our new tool
load_dotenv()
# Configure the Gemini API client
# This implementation uses the google-generative-ai library, which provides the underlying
# model capabilities that an ADK agent would leverage for function calling.
# Please refer to the official Gemini API documentation for the most up-to-date information:
# https://ai.google.dev/docs/gemini_api_overview
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))
class ADKAgent:
def __init__(self, agent_id: str, state_manager: StateManager):
self.agent_id = agent_id
self.state_manager = state_manager
self.model = genai.GenerativeModel(
'gemini-1.5-flash',
tools=[get_current_weather] # Register the tool here
)
# Load existing history or start new
self.history = self.state_manager.load_context(self.agent_id) or []
self.chat_session = self.model.start_chat(history=self.history)
print(f"Agent {self.agent_id} initialized with {len(self.history)} messages in history.")
def _save_state(self):
"""Saves the current chat history to the state manager."""
self.state_manager.save_context(self.agent_id, self.chat_session.history)
print(f"Agent {self.agent_id} state saved.")
def process_message(self, message: str) -> str:
"""
Processes a user message, interacts with the model, and handles tool calls.
"""
try:
# Send the user message to the chat session. This automatically adds it to history
# and gets the model's first response, which might include tool calls.
response = self.chat_session.send_message(message)
# Loop to handle multi-turn tool interactions until the model gives a final text response
while True:
if response.tool_calls:
print(f"DEBUG: Model requested tool calls: {response.tool_calls}")
tool_outputs = []
for tool_call in response.tool_calls:
tool_name = tool_call.function.name
tool_args = {k: v for k, v in tool_call.function.args.items()}
print(f"DEBUG: Invoking tool '{tool_name}' with args: {tool_args}")
# Dynamically call the tool function based on its name
if tool_name == "get_current_weather":
raw_output = get_current_weather(**tool_args)
parsed_output = json.loads(raw_output) # Parse the JSON string
# Wrap the output in glm.FunctionResponse and then in glm.ToolOutput
tool_outputs.append(
glm.ToolOutput(
function_response=glm.FunctionResponse(
name=tool_name,
response=parsed_output # Pass the parsed dictionary
)
)
)
else:
error_msg = f"ERROR: Unknown tool requested: {tool_name}"
print(error_msg)
tool_outputs.append(
glm.ToolOutput(
function_response=glm.FunctionResponse(
name=tool_name,
response={"error": error_msg}
)
)
)
# Send tool outputs back to the model. The model will then generate a response
# based on these outputs and its ongoing understanding of the conversation.
# This new response might be a final text response or another tool call.
response = self.chat_session.send_message(tool_outputs)
elif response.text:
# If the model provides a text response, it's the final answer for this turn.
final_response_text = response.text
break
else:
# Handle cases where the model returns neither text nor tool calls
print("WARNING: Model response contained neither text nor tool calls.")
final_response_text = "I received an unexpected response from the model. Please try again."
break
self._save_state() # Save state after processing message and potential tool calls
return final_response_text
except Exception as e:
print(f"An error occurred: {e}")
# In a production system, you'd want more robust error handling,
# potentially logging the full traceback and user message.
return "I encountered an error while processing your request. Please try again."
# Example usage (for testing purposes)
if __name__ == "__main__":
# Ensure your state manager is correctly configured (e.g., using Firestore)
# For a quick local test, you might use an in-memory state manager if you haven't set up Firestore yet.
# from state_manager_inmemory import InMemoryStateManager
# state_manager = InMemoryStateManager() # For local testing without cloud setup
# Assuming FirestoreStateManager is implemented from previous chapters
from state_manager_firestore import FirestoreStateManager
state_manager = FirestoreStateManager(project_id=os.getenv("GCP_PROJECT_ID"))
# To simulate a long-running session, use a fixed agent ID
session_id = "test_agent_with_tools_123"
agent = ADKAgent(session_id, state_manager)
print("\nAgent ready. Type 'exit' to quit.")
while True:
user_input = input("You: ")
if user_input.lower() == 'exit':
print("Exiting agent session.")
break
response = agent.process_message(user_input)
print(f"Agent: {response}")
time.sleep(0.1) # Small delay for readabilityKey Changes and Explanations:
import google.generativeai.types as glm: We importglmto explicitly useglm.ToolOutputandglm.FunctionResponsefor clearer code and type safety when handling tool results.tools=[get_current_weather]: When initializinggenai.GenerativeModel, we pass a list of our tool functions to thetoolsargument. The Gemini model automatically inspects the function signatures and docstrings to understand how and when to use them.while True:loop: The agent now includes a loop to handle potential multi-turn tool interactions. The model might call a tool, process its output, and then decide to call another tool before providing a final text response. This loop ensures all necessary tool calls are made until a text response is generated.if response.tool_calls:: After sending a message, the model’s response might includetool_calls. This indicates that the model has decided to invoke one or more of the registered tools.- Dynamic Tool Invocation: We check the
tool_nameand call the corresponding Python function (e.g.,get_current_weather(**tool_args)). The**tool_argsunpacks the dictionary of arguments into keyword arguments for the function. - Sending Tool Outputs Back (
glm.ToolOutputwithglm.FunctionResponse): This is critical. After executing a tool, its output must be parsed (if JSON string) and wrapped in aglm.FunctionResponseobject, which is then embedded within aglm.ToolOutputobject. Thisglm.ToolOutputis then sent back to thechat_sessionusingself.chat_session.send_message(tool_outputs). This allows the LLM to process the tool’s result and continue the conversation or workflow.raw_output = get_current_weather(**tool_args): Captures the JSON string from our tool.parsed_output = json.loads(raw_output): Converts the JSON string into a Python dictionary, which is the expected format forglm.FunctionResponse.glm.ToolOutput(function_response=glm.FunctionResponse(name=tool_name, response=parsed_output)): Correctly structures the tool’s output for the LLM.
_save_state(): The agent’s state (including the new messages and tool interactions) is saved after eachprocess_messagecall, ensuring persistence across sessions.
3. Update state_manager_firestore.py (if using Firestore)
Ensure your state_manager_firestore.py correctly handles serializing and deserializing the chat_session.history, which can now include glm.Content objects related to tool calls and tool outputs. The genai.to_dict() helper function is the most reliable way to convert these complex objects into a Firestore-compatible dictionary.
Modify state_manager_firestore.py:
# project_root/state_manager_firestore.py
from google.cloud import firestore
import json
from typing import List, Dict, Any
import google.generativeai as genai # Added import for genai.to_dict
class FirestoreStateManager:
def __init__(self, project_id: str, collection_name: str = "agent_states"):
self.db = firestore.Client(project=project_id)
self.collection_ref = self.db.collection(collection_name)
print(f"FirestoreStateManager initialized for project {project_id}, collection {collection_name}")
def save_context(self, agent_id: str, history: List[Dict[str, Any]]):
"""
Saves the agent's full conversational history, including tool calls and outputs,
to Firestore.
"""
doc_ref = self.collection_ref.document(agent_id)
serializable_history = []
for message in history:
# Use genai.to_dict to properly serialize glm.Content objects (which include tool calls/outputs)
serializable_history.append(genai.to_dict(message))
try:
doc_ref.set({"history": serializable_history, "last_updated": firestore.SERVER_TIMESTAMP})
print(f"Context for agent {agent_id} saved to Firestore.")
except Exception as e:
print(f"Error saving context for agent {agent_id}: {e}")
raise
def load_context(self, agent_id: str) -> List[Dict[str, Any]] | None:
"""
Loads the agent's conversational history from Firestore.
Returns None if no history is found.
"""
doc_ref = self.collection_ref.document(agent_id)
try:
doc = doc_ref.get()
if doc.exists:
data = doc.to_dict()
history = data.get("history", [])
print(f"Context for agent {agent_id} loaded from Firestore.")
# The genai library's start_chat method is robust; it can often accept
# a list of dictionaries that represent the history, automatically converting
# them back to its internal Content objects.
return history
else:
print(f"No context found for agent {agent_id}.")
return None
except Exception as e:
print(f"Error loading context for agent {agent_id}: {e}")
return NoneNote on genai.to_dict() and Firestore:
The google-generative-ai library’s chat_session.history contains glm.Content objects, which are complex types representing various parts of a conversation, including user prompts, model responses, tool calls, and tool outputs. The genai.to_dict() function ensures these objects are correctly converted into a dictionary structure that Firestore can store. When loading, Firestore returns these as dictionaries, and the genai.GenerativeModel.start_chat(history=...) method is generally robust enough to accept a list of these dictionaries, converting them back into its internal Content objects.
Testing & Verification
Now, let’s run our agent and verify that it correctly uses the tool and handles multi-step interactions, maintaining context.
Ensure Environment Variables are Set: Before running, set your API key and GCP project ID.
export GEMINI_API_KEY="YOUR_GEMINI_API_KEY" export GCP_PROJECT_ID="your-gcp-project-id"(Replace placeholders with your actual keys/IDs).
Run the Agent: Execute the main agent script from your project root.
python adk_agent.pyInteract with the Agent (Verification Scenarios):
Scenario 1: Simple Tool Invocation
- You: What’s the weather like in New York, NY?
- Expected Agent Output: You should observe
DEBUG: Model requested tool calls...andDEBUG: Invoking tool 'get_current_weather'...messages in your terminal. The agent’s final response should be a natural language summary of the mock weather data: “The weather in New York, NY is 22 degrees Celsius and Sunny.” - Verification: Confirm that the agent correctly identified the need for the tool, extracted the location, called the
get_current_weatherfunction (which prints a debug message), and then used the mock data to formulate its response.
Scenario 2: Tool Invocation with Specific Units
- You: What’s the temperature in London, UK in Fahrenheit?
- Expected Agent Output: Similar debug messages, but crucially, the
unitargument passed to the tool should be “fahrenheit”. The final response should reflect the converted temperature: “The weather in London, UK is 50 degrees Fahrenheit and Rainy.” - Verification: Check that the
unitparameter was correctly extracted and passed to the tool, and the conversion logic was applied.
Scenario 3: Multi-Step Reasoning with Persistence This scenario highlights the agent’s ability to reason based on tool output and maintain context.
- You: Is it a good day for a picnic in San Francisco?
- Expected Agent Output: The agent should first call the
get_current_weathertool for “San Francisco, CA”. Then, based on the description (“Cloudy”) and temperature (15 degrees Celsius) from the tool output, it should infer if it’s “good for a picnic”. A reasonable response might be: “The weather in San Francisco, CA is 15 degrees Celsius and Cloudy. It might be a bit cool and cloudy for a picnic.” - Verification: Ensure the tool was called and the agent’s subsequent response demonstrates reasoning based on the tool’s output, not just a direct quote.
Verification of Persistence (Pause/Resume):
- Run the agent, interact with it through one or more weather questions, then type
exitto quit. - Restart the agent with the same
session_id. - Ask a follow-up question that relies on previous context, e.g., “What about in London?” (if you previously asked about New York). The agent should remember the context and potentially infer the need for the tool without explicitly being told “weather”. You should see
Agent {agent_id} initialized with X messages in history.confirming history was loaded from Firestore.
Production Considerations
Integrating tools into your AI agent significantly enhances its capabilities but also introduces new considerations for building a robust, production-ready system.
1. Security of Tool Access
- API Key Management: Any external APIs called by your tools (e.g., actual weather APIs, database credentials) must have their API keys and secrets securely managed. Never hardcode these. Use services like Google Secret Manager to store and retrieve them at runtime.
- Input Validation: Tools should rigorously validate their inputs. The LLM might occasionally hallucinate arguments or provide malformed data. Your tool functions must handle unexpected inputs gracefully to prevent errors, crashes, or security vulnerabilities (e.g., SQL injection if interacting with a database directly).
- Permissions: Implement the principle of least privilege. Ensure the service account running your agent only has the minimum necessary permissions to call the external APIs or access resources used by its tools.
2. Error Handling and Resilience
- Tool Failures: External APIs can fail due to network issues, rate limits, invalid requests, or service outages. Your agent needs to gracefully handle these failures.
- Wrap all external tool calls in
try-exceptblocks. - Tools should return informative error messages or structured error objects.
- The agent should be programmed to acknowledge tool errors and potentially retry (with exponential backoff), offer alternatives, or inform the user.
- Wrap all external tool calls in
- Timeouts: External API calls can be slow. Implement strict timeouts for all HTTP requests made by your tools to prevent the agent from hanging indefinitely, impacting user experience and resource consumption.
3. Observability and Monitoring
- Logging Tool Calls: Implement comprehensive logging for every tool invocation, including its arguments, execution status (success/failure), and output. This is critical for debugging, understanding agent behavior, auditing, and compliance. Replace basic
printstatements with a structured logger (e.g., Python’sloggingmodule, integrated with Google Cloud Logging). - Performance Metrics: Monitor the latency and success rate of your tool calls. Slow tools can significantly degrade the agent’s responsiveness and overall user experience.
- Cost Tracking: If tools incur costs (e.g., paid APIs, serverless function invocations), track their usage to manage expenditure and identify potential cost optimizations.
4. Scalability
- Rate Limits: Be acutely aware of rate limits on external APIs. If your agent scales to handle many concurrent users, your tools might hit these limits. Implement robust retry mechanisms with exponential backoff and consider caching strategies for frequently accessed data.
- Stateless Tools: Design tools to be stateless where possible. The agent’s core state manager should handle conversational context and workflow state, not the tools themselves. Tools should perform their specific function and return a result without retaining memory of previous calls.
Common Issues & Solutions
Agent Doesn’t Use the Tool or Hallucinates Arguments:
- Issue: The LLM might ignore your registered tool, or invent arguments that don’t match your tool’s schema, leading to
KeyErroror unexpected behavior. - Solution:
- Improve Tool Description: Ensure the tool’s docstring is extremely clear and precise about what the tool does, its parameters, and when it should be used. Think of it as an instruction manual for the LLM. Be explicit about argument types and examples.
- Provide Few-Shot Examples: In your system prompt or initial conversation turns, you can provide examples of how the tool should be used, a technique called few-shot prompting.
- Schema Accuracy: Double-check that the Python function’s type hints and parameter names (which the model uses to infer schema) are correct and unambiguous.
- Issue: The LLM might ignore your registered tool, or invent arguments that don’t match your tool’s schema, leading to
Tool Output Not Processed Correctly:
- Issue: The tool returns data, but the agent’s subsequent response doesn’t seem to incorporate it meaningfully, or misinterprets it.
- Solution:
- Structured Output: Ensure your tool consistently returns well-structured data, ideally JSON. The LLM is significantly better at parsing well-formatted JSON than free-form text.
- Clear Tool Output Description: If the tool output is complex, consider adding a “tool output description” within your prompt to guide the LLM on how to interpret it.
- Follow-up Prompting: If the agent struggles, you can explicitly prompt it to “Summarize the data you just retrieved from the weather tool and tell me if it’s good for a picnic.”
Agent Gets Stuck in an Infinite Loop (e.g., repeatedly calling a tool):
- Issue: The agent might call a tool, get an unexpected output, and then decide to call the same tool again in a loop without making progress. This can lead to high costs and poor user experience.
- Solution:
- Clear Tool Success/Failure States: Ensure tool outputs clearly indicate success or failure. The LLM should be able to differentiate.
- Contextual Reasoning: The LLM should learn from the conversation history (which includes previous tool calls and outputs) not to repeat failed actions. If your history is not being saved/loaded correctly, this can exacerbate the problem.
- Max Tool Calls Safeguard: In production, implement a safeguard to limit the number of consecutive tool calls an agent can make within a single
process_messageinvocation to prevent runaway execution and costs. For example, allow a maximum of 3-5 tool calls before returning an error to the user.
Summary & Next Step
In this chapter, we significantly enhanced our ADK agent’s capabilities by integrating external tools and enabling it to perform multi-step actions. We learned:
- How to define a standard Python function as an agent tool, complete with docstrings for LLM understanding.
- How to register this tool with the Google ADK (specifically, the
genai.GenerativeModel). - The critical role of parsing tool outputs and sending
glm.ToolOutputobjects withglm.FunctionResponseback to the model for continued reasoning. - The importance of persistent state in maintaining context across complex, multi-turn workflows involving tools.
- Key production considerations for tool security, robust error handling, comprehensive observability, and scalable design.
Our agent can now intelligently decide when to use a tool to gather information, process that information, and provide a more informed response, making it far more capable than a purely conversational bot. This is a crucial step towards building truly autonomous and capable AI agents.
The next step is to prepare our agent for deployment to a production-like environment. This means containerizing our application using Docker, making it portable and scalable, ready for services like Google Cloud Run or Kubernetes.
This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.
References
- Gemini API Overview - Google AI for Developers
- Function calling with Gemini models - Google AI for Developers
- google-generative-ai Python client library - GitHub
- Python in Google Cloud - Official Documentation
- Google Secret Manager - Official Documentation
- Google Cloud Firestore - Official Documentation
- Python
loggingmodule - Official Documentation