chore: add Gemini API docs as a new datastore for the ADK Answering Agent

PiperOrigin-RevId: 794247007
This commit is contained in:
Xuan Yang
2025-08-12 13:30:00 -07:00
committed by Copybara-Service
parent 7d2cb654f0
commit 5fba1963c3
6 changed files with 129 additions and 11 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install google-adk
pip install google-adk google-cloud-discoveryengine
- name: Run Answering Script
env:
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from adk_answering_agent.gemini_assistant.agent import root_agent as gemini_assistant_agent
from adk_answering_agent.settings import BOT_RESPONSE_LABEL
from adk_answering_agent.settings import IS_INTERACTIVE
from adk_answering_agent.settings import OWNER
@@ -22,6 +23,7 @@ from adk_answering_agent.tools import add_label_to_discussion
from adk_answering_agent.tools import convert_gcs_links_to_https
from adk_answering_agent.tools import get_discussion_and_comments
from google.adk.agents.llm_agent import Agent
from google.adk.tools.agent_tool import AgentTool
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
if IS_INTERACTIVE:
@@ -52,10 +54,10 @@ root_agent = Agent(
* The latest comment is not from you or other agents (marked as "Response from XXX Agent").
* The latest comment is asking a question or requesting information.
4. Use the `VertexAiSearchTool` to find relevant information before answering.
* If you need infromation about Gemini API, ask the `gemini_assistant` agent to provide the information and references.
* You can call the `gemini_assistant` agent with multiple queries to find all the relevant information.
5. If you can find relevant information, use the `add_comment_to_discussion` tool to add a comment to the discussion.
6. If you post a commment and the discussion does not have a label named {BOT_RESPONSE_LABEL},
add the label {BOT_RESPONSE_LABEL} to the discussion using the `add_label_to_discussion` tool.
6. If you post a comment, add the label {BOT_RESPONSE_LABEL} to the discussion using the `add_label_to_discussion` tool.
IMPORTANT:
* {APPROVAL_INSTRUCTION}
@@ -63,17 +65,20 @@ root_agent = Agent(
information that is not in the document store. Do not invent citations which are not in the document store.
* **Be Objective**: your answer should be based on the facts you found in the document store, do not be misled by user's assumptions or user's understanding of ADK.
* If you can't find the answer or information in the document store, **do not** respond.
* Inlclude a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>".
* Start with a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>".
* Have a divider line between the TLDR and your detail response.
* Do not respond to any other discussion except the one specified by the user.
* Please include your justification for your decision in your output
to the user who is telling with you.
* If you uses citation from the document store, please provide a footnote
referencing the source document format it as: "[1] publicly accessible HTTPS URL of the document".
* You can use the `convert_gcs_links_to_https` tool to convert GCS links to HTTPS links.
* You **should always** use the `convert_gcs_links_to_https` tool to convert GCS links (e.g. "gs://...") to HTTPS links.
* **Do not** use the `convert_gcs_links_to_https` tool for non-GCS links.
* Make sure the citation URL is valid. Otherwise do not list this specific citation.
""",
tools=[
VertexAiSearchTool(data_store_id=VERTEXAI_DATASTORE_ID),
AgentTool(gemini_assistant_agent),
get_discussion_and_comments,
add_comment_to_discussion,
add_label_to_discussion,
@@ -0,0 +1,15 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import agent
@@ -0,0 +1,94 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from typing import Any
from typing import Dict
from typing import List
from adk_answering_agent.settings import ADK_GCP_SA_KEY
from adk_answering_agent.settings import GEMINI_API_DATASTORE_ID
from adk_answering_agent.utils import error_response
from google.adk.agents.llm_agent import Agent
from google.api_core.exceptions import GoogleAPICallError
from google.cloud import discoveryengine_v1beta as discoveryengine
from google.oauth2 import service_account
def search_gemini_api_docs(queries: List[str]) -> Dict[str, Any]:
"""Searches Gemini API docs using Vertex AI Search.
Args:
queries: The list of queries to search.
Returns:
A dictionary containing the status of the request and the list of search
results, which contains the title, url and snippets.
"""
try:
adk_gcp_sa_key_info = json.loads(ADK_GCP_SA_KEY)
client = discoveryengine.SearchServiceClient(
credentials=service_account.Credentials.from_service_account_info(
adk_gcp_sa_key_info
)
)
except (TypeError, ValueError) as e:
return error_response(f"Error creating Vertex AI Search client: {e}")
serving_config = f"{GEMINI_API_DATASTORE_ID}/servingConfigs/default_config"
results = []
try:
for query in queries:
request = discoveryengine.SearchRequest(
serving_config=serving_config,
query=query,
page_size=20,
)
response = client.search(request=request)
for item in response.results:
snippets = []
for snippet in item.document.derived_struct_data.get("snippets", []):
snippets.append(snippet.get("snippet"))
results.append({
"title": item.document.derived_struct_data.get("title"),
"url": item.document.derived_struct_data.get("link"),
"snippets": snippets,
})
except GoogleAPICallError as e:
return error_response(f"Error from Vertex AI Search: {e}")
return {"status": "success", "results": results}
root_agent = Agent(
model="gemini-2.5-pro",
name="gemini_assistant",
description="Answer questions about Gemini API.",
instruction="""
You are a helpful assistant that responds to questions about Gemini API based on information
found in the document store. You can access the document store using the `search_gemini_api_docs` tool.
When user asks a question, here are the steps:
1. Use the `search_gemini_api_docs` tool to find relevant information before answering.
* You can call the tool with multiple queries to find all the relevant information.
2. Provide a response based on the information you found in the document store. Reference the source document in the response.
IMPORTANT:
* Your response should be based on the information you found in the document store. Do not invent
information that is not in the document store. Do not invent citations which are not in the document store.
* If you can't find the answer or information in the document store, just respond with "I can't find the answer or information in the document store".
* If you uses citation from the document store, please always provide a footnote referencing the source document format it as: "[1] URL of the document".
""",
tools=[search_gemini_api_docs],
)
@@ -31,6 +31,9 @@ if not VERTEXAI_DATASTORE_ID:
GOOGLE_CLOUD_PROJECT = os.getenv("GOOGLE_CLOUD_PROJECT")
GCS_BUCKET_NAME = os.getenv("GCS_BUCKET_NAME")
GEMINI_API_DATASTORE_ID = os.getenv("GEMINI_API_DATASTORE_ID")
ADK_GCP_SA_KEY = os.getenv("ADK_GCP_SA_KEY")
ADK_DOCS_ROOT_PATH = os.getenv("ADK_DOCS_ROOT_PATH")
ADK_PYTHON_ROOT_PATH = os.getenv("ADK_PYTHON_ROOT_PATH")
@@ -125,11 +125,12 @@ def add_comment_to_discussion(
}
}
"""
comment_body = (
"**Response from ADK Answering Agent (experimental, answer may be"
" inaccurate)**\n\n"
+ comment_body
)
if not comment_body.startswith("**Response from ADK Answering Agent"):
comment_body = (
"**Response from ADK Answering Agent (experimental, answer may be"
" inaccurate)**\n\n"
+ comment_body
)
variables = {"discussionId": discussion_id, "body": comment_body}
try: