LLM Lokal sebagai Otak AI Agent di PC Tanpa GPU Diskrit
Menjalankan model coding 30B di PC rumahan yang hanya punya iGPU, lalu menyambungkannya ke harness AI agent. Tujuannya: agent bisa bekerja tanpa mengirim kode ke layanan cloud.
Lembar data
- Peran
- Perancang dan pelaksana eksperimen
- Tim
- Solo, dikerjakan bersama Claude Code sebagai asisten
- Periode
- Oktober 2026 – sekarang
- Status
- Eksperimen berjalan. Server sudah berfungsi dan sudah diuji dengan Codex CLI
- Stack
- llama.cpp (Vulkan), Qwen3-Coder-30B-A3B (GGUF Q4), CachyOS, systemd, ufw, Codex CLI
- Repo
- Repositori privat
5:55 → 11 detik
Waktu muat model
24,7 token/s
Generate, konteks pendek
0,5 detik
Pertanyaan lanjutan, prompt cache
60,6 GB/s
Bandwidth RAM
Ringkasan
Saya ingin tahu seberapa jauh AI agent bisa berjalan di perangkat sendiri. Hasilnya, satu PC berisi Ryzen 7 8700G dengan RAM 32 GB, tanpa kartu grafis terpisah, sekarang bisa melayani model Qwen3-Coder-30B-A3B lewat API yang kompatibel dengan OpenAI. Server dinyalakan hanya saat dibutuhkan (llm start), siap dalam sekitar 10 detik, dan bisa dipakai oleh harness agent di PC yang sama maupun PC lain di jaringan lokal.
Memilih Model dari Batasan, Bukan dari Leaderboard
Saya tidak mulai dengan pertanyaan “model apa yang paling pintar?”. Pertanyaan pertama saya: “apa yang membatasi kecepatan di mesin ini?”. Jawabannya bisa diukur, yaitu bandwidth RAM. Benchmark baca multithread menghasilkan 60,6 GB/s. Angka ini sekaligus memastikan RAM sudah berjalan dual channel, karena single channel hanya mencapai sekitar 30 GB/s.
Dari batasan itu, keputusannya jadi jelas:
- Model dense 30B ke atas tidak layak. Setiap token harus membaca seluruh bobot model dari RAM, sehingga kecepatannya hanya beberapa token per detik.
- Model MoE (Mixture of Experts) paling masuk akal. Qwen3-Coder-30B-A3B punya 30 miliar parameter, tetapi hanya sekitar 3,3 miliar yang aktif per token. Kualitasnya mendekati model besar, kecepatannya mendekati model kecil.
- Model ini dilatih untuk agentic coding, sehingga tool calling-nya lebih bisa diandalkan dibanding model chat umum.
- Kelas di atasnya tidak muat. Model seperti GLM-4.5-Air atau gpt-oss-120b butuh lebih dari 45 GB RAM.
Membuat iGPU Bisa Memuat Model 20 GB
Model dan konteks 64k token butuh sekitar 20,5 GB memori grafis. Secara default, kernel Linux hanya mengizinkan iGPU meminjam setengah RAM (15,2 GB) lewat mekanisme GTT. Saya menaikkan batas itu menjadi 24 GB lewat parameter kernel:
ttm.pages_limit=6291456 ttm.page_pool_size=6291456 amdgpu.gttsize=24576
Saya sengaja memilih GTT daripada menaikkan VRAM di BIOS. VRAM BIOS memotong RAM secara permanen, sedangkan GTT hanya berupa batas atas: saat LLM mati, RAM tersebut kembali bisa dipakai aplikasi lain.
Server yang Menyala Hanya Saat Dibutuhkan
Versi pertama saya pasang sebagai service sistem yang otomatis jalan saat boot. Ternyata ini keputusan yang salah. Setiap kali PC dinyalakan, model 17,7 GB langsung dimuat, sehingga desktop terasa berat di menit-menit awal.
Versi akhirnya memakai user service systemd tanpa bagian [Install], sehingga service ini memang tidak bisa ikut jalan saat boot. Untuk mengontrolnya, saya membuat satu perintah sederhana:
| Perintah | Fungsi |
|---|---|
llm start |
Menyalakan server dan menunggu sampai model siap |
llm stop |
Mematikan server dan membebaskan sekitar 21 GB RAM |
llm status |
Status, endpoint, dan pemakaian memori iGPU |
llm key |
Menampilkan API key untuk dipasang di harness |
Akses dari jaringan dibatasi dua lapis: API key wajib (request tanpa key ditolak dengan HTTP 401), dan firewall hanya membuka port untuk subnet lokal.
Temuan yang Tidak Saya Cari: SSD yang Melambat
Pada percobaan pertama, model butuh 5 menit 55 detik untuk dimuat. Mengganti mode pemuatan llama.cpp tidak membantu, bahkan salah satunya membuat waktu muat naik menjadi 7 menit 24 detik. Jadi saya berhenti mengutak-atik software dan mulai mengukur hardware:
| Data yang dibaca | Kecepatan |
|---|---|
| File model, sekitar 1 jam setelah diunduh | 42–50 MB/s |
| Data lama, dibaca langsung dari device | 23–32 MB/s |
| File yang baru saja ditulis | 4,2 GB/s |
SSD NVMe ini membaca data yang sudah “mengendap” sekitar 100 kali lebih lambat daripada data baru. Gejala ini dikenal sebagai stale-data read degradation. Kondisi SMART-nya normal, jadi masalah ini tidak akan terlihat kalau saya hanya mengecek kesehatan disk. Setelah file model ditulis ulang ke blok baru, waktu muat turun dari 5 menit 55 detik menjadi 11 detik. Prosedur ini sekarang tersedia sebagai llm refresh.
Pelajaran terbesar dari eksperimen ini justru datang dari sini: ukur dulu di lapisan paling bawah sebelum menyalahkan lapisan yang paling terlihat.
Hasil Terukur
Benchmark terkontrol (request langsung ke server):
| Uji | Hasil |
|---|---|
| Kecepatan generate, konteks pendek | 24,7 token/s |
| Kecepatan generate, konteks sekitar 14,5k token | 16,5 token/s |
| Pemrosesan prompt sekitar 14,5k token | 229 token/s (63 detik) |
| Pertanyaan lanjutan dengan prompt cache | 0,5 detik |
| Tool calling | Berhasil, dengan argumen JSON yang valid |
Pemakaian nyata dengan Codex CLI (dari log server):
| Uji | Hasil |
|---|---|
| Pemrosesan prompt | 660 token baru dalam 10,7 detik (61 token/s) |
| Kecepatan generate | 1.054 token dalam 104 detik (10,1 token/s) |
Angka dari Codex lebih rendah daripada benchmark, dan itu wajar. Agent membawa riwayat percakapan dan konteks project yang panjang. Semakin panjang konteks, semakin lambat setiap token dihasilkan. Bagian prompt yang baru juga diproses dalam potongan kecil, dan potongan kecil kurang efisien dibanding satu prompt besar.
Menyambungkan ke Codex
Codex versi 0.159 hanya menerima provider dengan format Responses API (wire_api = "responses"). Format ini ternyata sudah didukung llama.cpp. Saya mendaftarkan server lokal sebagai provider tambahan dan membuat perintah terpisah, codex-lokal. Dengan begitu, codex biasa tetap memakai model cloud, sementara codex-lokal menyalakan server lokal (kalau belum jalan) dan memakainya.
Codex memberi peringatan bahwa metadata model qwen3-coder-30b tidak dikenal, sehingga memakai pengaturan fallback. Context window sudah saya tetapkan sendiri. Kecocokan format tool dan instruksi sistem untuk model non-OpenAI masih perlu diamati lebih lanjut.
Pelajaran
- Mulai dari batasan yang bisa diukur. Bandwidth RAM menentukan pilihan model lebih tegas daripada skor benchmark mana pun.
- Autostart bukan pilihan default yang netral. Untuk proses yang memakai 21 GB RAM, menyala hanya saat dibutuhkan jauh lebih masuk akal.
- Gejala di aplikasi belum tentu masalah di aplikasi. Loading model yang lambat ternyata berasal dari SSD, dan itu baru ketahuan setelah diukur di level device.
- LLM lokal di iGPU bisa dipakai untuk agent, dengan ekspektasi yang jujur. Hasilnya cukup untuk tugas-tugas kecil dan data yang sensitif, tetapi belum menggantikan model cloud untuk pekerjaan panjang dan kompleks.