Begränsa LLMs med strukturerad utdata: Ollama, Qwen3 & Python eller Go
Några sätt att få strukturerad utdata från Ollama
Stora språkmodeller (LLMs) är kraftfulla, men i produktion vill vi sällan ha fritt formulerade stycken. Istället vill vi ha förutsägbart data: attribut, fakta eller strukturerade objekt som du kan mata in i en app. Det är LLM Strukturerad Utdata.
Nyligen introducerade Ollama stöd för strukturerad utdata (annons), vilket gör det möjligt att begränsa en modells svar till att matcha ett JSON-schema. Detta låser upp konsekventa datautdragningspipelines för uppgifter som att katalogisera LLM-funktioner, benchmarka modeller eller automatisera systemintegrering.

I det här inlägget kommer vi att täcka:
- Vad strukturerad utdata är och varför det är viktigt
- En enkel metod för att få strukturerad utdata från LLMs
- Hur Ollamas nya funktion fungerar
- Exempel på att extrahera LLM-funktioner:
Vad är Strukturerad Utdata?
Normalt genererar LLMs fri text:
“Modell X stöder resonemang med chain-of-thought, har ett kontextfönster på 200K tokens och talar engelska, kinesiska och spanska.”
Det är läsbart, men svårt att tolka.
Istället, med strukturerad utdata, frågar vi efter ett strikt schema:
{
"name": "Modell X",
"supports_thinking": true,
"max_context_tokens": 200000,
"languages": ["Engelska", "Kinesiska", "Spanska"]
}
Den här JSON-en är enkel att validera, lagra i en databas eller mata in i ett gränssnitt.
Enkel metod för att få Strukturerad Utdata från LLM
LLM:ar förstår ibland vad schemat är och vi kan be LLM att returnera utdata i JSON med ett visst schema. Qwen3-modellen från Alibaba är optimerad för resonemang och strukturerade svar. Du kan explicit instruera den att svara i JSON.
Exempel 1: Använda Qwen3 med ollama i Python, begärande JSON med schema
import json
import ollama
prompt = """
Du är en extraherare av strukturerad data.
Returnera endast JSON.
Text: "Elon Musk är 53 år och bor i Austin."
Schema: { "name": string, "age": int, "city": string }
"""
response = ollama.chat(model="qwen3", messages=[{"role": "user", "content": prompt}])
output = response['message']['content']
# Tolka JSON
try:
data = json.loads(output)
print(data)
except Exception as e:
print("Fel vid tolkningsförsök av JSON:", e)
Utdata:
{"name": "Elon Musk", "age": 53, "city": "Austin"}
Tvinga Schema-validering med Pydantic
För att undvika felaktiga utdata kan du validera mot ett Pydantic-schema i Python.
from pydantic import BaseModel
class Person(BaseModel):
name: str
age: int
city: str
# Antag att 'output' är JSON-strängen från Qwen3
data = Person.model_validate_json(output)
print(data.name, data.age, data.city)
Det här säkerställer att utdata följer den förväntade strukturen.
Ollamas Strukturerade Utdata
Ollama låter nu dig skicka med ett schema i parametern format. Modellen begränsas då till att svara endast i JSON som följer schemat (dokumentation).
I Python definierar du vanligtvis ditt schema med Pydantic och låter Ollama använda det som ett JSON-schema.
Exempel 2: Extrahera LLM-funktionsmetadata
Antag att du har en text som beskriver en LLM:s förmågor:
“Qwen3 har stark flerspråkig stöd (engelska, kinesiska, franska, spanska, arabiska). Den tillåter resonemangssteg (chain-of-thought). Kontextfönstret är 128K tokens.”
Du vill ha strukturerad data:
from pydantic import BaseModel
from typing import List
from ollama import chat
class LLMFeatures(BaseModel):
name: str
supports_thinking: bool
max_context_tokens: int
languages: List[str]
prompt = """
Analysera följande beskrivning och returnera modellens funktioner i JSON endast.
Modellbeskrivning:
'Qwen3 har stark flerspråkig stöd (engelska, kinesiska, franska, spanska, arabiska).
Den tillåter resonemangssteg (chain-of-thought).
Kontextfönstret är 128K tokens.'
"""
resp = chat(
model="qwen3",
messages=[{"role": "user", "content": prompt}],
format=LLMFeatures.model_json_schema(),
options={"temperature": 0},
)
print(resp.message.content)
Möjlig utdata:
{
"name": "Qwen3",
"supports_thinking": true,
"max_context_tokens": 128000,
"languages": ["Engelska", "Kinesiska", "Franska", "Spanska", "Arabiska"]
}
Exempel 3: Jämföra flera modeller
Mata in beskrivningar av flera modeller och extrahera i strukturerad form:
from typing import List
class ModelComparison(BaseModel):
models: List[LLMFeatures]
prompt = """
Extrahera funktioner för varje modell till JSON.
1. Llama 3.1 stöder resonemang. Kontextfönster är 128K. Språk: endast engelska.
2. GPT-4 Turbo stöder resonemang. Kontextfönster är 128K. Språk: engelska, japanska.
3. Qwen3 stöder resonemang. Kontextfönster är 128K. Språk: engelska, kinesiska, franska, spanska, arabiska.
"""
resp = chat(
model="qwen3",
messages=[{"role": "user", "content": prompt}],
format=ModelComparison.model_json_schema(),
options={"temperature": 0},
)
print(resp.message.content)
Utdata:
{
"models": [
{
"name": "Llama 3.1",
"supports_thinking": true,
"max_context_tokens": 128000,
"languages": ["Engelska"]
},
{
"name": "GPT-4 Turbo",
"supports_thinking": true,
"max_context_tokens": 128000,
"languages": ["Engelska", "Japanska"]
},
{
"name": "Qwen3",
"supports_thinking": true,
"max_context_tokens": 128000,
"languages": ["Engelska", "Kinesiska", "Franska", "Spanska", "Arabiska"]
}
]
}
Det här gör det trivialt att benchmarka, visualisera eller filtrera modeller efter deras funktioner.
Exempel 4: Detektera luckor automatiskt
Du kan tillåta null-värden när ett fält saknas:
from typing import Optional
class FlexibleLLMFeatures(BaseModel):
name: str
supports_thinking: Optional[bool]
max_context_tokens: Optional[int]
languages: Optional[List[str]]
Det här säkerställer att ditt schema förblir giltigt även om viss information saknas.
Fördelar, begränsningar & bästa praxis
Att använda strukturerad utdata genom Ollama (eller något annat system som stöder det) erbjuder många fördelar - men har också några begränsningar.
Fördelar
- Starkare garantier: Modellen begärs att följa ett JSON-schema istället för fri text.
- Enklare tolkningsförsök: Du kan direkt
json.loadseller validera med Pydantic/Zod, istället för regex eller heuristisk metod. - Schema-baserad utveckling: Du kan versionera ditt schema, lägga till fält (med standardvärden) och bibehålla bakåtkompatibilitet.
- Interoperabilitet: Nedströmsystem förväntar sig strukturerad data.
- Determinism (bättre med låg temperatur): När temperaturen är låg (t.ex. 0), är modellen mer benägen att strikt följa schemat. Ollamas dokumentation rekommenderar detta.
Begränsningar & fallgropar
- Schema-inkompatibilitet: Modellen kan fortfarande avvika - t.ex. missa ett obligatoriskt fält, byta ordning på nycklar eller inkludera extra fält. Du behöver validering.
- Komplexa scheman: Mycket djupa eller rekursiva JSON-scheman kan förvirra modellen eller leda till fel.
- Tvetydighet i prompt: Om din prompt är vag kan modellen gissa fält eller enheter felaktigt.
- Inkonsekvens mellan modeller: Vissa modeller kan vara bättre eller sämre på att följa strukturerade begränsningar.
- Tokenbegränsningar: Schemat i sig lägger till tokenkostnad till prompten eller API-anropet.
Bästa praxis & tips (hämtade från Ollamas blogg + erfarenhet)
- Använd Pydantic (Python) eller Zod (JavaScript) för att definiera dina scheman och automatiskt generera JSON-scheman. Detta undviker manuella fel.
- Inkludera alltid instruktioner som “svara endast i JSON” eller “inkludera inte kommentarer eller extra text” i din prompt.
- Använd temperature = 0 (eller mycket låg) för att minimera slumpmässighet och maximera schemaöverensstämmelse. Ollama rekommenderar determinism.
- Validera och eventuellt återförsök (t.ex. återförsök eller rensa upp) när JSON-tolkningsförsök misslyckas eller schemavalidering misslyckas.
- Börja med ett enklare schema, sedan utöka gradvis. Överkomplicera inte från början.
- Inkludera hjälpsamma men begränsade felinstruktioner: t.ex. om modellen inte kan fylla ett obligatoriskt fält, svara med
nullistället för att utelämna det (om ditt schema tillåter det).
Go Exempel 1: Extrahera LLM-funktioner
Här är ett enkelt Go-program som frågar Qwen3 om strukturerad utdata om en LLM:s funktioner.
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/ollama/ollama/api"
)
type LLMFeatures struct {
Name string `json:"name"`
SupportsThinking bool `json:"supports_thinking"`
MaxContextTokens int `json:"max_context_tokens"`
Languages []string `json:"languages"`
}
func main() {
client, err := api.ClientFromEnvironment()
if err != nil {
log.Fatal(err)
}
prompt := `
Analysera följande beskrivning och returnera modellens funktioner i JSON endast.
Beskrivning:
"Qwen3 har stark flerspråkig stöd (engelska, kinesiska, franska, spanska, arabiska).
Den tillåter resonemangssteg (chain-of-thought).
Kontextfönstret är 128K tokens."
`
// Definiera JSON-schemat för strukturerad utdata
formatSchema := map[string]any{
"type": "object",
"properties": map[string]any{
"name": map[string]string{
"type": "string",
},
"supports_thinking": map[string]string{
"type": "boolean",
},
"max_context_tokens": map[string]string{
"type": "integer",
},
"languages": map[string]any{
"type": "array",
"items": map[string]string{
"type": "string",
},
},
},
"required": []string{"name", "supports_thinking", "max_context_tokens", "languages"},
}
// Konvertera schema till JSON
formatJSON, err := json.Marshal(formatSchema)
if err != nil {
log.Fatal("Misslyckades med att marshala format-schema:", err)
}
req := &api.GenerateRequest{
Model: "qwen3:8b",
Prompt: prompt,
Format: formatJSON,
Options: map[string]any{"temperature": 0},
}
var features LLMFeatures
var rawResponse string
err = client.Generate(context.Background(), req, func(response api.GenerateResponse) error {
// Ackumulera innehåll medan det strömmar
rawResponse += response.Response
// Tolka endast när svaret är komplett
if response.Done {
if err := json.Unmarshal([]byte(rawResponse), &features); err != nil {
return fmt.Errorf("JSON-tolkningsfel: %v", err)
}
}
return nil
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Tolkat struct: %+v\n", features)
}
För att kompilera och köra det här Go-programmet - antag att vi har den här main.go-filen i en mapp ollama-struct,
Vi måste köra följande kommandon i den här mappen:
# initialisera modul
go mod init ollama-struct
# hämta alla beroenden
go mod tidy
# bygg & kör
go build -o ollama-struct main.go
./ollama-struct
Exempel på utdata
Tolkat struct: {Name:Qwen3 SupportsThinking:true MaxContextTokens:128000 Languages:[Engelska Kinesiska Franska Spanska Arabiska]}
Go Exempel 2: Jämföra Flera Modeller
Du kan utöka detta för att extrahera en lista med modeller för jämförelse.
type ModelComparison struct {
Models []LLMFeatures `json:"models"`
}
prompt = `
Extrahera funktioner från följande modellbeskrivningar och returnera som JSON:
1. PaLM 2: Denna modell har begränsade resonemangsförmågor och fokuserar på grundläggande språkförståelse. Den stöder ett kontextfönster på 8,000 tokens. Den stöder primärt endast engelska.
2. LLaMA 2: Denna modell har måttliga resonemangsförmågor och kan hantera vissa logiska uppgifter. Den kan bearbeta upp till 4,000 tokens i sitt kontextfönster. Den stöder engelska, spanska och italienska.
3. Codex: Denna modell har starka resonemangsförmågor specifikt för programmering och kodanalys. Den har ett kontextfönster på 16,000 tokens. Den stöder engelska, Python, JavaScript och Java.
Returnera ett JSON-objekt med en "models"-array som innehåller alla modeller.
`
// Definiera JSON-schemat för modelljämförelse
comparisonSchema := map[string]any{
"type": "object",
"properties": map[string]any{
"models": map[string]any{
"type": "array",
"items": map[string]any{
"type": "object",
"properties": map[string]any{
"name": map[string]string{
"type": "string",
},
"supports_thinking": map[string]string{
"type": "boolean",
},
"max_context_tokens": map[string]string{
"type": "integer",
},
"languages": map[string]any{
"type": "array",
"items": map[string]string{
"type": "string",
},
},
},
"required": []string{"name", "supports_thinking", "max_context_tokens", "languages"},
},
},
},
"required": []string{"models"},
}
// Konvertera schema till JSON
comparisonFormatJSON, err := json.Marshal(comparisonSchema)
if err != nil {
log.Fatal("Misslyckades med att marshala jämförelseschema:", err)
}
req = &api.GenerateRequest{
Model: "qwen3:8b",
Prompt: prompt,
Format: comparisonFormatJSON,
Options: map[string]any{"temperature": 0},
}
var comp ModelComparison
var comparisonResponse string
err = client.Generate(context.Background(), req, func(response api.GenerateResponse) error {
// Ackumulera innehåll medan det strömmar
comparisonResponse += response.Response
// Parsa endast när svaret är komplett
if response.Done {
if err := json.Unmarshal([]byte(comparisonResponse), &comp); err != nil {
return fmt.Errorf("JSON-parsningsfel: %v", err)
}
}
return nil
})
if err != nil {
log.Fatal(err)
}
for _, m := range comp.Models {
fmt.Printf("%s: Kontext=%d, Språk=%v\n", m.Name, m.MaxContextTokens, m.Languages)
}
Exempel på utdata
PaLM 2: Kontext=8000, Språk=[English]
LLaMA 2: Kontext=4000, Språk=[English Spanish Italian]
Codex: Kontext=16000, Språk=[English Python JavaScript Java]
Av någon anledning fungerar qwen3:4b bra på dessa exempel, precis som qwen3:8b.
Bästa Praktiker för Go-Utvecklare
- Använd temperatur 0 för maximal schemakompatibilitet.
- Validera med
json.Unmarshaloch fallback om parsning misslyckas. - Håll scheman enkla - djupnästade eller rekursiva JSON-strukturer kan orsaka problem.
- Tillåt valfria fält (använd
omitemptyi Go-struktureringsmärken) om du förväntar dig saknade data. - Lägg till återförsök om modellen ibland genererar ogiltig JSON.
Fullständigt exempel - Rita en Graf med LLM-Specifikationer (Steg-för-steg: från strukturerad JSON till jämförelsetabeller)

- Definiera ett schema för de data du vill ha
Använd Pydantic så att du både (a) kan generera ett JSON-schema för Ollama och (b) validera modellens svar.
from pydantic import BaseModel
from typing import List, Optional
class LLMFeatures(BaseModel):
name: str
supports_thinking: bool
max_context_tokens: int
languages: List[str]
- Be Ollama att returnera endast JSON i den formen
Skicka schemat i format= och sänk temperaturen för determinism.
from ollama import chat
prompt = """
Extrahera funktioner för varje modell. Returnera endast JSON som matchar schemat.
1) Qwen3 stöder chain-of-thought; 128K kontext; Engelska, Kinesiska, Franska, Spanska, Arabiska.
2) Llama 3.1 stöder chain-of-thought; 128K kontext; Engelska.
3) GPT-4 Turbo stöder chain-of-thought; 128K kontext; Engelska, Japanska.
"""
resp = chat(
model="qwen3",
messages=[{"role": "user", "content": prompt}],
format={"type": "array", "items": LLMFeatures.model_json_schema()},
options={"temperature": 0}
)
raw_json = resp.message.content # JSON-lista med LLMFeatures
- Validera & normalisera
Alltid validera innan du använder i produktion.
from pydantic import TypeAdapter
adapter = TypeAdapter(list[LLMFeatures])
models = adapter.validate_json(raw_json) # -> list[LLMFeatures]
- Bygg en jämförelsetabell (pandas)
Omvandla dina validerade objekt till en DataFrame som du kan sortera/filtera och exportera.
import pandas as pd
df = pd.DataFrame([m.model_dump() for m in models])
df["languages_count"] = df["languages"].apply(len)
df["languages"] = df["languages"].apply(lambda xs: ", ".join(xs))
# Ordna om kolumner för läsbarhet
df = df[["name", "supports_thinking", "max_context_tokens", "languages_count", "languages"]]
# Spara som CSV för vidare användning
df.to_csv("llm_feature_comparison.csv", index=False)
- (Valfritt) Snabba visuella representationer
Enkla grafer hjälper dig att snabbt öga skillnader mellan modeller.
import matplotlib.pyplot as plt
plt.figure()
plt.bar(df["name"], df["max_context_tokens"])
plt.title("Max Kontextfönster per Modell (tokens)")
plt.xlabel("Modell")
plt.ylabel("Max Kontext Tokens")
plt.xticks(rotation=20, ha="right")
plt.tight_layout()
plt.savefig("max_context_window.png")
TL;DR
Med Ollamas nya strukturerade utdata-stöd kan du behandla LLMs inte bara som chattbotar utan som dataextraktionsmotorer.
Exemplen ovan visade hur man automatiskt extraherar strukturerad metadata om LLM-funktioner som resonemangsförmåga, kontextfönsterstorlek och stödda språk - uppgifter som annars skulle kräva bräckliga parsningsmetoder.
Oavsett om du bygger en LLM-modellkatalog, en utvärderingsdashboard eller en AI-drivet forskningsassistent, gör strukturerade utdata integrationen smidig, tillförlitlig och produktionsklar.
Användbara länkar
- https://ollama.com/blog/structured-outputs
- Ollama cheatsheet
- Python Cheatsheet
- AWS SAM + AWS SQS + Python PowerTools
- Golang Cheatsheet
- Jämföra Go ORMs för PostgreSQL: GORM vs Ent vs Bun vs sqlc
- Omrankning av textdokument med Ollama och Qwen3 Embedding-modell - i Go
- AWS lambda-prestanda: JavaScript vs Python vs Golang