LangChainLangChain 1.4 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
43 small wins to finish your pathNext lesson

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.

Exampleticket.py
from pydantic import BaseModel


class Ticket(BaseModel):
    """A support ticket for one order."""
    order_id: str
    status: str

Given 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.

What one model call carries, and what comes back
The requestThe replythe conversation so farsystem promptthe tools, from bind_toolsresponse_format, a schemaruntime context, hiddenThe chat modelyours, or a hosted onetext: the answertool_calls: run thesea call to the schema toolusage_metadata, tokens
Hover or tap a piece to see what it is and which lesson built it.
Follow one call

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.

Exampleticket_model.py
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

Exampleagent.py
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)
Example
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.

Try it yourself
  • Add a field customer: str = "unknown" to Ticket and 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.