Cara Membuat LLM dari Awal: Panduan Lengkap & Pembelajaran Penting

Ashley Innocent

Ashley Innocent

7 April 2026

Cara Membuat LLM dari Awal: Panduan Lengkap & Pembelajaran Penting

Apidog untuk Perusahaan

Penerapan On-Premises

SSO & RBAC

Sesuai SOC 2

Jelajahi Apidog Enterprise

Intisari

Membangun model bahasa minimal dari awal hanya membutuhkan kurang dari 300 baris kode Python. Proses ini mengungkap dengan tepat bagaimana tokenisasi, perhatian, dan inferensi bekerja, yang membuat Anda menjadi konsumen API yang jauh lebih baik saat mengintegrasikan LLM produksi ke dalam aplikasi Anda.

Pendahuluan

Sebagian besar pengembang memperlakukan model bahasa sebagai kotak hitam. Anda mengirim teks masuk, token keluar, dan di antara itu semua, keajaiban terjadi. Model mental itu berfungsi dengan baik sampai Anda perlu men-debug integrasi API yang rusak, menyetel parameter pengambilan sampel, atau mencari tahu mengapa model Anda terus berhalusinasi data terstruktur.

GuppyLM, sebuah proyek yang baru-baru ini mencapai halaman depan HackerNews dengan 842 poin, membuat internalnya terlihat. Ini adalah transformer berparameter 8.7M yang ditulis dari awal dalam Python. Model ini dilatih dalam waktu kurang dari satu jam pada GPU konsumen. Kodenya muat dalam satu file. Tujuannya bukan untuk bersaing dengan GPT-4; tujuannya adalah untuk mengungkap apa sebenarnya yang dilakukan LLM.

Artikel ini menjelaskan cara membangun LLM kecil, apa saja komponennya, dan apa yang diajarkan oleh pemahaman internal ketika Anda bekerja dengan API AI secara profesional.

💡
Jika Anda menguji integrasi API AI, Skenario Uji Apidog memungkinkan Anda memverifikasi respons streaming, menegaskan struktur token, dan mensimulasikan penyelesaian kasus ekstrem tanpa membakar kredit produksi. Lebih lanjut tentang itu nanti
tombol

Apa yang membuat model bahasa "kecil"?

LLM produksi seperti GPT-4 memiliki ratusan miliar parameter. LLM "kecil" berada dalam kisaran 1M hingga 25M parameter. Proyek seperti GuppyLM (8.7M), nanoGPT Karpathy (124M), dan MicroLM (1-2M) semuanya termasuk dalam kategori ini.

LLM kecil dapat: - Dilatih di laptop atau Google Colab - Muat sepenuhnya di memori CPU - Diinspeksi, dimodifikasi, dan di-debug pada tingkat bobot

Mereka tidak dapat: - Menangani penalaran yang kompleks - Menghasilkan teks panjang yang koheren dengan andal - Menyamai kedalaman faktual model produksi

Nilainya bukan pada outputnya. Nilainya adalah pemahaman yang Anda dapatkan dari membangunnya.

Komponen inti: bagaimana LLM sebenarnya bekerja

Sebelum menulis kode apa pun, Anda perlu tahu apa yang dilakukan keempat bagian utama ini.

Tokenisasi

Tokenizer mengubah teks mentah menjadi ID bilangan bulat. "Hello, world!" menjadi sesuatu seperti [15496, 11, 995, 0]. Setiap bilangan bulat memetakan ke unit subkata dari kosakata tetap.

Mengapa ini penting untuk pekerjaan API: jumlah token secara langsung memengaruhi latensi dan biaya. Memahami bagaimana tokenizer membagi teks membantu Anda menulis prompt yang sesuai dengan jendela konteks dan menghindari pemotongan yang tidak terduga.

GuppyLM menggunakan tokenizer tingkat karakter sederhana. Model produksi seperti GPT-4 menggunakan BPE (byte-pair encoding) dengan kosakata 50K-100K token.

Lapisan embedding

Lapisan embedding mengubah ID token menjadi vektor padat. Setiap token mendapatkan vektor yang dipelajari (misalnya 384 dimensi di GuppyLM). Vektor-vektor ini membawa makna semantik: token yang serupa akhirnya berdekatan di ruang vektor.

