Google ADKgoogle-adk 2.8 · Python 3.10+
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
28 small wins to finish your pathNext lesson

Running an agent

An agent is a description. A runner is the thing that drives it, and it needs one more object first: somewhere to keep the conversation.

Three names arrive together here and stay for the rest of the course. A session is one conversation. A session service stores sessions. A runner takes your agent, a session and a message, and drives the loop.

What the runner does with your question
You send a message. Into a session that already exists.Step 1 of 4

The agent, with the model from lesson 4

python
from pretend_adk import PretendModel, say, call
from google.adk.agents import LlmAgent

def lookup_order(order_id: str) -> str:
    """Look up the status of an order by its id."""
    return f"Order {order_id} shipped on 3 March."

The imports, and the tool from lesson 2 unchanged. Nothing here is new.

python
agent = LlmAgent(    name="support",
    model=PretendModel(replies=[call("lookup_order", order_id="A17"),
                                say("Your order shipped on 3 March.")]),
    instruction="Help customers with their orders.",
    tools=[lookup_order],
)

Two replies are scripted: first ask for the tool, then answer. That is one trip round the loop, written out in advance so the lesson can be about the runner rather than the model.

A runner and a session

Example
from google.adk.runners import InMemoryRunner

runner = InMemoryRunner(agent=agent, app_name="demo")
session = await runner.session_service.create_session(app_name="demo", user_id="u1")

print("session id is a", type(session.id).__name__, "| events so far:", len(session.events))

InMemoryRunner is the runner plus a session service that keeps everything in memory. The session has an id, a history and a state, and the history is empty because nothing has happened yet.

Sending a message

A message is a content object with a role and parts, the same shape the model produces.

Example
from google.genai import types

question = types.Content(role="user", parts=[types.Part(text="Where is order A17?")])

async for event in runner.run_async(user_id="u1", session_id=session.id, new_message=question):
    print(event.author, "->", "final" if event.is_final_response() else "step")

Three events for one question, all from the agent. The first two are the tool request and its result. The last is the answer, and is_final_response() is how you tell.

Getting just the answer

Most of the time that is all you want, so it is worth keeping these four lines.

Example
session = await runner.session_service.create_session(app_name="demo", user_id="u1")

answer = ""
async for event in runner.run_async(user_id="u1", session_id=session.id, new_message=question):
    if event.is_final_response() and event.content:
        answer = "".join(part.text or "" for part in event.content.parts)

print(answer)

A fresh session, because the scripted model has used up its two replies. The loop keeps the text of whichever event says it is final, and that is your answer.

Sessions come first
The session has to exist before you can run in it. Forgetting create_session is the most common first error, and the message you get is about a missing session rather than a missing agent.
Try it yourself
  • Ask a second question in the same session and count the events.
  • Create a second session and ask the same question. It knows nothing about the first.

Every expert started right here.