Keluaran Terstruktur dengan Pydantic
Definisikan model Pydantic sebagai skema keluaran Anda, teruskan model tersebut ke API melalui fitur keluaran terstruktur yang baru, dan deserialisasikan respons secara otomatis menjadi objek Python bertipe.
Keluaran Terstruktur dengan Pydantic adalah pelajaran AI Engineering Academy gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar AI Engineering Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus AI Engineering Academy mencakup 4 pelajaran total.
Mengapa Pydantic untuk Keluaran LLM?
Pydantic adalah pustaka validasi data Python yang mendefinisikan skema data menggunakan petunjuk tipe Python. Pydantic unggul dalam memvalidasi dan melakukan deserialisasi data dari sumber eksternal — dan keluaran LLM adalah salah satu sumber eksternal paling tidak andal yang akan Anda temui. Menggabungkan skema Pydantic dengan keluaran terstruktur OpenAI memberikan respons yang aman tipe, tervalidasi, dan dideserialisasi secara otomatis dari model AI.
Alih-alih menulis data = json.loads(response) lalu mengekstrak bidang dan melakukan konversi tipe secara manual, Anda mendapatkan objek Python bertipe lengkap yang setiap bidangnya dijamin memiliki tipe yang benar, lengkap dengan pelengkapan otomatis di IDE dan validasi saat runtime. Beginilah cara tim rekayasa AI profesional menangani ekstraksi terstruktur.
Mendefinisikan Skema Pydantic Dasar
Model Pydantic adalah kelas yang mewarisi BaseModel dengan bidang yang didefinisikan menggunakan anotasi tipe Python. Tipe bidang dapat berupa tipe primitif Python, model Pydantic lain untuk struktur bertingkat, atau tipe dari modul typing untuk daftar, tipe opsional, dan gabungan.
from pydantic import BaseModel, Field
from typing import Optional, List
from enum import Enum
class Sentiment(str, Enum):
positive = 'positive'
negative = 'negative'
neutral = 'neutral'
class ReviewAnalysis(BaseModel):
sentiment: Sentiment
confidence: float = Field(ge=0.0, le=1.0, description='Confidence score 0-1')
key_themes: List[str] = Field(description='Main topics mentioned in the review')
summary: str = Field(max_length=200, description='One-sentence summary')
product_name: Optional[str] = Field(default=None, description='Product mentioned, if any')
would_recommend: Optional[bool] = None
# Pydantic validates types and constraints at instantiation
example = ReviewAnalysis(
sentiment=Sentiment.positive,
confidence=0.95,
key_themes=['fast delivery', 'good quality'],
summary='Customer loves the product and quick shipping.',
product_name='Wireless Headphones',
would_recommend=True
)
print(example.model_dump_json(indent=2))Pydantic dengan Keluaran Terstruktur OpenAI
Berikan kelas model Pydantic Anda secara langsung ke parameter response_format dari client.beta.chat.completions.parse(). SDK secara otomatis mengonversi model tersebut menjadi JSON Schema, mengirimkannya ke API, dan melakukan deserialisasi terhadap respons kembali menjadi objek Python bertipe.
import openai
from pydantic import BaseModel
from typing import List, Optional
from enum import Enum
client = openai.OpenAI()
class Sentiment(str, Enum):
positive = 'positive'
negative = 'negative'
neutral = 'neutral'
class ReviewAnalysis(BaseModel):
sentiment: Sentiment
confidence: float
key_themes: List[str]
summary: str
would_recommend: Optional[bool]
review_text = '''
I bought this laptop for my design work and I am blown away. It handles Photoshop
like a dream, the screen colors are beautiful, and it has not slowed down once in
three months. Battery life could be better but overall highly recommend!
'''
result = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Analyze the customer review and extract structured information.'},
{'role': 'user', 'content': review_text}
],
response_format=ReviewAnalysis
)
analysis = result.choices[0].message.parsed
print(f'Sentiment: {analysis.sentiment.value}')
print(f'Confidence: {analysis.confidence}')
print(f'Themes: {analysis.key_themes}')
print(f'Recommend: {analysis.would_recommend}')Model Pydantic Bertingkat
Skema Pydantic dapat merujuk pada model Pydantic lain, sehingga memungkinkan keluaran terstruktur bertingkat dengan tingkat kedalaman apa pun. Ini ideal untuk mengekstrak data hierarkis dari dokumen seperti kontrak, faktur, resume, dan rekam medis.
from pydantic import BaseModel
from typing import List, Optional
class Address(BaseModel):
street: Optional[str]
city: str
country: str
postal_code: Optional[str]
class ContactInfo(BaseModel):
email: Optional[str]
phone: Optional[str]
address: Optional[Address]
class Person(BaseModel):
full_name: str
age: Optional[int]
job_title: Optional[str]
contact: ContactInfo
skills: List[str]
# When you pass Person to response_format, the API generates:
# {
# "full_name": "...",
# "contact": {
# "email": "...",
# "address": { "city": "...", "country": "..." }
# },
# "skills": ["...", "..."]
# }
print('Nested model defined - pass to response_format for extraction')Validasi Bidang dengan Validator Pydantic
Validator Pydantic memungkinkan Anda menambahkan logika validasi khusus di luar pemeriksaan tipe sederhana. Anda dapat memvalidasi bahwa skor keyakinan berada di antara 0 dan 1, bahwa harga tidak negatif, atau bahwa string tanggal memiliki format yang benar. Saat LLM mengembalikan nilai yang gagal divalidasi, Pydantic memunculkan ValidationError yang dapat Anda tangkap dan tangani.
from pydantic import BaseModel, Field, field_validator
from typing import Optional
import re
class ExtractedContact(BaseModel):
name: str
email: Optional[str] = None
phone: Optional[str] = None
confidence: float = Field(ge=0.0, le=1.0)
@field_validator('email')
@classmethod
def validate_email(cls, v):
if v is not None:
# Basic email format check
if not re.match(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$', v):
raise ValueError(f'Invalid email format: {v}')
return v
@field_validator('phone')
@classmethod
def normalize_phone(cls, v):
if v is not None:
# Remove non-digit characters for normalization
digits = re.sub(r'[^0-9+]', '', v)
return digits
return v
try:
contact = ExtractedContact(name='Alice', email='not-an-email', confidence=0.9)
except Exception as e:
print(f'Validation error: {e}')Mengekstrak Daftar Objek
Pola yang umum adalah mengekstrak beberapa instans entitas yang sama dari sebuah dokumen — semua item baris dari faktur, semua item tindakan dari transkrip rapat, atau semua entitas dari artikel berita. Bungkus model Anda dalam model wadah dengan bidang daftar untuk menangani kasus ini dengan rapi.
import openai
from pydantic import BaseModel
from typing import List
client = openai.OpenAI()
class ActionItem(BaseModel):
task: str
assignee: str
due_date: str # or use datetime with proper parsing
priority: str # high / medium / low
class MeetingNotes(BaseModel):
meeting_title: str
action_items: List[ActionItem]
key_decisions: List[str]
meeting_transcript = '''
Q3 Planning Meeting - June 2025
Decision: Launch new feature in July.
Decision: Extend free trial to 30 days.
Action: Alice to finalize designs by June 30th - High priority.
Action: Bob to write API docs by July 5th - Medium priority.
Action: Carol to set up staging environment by June 28th - High priority.
'''
result = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Extract structured data from meeting notes.'},
{'role': 'user', 'content': meeting_transcript}
],
response_format=MeetingNotes
)
notes = result.choices[0].message.parsed
for item in notes.action_items:
print(f'[{item.priority.upper()}] {item.task} -> {item.assignee} by {item.due_date}')Bidang Opsional dan Nilai Bawaan
Dokumen dunia nyata tidak selalu lengkap. Resume mungkin tidak mencantumkan nomor telepon; faktur mungkin tidak memiliki nomor faktur; ulasan produk mungkin tidak menyebutkan nama produk. Rancang model Pydantic Anda agar dapat menangani data yang hilang dengan baik menggunakan bidang Optional dengan nilai bawaan yang sesuai.
Bidang yang dianotasi sebagai Optional[str] = None memberi tahu Pydantic dan LLM bahwa bidang tersebut boleh tidak ada. Model akan mengembalikan null dalam JSON untuk bidang yang tidak dapat diekstraknya, dan Pydantic akan melakukan deserialisasi menjadi None milik Python, sehingga Anda dapat menanganinya dengan rapi pada tahap berikutnya tanpa pengecualian KeyError.
Mengonversi Model Pydantic menjadi JSON Schema
Model Pydantic yang Anda definisikan secara otomatis dikonversi menjadi JSON Schema saat diteruskan ke API. Anda dapat memeriksa skema ini untuk memahami secara tepat apa yang akan diberlakukan oleh API, yang berguna untuk men-debug kasus ketika model tidak mengembalikan struktur yang Anda harapkan.
from pydantic import BaseModel, Field
from typing import List, Optional
import json
class ProductExtraction(BaseModel):
name: str = Field(description='Product name as mentioned in the text')
price_usd: Optional[float] = Field(default=None, description='Price in USD')
features: List[str] = Field(default_factory=list)
in_stock: bool = Field(description='Whether the product is currently available')
# See the JSON Schema that will be sent to the API
schema = ProductExtraction.model_json_schema()
print(json.dumps(schema, indent=2))
# This shows exactly what constraints the API will enforceMenangani Kegagalan Ekstraksi
Bahkan dengan keluaran terstruktur, ekstraksi dapat gagal dalam dua cara: model menolak merespons (mengembalikan penolakan), atau dokumen memang tidak memuat informasi yang diminta sehingga model mengembalikan null untuk bidang yang diperlukan — yang memicu kesalahan validasi Pydantic karena bidang yang diperlukan tidak boleh bernilai null.
Pendekatan paling aman adalah menjadikan semua bidang Optional dengan nilai bawaan, menerima nilai null untuk data yang hilang, dan menerapkan validasi logika bisnis Anda sendiri setelah ekstraksi. Hal ini memisahkan perhatian ekstraksi (mengambil data dari teks) dari perhatian validasi (memeriksa bahwa data memenuhi persyaratan Anda).
import openai
from pydantic import BaseModel, ValidationError
from typing import Optional
client = openai.OpenAI()
class ContactExtraction(BaseModel):
name: Optional[str] = None
email: Optional[str] = None
phone: Optional[str] = None
try:
result = client.beta.chat.completions.parse(
model='gpt-4o-mini',
messages=[
{'role': 'system', 'content': 'Extract contact information.'},
{'role': 'user', 'content': 'I would like to discuss partnership opportunities.'}
],
response_format=ContactExtraction
)
msg = result.choices[0].message
if msg.refusal:
print('Refused:', msg.refusal)
else:
contact = msg.parsed
if not any([contact.name, contact.email, contact.phone]):
print('No contact information found in text')
else:
print(contact.model_dump())
except ValidationError as e:
print('Validation failed:', e)Menggunakan Pustaka instructor dengan Pydantic
Pustaka instructor adalah paket pihak ketiga populer yang menambal klien OpenAI untuk mendukung ekstraksi berbasis Pydantic dengan percobaan ulang otomatis saat validasi gagal. Jika model mengembalikan keluaran yang gagal dalam validasi Pydantic Anda, instructor secara otomatis mencoba lagi dengan perintah yang menyertakan kesalahan validasi, sehingga model memiliki kesempatan untuk memperbaiki dirinya sendiri.
Ini sangat berguna dalam pipeline ekstraksi massal ketika Anda tidak dapat meninjau setiap hasil secara manual dan ingin sistem memperbaiki dirinya sendiri tanpa campur tangan manusia.
# pip install instructor
import instructor
import openai
from pydantic import BaseModel, Field
from typing import Optional
# Patch the OpenAI client with instructor
client = instructor.from_openai(openai.OpenAI())
class ProductInfo(BaseModel):
name: str
price_usd: float = Field(gt=0, description='Price must be positive')
brand: Optional[str] = None
# instructor automatically retries if Pydantic validation fails
product = client.chat.completions.create(
model='gpt-4o-mini',
messages=[
{'role': 'user', 'content': 'The Sony WH-1000XM5 headphones cost $279.99 at Best Buy.'}
],
response_model=ProductInfo, # instructor-specific parameter
max_retries=3
)
print(f'{product.name}: ${product.price_usd} by {product.brand}')Gabungan Terbedakan dan Skema Dinamis
Pydantic mendukung gabungan terbedakan — skema yang strukturnya bergantung pada nilai bidang pembeda. Ini berguna ketika berbagai tipe dokumen memiliki dasar yang sama tetapi bidang tambahan yang berbeda. Sebagai contoh, laporan pengeluaran mungkin memiliki tanda terima penerbangan (dengan keberangkatan/kedatangan) atau tanda terima hotel (dengan tanggal check-in/check-out).
Dengan menggunakan tipe Union bersama bidang pembeda Literal, Anda dapat mendefinisikan satu skema ekstraksi yang menangani berbagai varian dokumen, dengan model memilih subtipe yang benar berdasarkan isi dokumen. Pydantic secara otomatis memvalidasi terhadap subtipe yang benar berdasarkan nilai pembeda.
from pydantic import BaseModel
from typing import Union, Literal, Optional
class FlightExpense(BaseModel):
expense_type: Literal['flight']
airline: str
departure_city: str
arrival_city: str
amount_usd: float
class HotelExpense(BaseModel):
expense_type: Literal['hotel']
hotel_name: str
check_in: str
check_out: str
amount_usd: float
class MealExpense(BaseModel):
expense_type: Literal['meal']
restaurant: Optional[str]
amount_usd: float
class ExpenseReport(BaseModel):
submitter: str
expenses: list[Union[FlightExpense, HotelExpense, MealExpense]]
total_usd: float
print('Discriminated union schema - model selects correct subtype per item')Pemeriksaan Singkat
Uji pemahaman Anda tentang konsep Rekayasa AI dari pelajaran ini.
Ringkasan Pelajaran
Dalam pelajaran ini Anda mempelajari bahwa: subkelas Pydantic BaseModel mendefinisikan skema ekstraksi bertipe kuat yang diberlakukan oleh keluaran terstruktur OpenAI pada tingkat API, model bertingkat, bidang Optional, dan tipe List menangani struktur dokumen dunia nyata yang kompleks, dan pustaka instructor menambahkan percobaan ulang otomatis saat validasi gagal untuk pipeline ekstraksi massal yang tangguh. Selanjutnya, kita akan membangun pipeline ekstraksi informasi lengkap untuk sumber teks tidak terstruktur.
Pertanyaan yang Sering Diajukan
Apakah pelajaran “Keluaran Terstruktur dengan Pydantic” gratis?
Ya — teks lengkap “Keluaran Terstruktur dengan Pydantic” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus AI Engineering Academy, upgrade ke CoddyKit PRO. Kursus AI Engineering Academy mencakup 4 pelajaran total.
Apa yang akan aku pelajari di “Keluaran Terstruktur dengan Pydantic”?
Definisikan model Pydantic sebagai skema keluaran Anda, teruskan model tersebut ke API melalui fitur keluaran terstruktur yang baru, dan deserialisasikan respons secara otomatis menjadi objek Python… Kamu berlatih AI Engineering Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.
Apakah aku perlu pengalaman untuk memulai AI Engineering Academy?
Tidak diperlukan pengalaman sebelumnya. AI Engineering Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.
Berapa lama pelajaran “Keluaran Terstruktur dengan Pydantic” memakan waktu?
Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.
Bisakah aku menulis dan menjalankan kode dalam pelajaran AI Engineering Academy ini?
Ya. Setiap pelajaran AI Engineering Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.
Semua pelajaran dalam kursus ini
- Mode JSON dan response_format
- Keluaran Terstruktur dengan Pydantic
- Mengekstrak Data dari Teks Tidak Terstruktur
- Memvalidasi dan Mencoba Ulang Keluaran yang Buruk