Embedding posisi ditambahkan di atasnya, sehingga model mengetahui urutan token.

Blok Transformer

Ini adalah komputasi inti. Setiap blok memiliki dua bagian:

Self-attention: memungkinkan setiap token melihat semua token lain dalam urutan dan memutuskan mana yang penting untuk memprediksi token berikutnya. GuppyLM menggunakan 6 kepala perhatian di 6 lapisan.

Jaringan feed-forward: MLP dua lapis diterapkan pada representasi setiap token setelah perhatian. GuppyLM menggunakan aktivasi ReLU, yang lebih sederhana daripada SwiGLU yang digunakan dalam arsitektur yang lebih baru.

Kepala output

Setelah blok transformer terakhir, lapisan linear memproyeksikan representasi setiap token ke vektor dengan ukuran yang sama dengan kosakata. Terapkan softmax untuk mendapatkan probabilitas, pilih token berikutnya yang paling mungkin (atau sampel), dan ulangi.

Membangun LLM minimal dalam Python

Berikut adalah LLM minimal yang berfungsi berdasarkan pendekatan GuppyLM. Ini berjalan di PyTorch standar.

import torch
import torch.nn as nn
import torch.nn.functional as F

# Hyperparameters
VOCAB_SIZE = 256     # character-level: one slot per ASCII char
D_MODEL = 128        # embedding dimension
N_HEADS = 4          # attention heads
N_LAYERS = 3         # transformer blocks
SEQ_LEN = 64         # context window
DROPOUT = 0.1

class SelfAttention(nn.Module):
    def __init__(self, d_model, n_heads):
        super().__init__()
        self.n_heads = n_heads
        self.head_dim = d_model // n_heads
        self.qkv = nn.Linear(d_model, 3 * d_model, bias=False)
        self.proj = nn.Linear(d_model, d_model, bias=False)
        self.dropout = nn.Dropout(DROPOUT)

    def forward(self, x):
        B, T, C = x.shape
        qkv = self.qkv(x).reshape(B, T, 3, self.n_heads, self.head_dim)
        q, k, v = qkv.unbind(dim=2)
        q = q.transpose(1, 2)
        k = k.transpose(1, 2)
        v = v.transpose(1, 2)
        # Causal mask: each token can only attend to previous tokens
        scale = self.head_dim ** -0.5
        attn = (q @ k.transpose(-2, -1)) * scale
        mask = torch.triu(torch.ones(T, T, device=x.device), diagonal=1).bool()
        attn = attn.masked_fill(mask, float('-inf'))
        attn = F.softmax(attn, dim=-1)
        attn = self.dropout(attn)
        out = (attn @ v).transpose(1, 2).reshape(B, T, C)
        return self.proj(out)

class TransformerBlock(nn.Module):
    def __init__(self, d_model, n_heads):
        super().__init__()
        self.attn = SelfAttention(d_model, n_heads)
        self.ff = nn.Sequential(
            nn.Linear(d_model, 4 * d_model),
            nn.ReLU(),
            nn.Linear(4 * d_model, d_model),
            nn.Dropout(DROPOUT),
        )
        self.ln1 = nn.LayerNorm(d_model)
        self.ln2 = nn.LayerNorm(d_model)

    def forward(self, x):
        x = x + self.attn(self.ln1(x))
        x = x + self.ff(self.ln2(x))
        return x

class TinyLLM(nn.Module):
    def __init__(self):
        super().__init__()
        self.embed = nn.Embedding(VOCAB_SIZE, D_MODEL)
        self.pos_embed = nn.Embedding(SEQ_LEN, D_MODEL)
        self.blocks = nn.ModuleList([
            TransformerBlock(D_MODEL, N_HEADS) for _ in range(N_LAYERS)
        ])
        self.ln_f = nn.LayerNorm(D_MODEL)
        self.head = nn.Linear(D_MODEL, VOCAB_SIZE, bias=False)

    def forward(self, idx):
        B, T = idx.shape
        tok_emb = self.embed(idx)
        pos = torch.arange(T, device=idx.device)
        pos_emb = self.pos_embed(pos)
        x = tok_emb + pos_emb
        for block in self.blocks:
            x = block(x)
        x = self.ln_f(x)
        logits = self.head(x)
        return logits

