Lewati ke konten utama

Tutorial Gemma 4: Bangun Agen Coding AI Lokal dengan Gradio dan Ollama

Pelajari cara membangun asisten coding AI lokal dan multimodal bertenaga Gemma 4 melalui Ollama, dengan penggunaan tool agen dalam UI Gradio.
Diperbarui 28 Sep 2026  · 12 mnt Baca

Jelajahi bersama AI

ChatGPTClaudePerplexity

LLM lokal telah mencapai titik balik. Dengan jendela konteks panjang Gemma 4, dukungan multimodal bawaan, dan kemudahan akses Ollama, kini praktis untuk menjalankan asisten coding agen yang mumpuni sepenuhnya di mesin Anda sendiri.

Dalam tutorial ini, saya akan menunjukkan cara membangun asisten coding menggunakan Gemma 4 melalui Ollama, dengan antarmuka Gradio. Aplikasi ini memiliki tata letak panel terpisah dengan editor kode langsung di kiri dan panel chat agen di kanan. Anda dapat mengunggah gambar atau file kode sebagai konteks, mengaktifkan penggunaan tool agar model dapat menjalankan dan memvalidasi kode, serta menyalakan mode thinking untuk masalah yang lebih sulit.

Di akhir tutorial ini, Anda akan memiliki aplikasi lokal yang dapat:

  • Menulis, menjelaskan, dan men-debug kode dalam 15+ bahasa
  • Menjalankan kode Python dalam subprocess terisolasi dan mengembalikan hasilnya
  • Menerima gambar dan file teks sebagai konteks multimodal
  • Melakukan streaming respons secara real time dari model Gemma 4 yang berjalan lokal
  • Berjalan sebagai loop agen, memanggil tool dan menindaklanjuti berdasarkan hasilnya

Kode lengkap untuk tutorial ini tersedia di sini.

Apa itu Gemma 4?

Gemma 4 adalah keluarga model open-weights dari Google DeepMind, dirancang untuk deployment lokal dan riset. Model ini meneruskan lini Gemma dengan peningkatan pada kemampuan mengikuti instruksi, jendela konteks lebih panjang, serta penanganan input multimodal bawaan dan dibangun dari infrastruktur riset yang sama dengan Gemini 3.

Performa Model vs Ukuran

Gambar: Performa model vs Ukuran (sumber: blog Gemma 4)

Model seperti Gemma-4-26B(MOE) dan Gemma-4-31B mencapai skor Elo yang sebanding dengan model yang jauh lebih besar, menunjukkan performa-per-parameter yang kuat. Model 31B saat ini menempati peringkat ke-3 model open di dunia pada papan peringkat teks Arena AI, dan model 26B berada di posisi ke-6. Ini membuat Gemma 4 sangat cocok untuk deployment lokal dan lingkungan dengan sumber daya terbatas tanpa mengorbankan kapabilitas.

Keluarga model Gemma 4

Gemma 4 dirilis dalam empat ukuran fleksibel termasuk Effective 2B (E2B), Effective 4B (E4B), 26B Mixture of Experts (MoE), dan model Dense 31B. Keluarga ini terbagi menjadi dua tingkatan berbeda berdasarkan target deployment:

Model

Arsitektur

Total Parameter

Parameter Aktif/Efektif

Panjang Konteks

Modalitas

Gemma-4-31B

Dense Transformer

31B

31B

256K token

Teks, Visual, Video

Gemma-4-26B-A4B

MoE (128 Expert)

26B

3,8B aktif

256K token

Teks, Visual, Video

Gemma-4-E4B

Dense Transformer

7,9B (dengan embedding)

4,5B efektif

128K token

Teks, Audio, Visual, Video

Gemma-4-E2B

Dense Transformer

5,1B (dengan embedding)

2,3B efektif

128K token

Teks, Audio, Visual, Video

Mari menelusuri lebih dalam setiap varian:

Panduan Visual Gemma 4

