top of page
Writer's pictureDwain Barnes

Bringing Structure to LLM's with Ollama’s Structured Outputs




If you've ever worked with LLM models, you know how frustrating it can be when the output is inconsistent or difficult to work with. Whether you're parsing data from documents, building APIs, or extracting information from images, the lack of structure can slow you down or even derail a project. That’s where Ollama’s Structured Outputs come in, and trust me, it’s a game-changer.


 

What Are Structured Outputs?

Structured outputs let you constrain an AI model’s response to fit a specific format using a JSON schema. Instead of getting unpredictable free-form text, you get structured, reliable, and ready-to-use data. Think of it like giving the AI a set of blueprints to follow.

Here’s what makes structured outputs so exciting:

  • Consistency: Every response is formatted the same way, so you don’t need to clean or parse the data afterward.

  • Flexibility: You can define exactly what fields you need—strings, numbers, arrays, or even nested objects.

  • Usefulness: It’s perfect for real-world applications like extracting structured information from unstructured text or analysing images.


 

How Does It Work?

With Ollama, you define a schema, feed it to the model, and get structured responses in return. Here’s how it looks in practice.

Example 1: Extracting Country Information

Say you want details about a country, like its name, capital, and languages. You’d define a JSON schema like this:

{
  "type": "object",
  "properties": {
    "name": { "type": "string" },
    "capital": { "type": "string" },
    "languages": { "type": "array", "items": { "type": "string" } }
  },
  "required": ["name", "capital", "languages"]
}

Then, you’d pass it to the model:

from ollama import chat
from pydantic import BaseModel

class Country(BaseModel):
    name: str
    capital: str
    languages: list[str]

response = chat(
    messages=[{"role": "user", "content": "Tell me about Canada."}],
    model="llama3.1",
    format=Country.model_json_schema()
)

country = Country.model_validate_json(response.message.content)
print(country)

And just like that, the model returns this:

{
  "name": "Canada",
  "capital": "Ottawa",
  "languages": ["English", "French"]
}

No more wrangling with messy outputs—just clean, structured data.


 

Real-World Use Cases

Ollama’s structured outputs are perfect for a wide range of applications. Here are a few examples:

  1. Data Parsing from Text: Imagine parsing resumes to extract a candidate's name, skills, and education in a structured format.

  2. Image Analysis: Analyse an image to detect objects, colours, and even text in a structured way.

  3. Conversational Interfaces: Build chatbots that always return actionable, structured responses for APIs or databases.

  4. APIs: Ensure consistent responses in APIs powered by AI.


 

My Example: A Car Management System

Let me give you an example of how I used Ollama’s structured outputs in a project. I built a simple Car Management System that lets users add cars by entering descriptions or uploading images.

Adding Cars by Description

The system takes input like this:

"A red Tesla Model 3 registration number RF22 HTG."

Using Ollama, I extract structured data like this:


@app.route('/cars', methods=['POST', 'OPTIONS'])
@handle_errors
def add_car():
    """Add a new car using natural language description"""
    if request.method == 'OPTIONS':
        return '', 204
    
    data = request.json
    description = data.get('description', '')
    
    response = ollama.chat(
        messages=[{
            'role': 'user',
            'content': f'''Extract car information from this text.
            Pay special attention to UK registration plates which indicate the car's year.
            Format is XX## XXX where ## indicates year:
            - First half of year: March to August - number is the year (e.g., 22 = 2022)
            - Second half of year: September to February - number is year plus 50 (e.g., 72 = 2022)
            Include:
            - Make and model
            - Registration number if mentioned
            - Color
            - Body type
            - Features
            
            Text: {description}'''
        }],
        model='llama3.2:3B',
        format=Car.model_json_schema()
    )
    
    car_data = json.loads(response.message.content)
    
    # If plate number is provided, get the year
    if 'plate_number' in car_data:
        year = get_year_from_plate_number(car_data['plate_number'])
        if year:
            car_data['year'] = year
    
    car = Car(**car_data)
    car_database.append(car.model_dump())
    
    return jsonify(car.model_dump()), 201

And here’s the structured output:

{
  "make": "Tesla",
  "model": "Model 3",
  "year": 2022,
  "color": "red",
  "plate_number": "RF22 HTG"
}

Analysing Cars from Images

The system also lets users upload images of cars. Using Ollama’s vision model, I extract details like the make, model, and color of the car, as well as its condition and registration plate.

def analyze_cars_in_image(image_path: str) -> CarList:
    response = ollama.chat(
        messages=[
            {
                'role': 'user',
                'content': '''Analyze this image and identify all vehicles present. For each car:
                - Make and model
                - Registration plate number if visible (format: XX## XXX)
                - Color
                - Body type (sedan, SUV, truck, etc.)
                - Visible condition
                - Notable features (sunroof, spoiler, rims, etc.)
                - Any visible modifications
                Pay special attention to the registration plate format.
                Return the complete plate number if visible.''',
                'images': [image_path],
            }
      
        ],
        model='llama3.2-vision:11b-instruct-fp16',
        format=CarList.model_json_schema(),
        options={'temperature': 0}
    )
    
    cars_data = CarList.model_validate_json(response.message.content)
    
    # Process each car to determine year from plate
    processed_cars = []
    for car in cars_data.cars:
        if hasattr(car, 'plate_number') and car.plate_number:
            year = get_year_from_plate_number(car.plate_number)
            if year:
                car.year = year
        processed_cars.append(car)
    
    return CarList(cars=processed_cars)

Structured outputs make it so easy to plug this data directly into the system without any extra work.


I also built a web based front end. To see the full code visit my GitHub





 

Why I Love Ollama’s Structured Outputs

Honestly, the biggest draw for me is how much time it saves. I don’t have to write complex post-processing logic to clean or format the data I just define the schema, and the AI takes care of the rest. Whether I’m working on a small hobby project or something more complex, structured outputs make the entire workflow smoother and more reliable.

 

Getting Started

If you’re as excited as I am about structured outputs, here’s how you can get started:

  1. Install Ollama:

pip install ollama
  • Define Your Schema: Use Pydantic (Python) or Zod (JavaScript) to define the response format.

  • Integrate into Your App: Pass the schema to Ollama and let it handle the rest.


 

Final Thoughts

Ollama’s structured outputs are one of those features that make you wonder how you ever worked without them. Whether you’re building APIs, analysing images, or creating conversational AI, this tool ensures your outputs are consistent, reliable, and ready to use.

If you’re still parsing messy AI responses manually, it’s time to level up with structured outputs. Your future self will thank you.

19 views0 comments

Comentários


bottom of page