response_format: answers your code can use
An answer in sentences is hard for code to use. response_format asks the agent for an answer that fits a Pydantic class and returns it as structured_response.
The shop's ticket system wants two fields for every question, the order id and its status, not a sentence to parse. The shape is a Pydantic class.
from pydantic import BaseModel
class Ticket(BaseModel):
"""A support ticket for one order."""
order_id: str
status: strGiven a schema, create_agent picks a strategy. If the model supports structured output natively, as OpenAI's and Anthropic's do, it asks the provider for it. Otherwise it uses ToolStrategy: it adds one more tool, named after the class, and requires the model to call a tool on every turn. The arguments of that final call are the answer.
Pick one to watch it run, step by step.
A model that fills in the ticket
Your model has no native support, so it gets the extra tool. It needs to know what to do with it.
from langchain.messages import AIMessage
from shop_model import ShopModel
class TicketModel(ShopModel):
def decide(self, messages):
reply = super().decide(messages)
if reply.tool_calls or "Ticket" not in [t.name for t in self.tools]:
return reply
order_id, status = reply.text.rstrip(".").split(" ", 1)
args = {"order_id": order_id, "status": status}
return AIMessage("", tool_calls=[{"name": "Ticket", "args": args, "id": "call_ticket"}])TicketModel keeps every rule from lesson 6 and adds one. When the base model would answer in words and a tool called Ticket is bound, it splits its answer into an order id and a status and calls that tool instead.
Reading the answer
from langchain.agents import create_agent
from ticket import Ticket
from ticket_model import TicketModel
from tools import lookup_order
agent = create_agent(TicketModel(), tools=[lookup_order], response_format=Ticket)result = agent.invoke({"messages": [{"role": "user", "content": "Where is my order A17?"}]})
print(repr(result["structured_response"]))
for message in result["messages"]:
print(f"{message.type:<6} {message.text or message.tool_calls[0]['name']}")structured_response is a Ticket object, ready for code. The conversation shows how it got there: the lookup, then a call to the Ticket tool, then a tool message that ends the loop by returning the ticket.
- Add a field
customer: str = "unknown"toTicketand print the response again. - Ask about B22 and read the status the ticket gets.
- Print
result["structured_response"].model_dump()to get a plain dictionary.
Every expert started right here.