구조화 출력(Structured Outputs)
구조화 출력(Structured Outputs)
모델의 응답을 항상 같은 형태로 받고 싶을 때가 있어요. 예를 들어 구조화된 데이터를 추출하거나, 이미지를 설명하거나, 매번 일정한 형식으로 답변을 유지해야 하는 경우죠. 구조화 출력은 모델 응답에 JSON 스키마를 강제해서 이런 일을 가능하게 해 줍니다.
출처: 공식문서
참고: Ollama Cloud는 현재 구조화 출력을 지원하지 않습니다.
구조화된 JSON 생성하기
format에 "json"을 넘기면 모델이 JSON 형태로 응답하도록 지시합니다.
cURL:
curl -X POST http://localhost:11434/api/chat -H "Content-Type: application/json" -d '{
"model": "gpt-oss",
"messages": [{"role": "user", "content": "Tell me about Canada in one line"}],
"stream": false,
"format": "json"
}'
Python:
from ollama import chat
response = chat(
model='gpt-oss',
messages=[{'role': 'user', 'content': 'Tell me about Canada.'}],
format='json'
)
print(response.message.content)
JavaScript:
import ollama from 'ollama'
const response = await ollama.chat({
model: 'gpt-oss',
messages: [{ role: 'user', content: 'Tell me about Canada.' }],
format: 'json'
})
console.log(response.message.content)
JSON 스키마로 구조화 출력하기
format 필드에 JSON 스키마를 직접 제공하면 더 정밀하게 제어할 수 있어요.
스키마를 문자열로 프롬프트에도 함께 넣어 주면 모델 응답을 더 잘 고정(grounding)할 수 있어요.
cURL:
curl -X POST http://localhost:11434/api/chat -H "Content-Type: application/json" -d '{
"model": "gpt-oss",
"messages": [{"role": "user", "content": "Tell me about Canada."}],
"stream": false,
"format": {
"type": "object",
"properties": {
"name": {"type": "string"},
"capital": {"type": "string"},
"languages": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["name", "capital", "languages"]
}
}'
Python에서는 Pydantic 모델을 정의하고 model_json_schema()를 format에 넘긴 뒤, 응답을 검증할 수 있어요.
from ollama import chat
from pydantic import BaseModel
class Country(BaseModel):
name: str
capital: str
languages: list[str]
response = chat(
model='gpt-oss',
messages=[{'role': 'user', 'content': 'Tell me about Canada.'}],
format=Country.model_json_schema(),
)
country = Country.model_validate_json(response.message.content)
print(country)
JavaScript에서는 Zod 스키마를 z.toJSONSchema()로 직렬화해 넘기고, 구조화된 응답을 파싱합니다.
import ollama from 'ollama'
import * as z from 'zod'
const Country = z.object({
name: z.string(),
capital: z.string(),
languages: z.array(z.string()),
})
const response = await ollama.chat({
model: 'gpt-oss',
messages: [{ role: 'user', content: 'Tell me about Canada.' }],
format: z.toJSONSchema(Country),
})
const country = Country.parse(JSON.parse(response.message.content))
console.log(country)
예시: 구조화된 데이터 추출
반환받고 싶은 객체를 정의하고 모델이 필드를 채우게 하면 됩니다.
from ollama import chat
from pydantic import BaseModel
class Pet(BaseModel):
name: str
animal: str
age: int
color: str | None
favorite_toy: str | None
class PetList(BaseModel):
pets: list[Pet]
response = chat(
model='gpt-oss',
messages=[{'role': 'user', 'content': 'I have two cats named Luna and Loki...'}],
format=PetList.model_json_schema(),
)
pets = PetList.model_validate_json(response.message.content)
print(pets)
예시: 구조화 출력과 비전
비전 모델도 동일한 format 파라미터를 받기 때문에, 이미지에 대한 결정적인(고정된 형태의) 설명을 받을 수 있어요.
from ollama import chat
from pydantic import BaseModel
from typing import Literal, Optional
class Object(BaseModel):
name: str
confidence: float
attributes: str
class ImageDescription(BaseModel):
summary: str
objects: list[Object]
scene: str
colors: list[str]
time_of_day: Literal['Morning', 'Afternoon', 'Evening', 'Night']
setting: Literal['Indoor', 'Outdoor', 'Unknown']
text_content: Optional[str] = None
response = chat(
model='gemma4',
messages=[{
'role': 'user',
'content': 'Describe this photo and list the objects you detect.',
'images': ['path/to/image.jpg'],
}],
format=ImageDescription.model_json_schema(),
options={'temperature': 0},
)
image_description = ImageDescription.model_validate_json(response.message.content)
print(image_description)
안정적인 구조화 출력을 위한 팁
- 스키마를 Python의 Pydantic 또는 JavaScript의 Zod로 정의하면 재사용과 검증이 쉬워져요.
- 더 결정적인 결과를 원하면 temperature를 낮추세요(예:
0). - 구조화 출력은 OpenAI 호환 API에서
response_format으로도 동작합니다.
더 알아보기 (Learn more)
- OpenAI compatibility —
response_format으로 구조화 출력 쓰기 - Vision — 이미지 설명과 구조화 출력