Outlines: Structured Generation dari LLM dengan Constrained Decoding
Salah satu tantangan terbesar saat bekerja dengan Large Language Models (LLM) adalah mendapatkan output yang terstruktur dan valid secara konsisten. Ketika Anda membutuhkan JSON yang valid, enum dari pilihan tertentu, atau format spesifik lainnya, LLM seringkali menghasilkan output yang tidak sesuai format. Outlines hadir untuk menyelesaikan masalah ini dengan pendekatan constrained decoding di level token, menjamin output selalu valid secara struktural.
Bagaimana Constrained Decoding Bekerja?
Sebelum membahas Outlines, penting untuk memahami perbedaan dua pendekatan structured generation:
Pendekatan Retry-Based (seperti Instructor)
Library seperti Instructor menggunakan pendekatan "generate-then-validate":
Masalahnya: biaya API meningkat, latensi tidak dapat diprediksi, dan tidak ada jaminan konvergensi.
Pendekatan Constrained Decoding (Outlines)
Outlines menggunakan pendekatan yang fundamentally berbeda:
Hasilnya: output dijamin valid 100% tanpa perlu retry, dengan overhead komputasi yang minimal.
Instalasi
Instalasi Outlines cukup straightforward:
pip install outlines
Untuk menggunakan dengan model transformers lokal:
pip install outlines[transformers]
Untuk integrasi dengan llama.cpp:
pip install outlines[llamacpp]
Untuk integrasi dengan vLLM:
pip install outlines[vllm]
JSON Generation dengan Pydantic Models
Fitur paling populer dari Outlines adalah kemampuan menghasilkan JSON yang valid berdasarkan Pydantic model.
Contoh Dasar
import outlines
from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
Definisikan schema dengan Pydantic
class Alamat(BaseModel):
jalan: str = Field(description="Nama jalan dan nomor")
kota: str = Field(description="Nama kota")
provinsi: str = Field(description="Nama provinsi")
kodepos: str = Field(description="Kode pos 5 digit")
class Karyawan(BaseModel):
nama: str = Field(description="Nama lengkap karyawan")
usia: int = Field(ge=18, le=65, description="Usia karyawan")
email: str = Field(description="Alamat email")
departemen: str = Field(description="Departemen kerja")
gaji: float = Field(gt=0, description="Gaji bulanan")
alamat: Alamat
keahlian: List[str] = Field(description="Daftar keahlian")
Load model
model = outlines.models.transformers("microsoft/Phi-3-mini-4k-instruct")
Buat generator dengan schema JSON
generator = outlines.generate.json(model, Karyawan)
Generate data terstruktur
prompt = """Buatkan data karyawan fiktif untuk perusahaan teknologi di Jakarta.
Karyawan ini adalah seorang senior data engineer."""
result = generator(prompt)
print(type(result)) #
print(result.nama)
print(result.departemen)
print(result.modeldumpjson(indent=2))
Nested dan Complex Schemas
from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
import outlines
class Prioritas(str, Enum):
TINGGI = "tinggi"
SEDANG = "sedang"
RENDAH = "rendah"
class Status(str, Enum):
TODO = "todo"
INPROGRESS = "inprogress"
REVIEW = "review"
DONE = "done"
class SubTugas(BaseModel):
judul: str
selesai: bool
class Tugas(BaseModel):
id: int
judul: str = Field(maxlength=100)
deskripsi: str
prioritas: Prioritas
status: Status
assignee: str
estimasijam: float = Field(gt=0)