mirror of
https://github.com/EvolutionAPI/adk-python.git
synced 2025-07-13 23:17:35 -06:00
chore: Creates a sample main.py to demonstrate how to use adk as a library for the workflow agent in docs.
For Issue #573. PiperOrigin-RevId: 760380509
This commit is contained in:
parent
2ad1f79422
commit
9e767b3fe1
12
contributing/samples/workflow_agent_seq/README.md
Normal file
12
contributing/samples/workflow_agent_seq/README.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Workflow Agent Sample - SequentialAgent
|
||||||
|
|
||||||
|
Sample query:
|
||||||
|
|
||||||
|
* Write a quicksort method in python.
|
||||||
|
* Write a python function to do bubble sort.
|
||||||
|
|
||||||
|
To run in cli (after installing `google-adk`):
|
||||||
|
|
||||||
|
* `uv run main.py` (or `python main.py`)
|
||||||
|
|
||||||
|
Check sample output in `sample.output` file in this folder.
|
@ -15,80 +15,97 @@
|
|||||||
from google.adk.agents.llm_agent import LlmAgent
|
from google.adk.agents.llm_agent import LlmAgent
|
||||||
from google.adk.agents.sequential_agent import SequentialAgent
|
from google.adk.agents.sequential_agent import SequentialAgent
|
||||||
|
|
||||||
|
# Part of agent.py --> Follow https://google.github.io/adk-docs/get-started/quickstart/ to learn the setup
|
||||||
|
|
||||||
# --- 1. Define Sub-Agents for Each Pipeline Stage ---
|
# --- 1. Define Sub-Agents for Each Pipeline Stage ---
|
||||||
|
|
||||||
# Code Writer Agent
|
# Code Writer Agent
|
||||||
# Takes the initial specification (from user query) and writes code.
|
# Takes the initial specification (from user query) and writes code.
|
||||||
code_writer_agent = LlmAgent(
|
code_writer_agent = LlmAgent(
|
||||||
name="code_writer_agent",
|
name="CodeWriterAgent",
|
||||||
model="gemini-1.5-flash-001",
|
model="gemini-1.5-flash",
|
||||||
instruction="""You are a Code Writer AI.
|
# Change 3: Improved instruction
|
||||||
Based on the user's request, write the initial Python code.
|
instruction="""You are a Python Code Generator.
|
||||||
Output *only* the raw code block.
|
Based *only* on the user's request, write Python code that fulfills the requirement.
|
||||||
""",
|
Output *only* the complete Python code block, enclosed in triple backticks (```python ... ```).
|
||||||
description="Writes initial code based on a specification.",
|
Do not add any other text before or after the code block.
|
||||||
# Stores its output (the generated code) into the session state
|
""",
|
||||||
# under the key 'generated_code'.
|
description="Writes initial Python code based on a specification.",
|
||||||
output_key="generated_code",
|
output_key="generated_code", # Stores output in state['generated_code']
|
||||||
)
|
)
|
||||||
|
|
||||||
# Code Reviewer Agent
|
# Code Reviewer Agent
|
||||||
# Takes the code generated by the previous agent (read from state) and provides feedback.
|
# Takes the code generated by the previous agent (read from state) and provides feedback.
|
||||||
code_reviewer_agent = LlmAgent(
|
code_reviewer_agent = LlmAgent(
|
||||||
name="code_reviewer_agent",
|
name="CodeReviewerAgent",
|
||||||
model="gemini-2.0-flash-001",
|
model="gemini-2.0-flash",
|
||||||
instruction="""You are a Code Reviewer AI.
|
# Change 3: Improved instruction, correctly using state key injection
|
||||||
|
instruction="""You are an expert Python Code Reviewer.
|
||||||
|
Your task is to provide constructive feedback on the provided code.
|
||||||
|
|
||||||
Review the below Python code.
|
**Code to Review:**
|
||||||
|
```python
|
||||||
|
{generated_code}
|
||||||
|
```
|
||||||
|
|
||||||
```
|
**Review Criteria:**
|
||||||
{generated_code}
|
1. **Correctness:** Does the code work as intended? Are there logic errors?
|
||||||
```
|
2. **Readability:** Is the code clear and easy to understand? Follows PEP 8 style guidelines?
|
||||||
|
3. **Efficiency:** Is the code reasonably efficient? Any obvious performance bottlenecks?
|
||||||
|
4. **Edge Cases:** Does the code handle potential edge cases or invalid inputs gracefully?
|
||||||
|
5. **Best Practices:** Does the code follow common Python best practices?
|
||||||
|
|
||||||
Provide constructive feedback on potential errors, style issues, or improvements.
|
**Output:**
|
||||||
Focus on clarity and correctness.
|
Provide your feedback as a concise, bulleted list. Focus on the most important points for improvement.
|
||||||
Output only the review comments.
|
If the code is excellent and requires no changes, simply state: "No major issues found."
|
||||||
|
Output *only* the review comments or the "No major issues" statement.
|
||||||
""",
|
""",
|
||||||
description="Reviews code and provides feedback.",
|
description="Reviews code and provides feedback.",
|
||||||
# Stores its output (the review comments) into the session state
|
output_key="review_comments", # Stores output in state['review_comments']
|
||||||
# under the key 'review_comments'.
|
|
||||||
output_key="review_comments",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Code Refactorer Agent
|
# Code Refactorer Agent
|
||||||
# Takes the original code and the review comments (read from state) and refactors the code.
|
# Takes the original code and the review comments (read from state) and refactors the code.
|
||||||
code_refactorer_agent = LlmAgent(
|
code_refactorer_agent = LlmAgent(
|
||||||
name="code_refactorer_agent",
|
name="CodeRefactorerAgent",
|
||||||
model="gemini-2.0-flash-001",
|
model="gemini-2.0-flash",
|
||||||
instruction="""You are a Code Refactorer AI.
|
# Change 3: Improved instruction, correctly using state key injection
|
||||||
|
instruction="""You are a Python Code Refactoring AI.
|
||||||
|
Your goal is to improve the given Python code based on the provided review comments.
|
||||||
|
|
||||||
Below is the original Python code:
|
**Original Code:**
|
||||||
|
```python
|
||||||
|
{generated_code}
|
||||||
|
```
|
||||||
|
|
||||||
```
|
**Review Comments:**
|
||||||
{generated_code}
|
{review_comments}
|
||||||
```
|
|
||||||
|
|
||||||
Below are the review comments:
|
**Task:**
|
||||||
|
Carefully apply the suggestions from the review comments to refactor the original code.
|
||||||
|
If the review comments state "No major issues found," return the original code unchanged.
|
||||||
|
Ensure the final code is complete, functional, and includes necessary imports and docstrings.
|
||||||
|
|
||||||
{review_comments}
|
**Output:**
|
||||||
|
Output *only* the final, refactored Python code block, enclosed in triple backticks (```python ... ```).
|
||||||
Refactor the code based on the provided feedback.
|
Do not add any other text before or after the code block.
|
||||||
|
""",
|
||||||
Output *only* the final, refactored code block.
|
|
||||||
""",
|
|
||||||
description="Refactors code based on review comments.",
|
description="Refactors code based on review comments.",
|
||||||
# Stores its output (the refactored code) into the session state
|
output_key="refactored_code", # Stores output in state['refactored_code']
|
||||||
# under the key 'refactored_code'.
|
|
||||||
output_key="refactored_code",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- 2. Create the SequentialAgent ---
|
# --- 2. Create the SequentialAgent ---
|
||||||
# This agent orchestrates the pipeline by running the sub_agents in order.
|
# This agent orchestrates the pipeline by running the sub_agents in order.
|
||||||
code_pipeline_agent = SequentialAgent(
|
code_pipeline_agent = SequentialAgent(
|
||||||
name="code_pipeline_agent",
|
name="CodePipelineAgent",
|
||||||
sub_agents=[code_writer_agent, code_reviewer_agent, code_refactorer_agent],
|
sub_agents=[code_writer_agent, code_reviewer_agent, code_refactorer_agent],
|
||||||
|
description=(
|
||||||
|
"Executes a sequence of code writing, reviewing, and refactoring."
|
||||||
|
),
|
||||||
# The agents will run in the order provided: Writer -> Reviewer -> Refactorer
|
# The agents will run in the order provided: Writer -> Reviewer -> Refactorer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# For ADK tools compatibility, the root agent must be named `root_agent`
|
||||||
root_agent = code_pipeline_agent
|
root_agent = code_pipeline_agent
|
||||||
|
87
contributing/samples/workflow_agent_seq/main.py
Normal file
87
contributing/samples/workflow_agent_seq/main.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# 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 asyncio
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
|
import agent
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from google.adk.cli.utils import logs
|
||||||
|
from google.adk.runners import InMemoryRunner
|
||||||
|
from google.adk.sessions import Session
|
||||||
|
from google.genai import types
|
||||||
|
|
||||||
|
load_dotenv(override=True)
|
||||||
|
logs.log_to_tmp_folder()
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
app_name = 'my_app'
|
||||||
|
user_id_1 = 'user1'
|
||||||
|
runner = InMemoryRunner(
|
||||||
|
app_name=app_name,
|
||||||
|
agent=agent.root_agent,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def run_prompt(session: Session, new_message: str) -> Session:
|
||||||
|
content = types.Content(
|
||||||
|
role='user', parts=[types.Part.from_text(text=new_message)]
|
||||||
|
)
|
||||||
|
print('** User says:', content.model_dump(exclude_none=True))
|
||||||
|
async for event in runner.run_async(
|
||||||
|
user_id=user_id_1,
|
||||||
|
session_id=session.id,
|
||||||
|
new_message=content,
|
||||||
|
):
|
||||||
|
if not event.content or not event.content.parts:
|
||||||
|
continue
|
||||||
|
if event.content.parts[0].text:
|
||||||
|
print(f'** {event.author}: {event.content.parts[0].text}')
|
||||||
|
elif event.content.parts[0].function_call:
|
||||||
|
print(
|
||||||
|
f'** {event.author}: fc /'
|
||||||
|
f' {event.content.parts[0].function_call.name} /'
|
||||||
|
f' {event.content.parts[0].function_call.args}\n'
|
||||||
|
)
|
||||||
|
elif event.content.parts[0].function_response:
|
||||||
|
print(
|
||||||
|
f'** {event.author}: fr /'
|
||||||
|
f' {event.content.parts[0].function_response.name} /'
|
||||||
|
f' {event.content.parts[0].function_response.response}\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
return cast(
|
||||||
|
Session,
|
||||||
|
await runner.session_service.get_session(
|
||||||
|
app_name=app_name, user_id=user_id_1, session_id=session.id
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
session_1 = await runner.session_service.create_session(
|
||||||
|
app_name=app_name, user_id=user_id_1
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f'----Session to create memory: {session_1.id} ----------------------')
|
||||||
|
session_1 = await run_prompt(
|
||||||
|
session_1, 'Write a python function to do quicksort.'
|
||||||
|
)
|
||||||
|
session_1 = await run_prompt(
|
||||||
|
session_1, 'Write another python function to do bubble sort.'
|
||||||
|
)
|
||||||
|
print('-------------------------------------------------------------------')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
82
contributing/samples/workflow_agent_seq/sample.output
Normal file
82
contributing/samples/workflow_agent_seq/sample.output
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
----Session to create memory: a05683c9-4a19-4ba8-b810-e90fc48be566 ----------------------
|
||||||
|
** User says: {'parts': [{'text': 'Write a python function to do quicksort.'}], 'role': 'user'}
|
||||||
|
** CodeWriterAgent: ```python
|
||||||
|
def quicksort(arr):
|
||||||
|
if len(arr) < 2:
|
||||||
|
return arr
|
||||||
|
else:
|
||||||
|
pivot = arr[0]
|
||||||
|
less = [i for i in arr[1:] if i <= pivot]
|
||||||
|
greater = [i for i in arr[1:] if i > pivot]
|
||||||
|
return quicksort(less) + [pivot] + quicksort(greater)
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
** CodeReviewerAgent: * **Correctness:** The code is functionally correct.
|
||||||
|
* **Readability:** The code is fairly readable, utilizing list comprehensions effectively.
|
||||||
|
* **Efficiency:** The space complexity is `O(n)` due to the creation of new lists (`less` and `greater`) in each recursive call. Choosing the first element as the pivot can lead to `O(n^2)` time complexity in the worst-case scenario (e.g., a sorted array). A better pivot selection strategy (e.g., random pivot) would improve average performance.
|
||||||
|
* **Best Practices:** While the code works, it's not the most efficient implementation of quicksort due to the space complexity and potential for worst-case time complexity. An in-place quicksort algorithm would be more efficient in terms of space.
|
||||||
|
|
||||||
|
** CodeRefactorerAgent: ```python
|
||||||
|
import random
|
||||||
|
|
||||||
|
def quicksort(arr):
|
||||||
|
"""
|
||||||
|
Sorts a list using the quicksort algorithm. This implementation
|
||||||
|
uses a randomly selected pivot to improve average-case performance
|
||||||
|
and performs the sort in-place to reduce space complexity.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
arr (list): The list to be sorted.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: The sorted list.
|
||||||
|
"""
|
||||||
|
def _quicksort(arr, low, high):
|
||||||
|
if low < high:
|
||||||
|
pi = partition(arr, low, high)
|
||||||
|
_quicksort(arr, low, pi-1)
|
||||||
|
_quicksort(arr, pi+1, high)
|
||||||
|
|
||||||
|
def partition(arr, low, high):
|
||||||
|
# Choose a random pivot
|
||||||
|
pivot_index = random.randint(low, high)
|
||||||
|
arr[pivot_index], arr[high] = arr[high], arr[pivot_index]
|
||||||
|
pivot = arr[high]
|
||||||
|
|
||||||
|
i = (low - 1)
|
||||||
|
for j in range(low, high):
|
||||||
|
if arr[j] <= pivot:
|
||||||
|
i += 1
|
||||||
|
arr[i], arr[j] = arr[j], arr[i]
|
||||||
|
|
||||||
|
arr[i + 1], arr[high] = arr[high], arr[i + 1]
|
||||||
|
return (i + 1)
|
||||||
|
|
||||||
|
_quicksort(arr, 0, len(arr)-1)
|
||||||
|
return arr
|
||||||
|
```
|
||||||
|
** User says: {'parts': [{'text': 'Write another python function to do bubble sort.'}], 'role': 'user'}
|
||||||
|
** CodeWriterAgent: ```python
|
||||||
|
def bubble_sort(arr):
|
||||||
|
n = len(arr)
|
||||||
|
for i in range(n):
|
||||||
|
for j in range(0, n-i-1):
|
||||||
|
if arr[j] > arr[j+1]:
|
||||||
|
arr[j], arr[j+1] = arr[j+1], arr[j]
|
||||||
|
return arr
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
** CodeReviewerAgent: No major issues found.
|
||||||
|
|
||||||
|
** CodeRefactorerAgent: ```python
|
||||||
|
def bubble_sort(arr):
|
||||||
|
n = len(arr)
|
||||||
|
for i in range(n):
|
||||||
|
for j in range(0, n-i-1):
|
||||||
|
if arr[j] > arr[j+1]:
|
||||||
|
arr[j], arr[j+1] = arr[j+1], arr[j]
|
||||||
|
return arr
|
||||||
|
```
|
||||||
|
-------------------------------------------------------------------
|
Loading…
Reference in New Issue
Block a user