mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
feat: Add the ask_data_insights tool for natural language queries on BigQuery data
PiperOrigin-RevId: 799267061
This commit is contained in:
committed by
Copybara-Service
parent
6806deaf88
commit
47b88d2b06
@@ -25,6 +25,16 @@ distributed via the `google.adk.tools.bigquery` module. These tools include:
|
|||||||
|
|
||||||
Runs a SQL query in BigQuery.
|
Runs a SQL query in BigQuery.
|
||||||
|
|
||||||
|
1. `ask_data_insights`
|
||||||
|
|
||||||
|
Natural language-in, natural language-out tool that answers questions
|
||||||
|
about structured data in BigQuery. Provides a one-stop solution for generating
|
||||||
|
insights from data.
|
||||||
|
|
||||||
|
**Note**: This tool requires additional setup in your project. Please refer to
|
||||||
|
the official [Conversational Analytics API documentation](https://cloud.google.com/gemini/docs/conversational-analytics-api/overview)
|
||||||
|
for instructions.
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
Set up environment variables in your `.env` file for using
|
Set up environment variables in your `.env` file for using
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from typing import Union
|
|||||||
from google.adk.agents.readonly_context import ReadonlyContext
|
from google.adk.agents.readonly_context import ReadonlyContext
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
|
from . import data_insights_tool
|
||||||
from . import metadata_tool
|
from . import metadata_tool
|
||||||
from . import query_tool
|
from . import query_tool
|
||||||
from ...tools.base_tool import BaseTool
|
from ...tools.base_tool import BaseTool
|
||||||
@@ -80,6 +81,7 @@ class BigQueryToolset(BaseToolset):
|
|||||||
metadata_tool.list_dataset_ids,
|
metadata_tool.list_dataset_ids,
|
||||||
metadata_tool.list_table_ids,
|
metadata_tool.list_table_ids,
|
||||||
query_tool.get_execute_sql(self._tool_settings),
|
query_tool.get_execute_sql(self._tool_settings),
|
||||||
|
data_insights_tool.ask_data_insights,
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -34,14 +34,16 @@ def ask_data_insights(
|
|||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
"""Answers questions about structured data in BigQuery tables using natural language.
|
"""Answers questions about structured data in BigQuery tables using natural language.
|
||||||
|
|
||||||
This function takes auser's question (which can include conversational
|
This function takes a user's question (which can include conversational
|
||||||
history for context) andreferences to specific BigQuery tables, and sends
|
history for context) and references to specific BigQuery tables, and sends
|
||||||
them to a stateless conversational API.
|
them to a stateless conversational API.
|
||||||
|
|
||||||
The API uses a GenAI agent to understand the question, generate and execute
|
The API uses a GenAI agent to understand the question, generate and execute
|
||||||
SQL queries and Python code, and formulate an answer. This function returns a
|
SQL queries and Python code, and formulate an answer. This function returns a
|
||||||
detailed, sequential log of this entire process, which includes any generated
|
detailed, sequential log of this entire process, which includes any generated
|
||||||
SQL or Python code, the data retrieved, and the final text answer.
|
SQL or Python code, the data retrieved, and the final text answer. The final
|
||||||
|
answer is always in plain text, as the underlying API is instructed not to
|
||||||
|
generate any charts, graphs, images, or other visualizations.
|
||||||
|
|
||||||
Use this tool to perform data analysis, get insights, or answer complex
|
Use this tool to perform data analysis, get insights, or answer complex
|
||||||
questions about the contents of specific BigQuery tables.
|
questions about the contents of specific BigQuery tables.
|
||||||
@@ -123,9 +125,22 @@ def ask_data_insights(
|
|||||||
}
|
}
|
||||||
ca_url = f"https://geminidataanalytics.googleapis.com/v1alpha/projects/{project_id}/locations/{location}:chat"
|
ca_url = f"https://geminidataanalytics.googleapis.com/v1alpha/projects/{project_id}/locations/{location}:chat"
|
||||||
|
|
||||||
|
instructions = """**INSTRUCTIONS - FOLLOW THESE RULES:**
|
||||||
|
1. **CONTENT:** Your answer should present the supporting data and then provide a conclusion based on that data.
|
||||||
|
2. **OUTPUT FORMAT:** Your entire response MUST be in plain text format ONLY.
|
||||||
|
3. **NO CHARTS:** You are STRICTLY FORBIDDEN from generating any charts, graphs, images, or any other form of visualization.
|
||||||
|
"""
|
||||||
|
|
||||||
|
final_query_text = f"""
|
||||||
|
{instructions}
|
||||||
|
|
||||||
|
**User Query and Context:**
|
||||||
|
{user_query_with_context}
|
||||||
|
"""
|
||||||
|
|
||||||
ca_payload = {
|
ca_payload = {
|
||||||
"project": f"projects/{project_id}",
|
"project": f"projects/{project_id}",
|
||||||
"messages": [{"userMessage": {"text": user_query_with_context}}],
|
"messages": [{"userMessage": {"text": final_query_text}}],
|
||||||
"inlineContext": {
|
"inlineContext": {
|
||||||
"datasourceReferences": {
|
"datasourceReferences": {
|
||||||
"bq": {"tableReferences": table_references}
|
"bq": {"tableReferences": table_references}
|
||||||
@@ -289,7 +304,7 @@ def _handle_data_response(
|
|||||||
schema = resp["result"]["schema"]
|
schema = resp["result"]["schema"]
|
||||||
headers = [field.get("name") for field in schema.get("fields", [])]
|
headers = [field.get("name") for field in schema.get("fields", [])]
|
||||||
|
|
||||||
all_rows = resp["result"]["data"]
|
all_rows = resp["result"].get("data", [])
|
||||||
total_rows = len(all_rows)
|
total_rows = len(all_rows)
|
||||||
|
|
||||||
compact_rows = []
|
compact_rows = []
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ from unittest import mock
|
|||||||
from google.adk.tools.bigquery.client import get_bigquery_client
|
from google.adk.tools.bigquery.client import get_bigquery_client
|
||||||
from google.auth.exceptions import DefaultCredentialsError
|
from google.auth.exceptions import DefaultCredentialsError
|
||||||
from google.oauth2.credentials import Credentials
|
from google.oauth2.credentials import Credentials
|
||||||
import pytest
|
|
||||||
|
|
||||||
|
|
||||||
def test_bigquery_client_project():
|
def test_bigquery_client_project():
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ async def test_bigquery_toolset_tools_default():
|
|||||||
tools = await toolset.get_tools()
|
tools = await toolset.get_tools()
|
||||||
assert tools is not None
|
assert tools is not None
|
||||||
|
|
||||||
assert len(tools) == 5
|
assert len(tools) == 6
|
||||||
assert all([isinstance(tool, GoogleTool) for tool in tools])
|
assert all([isinstance(tool, GoogleTool) for tool in tools])
|
||||||
|
|
||||||
expected_tool_names = set([
|
expected_tool_names = set([
|
||||||
@@ -50,6 +50,7 @@ async def test_bigquery_toolset_tools_default():
|
|||||||
"list_table_ids",
|
"list_table_ids",
|
||||||
"get_table_info",
|
"get_table_info",
|
||||||
"execute_sql",
|
"execute_sql",
|
||||||
|
"ask_data_insights",
|
||||||
])
|
])
|
||||||
actual_tool_names = set([tool.name for tool in tools])
|
actual_tool_names = set([tool.name for tool in tools])
|
||||||
assert actual_tool_names == expected_tool_names
|
assert actual_tool_names == expected_tool_names
|
||||||
|
|||||||
Reference in New Issue
Block a user