docs(config): add examples for config agents

PiperOrigin-RevId: 793871778
This commit is contained in:
Liang Wu
2025-08-11 18:09:55 -07:00
committed by Copybara-Service
parent 88114d7c73
commit d87feb8ddb
41 changed files with 761 additions and 0 deletions
@@ -0,0 +1,7 @@
# Basic Confg-based Agent
This sample only covers:
* name
* description
* model
@@ -0,0 +1,9 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: assistant_agent
model: gemini-2.5-flash
description: A helper agent that can answer users' questions.
instruction: |
You are an agent to help answer users' various questions.
1. If the user's intention is not clear, ask clarifying questions to better understand their needs.
2. Once the intention is clear, provide accurate and helpful answers to the user's questions.
@@ -0,0 +1,79 @@
from google.genai import types
async def before_agent_callback(callback_context):
print('@before_agent_callback')
return None
async def after_agent_callback(callback_context):
print('@after_agent_callback')
return None
async def before_model_callback(callback_context, llm_request):
print('@before_model_callback')
return None
async def after_model_callback(callback_context, llm_response):
print('@after_model_callback')
return None
def after_agent_callback1(callback_context):
print('@after_agent_callback1')
def after_agent_callback2(callback_context):
print('@after_agent_callback2')
# ModelContent (or Content with role set to 'model') must be returned.
# Otherwise, the event will be excluded from the context in the next turn.
return types.ModelContent(
parts=[
types.Part(
text='(stopped) after_agent_callback2',
),
],
)
def after_agent_callback3(callback_context):
print('@after_agent_callback3')
def before_agent_callback1(callback_context):
print('@before_agent_callback1')
def before_agent_callback2(callback_context):
print('@before_agent_callback2')
def before_agent_callback3(callback_context):
print('@before_agent_callback3')
def before_tool_callback1(tool, args, tool_context):
print('@before_tool_callback1')
def before_tool_callback2(tool, args, tool_context):
print('@before_tool_callback2')
def before_tool_callback3(tool, args, tool_context):
print('@before_tool_callback3')
def after_tool_callback1(tool, args, tool_context, tool_response):
print('@after_tool_callback1')
def after_tool_callback2(tool, args, tool_context, tool_response):
print('@after_tool_callback2')
return {'test': 'after_tool_callback2', 'response': tool_response}
def after_tool_callback3(tool, args, tool_context, tool_response):
print('@after_tool_callback3')
@@ -0,0 +1,43 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: hello_world_agent
model: gemini-2.0-flash
description: hello world agent that can roll a dice and check prime numbers.
instruction: |
You roll dice and answer questions about the outcome of the dice rolls.
You can roll dice of different sizes.
You can use multiple tools in parallel by calling functions in parallel(in one request and in one round).
It is ok to discuss previous dice roles, and comment on the dice rolls.
When you are asked to roll a die, you must call the roll_die tool with the number of sides. Be sure to pass in an integer. Do not pass in a string.
You should never roll a die on your own.
When checking prime numbers, call the check_prime tool with a list of integers. Be sure to pass in a list of integers. You should never pass in a string.
You should not check prime numbers before calling the tool.
When you are asked to roll a die and check prime numbers, you should always make the following two function calls:
1. You should first call the roll_die tool to get a roll. Wait for the function response before calling the check_prime tool.
2. After you get the function response from roll_die tool, you should call the check_prime tool with the roll_die result.
2.1 If user asks you to check primes based on previous rolls, make sure you include the previous rolls in the list.
3. When you respond, you must include the roll_die result from step 1.
You should always perform the previous 3 steps when asking for a roll and checking prime numbers.
You should not rely on the previous history on prime results.
tools:
- name: callbacks.tools.roll_die
- name: callbacks.tools.check_prime
before_agent_callbacks:
- name: callbacks.callbacks.before_agent_callback1
- name: callbacks.callbacks.before_agent_callback2
- name: callbacks.callbacks.before_agent_callback3
after_agent_callbacks:
- name: callbacks.callbacks.after_agent_callback1
- name: callbacks.callbacks.after_agent_callback2
- name: callbacks.callbacks.after_agent_callback3
before_model_callbacks:
- name: callbacks.callbacks.before_model_callback
after_model_callbacks:
- name: callbacks.callbacks.after_model_callback
before_tool_callbacks:
- name: callbacks.callbacks.before_tool_callback1
- name: callbacks.callbacks.before_tool_callback2
- name: callbacks.callbacks.before_tool_callback3
after_tool_callbacks:
- name: callbacks.callbacks.after_tool_callback1
- name: callbacks.callbacks.after_tool_callback2
- name: callbacks.callbacks.after_tool_callback3
@@ -0,0 +1,48 @@
import random
from google.adk.tools.tool_context import ToolContext
def roll_die(sides: int, tool_context: ToolContext) -> int:
"""Roll a die and return the rolled result.
Args:
sides: The integer number of sides the die has.
Returns:
An integer of the result of rolling the die.
"""
result = random.randint(1, sides)
if not 'rolls' in tool_context.state:
tool_context.state['rolls'] = []
tool_context.state['rolls'] = tool_context.state['rolls'] + [result]
return result
def check_prime(nums: list[int]) -> str:
"""Check if a given list of numbers are prime.
Args:
nums: The list of numbers to check.
Returns:
A str indicating which number is prime.
"""
primes = set()
for number in nums:
number = int(number)
if number <= 1:
continue
is_prime = True
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
is_prime = False
break
if is_prime:
primes.add(number)
return (
'No prime numbers found.'
if not primes
else f"{', '.join(str(num) for num in primes)} are prime numbers."
)
@@ -0,0 +1,10 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: search_agent
model: gemini-2.0-flash
description: 'an agent whose job it is to perform Google search queries and answer questions about the results.'
instruction: You are an agent whose job is to perform Google search queries and answer questions about the results.
tools:
- name: google_search
generate_content_config:
temperature: 0.1
max_output_tokens: 2000
@@ -0,0 +1,57 @@
from __future__ import annotations
from keyword import kwlist
from typing import Any
from typing import AsyncGenerator
from typing import ClassVar
from typing import Dict
from typing import Type
from google.adk.agents import BaseAgent
from google.adk.agents.base_agent_config import BaseAgentConfig
from google.adk.agents.invocation_context import InvocationContext
from google.adk.events.event import Event
from google.genai import types
from pydantic import ConfigDict
from typing_extensions import override
class MyCustomAgentConfig(BaseAgentConfig):
model_config = ConfigDict(
extra="forbid",
)
agent_class: str = "core_cutom_agent.my_agents.MyCustomAgent"
my_field: str = ""
class MyCustomAgent(BaseAgent):
my_field: str = ""
config_type: ClassVar[type[BaseAgentConfig]] = MyCustomAgentConfig
@override
@classmethod
def _parse_config(
cls: Type[MyCustomAgent],
config: MyCustomAgentConfig,
config_abs_path: str,
kwargs: Dict[str, Any],
) -> Dict[str, Any]:
if config.my_field:
kwargs["my_field"] = config.my_field
return kwargs
async def _run_async_impl(
self, ctx: InvocationContext
) -> AsyncGenerator[Event, None]:
yield Event(
invocation_id=ctx.invocation_id,
author=self.name,
content=types.ModelContent(
parts=[
types.Part(
text=f"I feel good! value in my_field: `{self.my_field}`"
)
]
),
)
@@ -0,0 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: working_agent
agent_class: core_custom_agent.my_agents.MyCustomAgent
description: Handles all the work.
my_field: my_field_value
+3
View File
@@ -0,0 +1,3 @@
# Config-based Agent Sample - LLM multi-agent
http://google3/third_party/py/google/adk/open_source_workspace/contributing/samples/hello_world_ma/
+74
View File
@@ -0,0 +1,74 @@
import random
from google.adk.examples.example import Example
from google.adk.tools.example_tool import ExampleTool
from google.genai import types
def roll_die(sides: int) -> int:
"""Roll a die and return the rolled result."""
return random.randint(1, sides)
def check_prime(nums: list[int]) -> str:
"""Check if a given list of numbers are prime."""
primes = set()
for number in nums:
number = int(number)
if number <= 1:
continue
is_prime = True
for i in range(2, int(number**0.5) + 1):
if number % i == 0:
is_prime = False
break
if is_prime:
primes.add(number)
return (
"No prime numbers found."
if not primes
else f"{', '.join(str(num) for num in primes)} are prime numbers."
)
example_tool = ExampleTool(
examples=[
Example(
input=types.UserContent(
parts=[types.Part(text="Roll a 6-sided die.")]
),
output=[
types.ModelContent(
parts=[types.Part(text="I rolled a 4 for you.")]
)
],
),
Example(
input=types.UserContent(
parts=[types.Part(text="Is 7 a prime number?")]
),
output=[
types.ModelContent(
parts=[types.Part(text="Yes, 7 is a prime number.")]
)
],
),
Example(
input=types.UserContent(
parts=[
types.Part(
text="Roll a 10-sided die and check if it's prime."
)
]
),
output=[
types.ModelContent(
parts=[types.Part(text="I rolled an 8 for you.")]
),
types.ModelContent(
parts=[types.Part(text="8 is not a prime number.")]
),
],
),
]
)
@@ -0,0 +1,12 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
model: gemini-2.5-flash
name: prime_agent
description: Handles checking if numbers are prime.
instruction: |
You are responsible for checking whether numbers are prime.
When asked to check primes, you must call the check_prime tool with a list of integers.
Never attempt to determine prime numbers manually.
Return the prime number results to the root agent.
tools:
- name: ma_llm.check_prime
@@ -0,0 +1,11 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
model: gemini-2.5-flash
name: roll_agent
description: Handles rolling dice of different sizes.
instruction: |
You are responsible for rolling dice based on the user's request.
When asked to roll a die, you must call the roll_die tool with the number of sides as an integer.
tools:
- name: ma_llm.roll_die
@@ -0,0 +1,26 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
model: gemini-2.5-flash
name: root_agent
description: Iterative writing pipeline agent.
# global_instruction: You are DicePrimeBot, ready to roll dice and check prime numbers.
instruction: |
You are a helpful assistant that can roll dice and check if numbers are prime.
You delegate rolling dice tasks to the roll_agent and prime checking tasks to the prime_agent.
Follow these steps:
1. If the user asks to roll a die, delegate to the roll_agent.
2. If the user asks to check primes, delegate to the prime_agent.
3. If the user asks to roll a die and then check if the result is prime, call roll_agent first, then pass the result to prime_agent.
Always clarify the results before proceeding.
sub_agents:
- config_path: roll_agent.yaml
- config_path: prime_agent.yaml
tools:
- name: ma_llm.example_tool
generate_content_config:
safety_settings:
- category: HARM_CATEGORY_DANGEROUS_CONTENT
threshold: 'OFF'
+16
View File
@@ -0,0 +1,16 @@
# Config-based Agent Sample - Sequential and Loop Workflow
A multi-agent setup with a sequential and loop workflow.
The whole process is:
1. An initial writing agent will author a 1-2 sentence as starting point.
2. A critic agent will review and provide feedback.
3. A refiner agent will revise based on critic agent's feedback.
4. Loop back to #2 until critic agent says "No major issues found."
Sample queries:
> initial topic: badminton
> initial topic: AI hurts human
@@ -0,0 +1,8 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LoopAgent
name: RefinementLoop
description: Refinement loop agent.
max_iterations: 5
sub_agents:
- config_path: writer_agents/critic_agent.yaml
- config_path: writer_agents/refiner_agent.yaml
@@ -0,0 +1,7 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: SequentialAgent
name: IterativeWritingPipeline
description: Iterative writing pipeline agent.
sub_agents:
- config_path: writer_agents/initial_writer_agent.yaml
- config_path: loop_agent.yaml
@@ -0,0 +1,32 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: CriticAgent
model: gemini-2.5-pro
description: Reviews the current draft, providing critique if clear improvements are needed, otherwise signals completion.
instruction: |
You are a Constructive Critic AI reviewing a document draft (typically at least 10 sentences). Your goal is balanced feedback.
**Document to Review:**
```
{{current_document}}
```
**Task:**
Review the document for the following cretiria:
- content length: at least 10 sentences;
- clarity: the content must be clear;
- engagement: the content should be engaging and relevant to the topic;
- basic coherence according to the initial topic (if known).
IF you identify 1-2 *clear and actionable* ways the document could be improved to better capture the topic or enhance reader engagement (e.g., "Needs a stronger opening sentence", "Clarify the character's goal"):
Provide these specific suggestions concisely. Output *only* the critique text.
ELSE IF the document is coherent, addresses the topic adequately for its length, and has no glaring errors or obvious omissions:
Respond *exactly* with the phrase "No major issues found." and nothing else. It doesn't need to be perfect, just functionally complete for this stage. Avoid suggesting purely subjective stylistic preferences if the core is sound.
Do not add explanations. Output only the critique OR the exact completion phrase.
IF output the critique, ONLY output JUST ONE aspect each time.
include_contents: none
output_key: criticism
@@ -0,0 +1,13 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: InitialWriterAgent
model: gemini-2.0-flash
description: Writes the initial document draft based on the topic, aiming for some initial substance.
instruction: |
You are a Creative Writing Assistant tasked with starting a story.
Write the *first draft* of a short story (aim for 1-2 sentences).
Base the content *only* on the topic provided by user. Try to introduce a specific element (like a character, a setting detail, or a starting action) to make it engaging.
Output *only* the story/document text. Do not add introductions or explanations.
output_key: current_document
@@ -0,0 +1,25 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
agent_class: LlmAgent
name: RefinerAgent
model: gemini-2.0-flash
description: Refines the document based on critique, or calls exit_loop if critique indicates completion.
instruction: |
You are a Creative Writing Assistant refining a document based on feedback OR exiting the process.
**Current Document:**
```
{{current_document}}
```
**Critique/Suggestions:**
{{criticism}}
**Task:**
Analyze the 'Critique/Suggestions'.
IF the critique is *exactly* "No major issues found.":
You MUST call the 'exit_loop' function. Do not output any text.
ELSE (the critique contains actionable feedback):
Carefully apply the suggestions to improve the 'Current Document'. Output *only* the refined document text.
Do not add explanations. Either output the refined document OR call the exit_loop function.
output_key: current_document
tools:
- name: exit_loop

Some files were not shown because too many files have changed in this diff Show More