Gambar: Panduan Visual Gemma 4 (sumber)

  • 31B Dense adalah model andalan yang dioptimalkan untuk deployment pusat data dan beban kerja penalaran kompleks. Mendukung jendela konteks 256K token dengan sliding window 1024-token untuk pemrosesan konteks panjang yang efisien.
  • 26B-A4B (MoE) adalah model MoE pertama Gemma yang merutekan token melalui 128 expert sambil hanya menjaga 3,8B parameter aktif per forward pass. Ini memberi kualitas mendekati 31B dengan sebagian kecil biaya komputasi per token sehingga cocok untuk serving throughput tinggi.
  • E4B dan E2B adalah tier on-device dan mobile. Berbeda dengan varian yang lebih besar, keduanya mencakup input audio bawaan untuk pengenalan ucapan selain visi dan video, menjadikannya model paling kapabel secara multimodal di keluarga ini untuk deployment edge.

Keempat model tersedia di bawah lisensi Apache 2.0 dan dapat dideploy secara lokal melalui Ollama, vLLM, llama.cpp, atau Unsloth.

Untuk tugas pemrograman, Gemma 4 unggul dalam:

  • Menulis kode lengkap dan terstruktur beserta penjelasan
  • Melakukan penalaran atas codebase yang ada saat diberikan sebagai konteks
  • Penggunaan tool dan alur kerja agen saat dipasangkan dengan lapisan orkestrasi
  • Menangani gambar bersamaan dengan kode (mis., membaca tangkapan layar UI dan menghasilkan HTML yang sesuai)

Dalam tutorial ini, kita menggunakan varian gemma4:e4b (9,6GB) melalui Ollama yang merupakan versi terkuantisasi dan cocok untuk inferensi lokal pada perangkat konsumen. 

Menjalankan Gemma 4 melalui Ollama

Ollama menangani pengunduhan model, kuantisasi, serving, dan menyediakan HTTP API yang kompatibel dengan OpenAI. Untuk tutorial ini, Ollama bertindak sebagai backend inferensi, dan aplikasi kita berkomunikasi dengannya melalui localhost:11434.

Untuk menarik dan menjalankan model:

curl -fsSL https://ollama.com/install.sh | sh
ollama pull gemma4:e4b 
ollama serve

Perintah di atas menginstal Ollama secara lokal menggunakan skrip instalasi resmi. Kita kemudian mengunduh varian model gemma 4:e4b secara lokal untuk inferensi on device. Terakhir, ollama serve menjalankan server Ollama, memungkinkan aplikasi kita mengirim permintaan ke model.

Setelah server berjalan, aplikasi Gradio akan terhubung secara otomatis.

Demo Gemma 4: Bangun Asisten Coding dengan Ollama

Di bagian ini, kita akan membangun asisten kode selangkah demi selangkah. Secara garis besar, berikut yang dilakukan aplikasi:

  • Menerima pesan berbahasa natural di panel chat, dengan lampiran gambar atau file opsional

  • Menyuntikkan kode editor saat ini sebagai konteks untuk model

  • Mengirim permintaan streaming ke Gemma 4 melalui endpoint /api/chat Ollama

  • Secara opsional memanggil tool (eksekusi kode, evaluasi matematika) dalam loop agen

  • Mendorong blok kode yang diekstrak dari respons ke editor langsung

Mari kita bangun selangkah demi selangkah.

Demo akhir

Langkah 1: Instal dependensi

Aplikasi memerlukan beberapa pustaka untuk UI, penanganan gambar, dan komunikasi HTTP. Karena model berjalan secara lokal melalui Ollama, tidak ada dependensi SDK cloud.

pip install gradio requests pillow

Dalam proyek ini, kita akan menggunakan:

  • gradio untuk editor panel terpisah dan UI chat

  • requests untuk berkomunikasi dengan HTTP API Ollama

  • pillow untuk dukungan penanganan gambar di UI

Ini menjaga lingkungan tetap ringan dan bekerja di mesin apa pun yang menjalankan Ollama, termasuk macOS dengan Apple Silicon, Linux, dan Windows melalui WSL.

Langkah 2: Konfigurasi dan konstanta

Sebelum menulis logika, kita mendefinisikan impor, nama model, URL dasar Ollama, bahasa yang didukung, dan system prompt bawaan. Konstanta ini mengendalikan perilaku seluruh aplikasi.

import base64
import json
import math
import os
import re
import subprocess
import tempfile
from pathlib import Path
import gradio as gr
import requests

