Chapter 5 · stop parsing prose, start declaring schemas
responses.parse and Gemini response_schemaThe model hands you a string.
That's fine for a human. It's a bug the moment code reads it — the day it writes "Sure! Here's the JSON:" in front of the answer.
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
Declare the shape once. Both providers enforce it.
response = client.responses.parse(
model="gpt-5.4-nano",
input=f"Extract the event:\n{TEXT}",
text_format=CalendarEvent,
)
event = response.output_parsed # a real CalendarEvent
Enforced at decode time, not suggested in the prompt.
response = client.models.generate_content(
model="gemini-3.1-flash-lite",
contents=f"Extract the event:\n{TEXT}",
config=types.GenerateContentConfig(
response_mime_type="application/json",
response_schema=CalendarEvent,
),
)
event = response.parsedOne Pydantic model. text_format in OpenAI,
response_schema in Gemini. The shape stops being a
per-provider concern.
Each one is a docker compose up web app.
When output feeds code, declare a schema. It turns "usually parseable" into "validated or it failed". "Usually" is the word that pages you at 2am.