AI Hints
Home›NLP Tutorial›Large Language Models
NLP · Lesson 27 of 106

Structured Output

From words to data.

⏱ 2 min read▶ Video at 48:32🎓 Free
Watch this lesson in the NLP courseWatch on YouTube ↗Full NLP course

A paragraph is great for a person, but useless to a database. If Scribe is going to route tickets, it has to return exact fields, every single time. Good news. You can force a language model to reply in exactly the shape that you need.

Structured Output
From the video: Structured Output
  • Paragraphs don't fit databases
  • Exact fields, every time
  • Force the shape

Forcing a schema

We define the shape that we want, as a Pydantic class. A category, an urgency number, an order number, and a summary. We pass that to the model as a response schema. Run it. Look at that. Perfect JSON. It read a messy message, and filled in each field, with the order number, and a high urgency because of the birthday. This one trick turns a language model into a powerful extraction engine, with no training at all. A single call does the job of several of our earlier models.

structured.pypython
import json
from google import genai
from google.genai import types
from pydantic import BaseModel

class Ticket(BaseModel):
    category: str
    urgency: int
    order_number: str
    summary: str

client = genai.Client()
reply = client.models.generate_content(
    model="gemini-flash-latest",
    config=types.GenerateContentConfig(response_mime_type="application/json",
                                       response_schema=Ticket),
    contents="Classify this. Urgency 1 to 5. Message: Order #48213 still has "
             "not come and it was a birthday gift for tomorrow!")

print(json.dumps(json.loads(reply.text), indent=1))
Output
{
 "category": "Delivery Delay",
 "urgency": 5,
 "order_number": "48213",
 "summary": "Order not received and urgently needed for a birthday tomorrow."
}

What will this cost?

Language models charge by the token, so you need to count them. Here we use a tokeniser to see how text splits. Run it. Hello is short, but unbelievably takes several tokens. Next, a simple estimate. Two thousand tickets a day, at four hundred tokens each, gives a daily cost. Always do this sum before launch. It decides whether to use a big model, a small one, or the free classic tools from earlier in the course.

cost.pypython
import tiktoken

enc = tiktoken.get_encoding("cl100k_base")

for text in ["Hello!", "unbelievably", "Bright Books ships worldwide."]:
    ids = enc.encode(text)
    print(f"{len(ids):>2} tokens  {[enc.decode([i]) for i in ids]}")

tickets_per_day, tokens_each, price_per_million = 2000, 400, 0.30
daily = tickets_per_day * tokens_each / 1_000_000 * price_per_million
print(f"Estimated cost per day: ${daily:.2f}")
Output
 2 tokens  ['Hello', '!']
 3 tokens  ['un', 'belie', 'vably']
 5 tokens  ['Bright', ' Books', ' ships', ' worldwide', '.']
Estimated cost per day: $0.24

Stopping hallucinations

Language models will invent answers if they're allowed to. A simple rule helps a lot. Tell it to use only the text that you provide, and give it an exact way to say, I don't know. Here, the policy says nothing about gift wrapping. Run it. It refuses to make something up. That's a tiny example of the single most important pattern in modern NLP. Give the model the facts. Next, we'll build that properly.

grounded.pypython
from google import genai

client = genai.Client()

question = ("Using only the policy, answer the question. If the policy does "
            "not say, reply exactly: NOT IN POLICY.\n\n"
            "Policy: Returns are accepted within 30 days if unread.\n"
            "Question: Do you offer free gift wrapping?")

print(client.models.generate_content(model="gemini-flash-latest",
                                     contents=question).text.strip())
Output
NOT IN POLICY.

Summary

Force a schema for clean data, count your tokens, and ground answers in real text. That last idea is so important that it has a name. Next, we build the thing that most companies want from AI. RAG.

Key takeaways
  • response_schema forces JSON
  • Count tokens before launch
  • Give it a way to say I don't know
Next up: What Is RAG? — answering from your own documents