OLLAMA_BASE = "http://localhost:11434"
MODEL       = "gemma4:e4b"
LANGUAGES = [
    "python", "javascript", "typescript", "bash", "sql",
    "rust", "go", "java", "c", "cpp", "html", "css",
    "json", "yaml", "markdown", "plaintext",
]
TEXT_EXTS = {
    ".py", ".js", ".ts", ".jsx", ".tsx", ".html", ".css",
    ".json", ".yaml", ".yml", ".toml", ".md", ".txt",
    ".csv", ".sql", ".sh", ".bash", ".rs", ".go",
    ".java", ".c", ".cpp", ".h", ".hpp", ".rb", ".php",
}
IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".gif", ".bmp"}
DEFAULT_SYSTEM = """\
You are an expert coding assistant. When you write code:
- Always wrap it in a markdown code block with the language tag
- Write complete, working code — not fragments
- Briefly explain what the code does
You have a code-runner tool. Use it to validate logic when helpful.\
"""

Set TEXT_EXTS dan IMAGE_EXTS menggerakkan dua perilaku lampiran berbeda. File teks/kode dibaca dan disuntikkan sebagai konteks ke dalam prompt, sementara file gambar di-base64-encoded dan dikirim dalam field images untuk kemampuan visi Gemma 4.

System prompt DEFAULT_SYSTEM membentuk gaya generasi kode model, secara khusus meminta blok kode lengkap dengan tag bahasa, karena aplikasi mem-parsing ini untuk mendorong kode ke editor.

Langkah 3: Definisikan tool agen

Asisten dapat beroperasi dalam mode agen di mana ia memanggil tool selama inferensi. Kita mendefinisikan dua tool dalam skema function-calling standar yang didukung Ollama:

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "run_code",
            "description": (
                "Execute Python code in a sandboxed subprocess and return "
                "stdout + stderr. Use this to validate, test, or demonstrate code."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "string",
                        "description": "Python code to run (max ~50 lines, 5 s timeout).",
                    }
                },
                "required": ["code"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "Evaluate a mathematical expression precisely.",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "Python-compatible math expression, e.g. 'math.sqrt(2) * 100'",
                    }
                },
                "required": ["expression"],
            },
        },
    },
]

Cuplikan kode di atas mendefinisikan tool run_code, yang mengeksekusi Python dalam file sementara melalui subprocess dengan batas waktu 5 detik dan menangkap stdout serta stderr. Ini memungkinkan model memvalidasi logika, menjalankan contoh, atau menghasilkan output langsung, bukan hanya teks statis.

Sementara itu, tool calculate mengevaluasi ekspresi matematika dalam namespace terbatas menggunakan hanya modul math dan built-in yang aman. Ini menangani kasus ketika model memerlukan hasil numerik presisi tanpa menyalakan proses Python penuh.

Langkah 4: Eksekusi tool

Lapisan eksekusi memetakan nama tool ke implementasinya. Ini dipanggil selama loop agen kapan pun model mengembalikan blok tool_calls.

def _run_python(code: str) -> str:
    with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
        f.write(code)
        tmp = f.name
    try:
        r = subprocess.run(
            ["python3", tmp],
            capture_output=True, text=True, timeout=5,
        )
        out = (r.stdout + r.stderr).strip()
        return out[:3000] if out else "(no output)"
    except subprocess.TimeoutExpired:
        return "⏱ Timed out (>5 s)"
    except Exception as e:
        return f"Error: {e}"
    finally:
        os.unlink(tmp)

def _calculate(expr: str) -> str:
    ns = {k: getattr(math, k) for k in dir(math) if not k.startswith("_")}
    ns.update({"abs": abs, "round": round})
    try:
        return str(eval(expr, {"__builtins__": {}}, ns))  # noqa: S307
    except Exception as e:
        return f"Error: {e}"

def execute_tool(name: str, args: dict) -> str:
    if name == "run_code":
        return _run_python(args.get("code", ""))
    if name == "calculate":
        return _calculate(args.get("expression", ""))
    return f"Unknown tool: {name}"