# Initialize and count parameters
model = TinyLLM()
total_params = sum(p.numel() for p in model.parameters())
print(f"Model size: {total_params:,} parameters")  # ~1.2M

Loop pelatihan

import torch.optim as optim

def train(model, data, epochs=100, lr=3e-4):
    optimizer = optim.AdamW(model.parameters(), lr=lr)
    model.train()
    for epoch in range(epochs):
        # data: tensor of token IDs, shape [batch, seq_len+1]
        x = data[:, :-1]   # input: all tokens except last
        y = data[:, 1:]    # target: all tokens shifted by 1
        logits = model(x)
        loss = F.cross_entropy(logits.reshape(-1, VOCAB_SIZE), y.reshape(-1))
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if epoch % 10 == 0:
            print(f"Epoch {epoch}, loss: {loss.item():.4f}")

Inferensi (pembuatan teks)

@torch.no_grad()
def generate(model, prompt_ids, max_new_tokens=50, temperature=1.0, top_k=10):
    model.eval()
    ids = torch.tensor([prompt_ids])
    for _ in range(max_new_tokens):
        idx_cond = ids[:, -SEQ_LEN:]  # crop to context window
        logits = model(idx_cond)
        logits = logits[:, -1, :] / temperature  # last token only
        # top-k sampling
        v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
        logits[logits < v[:, [-1]]] = float('-inf')
        probs = F.softmax(logits, dim=-1)
        next_id = torch.multinomial(probs, num_samples=1)
        ids = torch.cat([ids, next_id], dim=1)
    return ids[0].tolist()

Apa yang diajarkan ini tentang perilaku API AI

Membangun ini mengungkapkan beberapa hal yang membuat Anda menjadi konsumen API yang lebih baik.

Suhu dan pengambilan sampel bersifat mekanis, bukan magis

Suhu membagi logit sebelum softmax. Suhu yang lebih tinggi = distribusi yang lebih datar = output yang lebih acak. Suhu yang lebih rendah = distribusi yang lebih tajam = output yang lebih deterministik. Ketika API produksi Anda mengembalikan hasil yang tidak konsisten dengan temperature=0.0, itu bukan bug. Suhu nol yang sebenarnya adalah argmax serakah, dan banyak API sedikit menurunkannya untuk menghindari output yang merosot.

Jendela konteks adalah batasan keras, bukan saran lunak

Baris idx_cond = ids[:, -SEQ_LEN:] dalam loop inferensi menunjukkan dengan tepat apa yang terjadi pada batas konteks. Model secara diam-diam menghapus token yang lebih lama. Jika integrasi API Anda mengasumsikan model mengingat riwayat percakapan lengkap, itu tidak berlaku setelah titik tertentu. Lihat [internal: how-ai-agent-memory-works] untuk bagaimana agen menangani masalah ini.

Token streaming hanyalah langkah inferensi yang terlihat

API streaming tidak melakukan hal yang berbeda secara arsitektur. Mereka menjalankan loop inferensi dan mengirim setiap token ke aliran respons saat dihasilkan. Memahami ini membantu ketika Anda menulis logika percobaan ulang: aliran yang terputus di tengah generasi tidak dapat dilanjutkan, harus dimulai ulang.

Logit menjelaskan mengapa output terstruktur sulit

Model menetapkan probabilitas untuk setiap token dalam kosakata pada setiap langkah. Menghasilkan JSON yang valid membutuhkan token yang tepat untuk menang di setiap posisi. Pustaka seperti Outlines dan Guidance membatasi distribusi logit untuk menerapkan tata bahasa pada waktu inferensi. Ketika Anda melihat API AI menawarkan mode "output terstruktur", inilah yang mereka lakukan secara internal.

Cara menguji integrasi API AI dengan Apidog

Setelah Anda memahami cara kerja inferensi LLM, Anda dapat menulis pengujian API yang jauh lebih baik. Skenario Uji Apidog memungkinkan Anda merangkai panggilan API dan menegaskan struktur respons AI.

