From bf79399dbba06491e4951c32152c9aee7a88f133 Mon Sep 17 00:00:00 2001 From: adk-bot Date: Thu, 9 Oct 2025 19:21:21 +0000 Subject: [PATCH] docs: Update documentation for using multiple built-in tools --- docs/tools/built-in-tools.md | 287 +++++++++++++---------------------- 1 file changed, 107 insertions(+), 180 deletions(-) diff --git a/docs/tools/built-in-tools.md b/docs/tools/built-in-tools.md index dfd77148e..7262bde86 100644 --- a/docs/tools/built-in-tools.md +++ b/docs/tools/built-in-tools.md @@ -176,9 +176,10 @@ These are a set of tools aimed to provide integration with BigQuery, namely: * **`get_dataset_info`**: Fetches metadata about a BigQuery dataset. * **`list_table_ids`**: Fetches table ids present in a BigQuery dataset. * **`get_table_info`**: Fetches metadata about a BigQuery table. -* **`execute_sql`**: Runs a SQL query in BigQuery and fetch the result. +* **`execute_sql`**: Runs a SQL query in BigQuery and fetch the result. This tool includes a `dry_run` parameter that allows you to validate a query and get information about it without actually running it. * **`forecast`**: Runs a BigQuery AI time series forecast using the `AI.FORECAST` function. * **`ask_data_insights`**: Answers questions about data in BigQuery tables using natural language. +* **`analyze_contribution`**: Analyzes the contribution of specified dimensions to a metric in a BigQuery table. They are packaged in the toolset `BigQueryToolset`. @@ -210,6 +211,104 @@ They are packaged in the toolset `SpannerToolset`. ``` +### Customizing Spanner Tools + +You can create custom Spanner tools to tailor their functionality to your specific needs. This is particularly useful for creating tools that execute predefined queries with template or parameterized SQL. + +#### Template SQL + +You can create a custom tool that uses a template SQL query. This is useful when you want to create a tool that executes a specific query with some parts of the query being dynamic. + +The following example shows how to create a tool that counts the rows in a table, where the table name is provided as an argument. + +```python +from google.adk.tools.spanner import utils as spanner_tool_utils +from google.adk.tools.tool_context import ToolContext +from google.auth.credentials import Credentials +from google.adk.tools.spanner.settings import SpannerToolSettings + +def count_rows_in_table( + table_name: str, + credentials: Credentials, + settings: SpannerToolSettings, + tool_context: ToolContext, +): + """Counts the total number of rows for a specified table. + + Args: + table_name: The name of the table for which to count rows. + + Returns: + The total number of rows in the table. + """ + + sql_template = f"SELECT COUNT(*) FROM {table_name}" + + return spanner_tool_utils.execute_sql( + project_id="", + instance_id="", + database_id="", + query=sql_template, + credentials=credentials, + settings=settings, + tool_context=tool_context, + ) +``` + +!!! warning "Security" + Using f-strings to create SQL queries can make your application vulnerable to SQL injection attacks. It is recommended to use parameterized queries whenever possible. + +#### Parameterized SQL + +To prevent SQL injection attacks, you can use parameterized queries. The `execute_sql` function supports parameterized queries through the `params` and `params_types` arguments. + +The following example shows how to create a tool that searches for hotels in a specific location using a parameterized query. + +```python +from google.adk.tools.spanner import utils as spanner_tool_utils +from google.adk.tools.tool_context import ToolContext +from google.auth.credentials import Credentials +from google.adk.tools.spanner.settings import SpannerToolSettings +from google.cloud.spanner_v1 import param_types as spanner_param_types + +def search_hotels( + location_name: str, + credentials: Credentials, + settings: SpannerToolSettings, + tool_context: ToolContext, +): + """Search hotels for a specific location. + + This function takes a geographical location name and returns a list of hotels + in that area, including key details for each. + + Args: + location_name (str): The geographical location (e.g., city or town) for the + hotel search. + + Returns: + The hotels name, rating and description. + """ + + sql_template = """ + SELECT name, rating, description FROM hotels + WHERE location_name = @location_name + """ + return spanner_tool_utils.execute_sql( + project_id="", + instance_id="", + database_id="", + query=sql_template, + credentials=credentials, + settings=settings, + tool_context=tool_context, + params={"location_name": location_name}, + params_types={"location_name": spanner_param_types.STRING}, + ) +``` + +In this example, `@location_name` is a parameter in the SQL query. The value for this parameter is passed in the `params` dictionary, and its type is specified in the `params_types` dictionary. This ensures that the value is properly escaped, preventing SQL injection attacks. + ### Bigtable These are a set of tools aimed to provide integration with Bigtable, namely: @@ -228,199 +327,27 @@ They are packaged in the toolset `BigtableToolset`. --8<-- "examples/python/snippets/tools/built-in-tools/bigtable.py" ``` -## Use Built-in tools with other tools +## Using Multiple Built-in Tools -The following code sample demonstrates how to use multiple built-in tools or how -to use built-in tools with other tools by using multiple agents: +You can use multiple built-in tools, such as `VertexAiSearchTool` and `google_search`, together in the same agent. This allows you to create powerful agents that can perform a variety of tasks, such as searching for information and then using that information in a code execution environment. + +The following code sample demonstrates how to use `google_search` and the `BuiltInCodeExecutor` in the same agent: === "Python" - ```py - from google.adk.tools.agent_tool import AgentTool + ```python from google.adk.agents import Agent from google.adk.tools import google_search from google.adk.code_executors import BuiltInCodeExecutor - search_agent = Agent( - model='gemini-2.0-flash', - name='SearchAgent', - instruction=""" - You're a specialist in Google Search - """, - tools=[google_search], - ) - coding_agent = Agent( - model='gemini-2.0-flash', - name='CodeAgent', - instruction=""" - You're a specialist in Code Execution - """, - code_executor=BuiltInCodeExecutor(), - ) - root_agent = Agent( - name="RootAgent", - model="gemini-2.0-flash", - description="Root Agent", - tools=[AgentTool(agent=search_agent), AgentTool(agent=coding_agent)], - ) - ``` - -=== "Java" - - ```java - import com.google.adk.agents.BaseAgent; - import com.google.adk.agents.LlmAgent; - import com.google.adk.tools.AgentTool; - import com.google.adk.tools.BuiltInCodeExecutionTool; - import com.google.adk.tools.GoogleSearchTool; - import com.google.common.collect.ImmutableList; - - public class NestedAgentApp { - - private static final String MODEL_ID = "gemini-2.0-flash"; - - public static void main(String[] args) { - - // Define the SearchAgent - LlmAgent searchAgent = - LlmAgent.builder() - .model(MODEL_ID) - .name("SearchAgent") - .instruction("You're a specialist in Google Search") - .tools(new GoogleSearchTool()) // Instantiate GoogleSearchTool - .build(); - - - // Define the CodingAgent - LlmAgent codingAgent = - LlmAgent.builder() - .model(MODEL_ID) - .name("CodeAgent") - .instruction("You're a specialist in Code Execution") - .tools(new BuiltInCodeExecutionTool()) // Instantiate BuiltInCodeExecutionTool - .build(); - - // Define the RootAgent, which uses AgentTool.create() to wrap SearchAgent and CodingAgent - BaseAgent rootAgent = - LlmAgent.builder() - .name("RootAgent") - .model(MODEL_ID) - .description("Root Agent") - .tools( - AgentTool.create(searchAgent), // Use create method - AgentTool.create(codingAgent) // Use create method - ) - .build(); - - // Note: This sample only demonstrates the agent definitions. - // To run these agents, you'd need to integrate them with a Runner and SessionService, - // similar to the previous examples. - System.out.println("Agents defined successfully:"); - System.out.println(" Root Agent: " + rootAgent.name()); - System.out.println(" Search Agent (nested): " + searchAgent.name()); - System.out.println(" Code Agent (nested): " + codingAgent.name()); - } - } - ``` - - -### Limitations - -!!! warning - - Currently, for each root agent or single agent, only one built-in tool is - supported. No other tools of any type can be used in the same agent. - - For example, the following approach that uses ***a built-in tool along with - other tools*** within a single agent is **not** currently supported: - -=== "Python" - - ```py root_agent = Agent( - name="RootAgent", - model="gemini-2.0-flash", - description="Root Agent", - tools=[custom_function], - code_executor=BuiltInCodeExecutor() # <-- not supported when used with tools - ) - ``` - -=== "Java" - - ```java - LlmAgent searchAgent = - LlmAgent.builder() - .model(MODEL_ID) - .name("SearchAgent") - .instruction("You're a specialist in Google Search") - .tools(new GoogleSearchTool(), new YourCustomTool()) // <-- not supported - .build(); - ``` - -!!! warning - - Built-in tools cannot be used within a sub-agent. - -For example, the following approach that uses built-in tools within sub-agents -is **not** currently supported: - -=== "Python" - - ```py - search_agent = Agent( model='gemini-2.0-flash', - name='SearchAgent', + name='SearchAndCodeAgent', instruction=""" - You're a specialist in Google Search + You are a specialist in Google Search and Code Execution. """, tools=[google_search], - ) - coding_agent = Agent( - model='gemini-2.0-flash', - name='CodeAgent', - instruction=""" - You're a specialist in Code Execution - """, code_executor=BuiltInCodeExecutor(), ) - root_agent = Agent( - name="RootAgent", - model="gemini-2.0-flash", - description="Root Agent", - sub_agents=[ - search_agent, - coding_agent - ], - ) - ``` - -=== "Java" - - ```java - LlmAgent searchAgent = - LlmAgent.builder() - .model("gemini-2.0-flash") - .name("SearchAgent") - .instruction("You're a specialist in Google Search") - .tools(new GoogleSearchTool()) - .build(); - - LlmAgent codingAgent = - LlmAgent.builder() - .model("gemini-2.0-flash") - .name("CodeAgent") - .instruction("You're a specialist in Code Execution") - .tools(new BuiltInCodeExecutionTool()) - .build(); - - - LlmAgent rootAgent = - LlmAgent.builder() - .name("RootAgent") - .model("gemini-2.0-flash") - .description("Root Agent") - .subAgents(searchAgent, codingAgent) // Not supported, as the sub agents use built in tools. - .build(); ```