Beberapa pilihan desain keamanan yang patut dicatat dari tumpukan eksekusi tool adalah:

  • fungsi _run_python() menulis ke file sementara dan membersihkannya, mencegah file tersisa bahkan saat terjadi error

  • Output dibatasi hingga 3.000 karakter untuk menghindari membanjiri konteks dengan cetakan yang masif

  • Fungsi _calculate() menggunakan eval() dengan __builtins__ disetel ke dict kosong, mencegah akses ke built-in Python di luar fungsi math yang secara eksplisit diizinkan

  • Timeout adalah jendela keras 5 detik, cukup lama untuk sebagian besar tugas validasi, cukup pendek untuk mencegah proses tak terkendali

Langkah 5: Utilitas pembantu

Sebelum membangun logika chat inti, kita memerlukan beberapa fungsi utilitas yang menangani path file, encoding gambar, dan ekstraksi kode. Fungsi pembantu ini dipanggil di seluruh pipeline streaming.

def encode_image(path: str) -> str | None:
    if not path:
        return None
    try:
        with open(path, "rb") as f:
            return base64.b64encode(f.read()).decode()
    except Exception:
        return None

def file_as_context(path: str) -> str | None:
    if not path:
        return None
    p = Path(path)
    if p.suffix.lower() not in TEXT_EXTS:
        return None
    try:
        content = p.read_text(encoding="utf-8", errors="replace")[:8000]
        lang = p.suffix.lstrip(".")
        return f"\n\n**Attached file — {p.name}:**\n```{lang}\n{content}\n```"
    except Exception:
        return None

def resolve_gradio_path(val) -> str | None:
    if val is None:
        return None
    if isinstance(val, Path):
        s = str(val)
        return s if s.strip() else None
    if isinstance(val, str):
        s = val.strip()
        return s if s else None
    if isinstance(val, dict):
        p = val.get("path")
        if isinstance(p, str) and p.strip():
            return p.strip()
        nested = val.get("file")
        if isinstance(nested, dict):
            np = nested.get("path")
            if isinstance(np, str) and np.strip():
                return np.strip()
        return None
    name = getattr(val, "name", None)
    if isinstance(name, str) and name.strip():
        return name.strip()
    return None

def is_image_path(path: str | None) -> bool:
    return bool(path) and Path(path).suffix.lower() in IMAGE_EXTS

def extract_last_code_block(text: str) -> tuple[str | None, str]:
    blocks = re.findall(r"```(\w*)\n(.*?)```", text, re.DOTALL)
    if blocks:
        lang, code = blocks[-1]
        return code.strip(), lang.strip() or "python"
    return None, "python"

def ollama_ok() -> bool:
    try:
        requests.get(f"{OLLAMA_BASE}/", timeout=2)
        return True
    except Exception:
        return False

def _gradio_content_to_text(content) -> str:
    if content is None:
        return ""
    if isinstance(content, str):
        return content
    if isinstance(content, list):
        parts: list[str] = []
        for block in content:
            if isinstance(block, dict):
                if block.get("type") == "text":
                    parts.append(str(block.get("text", "")))
                elif "text" in block:
                    parts.append(str(block["text"]))
            elif isinstance(block, str):
                parts.append(block)
        return "".join(parts)
    return str(content)

def _append_chat_turn(
    history: list | None, user_text: str, assistant_text: str
) -> list:
    base = list(history) if history else []
    return base + [
        {"role": "user", "content": user_text},
        {"role": "assistant", "content": assistant_text},
    ]

def run_code_btn(code: str) -> str:
    if not code.strip():
        return "Nothing to run."
    result = _run_python(code)
    return result

