Lab 6 Solution: Programmatic Execution with the ADK Runner
Goal
In this lab, you learned how to run an ADK agent programmatically from within a Python script, using the standard Runner. You imported and ran the Haiku Poet agent you built in Module 4.
This demonstrated the canonical way to execute an agent as part of a larger Python application, without using the adk command-line tools.
Step 1: Prepare the Project
-
Navigate to your
adk-trainingdirectory:cd /path/to/your/adk-training -
Create the dedicated directory and script:
mkdir run_haiku_agent
cd run_haiku_agent
# Create run_haiku_agent.py inside this folder
Step 2: Complete the run_haiku_agent.py Script
Here is the complete run_haiku_agent.py script:
import asyncio
import sys
import os
# Add the parent directory to sys.path so we can import our agents
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
# Import the root_agent from your haiku_poet_agent directory.
from haiku_poet_agent.agent import root_agent as haiku_agent
async def main():
# Create a Session Service.
session_service = InMemorySessionService()
# Initialize the Runner, passing in the session service.
runner = Runner(
app_name="haiku_poet_agent",
agent=haiku_agent,
session_service=session_service
)
# Create a new session for your agent.
session = await session_service.create_session(
app_name="haiku_poet_agent",
user_id="user123",
)
# Package your query.
query_string = "A quiet morning with a cup of coffee."
new_message = types.Content(
parts=[types.Part(text=query_string)],
role="user",
)
# Run the agent.
# We pass the user_id and session_id (which the runner uses to fetch the session from the service)
async for event in runner.run_async(
user_id="user123",
session_id=session.id,
new_message=new_message
):
# Print the text from the final agent response.
if event.is_final_response():
if event.content and event.content.parts:
print(event.content.parts[0].text)
if __name__ == "__main__":
asyncio.run(main())
Step 3: Run the Script
-
Ensure your virtual environment is active.
-
Run the script from your
run_haiku_agentdirectory:python run_haiku_agent.py
Step 4: Observe the Output
If your script is correct, you will see the haiku response printed directly to your console.
Lab Summary
You have successfully run an agent programmatically using the standard Runner. This is the foundation for integrating your agent into any larger Python application.
Self-Reflection Answers
-
Why is it important to decouple the
Runnerfrom theSessionService? What advantage does this give you in a production environment?- Answer: Decoupling
RunnerfromSessionServicepromotes a modular architecture, making theRunnerstateless and reusable across different session management strategies. In a production environment, this allows you to easily swapInMemorySessionServicefor persistent alternatives likeFirestoreSessionServiceor custom implementations without modifying the coreRunnerlogic. This flexibility is crucial for scaling, handling failures, and integrating with diverse backend systems where session state needs to be reliably stored and retrieved.
- Answer: Decoupling
-
The
runner.run_asyncmethod returns a stream of events. Why is this streaming approach useful in a real-world application compared to a function that just returns the final string?- Answer: The streaming approach of
runner.run_asyncis highly beneficial in real-world applications for several reasons:- Real-time Feedback: It allows for immediate partial responses (e.g., streaming LLM output word-by-word), improving the user experience by reducing perceived latency.
- Progress Indicators: Developers can use intermediate events (like tool calls or agent thoughts) to display progress indicators or provide more context to the user about what the agent is doing.
- Handling Long-Running Tasks: For agents performing complex or long-running tasks, streaming prevents the client from blocking indefinitely, allowing it to process information incrementally.
- Answer: The streaming approach of
-
How would you modify this script to have a continuous conversation with the agent instead of just sending one message? (Hint: Think about loops and reusing the session object).
-
Answer: To have a continuous conversation, you would wrap the query and
runner.run_asynccall within an asynchronous loop. Before each iteration, you would take new user input, and then reuse the samesession.idto maintain context.# ... (imports and main setup)
while True:
user_input = input("\n[User]: ")
if user_input.lower() == "exit":
break
new_message = types.Content(
parts=[types.Part(text=user_input)],
role="user",
)
print("[Agent]: ", end="")
async for event in runner.run_async(
user_id="user123",
session_id=session.id,
new_message=new_message
):
if event.is_final_response():
if event.content and event.content.parts:
print(event.content.parts[0].text)
-