Tutorial Distilabel: Framework Generasi Data Sintetis untuk Fine-Tuning LLM
Dalam dunia pengembangan Large Language Model (LLM), kualitas data pelatihan merupakan faktor penentu keberhasilan model. Distilabel hadir sebagai framework open-source dari Argilla yang memungkinkan Anda membangun pipeline untuk menghasilkan data sintetis berkualitas tinggi, melakukan evaluasi model, dan menyiapkan dataset untuk fine-tuning. Tutorial ini akan membahas secara mendalam cara menggunakan Distilabel mulai dari instalasi hingga pembuatan pipeline produksi yang kompleks.
Apa Itu Distilabel?
Distilabel adalah framework Python yang dikembangkan oleh tim Argilla untuk membuat pipeline generasi data sintetis dan evaluasi LLM. Framework ini dirancang untuk mengatasi tantangan utama dalam pengembangan AI: mendapatkan data pelatihan berkualitas tinggi dalam jumlah besar tanpa biaya anotasi manual yang mahal.
Fitur utama Distilabel meliputi:
- Pipeline berbasis DAG: Arsitektur Directed Acyclic Graph yang memungkinkan pemrosesan data secara paralel dan efisien
- Multi-provider LLM: Dukungan untuk OpenAI, Anthropic, Google, Hugging Face, vLLM, Ollama, dan banyak lagi
- Teknik generasi canggih: Implementasi built-in untuk Self-Instruct, Evol-Instruct, UltraFeedback, Magpie, dan teknik lainnya
- Skalabilitas: Kemampuan menjalankan pipeline di kluster Ray untuk pemrosesan data skala besar
- Integrasi Argilla dan Hugging Face Hub: Ekspor data langsung ke Argilla untuk validasi manusia atau ke Hugging Face Hub
Instalasi
Prasyarat
Pastikan Anda memiliki Python 3.9 atau lebih baru terinstal di sistem Anda.
Instalasi Dasar
pip install distilabel
Instalasi dengan Provider Tertentu
Distilabel menggunakan sistem extras untuk menginstal dependensi provider LLM:
# Untuk menggunakan OpenAI
pip install "distilabel[openai]"
Untuk menggunakan Anthropic
pip install "distilabel[anthropic]"
Untuk menggunakan vLLM (lokal)
pip install "distilabel[vllm]"
Untuk menggunakan Hugging Face Inference Endpoints
pip install "distilabel[hf-inference-endpoints]"
Untuk menggunakan Ollama
pip install "distilabel[ollama]"
Instalasi lengkap semua provider
pip install "distilabel[openai,anthropic,vllm,ollama]"
Instalasi dengan Ray untuk Skalabilitas
pip install "distilabel[ray,openai]"
Verifikasi Instalasi
import distilabel
print(distilabel.version)
Konfigurasi API Key
Sebelum menggunakan provider LLM berbasis cloud, konfigurasikan API key:
export OPENAIAPIKEY="sk-your-api-key"
export ANTHROPICAPIKEY="your-anthropic-key"
export HFTOKEN="hfyour-token"
Penggunaan Dasar
Konsep Utama
Distilabel dibangun di atas tiga konsep utama:
Menjalankan LLM Sederhana
from distilabel.llms import OpenAILLM
llm = OpenAILLM(model="gpt-4o-mini")
llm.load()
result = llm.generateoutputs(
inputs=[
[
{"role": "user", "content": "Jelaskan apa itu machine learning dalam 2 kalimat."}
]
]
)
print(result[0][0])
Pipeline Pertama: Generasi Teks Sederhana
from distilabel.llms import OpenAILLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import TextGeneration
from distilabel.steps import LoadDataFromDicts
data = [
{"instruction": "Jelaskan konsep neural network untuk pemula."},
{"instruction": "Apa perbedaan antara supervised dan unsupervised learning?"},
{"instruction": "Bagaimana cara kerja gradient descent?"},
]
with Pipeline(name="tutorial-dasar") as pipeline:
loaddata = LoadDataFromDicts(data=data)
textgen = TextGeneration(
llm=OpenAILLM(model="gpt-4o-mini"),
numgenerations=1,
)
loaddata >> textgen
distiset = pipeline.run()
df = distiset["default"]["train"].topandas()
print(df[["instruction", "generation"]].tostring())
Menggunakan Multiple LLM
Salah satu kekuatan Distilabel adalah kemampuan menggunakan beberapa LLM dalam satu pipeline:
from distilabel.llms import OpenAILLM, AnthropicLLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import TextGeneration
from distilabel.steps import LoadDataFromDicts, CombineOutputs
data = [
{"instruction": "Apa itu transfer learning?"},
{"instruction": "Jelaskan konsep attention mechanism."},
]
with Pipeline(name="multi-llm") as pipeline:
loaddata = LoadDataFromDicts(data=data)
genopenai = TextGeneration(
name="genopenai",
llm=OpenAILLM(model="gpt-4o-mini"),
numgenerations=1,
outputmappings={"generation": "generationopenai"},
)
genanthropic = TextGeneration(
name="genanthropic",
llm=AnthropicLLM(model="claude-sonnet-4-6"),
numgenerations=1,
outputmappings={"generation": "generationanthropic"},
)
combine = CombineOutputs()
loaddata >> [genopenai, genanthropic] >> combine
distiset = pipeline.run()
Penggunaan Lanjutan
Self-Instruct: Generasi Dataset Instruksi
Self-Instruct adalah teknik yang memungkinkan LLM menghasilkan instruksi pelatihan baru berdasarkan seed instructions. Ini sangat berguna untuk memperluas dataset fine-tuning:
from distilabel.llms import OpenAILLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import SelfInstruct
from distilabel.steps import LoadDataFromDicts
seeddata = [
{
"input": "Kamu adalah asisten AI yang ahli dalam data science dan machine learning. "
"Tugasmu adalah membantu pengguna memahami konsep-konsep teknis dengan cara yang mudah dipahami."
}
]
with Pipeline(name="self-instruct-pipeline") as pipeline:
loaddata = LoadDataFromDicts(data=seeddata)
selfinstruct = SelfInstruct(
llm=OpenAILLM(model="gpt-4o-mini"),
numinstructions=5,
criteriaforquerygeneration=(
"Instruksi harus berkaitan dengan data science, machine learning, atau AI. "
"Instruksi harus bervariasi dalam tingkat kesulitan. "
"Instruksi harus praktis dan bisa dijawab secara konkret."
),
)
loaddata >> selfinstruct
distiset = pipeline.run()
df = distiset["default"]["train"].topandas()
for idx, row in df.iterrows():
print(f"\nInstruksi yang dihasilkan:")
for instruction in row["instructions"]:
print(f" - {instruction}")
Evol-Instruct: Evolusi Instruksi
Evol-Instruct adalah teknik dari paper WizardLM yang mengembangkan instruksi sederhana menjadi lebih kompleks dan menantang:
from distilabel.llms import OpenAILLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import EvolInstruct
from distilabel.steps import LoadDataFromDicts
data = [
{"instruction": "Hitung rata-rata dari sebuah list."},
{"instruction": "Buat fungsi untuk sorting."},
{"instruction": "Jelaskan apa itu API."},
]
with Pipeline(name="evol-instruct-pipeline") as pipeline:
loaddata = LoadDataFromDicts(data=data)
evolinstruct = EvolInstruct(
llm=OpenAILLM(model="gpt-4o-mini"),
numevolutions=3,
storeevolutions=True,
includeoriginalinstruction=True,
)
loaddata >> evolinstruct
distiset = pipeline.run()
df = distiset["default"]["train"].topandas()
for idx, row in df.iterrows():
print(f"\nOriginal: {row['instruction']}")
print(f"Evolved: {row['evolvedinstruction']}")
UltraFeedback: Evaluasi dan Scoring Respons
UltraFeedback memungkinkan Anda mengevaluasi kualitas respons dari berbagai model, yang berguna untuk membuat dataset preference untuk RLHF/DPO:
from distilabel.llms import OpenAILLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import TextGeneration, UltraFeedback
from distilabel.steps import LoadDataFromDicts, CombineOutputs, FormatTextGenerationDPO
data = [
{"instruction": "Jelaskan perbedaan antara list dan tuple di Python."},
{"instruction": "Bagaimana cara mengoptimasi query SQL yang lambat?"},
]
with Pipeline(name="ultrafeedback-pipeline") as pipeline:
loaddata = LoadDataFromDicts(data=data)
gen1 = TextGeneration(
name="genmodela",
llm=OpenAILLM(model="gpt-4o-mini"),
outputmappings={"generation": "generationa"},
)
gen2 = TextGeneration(
name="genmodelb",
llm=OpenAILLM(model="gpt-4o"),
outputmappings={"generation": "generationb"},
)
combine = CombineOutputs()
feedback = UltraFeedback(
llm=OpenAILLM(model="gpt-4o"),
aspect="overall-quality",
)
formatdpo = FormatTextGenerationDPO()
loaddata >> [gen1, gen2] >> combine >> feedback >> formatdpo
distiset = pipeline.run()
Magpie: Generasi Data Percakapan dari Pre-trained LLM
Magpie adalah teknik yang mengekstrak kemampuan instruction-following dari LLM yang sudah di-align untuk menghasilkan pasangan instruksi-respons berkualitas:
from distilabel.llms import OpenAILLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import Magpie
with Pipeline(name="magpie-pipeline") as pipeline:
magpie = Magpie(
llm=OpenAILLM(model="gpt-4o-mini"),
nturns=1,
numrows=20,
systemprompt=(
"Kamu adalah asisten AI yang ahli dalam pemrograman Python. "
"Berikan jawaban yang detail dengan contoh kode."
),
)
distiset = pipeline.run()
df = distiset["default"]["train"].topandas()
for idx, row in df.iterrows():
print(f"\n{'='*60}")
print(f"Instruksi: {row['instruction'][:100]}...")
print(f"Respons: {row['generation'][:100]}...")
Membuat Custom Task
Anda dapat membuat task kustom untuk kebutuhan spesifik:
from typing import Any
from distilabel.steps.tasks import Task
from distilabel.steps.tasks.typing import ChatType
class CodeReviewTask(Task):
systemprompt: str = (
"Kamu adalah senior code reviewer yang berpengalaman. "
"Review kode berikut dan berikan feedback konstruktif."
)
@property
def inputs(self) -> list[str]:
return ["code"]
@property
def outputs(self) -> list[str]:
return ["review", "score", "suggestions"]
def formatinput(self, input: dict[str, Any]) -> ChatType:
return [
{"role": "system", "content": self.systemprompt},
{
"role": "user",
"content": (
f"Review kode berikut:\n\n
python\n{input['code']}\n``\n\n"
"Berikan output dalam format:\n"
"REVIEW: [review detail]\n"
"SCORE: [1-10]\n"
"SUGGESTIONS: [saran perbaikan]"
),
},
]
def formatoutput(
self, output: str | None, input: dict[str, Any] | None = None
) -> dict[str, Any]:
if output is None:
return {"review": None, "score": None, "suggestions": None}
parts = output.split("\n")
review = ""
score = ""
suggestions = ""
for part in parts:
if part.startswith("REVIEW:"):
review = part.replace("REVIEW:", "").strip()
elif part.startswith("SCORE:"):
score = part.replace("SCORE:", "").strip()
elif part.startswith("SUGGESTIONS:"):
suggestions = part.replace("SUGGESTIONS:", "").strip()
return {"review": review, "score": score, "suggestions": suggestions}
Structured Generation dengan JSON Schema
Distilabel mendukung generasi terstruktur menggunakan JSON schema:
python
from distilabel.llms import OpenAILLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import TextGeneration
from distilabel.steps import LoadDataFromDicts
structuredllm = OpenAILLM(
model="gpt-4o-mini",
structuredoutput={
"format": "json",
"schema": {
"type": "object",
"properties": {
"topic": {"type": "string", "description": "Topik utama"},
"difficulty": {
"type": "string",
"enum": ["beginner", "intermediate", "advanced"],
},
"keyconcepts": {
"type": "array",
"items": {"type": "string"},
"description": "Konsep-konsep kunci",
},
"explanation": {
"type": "string",
"description": "Penjelasan detail",
},
},
"required": ["topic", "difficulty", "keyconcepts", "explanation"],
},
},
)
data = [
{"instruction": "Jelaskan tentang Retrieval-Augmented Generation (RAG)."},
{"instruction": "Apa itu Model Quantization dalam konteks LLM?"},
]
with Pipeline(name="structured-output") as pipeline:
loaddata = LoadDataFromDicts(data=data)
textgen = TextGeneration(
llm=structuredllm,
numgenerations=1,
)
loaddata >> textgen
distiset = pipeline.run()
Pipeline dengan Caching dan Checkpoint
Distilabel secara otomatis menyimpan cache untuk menghindari pemrosesan ulang:
python
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import TextGeneration
from distilabel.steps import LoadDataFromDicts
from distilabel.llms import OpenAILLM
with Pipeline(
name="cached-pipeline",
cachedir="./pipelinecache",
) as pipeline:
loaddata = LoadDataFromDicts(
data=[{"instruction": f"Buat fakta menarik tentang angka {i}"} for i in range(100)]
)
textgen = TextGeneration(
llm=OpenAILLM(model="gpt-4o-mini"),
numgenerations=1,
inputbatchsize=10,
)
loaddata >> textgen
distiset = pipeline.run()
print(f"Total data: {len(distiset['default']['train'])}")
Ekspor ke Hugging Face Hub dan Argilla
python
distiset = pipeline.run()
Push ke Hugging Face Hub
distiset.pushtohub(
repoid="username/my-synthetic-dataset",
private=True,
token="hfyourtoken",
)
Atau push ke Argilla untuk validasi manusia
import argilla as rg
client = rg.Argilla(apiurl="http://localhost:6900", apikey="your-key")
dataset = rg.Dataset(
name="synthetic-review",
workspace="default",
settings=rg.Settings(
fields=[
rg.TextField(name="instruction"),
rg.TextField(name="generation"),
],
questions=[
rg.RatingQuestion(name="quality", values=[1, 2, 3, 4, 5]),
rg.TextQuestion(name="feedback"),
],
),
)
dataset.create()
records = [
rg.Record(
fields={
"instruction": row["instruction"],
"generation": row["generation"],
}
)
for , row in df.iterrows()
]
dataset.records.log(records)
Best Practices
1. Desain Pipeline yang Modular
Pisahkan setiap tahap pemrosesan ke dalam step yang berbeda. Ini memudahkan debugging, reuse, dan testing:
python
with Pipeline(name="modular-pipeline") as pipeline:
loaddata = LoadDataFromDicts(data=data)
generate = TextGeneration(llm=llm, name="generate")
evaluate = UltraFeedback(llm=judgellm, name="evaluate")
formatoutput = FormatTextGenerationDPO(name="format")
loaddata >> generate >> evaluate >> formatoutput
2. Gunakan Batch Size yang Tepat
Sesuaikan
inputbatchsize dengan kapasitas API dan kebutuhan memori:
python
textgen = TextGeneration(
llm=OpenAILLM(model="gpt-4o-mini"),
inputbatchsize=50,
)
Untuk dataset besar, gunakan batch size yang lebih kecil untuk menghindari rate limiting. Untuk dataset kecil, batch size yang lebih besar meningkatkan throughput.
3. Implementasikan Error Handling
Gunakan parameter
retries dan tangani kegagalan dengan baik:
python
llm = OpenAILLM(
model="gpt-4o-mini",
maxretries=3,
timeout=120,
)
4. Validasi Kualitas Data
Selalu validasi output sebelum menggunakan untuk fine-tuning:
python
import json
df = distiset["default"]["train"].topandas()
Filter respons kosong
dfclean = df[df["generation"].notna() & (df["generation"] != "")]
Filter berdasarkan panjang minimum
dfclean = dfclean[dfclean["generation"].str.len() > 50]
Simpan dataset yang sudah dibersihkan
print(f"Data valid: {len(dfclean)} dari {len(df)} total")
5. Gunakan System Prompt yang Spesifik
System prompt yang detail menghasilkan data yang lebih konsisten dan berkualitas:
python
textgen = TextGeneration(
llm=llm,
systemprompt=(
"Kamu adalah instruktur machine learning berpengalaman dengan keahlian "
"dalam Python, TensorFlow, dan PyTorch. Jawab pertanyaan dengan detail, "
"sertakan contoh kode yang bisa langsung dijalankan, dan jelaskan setiap "
"langkah dengan bahasa yang mudah dipahami oleh pemula."
),
)
6. Diversifikasi Sumber Data
Gabungkan beberapa teknik untuk dataset yang lebih kaya:
python
with Pipeline(name="diverse-pipeline") as pipeline:
loadseeds = LoadDataFromDicts(data=seeddata)
selfinstruct = SelfInstruct(
name="expand",
llm=llm,
numinstructions=10,
)
evolinstruct = EvolInstruct(
name="evolve",
llm=llm,
numevolutions=2,
)
generate = TextGeneration(
name="answer",
llm=llm,
)
loadseeds >> selfinstruct >> evolinstruct >> generate
7. Monitor Penggunaan Token
Pantau konsumsi token untuk mengontrol biaya:
python
distiset = pipeline.run()
Periksa statistik pipeline
print(f"Pipeline selesai")
print(f"Total baris diproses: {len(distiset['default']['train'])}")
8. Gunakan LLM Lokal untuk Iterasi Cepat
Saat mengembangkan pipeline, gunakan model lokal via Ollama untuk menghemat biaya:
python
from distilabel.llms import OllamaLLM
devllm = OllamaLLM(model="llama3.2")
prodllm = OpenAILLM(model="gpt-4o")
llm = devllm # Ganti ke prodllm saat siap produksi
``
Kesimpulan
Distilabel adalah framework yang sangat powerful untuk membangun pipeline generasi data sintetis dan evaluasi LLM. Dengan arsitektur berbasis pipeline yang fleksibel, dukungan multi-provider, dan implementasi teknik-teknik canggih seperti Self-Instruct, Evol-Instruct, dan UltraFeedback, Distilabel mempermudah proses pembuatan dataset berkualitas tinggi untuk fine-tuning model.
Poin-poin penting yang perlu diingat:
- Mulai dari yang sederhana: Buat pipeline dasar terlebih dahulu, lalu tambahkan kompleksitas secara bertahap
- Validasi selalu: Jangan pernah menggunakan data sintetis tanpa validasi kualitas
- Iterasi dengan model lokal: Gunakan Ollama atau vLLM untuk pengembangan, lalu beralih ke API produksi
- Manfaatkan integrasi: Gunakan Argilla untuk human-in-the-loop validation dan Hugging Face Hub untuk berbagi dataset
- Perhatikan biaya: Monitor penggunaan token dan gunakan caching untuk menghindari pemrosesan ulang
Dengan menggabungkan Distilabel ke dalam workflow pengembangan AI Anda, Anda dapat secara signifikan mengurangi biaya dan waktu yang dibutuhkan untuk menyiapkan data pelatihan berkualitas tinggi, sambil tetap mempertahankan kontrol penuh atas proses generasi data.