Utilitas ini memungkinkan penanganan input multimodal dan output terstruktur dengan mulus:

  • fungsi encode_image(): Fungsi ini mengonversi file gambar menjadi string base64 agar dapat diteruskan ke field images Ollama. Ini memungkinkan Gemma memproses gambar bersama teks untuk penalaran multimodal.

  • fungsi file_as_context(): Fungsi ini membaca file teks/kode dan menyuntikkannya langsung ke prompt sebagai blok markdown terformat. Ini menghindari kebutuhan sistem retrieval terpisah karena semuanya diberikan inline sebagai konteks.

  • fungsi resolve_gradio_path(): Fungsi ini menormalkan berbagai format file yang dikembalikan Gradio menjadi path file yang dapat digunakan. Ini mencegah bug kasus tepi dalam penanganan file.

  • fungsi is_image_path(): Ini adalah pemeriksaan cepat apakah file tertentu merupakan gambar atau bukan. Ini membantu merutekan input gambar dengan benar.

  • fungsi extract_last_code_block(): Berikutnya, kita mengekstrak blok kode terakhir dari respons model. 

  • fungsi ollama_ok(): Kita memverifikasi bahwa server Ollama lokal berjalan sebelum membuat permintaan.

  • fungsi _gradio_content_to_text() dan _append_chat_turn(): Kita meratakan format pesan terstruktur Gradio menjadi teks biasa untuk pemrosesan yang konsisten dan mempertahankan riwayat chat.

  • fungsi run_code_btn(): Terakhir, kita mengeksekusi kode yang dihasilkan ketika pengguna menekan tombol Run code di UI menggunakan fungsi ini.

Kini setelah kita memiliki utilitas pembantu, kita dapat mengimplementasikan fungsi inti chat().

Langkah 6: Generator streaming chat inti

Fungsi ini menggerakkan seluruh loop interaksi, dari menyiapkan input hingga streaming respons dan menangani eksekusi tool.

Secara garis besar, fungsi chat():

  • membangun riwayat percakapan
  • memperkaya input pengguna saat ini dengan konteks (kode, file, gambar)
  • mengirim permintaan streaming ke Ollama
  • secara opsional mengeksekusi tool (mode agen)
  • menghasilkan respons parsial untuk pembaruan UI waktu nyata
def chat(
    message, history, image_path, file_path,
    editor_code, language, system_prompt,
    agentic, thinking, temperature,
):

Fungsi ini mengikuti urutan langkah demi langkah berikut:

Langkah 1: Bangun riwayat pesan

Kita mulai dengan mengonversi giliran chatbot sebelumnya ke format pesan Ollama. System prompt ditambahkan di awal untuk membimbing perilaku model yang memastikan model memiliki konteks percakapan penuh sebelum menghasilkan respons.

for h in history or []:
        if not isinstance(h, dict):
            continue
        role = h.get("role")
        if role not in ("user", "assistant"):
            continue
        messages.append(
            {"role": role, "content": _gradio_content_to_text(h.get("content"))}
        )
    content = message

Langkah 2: Susun giliran pengguna

Selanjutnya, kita membangun pesan pengguna saat ini dengan menyuntikkan konteks tambahan. Jika pengguna sedang bekerja dengan kode, kita menambahkan isi editor:

if editor_code.strip() and editor_code.strip() != STARTER_CODE.strip():
    content += (
        f"\n\n**Current code in editor ({language}):**\n"
        f"```{language}\n{editor_code}\n```"
    )

Demikian pula, file yang diunggah ditambahkan sebagai konteks inline dan gambar di-encode base64 dan diteruskan melalui field images. Ini memungkinkan model melakukan penalaran atas teks, kode, dan gambar secara bersamaan.

Langkah 3: Kirim permintaan ke Ollama

Payload mencakup nama model, riwayat pesan, flag streaming, dan opsi sebagai berikut:

payload = {
    "model": MODEL,
    "messages": messages,
    "stream": True,
    "options": options,
}

if agentic:
    payload["tools"] = TOOLS

Jika mode thinking diaktifkan, options["think"] = True disetel, yang mengaktifkan penalaran chain-of-thought yang diperluas pada model yang didukung.

Langkah 4: Tangani panggilan tool (mode agen)

Jika mode agen diaktifkan, model dapat mengembalikan panggilan tool alih-alih teks. Ini terjadi ketika setiap tool dieksekusi dan hasilnya ditambahkan ke percakapan. Lalu, permintaan tindak lanjut dikirim untuk melanjutkan generasi.

if agentic and msg.get("tool_calls"):
    for tc in msg["tool_calls"]:
        fn_name = tc["function"]["name"]
        fn_args = tc["function"]["arguments"]
        result = execute_tool(fn_name, fn_args)
        if fn_name == "run_code" and fn_args.get("code"):
            new_code = fn_args["code"]
        messages.append(msg)
        messages.append({"role": "tool", "content": result})
    resp2 = requests.post(f"{OLLAMA_BASE}/api/chat", ...)