Misalnya, saat menguji API obrolan streaming:

  1. Buat Skenario Uji di Apidog dengan endpoint /v1/chat/completions Anda
  2. Atur pernyataan untuk memverifikasi struktur respons: response.choices[0].finish_reason == "stop", response.usage.total_tokens < 4096
  3. Tambahkan langkah lanjutan yang mengirim respons sebagai konteks ke giliran berikutnya, mensimulasikan percakapan multi-giliran
  4. Gunakan Smart Mock Apidog untuk menguji endpoint AI dan menguji penanganan kesalahan aplikasi Anda: simulasikan finish_reason: "length" (output terpotong), finish_reason: "content_filter", dan batas waktu jaringan di tengah aliran

Beginilah cara Anda menguji integrasi AI tanpa membakar kredit API pada setiap CI run. Lihat [internal: api-testing-tutorial] untuk melihat gambaran yang lebih luas tentang pendekatan pengujian API.

Menguji pernyataan jumlah token

{
  "assertions": [
    {
      "field": "response.usage.completion_tokens",
      "operator": "less_than",
      "value": 512
    },
    {
      "field": "response.choices[0].finish_reason",
      "operator": "equals",
      "value": "stop"
    },
    {
      "field": "response.choices[0].message.content",
      "operator": "not_empty"
    }
  ]
}

Jalankan ini di beberapa model (GPT-4o, Claude 3.5 Sonnet, Gemini 1.5 Pro) dalam satu Skenario Uji untuk menangkap perbedaan skema API sebelum mencapai produksi.

Lanjutan: kuantisasi dan optimisasi inferensi

Setelah Anda memiliki LLM kecil yang berfungsi, dua teknik patut dipahami karena secara langsung berlaku untuk cara model produksi dilayani.

Kuantisasi

Bobot dalam model kita adalah float 32-bit secara default. Kuantisasi menguranginya menjadi bilangan bulat 8-bit (INT8) atau bahkan 4-bit (INT4). Ini mengurangi penggunaan memori sebanyak 4-8x dengan kehilangan akurasi yang moderat.

# Example: dynamic INT8 quantization in PyTorch
import torch.quantization
quantized_model = torch.quantization.quantize_dynamic(
    model, {nn.Linear}, dtype=torch.qint8
)

API produksi menjalankan model terkuantisasi. Ketika Anda melihat kualitas output yang berbeda pada "versi" yang berbeda dari model yang sama, kuantisasi sering kali terlibat.

Cache KV

Dalam loop inferensi kita, kita menghitung ulang perhatian di seluruh urutan setiap langkah. Sistem produksi menyimpan pasangan kunci-nilai dari token sebelumnya (cache KV) sehingga setiap token baru hanya membutuhkan satu komputasi perhatian baru. Inilah sebabnya mengapa token pertama dalam respons streaming membutuhkan waktu lebih lama daripada token berikutnya.

LLM kecil vs. API produksi: kapan menggunakan masing-masing

Kasus Penggunaan LLM Kecil API Produksi
Mempelajari internal model Terbaik untuk Berlebihan
Membuat prototipe aplikasi baru Kualitas tidak memadai Terbaik untuk
Data pribadi/sensitif Pilihan bagus Tergantung penyedia
Penyebaran offline/edge Layak Tidak mungkin
Sensitif biaya, volume tinggi Mungkin dengan kompromi Mahal pada skala besar
Tugas yang membutuhkan penalaran berat Tidak layak Diperlukan

Jawaban sebenarnya bagi sebagian besar pengembang: gunakan API produksi untuk aplikasi Anda, tetapi jalankan model kecil untuk memahami apa yang terjadi di balik layar. Keduanya tidak bersaing. Artikel [internal: open-source-coding-assistants-2026] membahas alat yang mengaburkan batas ini dengan pengaturan "bring-your-own-model".

Kesimpulan

