Course Content
LangGraph Agents
7 sections · 49 lessons
How do you implement structured tool outputs and robust parsing in a graph workflow?
What you need to know
Into the tool
1from typing import Literal2from pydantic import BaseModel, Field3from langchain.tools import tool45class RefundArgs(BaseModel):6 order_id: str = Field(pattern=r"^OD-\d{5,}$", description="Order id like OD-88123")7 amount_inr: int = Field(gt=0, le=100_000)8 reason: Literal["damaged", "not_delivered", "wrong_item", "other"]910@tool(args_schema=RefundArgs)11def issue_refund(order_id: str, amount_inr: int, reason: str) -> dict:12 """Issue a refund for a delivered order. Needs human approval above Rs 5,000."""13 return {"refund_id": "RF-" + order_id[3:], "status": "queued", "amount_inr": amount_inr}The docstring and field descriptions become what the model reads. Pattern and range checks run before the function body.
Out of the tool
- Return a dict or a list of dicts with stable keys.
- Keep what the model needs short; put the full result in state if other nodes need it.
- A tool can return
Command(update={...})to write typed state directly, including aToolMessagefor its call.
Final structured answer
1class Decision(BaseModel):2 decision: Literal["refund", "replace", "reject"]3 amount_inr: int4 reason: str56agent = create_agent("anthropic:claude-sonnet-4-5", tools=[...], response_format=Decision)7result = agent.invoke({"messages": [...]})8result["structured_response"] # a Decision objectresponse_format uses the provider's native structured output when supported, or a tool-call strategy otherwise (ProviderStrategy, ToolStrategy).
Repair on failure
On a ValidationError, write the error and the bad output to state and route to a repair node that shows both to the model. Two attempts, then a fallback such as a human queue.
Size control
A tool returning 500 rows into messages fills the context window. Summarise, paginate, or return the top N plus a count.
A real-life example
A logistics company's agent answered "where is my parcel?" by calling a tracking API that returned 4 KB of raw scan events. The model sometimes read an old "Out for delivery" line as current. The team changed the tool to return {"status": "IN_TRANSIT", "last_scan": "Nagpur hub", "eta": "2026-09-26"} and put the full event list in state for a support dashboard. Wrong-status answers fell from 7% to under 1%, and each turn used 1,100 fewer tokens.
Follow-up questions to expect
- "What if the model keeps producing invalid arguments?" — Improve field descriptions and examples first; then cap retries and fall back. Constant invalid calls usually mean the schema is confusing.
- "JSON mode or structured output?" — Structured output with a schema. JSON mode guarantees valid JSON, not your fields.
- "Where do you validate business rules like 'refund less than order value'?" — In the tool or a policy node with access to the order, since the schema alone does not know the order.