Answers with a fixed shape
Prose is fine for a person and awful for a program. Two fields turn an answer into something your code can use.
The shape you want back
from pydantic import BaseModel
class Triage(BaseModel):
category: str
urgent: boolAn ordinary Pydantic model: two fields with types. This is the shape the final answer has to take.
agent = LlmAgent(
name="triage",
model=PretendModel(replies=[say('{"category": "billing", "urgent": true}')]),
instruction="Sort the ticket. Reply as JSON with category and urgent.",
output_schema=Triage,
output_key="triage",
)output_schema says what the answer must look like. output_key says where to put it in session state when it arrives.
Where the answer lands
runner = InMemoryRunner(agent=agent, app_name="demo")
session = await runner.session_service.create_session(app_name="demo", user_id="u1")
message = types.Content(role="user", parts=[types.Part(text="I was charged twice")])
async for _ in runner.run_async(user_id="u1", session_id=session.id, new_message=message):
pass
done = await runner.session_service.get_session(
app_name="demo", user_id="u1", session_id=session.id)
print("state:", dict(done.state))
print("type: ", type(done.state["triage"]).__name__)Not a sentence to parse. It arrived in state, already a dictionary, under the key you named. The next agent, or the next line of your code, reads it directly.
The documentation is exact about the pairing: with a schema set, the parsed response is stored under the key. Without a schema, the text itself is stored, which is still useful.
The limitation to plan around
Using output_schema together with tools in the same request is only supported by specific models. If your agent needs both, the usual answer is two agents: one that does the work with tools, and one that formats the result. That pattern is lesson 17.
If the reply fails validation, ADK logs the error and stores the raw string under your key instead of a parsed object, so checking the type is cheap insurance.
output_key is useful on its own, without a schema. It is the simplest way for one agent to leave something behind for the next one, which is most of how multi-agent setups actually communicate.- Make the stand-in reply with something that is not valid JSON and print what lands in state.
- Drop the schema and keep the key. Notice the text is stored instead.
Slow is fine. Stopping is the only problem.