Ini menciptakan loop agen satu giliran di mana model memanggil tool, melihat hasilnya, lalu melanjutkan menghasilkan respons akhir. Log panggilan tool ditambahkan ke chat untuk pengguna.

Langkah 5: Ekstrak kode dan perbarui editor

Terakhir, setelah streaming selesai, kita mengekstrak blok kode terakhir dari respons:

extracted, _ = extract_last_code_block(full_response)

if extracted:
    new_code = extracted

Secara keseluruhan, model menghasilkan kode, editor diperbarui secara otomatis dan tidak diperlukan copy-paste manual.

Langkah 7: Tata letak UI Gradio

Dengan logika inti sudah siap, kini kita merancang antarmuka pengguna menggunakan Gradio. Tujuannya adalah membuat tata letak yang mendukung alur kerja pemrograman dan interaksi berbantuan AI secara berdampingan.

Kita menggunakan gr.Blocks untuk mendefinisikan tata letak dua kolom:

  • panel kiri berfokus pada pengeditan dan eksekusi kode
  • panel kanan menangani chat, lampiran, dan kontrol model
with gr.Blocks(title="Gemma 4 · Code Assistant") as demo:
    with gr.Row(equal_height=False):
        # LEFT: Code Editor
        with gr.Column(scale=11):
            with gr.Row():
                lang_sel = gr.Dropdown(choices=LANGUAGES, value="python", label="Language")
                run_btn  = gr.Button("Run Code", elem_classes=["run-btn"])
                clear_ed = gr.Button("Clear")
            code_editor = gr.Code(
                value=STARTER_CODE,
                language="python",
                label="Editor",
                lines=24,
                interactive=True,
            )
            run_output = gr.Textbox(
                label="Output",
                lines=6,
                interactive=False,
                elem_id="run-output",
            )
        # RIGHT: Chat
        with gr.Column(scale=9):
            chatbot = gr.Chatbot(value=[], elem_id="chatbot", height=430)
            with gr.Row():
                image_upload = gr.Image(label="Image (vision)", type="filepath")
                file_upload  = gr.File(label="Code / text file")
            with gr.Row():
                msg_input = gr.Textbox(placeholder="Ask the agent...", scale=6)
                send_btn  = gr.Button("Send", variant="primary")
            with gr.Row():
                agentic_cb  = gr.Checkbox(label="Enable Agentic", value=True)
                thinking_cb = gr.Checkbox(label="Enable Thinking", value=False)
                clear_chat  = gr.Button("Clear chat")
            with gr.Accordion("Settings", open=False):
                sys_prompt  = gr.Textbox(value=DEFAULT_SYSTEM, label="System prompt")
                temperature = gr.Slider(minimum=0.0, maximum=2.0, value=0.7)

Mari pahami bagaimana UI bekerja bersama semua komponen yang telah kita bahas di atas:

  • Ruang kerja kode: Panel kiri mencakup pemilih bahasa, editor kode, serta kontrol run/clear. Output eksekusi ditampilkan dalam textbox yang disorot.
  • Chat dan interaksi: Panel kanan berisi chatbot untuk percakapan, kotak input untuk kueri, serta dukungan lampiran seperti gambar untuk penalaran multimodal dan file untuk injeksi konteks. Toggle tambahan mengaktifkan penggunaan tool agen dan mode penalaran opsional.
  • Tata letak dan kegunaan: Antarmuka menggunakan tata letak dua kolom dengan pembagian 55/45, memprioritaskan editor kode sambil menjaga chat tetap mudah diakses. Keseimbangan ini memastikan alur kerja mulus antara pemrograman, bantuan AI, dan eksekusi.

Langkah 8: Pengkabelan event

Event kirim dan submit berbagi input dan output yang sama, sehingga baik klik tombol maupun menekan Enter di kotak teks memicu perilaku identik:

_inputs = [
    msg_input, chatbot, image_upload, file_upload,
    code_editor, lang_sel,
    sys_prompt, agentic_cb, thinking_cb, temperature,
]
_outputs = [chatbot, code_editor, msg_input]
send_btn.click(fn=respond, inputs=_inputs, outputs=_outputs)
msg_input.submit(fn=respond, inputs=_inputs, outputs=_outputs)

Pembungkus respond() di sini mengonversi objek path file Gradio menjadi string path file biasa sebelum meneruskannya ke generator streaming. Kemudian menghasilkan (history, code, "") pada setiap chunk sehingga string kosong mengosongkan input pesan pada yield pertama.

Langkah 9: Tema dan CSS

Untuk meningkatkan kegunaan dan konsistensi visual, kita menambahkan tema khusus dan lapisan CSS di atas gaya default Gradio. Ini memberi aplikasi tampilan yang rapi terinspirasi GitHub dengan dukungan mode terang dan gelap. Langkah ini sepenuhnya opsional.

Kita mulai dengan mendefinisikan tema dasar menggunakan gr.themes.Base:

THEME = gr.themes.Base(
    primary_hue   = "blue",
    secondary_hue = "slate",
    neutral_hue   = "slate",
    font      = [gr.themes.GoogleFont("Inter"), "system-ui", "sans-serif"],
    font_mono = [gr.themes.GoogleFont("JetBrains Mono"), "monospace"],
)

Ini menetapkan palet warna yang konsisten dan tipografi UI yang bersih (Inter) dengan font monospace ramah developer (JetBrains Mono). Selanjutnya, kita menimpa variabel CSS kunci untuk mengontrol tampilan aplikasi:

gradio-app {
    --body-background-fill:   #f0f3f7;
    --block-background-fill:  #ffffff;
    --body-text-color:        #1f2328;
    --button-primary-background-fill: #1a7f37;
}

body.dark gradio-app {
    --body-background-fill:   #0d1117;
    --block-background-fill:  #1c2128;
    --body-text-color:        #e6edf3;
    --button-primary-background-fill: #238636;
}

Di sini, blok pertama mendefinisikan tema terang, sementara blok kedua menimpa nilai untuk mode gelap. Meski opsional, penambahan tema khusus dan CSS secara signifikan meningkatkan pengalaman pengguna.

Dengan UI kini tersusun dan ditata sepenuhnya, kita siap ke langkah terakhir yaitu meluncurkan aplikasi.

Langkah 10: Peluncuran

Terakhir, aplikasi diluncurkan dengan:

if __name__ == "__main__":
    print(f"Model  : {MODEL}")
    print(f"Ollama : {OLLAMA_BASE}")
    if not ollama_ok():
        print("Ollama not detected — run ollama serve before chatting")
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False,
        theme=THEME,
        css=CSS,
    )

Di sini, server_name="0.0.0.0" membuat aplikasi dapat diakses pada jaringan lokal Anda dan menyetel share=False menjaga semuanya tetap lokal.  Pemeriksaan ollama_ok() melakukan GET cepat ke localhost:11434 dan memberi peringatan saat startup jika Ollama tidak berjalan, alih-alih memunculkan error hanya saat pengguna pertama kali mengirim pesan.

Terakhir, buka http://localhost:7860 setelah aplikasi berjalan.

Berikut alur eksekusi lengkap dari perspektif pengguna:

Demo dengan pembuatan kode

  • Pengguna mengetik pesan di panel chat, opsional mengunggah gambar atau file kode dan menyalakan mode agen/thinking

  • Saat submit, fungsi respond() membangun permintaan lengkap ke Ollama, termasuk kode editor saat ini dan lampiran apa pun sebagai konteks

  • Permintaan melakukan streaming token demi token dan respons parsial dihasilkan ke chatbot Gradio untuk rendering langsung

  • Jika mode agen aktif dan model memutuskan memanggil tool, tool berjalan secara lokal, hasil ditambahkan ke percakapan, dan permintaan lanjutan melakukan streaming jawaban akhir

  • Setelah streaming selesai, blok kode berpagar terakhir dalam respons diekstrak dan otomatis dimasukkan ke editor

Kesimpulan

Dalam tutorial ini, kita membangun asisten coding AI sepenuhnya lokal menggunakan Gemma 4, Ollama, dan Gradio. Aplikasi mendukung input multimodal, penggunaan tool nyata, respons streaming, dan editor kode langsung, semuanya berjalan di mesin Anda sendiri tanpa API eksternal.

