← Semua pembelajaran / Python untuk AI Engineer
Fase 2 · Type Hints & Pydantic

Pydantic — JSON Schema

model_json_schema() mengubah model Pydantic jadi JSON Schema — format yang dipakai LLM untuk mendefinisikan tool.

Sumber asli pydantic.dev Resmi Rangkuman ~6 menit baca

Intisari

  • Model.model_json_schema() menghasilkan JSON Schema standar dari sebuah model Pydantic.
  • JSON Schema adalah satu-satunya bahasa yang dipakai LLM untuk memahami bentuk tool dan output terstruktur.
  • description pada field ikut masuk ke skema — dan LLM membacanya. Tulis dengan serius.
  • Literal menjadi enum di skema, sehingga model tahu persis nilai apa yang sah.
  • Baca halaman ini sebelum Fase 4. Ini titik di mana keterampilan Python-mu berubah jadi keterampilan GenAI.

Satu baris yang mengubah segalanya

from typing import Literal
from pydantic import BaseModel, Field

class CariTiket(BaseModel):
    status: Literal["open", "closed", "pending"] = Field(
        description="Status tiket yang dicari"
    )
    limit: int = Field(default=10, ge=1, le=100, description="Jumlah maksimal hasil")

print(CariTiket.model_json_schema())
{
  "type": "object",
  "title": "CariTiket",
  "properties": {
    "status": {
      "type": "string",
      "enum": ["open", "closed", "pending"],
      "description": "Status tiket yang dicari"
    },
    "limit": {
      "type": "integer",
      "default": 10,
      "minimum": 1,
      "maximum": 100,
      "description": "Jumlah maksimal hasil"
    }
  },
  "required": ["status"]
}

Inilah jembatannya. Kamu menulis Python biasa dengan type hint. Pydantic menerjemahkannya jadi JSON Schema. Dan JSON Schema adalah format yang dipahami LLM untuk mengetahui: tool apa yang tersedia, argumen apa yang diterimanya, dan nilai apa yang sah. Tanpa Fase 2, Fase 4 hanya jadi penyalinan kode tanpa pemahaman.

Di mana JSON Schema muncul

TempatPerannyaFase
Definisi tool LLMMemberitahu model bentuk argumen tool4
Structured outputMemaksa model membalas dengan bentuk tertentu4
OpenAPI FastAPIDokumentasi otomatis di /docs5
Bedrock Agents / ConverseDefinisi tool versi AWS4 & 7

Bagaimana tipe Python dipetakan

PythonJSON Schema
str{"type": "string"}
int{"type": "integer"}
float{"type": "number"}
bool{"type": "boolean"}
list[str]{"type": "array", "items": {"type": "string"}}
dict[str, int]{"type": "object", "additionalProperties": ...}
Literal["a","b"]{"enum": ["a", "b"]}
str | None{"anyOf": [{"type":"string"}, {"type":"null"}]}
Model bersarang$ref ke $defs
datetime{"type": "string", "format": "date-time"}

Menulis field agar LLM paham

Model bahasa membaca description untuk memutuskan cara mengisi argumen. Bandingkan:

# ❌ Model harus menebak
class Cari(BaseModel):
    q: str
    n: int = 10

# ✅ Model tahu persis apa yang diminta
class Cari(BaseModel):
    """Cari dokumen di basis pengetahuan internal perusahaan."""

    q: str = Field(
        description="Kata kunci pencarian dalam bahasa alami. "
                    "Contoh: 'kebijakan cuti tahunan'"
    )
    n: int = Field(
        default=10, ge=1, le=50,
        description="Jumlah dokumen yang dikembalikan. Gunakan 3-5 untuk "
                    "pertanyaan spesifik, 10+ untuk topik luas."
    )

Docstring class menjadi description tingkat skema — itulah penjelasan kapan tool ini dipakai. Field(description=...) menjelaskan apa tiap argumennya. Keduanya adalah prompt engineering, hanya saja letaknya di kode.

Batasan yang dipahami LLM

class Permintaan(BaseModel):
    status: Literal["open", "closed"]        # → enum: model tidak bisa mengarang nilai lain
    limit: int = Field(ge=1, le=100)         # → minimum/maximum
    email: str = Field(pattern=r"^\S+@\S+$") # → pattern
    tag: list[str] = Field(max_length=5)     # → maxItems

Literal adalah yang paling berdampak. Tanpa itu, model bisa mengarang nilai seperti "OPEN" atau "aktif" dan kodemu harus menanganinya. Dengan enum di skema, ruang kemungkinannya tertutup.

Structured output — arah sebaliknya

from pydantic import BaseModel

class Ekstraksi(BaseModel):
    nama: str
    email: str
    minat: list[str]

response = client.messages.parse(
    model="claude-opus-5",
    max_tokens=4096,
    messages=[{"role": "user", "content": "Ekstrak: Budi ([email protected]), tertarik API."}],
    output_format=Ekstraksi,
)

data = response.parsed_output      # instance Ekstraksi, sudah tervalidasi

Di balik layar: SDK memanggil Ekstraksi.model_json_schema(), mengirimkannya ke API sebagai batasan format keluaran, lalu memvalidasi balasan model terhadap model yang sama. Kamu menulis satu class, dan mendapat jaminan bentuk data dari ujung ke ujung.

Menyesuaikan skema

class Tiket(BaseModel):
    model_config = ConfigDict(
        json_schema_extra={
            "examples": [{"judul": "Server down", "prioritas": "high"}]
        }
    )
    judul: str
    prioritas: str
# Untuk keperluan API yang bedakan input dan output
Tiket.model_json_schema(mode="validation")   # skema untuk data masuk (default)
Tiket.model_json_schema(mode="serialization")  # skema untuk data keluar

Model bersarang dan $defs

class Alamat(BaseModel):
    kota: str

class Pengguna(BaseModel):
    nama: str
    alamat: Alamat
{
  "type": "object",
  "properties": {
    "nama": {"type": "string"},
    "alamat": {"$ref": "#/$defs/Alamat"}
  },
  "required": ["nama", "alamat"],
  "$defs": {
    "Alamat": {
      "type": "object",
      "properties": {"kota": {"type": "string"}},
      "required": ["kota"]
    }
  }
}

Perhatian untuk Fase 4: beberapa penyedia LLM membatasi kedalaman bersarang atau tidak mendukung $ref pada definisi tool. Untuk tool, jaga skemanya tetap datar — satu level field sederhana. Simpan struktur bersarang untuk model internal aplikasimu.

Yang tidak didukung di skema tool ketat

Beberapa batasan Pydantic tidak punya padanan di JSON Schema mode ketat:

Artinya: LLM tetap bisa mengirim argumen yang lolos skema tapi gagal validator Python-mu. Selalu jalankan model_validate() pada argumen tool sebelum memakainya — skema adalah panduan bagi model, bukan pengganti validasi.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.