Membangun LLM kecil dari awal membutuhkan waktu akhir pekan. Yang Anda dapatkan bukanlah sistem produksi; ini adalah model mental yang berfungsi tentang bagaimana setiap model bahasa, dari GuppyLM hingga GPT-4o, sebenarnya bekerja. Pemahaman itu terbayar setiap kali Anda men-debug integrasi streaming, menyetel parameter pengambilan sampel, atau merancang pernyataan untuk pengujian API AI Anda.

Proyek GuppyLM adalah titik awal yang baik. Kloning, latih pada dataset teks apa pun, dan luangkan sore untuk membaca loop inferensi. Kemudian kembali ke integrasi API produksi Anda dan Anda akan melihatnya secara berbeda.

Coba Skenario Uji Apidog untuk membawa ketelitian yang sama ke pengujian API AI Anda seperti yang akan Anda terapkan pada sistem backend lainnya.

tombol

FAQ

Berapa banyak parameter yang dibutuhkan LLM "kecil" untuk menghasilkan teks yang koheren?Sekitar 10M-50M parameter dengan dataset pelatihan yang layak dapat menghasilkan kalimat yang koheren secara lokal. Di bawah 1M, Anda akan mendapatkan omong kosong pada sebagian besar tugas. GuppyLM pada 8.7M berfungsi untuk percakapan singkat di domain pelatihannya (60 topik).

Bisakah saya menjalankan LLM kecil tanpa GPU?Ya. Model di bawah 100M parameter berjalan dengan baik di CPU, meskipun inferensi lebih lambat. Model di atas (1.2M parameter) menghasilkan token dalam milidetik di CPU laptop.

Dataset apa yang harus saya latih?Model tingkat karakter bekerja dengan baik dengan teks Project Gutenberg, subset Wikipedia, atau korpus teks biasa apa pun. GuppyLM menggunakan dataset percakapan 60K entri di HuggingFace (arman-bd/guppylm-60k-generic). Untuk pembuatan kode, gunakan The Stack atau CodeParrot.

Apa perbedaan antara suhu dan pengambilan sampel top-k?Suhu menskalakan distribusi logit (mengontrol keacakan keseluruhan). Top-k membatasi kumpulan pengambilan sampel ke k token yang paling mungkin sebelum menerapkan suhu. Keduanya diterapkan bersama: pertama top-k memfilter kandidat, kemudian suhu membentuk probabilitas dalam kumpulan itu.

Mengapa LLM saya terkadang mengulang dirinya sendiri?Pengulangan adalah mode kegagalan di mana model menetapkan probabilitas tinggi pada token yang baru saja dibuat karena muncul dalam konteks. API produksi menggunakan penalti pengulangan (penyesuaian logit yang mendiskon token yang baru saja dibuat). Tambahkan repetition_penalty=1.1 dalam panggilan API Anda untuk mengurangi ini.

Berapa lama waktu yang dibutuhkan untuk melatih LLM kecil?Model di atas dilatih hingga output koheren dalam waktu kurang dari 2 jam pada satu GPU (RTX 3060 atau setara). GuppyLM dilatih di Colab dalam waktu yang kira-kira sama. Model yang lebih besar (100M+) membutuhkan pengaturan multi-GPU dan berhari-hari pelatihan.

Apa cara tercepat untuk beralih dari LLM kecil ke endpoint API nyata?Ekspor ke format GGUF menggunakan skrip konversi llama.cpp, lalu sajikan dengan llama-server. Ini memberi Anda endpoint API yang kompatibel dengan OpenAI yang berjalan secara lokal. Anda kemudian dapat mengarahkan Apidog ke sana untuk pengujian, lihat [internal: rest-api-best-practices].

Bagaimana LLM produksi menangani konteks yang lebih panjang dari jendela pelatihannya?Teknik seperti RoPE (Rotary Position Embedding) dengan penskalaan yang diperluas, sliding window attention, dan retrieval-augmented generation semuanya memperluas konteks yang efektif. Arsitektur transformer inti tidak berubah; ini adalah modifikasi pada cara informasi posisi dikodekan dan bagaimana jendela perhatian diterapkan.

Mengembangkan API dengan Apidog

Apidog adalah alat pengembangan API yang membantu Anda mengembangkan API dengan lebih mudah dan efisien.

Cara Membuat LLM dari Awal: Panduan Lengkap & Pembelajaran Penting