Pendekatan konteks-utuh dengan menyuntikkan kode editor langsung ke setiap prompt lebih sederhana daripada RAG untuk alur kerja satu file dan sangat efektif untuk tugas seperti menjelaskan, merapikan, atau memperluas kode yang sedang Anda sunting.

Dari sini, Anda dapat memperluas proyek ke beberapa arah:

  • Tambahkan panel pohon file untuk mendukung proyek multi-file dan sisipkan file yang dipilih sebagai konteks
  • Tambahkan dukungan untuk model Ollama tambahan melalui dropdown, memungkinkan pengguna beralih antara Gemma 4, Llama 3, dan lainnya
  • Persistenkan riwayat percakapan ke disk agar sesi bertahan saat aplikasi di-restart

Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

Saya adalah Google Developers Expert di ML (Gen AI), Kaggle 3x Expert, dan Women Techmakers Ambassador dengan pengalaman lebih dari 3 tahun di bidang teknologi. Saya ikut mendirikan startup health-tech pada 2020 dan sedang menempuh studi magister ilmu komputer di Georgia Tech dengan spesialisasi machine learning.

Gemma 4 FAQs

Apakah ini memerlukan GPU?

Tidak harus. Gemma 4 e4b adalah model terkuantisasi yang dapat berjalan di CPU, meskipun GPU akan sangat meningkatkan kecepatan inferensi.

Apa perbedaan antara mode agen dan chat reguler?

Dalam mode reguler, model hanya melakukan streaming teks. Dalam mode agen, model dapat memanggil run_code atau calculate, memeriksa hasilnya, dan mengintegrasikannya sebelum menyelesaikan respons.

Bagaimana editor memperbarui otomatis saat agen menulis kode?

Fungsi pembantu extract_last_code_block() memindai respons asisten untuk blok kode berpagar terakhir dan mendorongnya ke editor setelah streaming selesai. Inilah alasan system prompt menginstruksikan model agar selalu membungkus kode dalam blok berpagar dengan tag bahasa.

Apa yang terjadi jika Ollama tidak berjalan?

Pemeriksaan ollama_ok() menangkap ini saat startup dan pada setiap pengiriman chat. Jika Ollama tidak dapat dijangkau, chat mengembalikan pesan error terformat alih-alih crash.

Topik
Kecerdasan Buatan

Belajar bersama DataCamp

Kursus

AI Praktis dengan Google Gemini dan NotebookLM

2 jam
9.8K
Gunakan Master Gemini dan NotebookLM untuk mengotomatisasi tugas, meningkatkan produktivitas, dan bekerja lebih cerdas di ekosistem AI Google.
Lihat DetailRight Arrow
Mulai Kursus
Lihat SelengkapnyaRight Arrow
Terkait

blogs

12 Alternatif ChatGPT Terbaik yang Bisa Anda Coba pada 2026

Artikel ini menyajikan daftar alternatif ChatGPT yang akan meningkatkan produktivitas Anda.
Javier Canales Luna's photo

Javier Canales Luna

14 mnt

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026

Kuasai pertanyaan wawancara basis data, dari konsep SQL dasar hingga skenario desain sistem tingkat lanjut. Panduan mendalam ini mencakup semua yang Anda perlukan untuk sukses di wawancara DBMS dan meraih peran berikutnya.
Dario Radečić's photo

Dario Radečić

15 mnt

blogs

Spaghetti Plot dan Jalur Badai

Temukan alasan mengapa Anda sebaiknya (tidak) menggunakan spaghetti plot untuk menyampaikan ketidakpastian jalur prediksi badai serta dampaknya terhadap interpretasi.
Hugo Bowne-Anderson's photo

Hugo Bowne-Anderson

13 mnt

blogs

Tutorial Korelasi di R

Dapatkan pengenalan dasar-dasar korelasi di R: pelajari lebih lanjut tentang koefisien korelasi, matriks korelasi, plotting korelasi, dan sebagainya.
David Woods's photo

David Woods

13 mnt

Lihat SelengkapnyaLihat Selengkapnya