Outlines: Structured Generation dari LLM dengan Constrained Decoding

# 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 val...

By Ruby Abdullah · · tutorial
OutlinesLLMStructured GenerationConstrained DecodingPython

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":

  • LLM menghasilkan output bebas
  • Output di-parse dan divalidasi
  • Jika gagal, prompt diperbaiki dan LLM dipanggil ulang
  • Ulangi sampai output valid atau batas retry tercapai
  • Masalahnya: biaya API meningkat, latensi tidak dapat diprediksi, dan tidak ada jaminan konvergensi.

    Pendekatan Constrained Decoding (Outlines)

    Outlines menggunakan pendekatan yang fundamentally berbeda:

  • Sebelum generasi, Outlines membangun finite-state machine (FSM) atau regular expression automaton dari schema yang diinginkan
  • Pada setiap langkah token generation, Outlines menghitung token mana saja yang valid berdasarkan state saat ini
  • Probabilitas token yang tidak valid diset ke nol (masked)
  • LLM hanya bisa memilih dari token yang valid
  • 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)

    Artikel Terkait

    Tutorial SGLang: Serving LLM Cepat dan Pemrograman Structured Generation

    SGLang: Serving LLM yang Cepat dan Model Pemrograman untuk Generasi Terstruktur SGLang adalah dua hal dalam satu paket: ...

    Tutorial TRL: Post-Training LLM dengan SFT, DPO, dan Reward Modeling

    Post-Training LLM dengan TRL: SFT, Reward Modeling, dan DPO Setelah sebuah base language model selesai dipretraining, mo...

    Tutorial Axolotl: Fine-Tuning LLM Berbasis Konfigurasi YAML

    Fine-Tuning LLM Berbasis Konfigurasi dengan Axolotl Kebanyakan proyek fine-tuning dimulai dengan cara yang sama: seseora...

    Tutorial PydanticAI: Framework Agent LLM yang Type-Safe

    Membangun Agen LLM yang Type-Safe dengan PydanticAI PydanticAI adalah framework agen dari tim di balik Pydantic, diranca...