Mengapa Membutuhkan Arsitektur Hibrida?
Mengirim seluruh prompt ke frontier model seperti Claude 3 Opus atau GPT-4o menghasilkan tagihan operasional tinggi dan ketergantungan penuh pada vendor eksternal. Sebaliknya, menjalankan seluruh beban kerja inferensi pada kluster lokal membutuhkan belanja modal (capex) perangkat keras besar dan pemeliharaan infrastruktur berkelanjutan.
Arsitektur hibrida memecahkan masalah ini dengan membagi beban kerja secara dinamis: tugas terstruktur, klasifikasi, ekstraksi entitas, dan penalaran sederhana ditangani secara lokal menggunakan Small Language Models (SLM) seperti Qwen 2.5 atau Llama 3 via engine inferensi teroptimasi (misal: vLLM atau Ollama). Sementara tugas penalaran tingkat tinggi, analisis kode multi-file, dan sintesis kompleks dialihkan ke Cloud API.
Trade-off Teknis: Biaya, Latensi, dan Footprint Hardware
1. Footprint VRAM dan Compute Lokal
Model lokal dibatasi kapasitas VRAM kartu grafis. Untuk inferensi stabil, kalkulasi kebutuhan VRAM dasar model FP16 memerlukan sekitar 2 byte memori per parameter. Model 7B pada FP16 membutuhkan ~14 GB VRAM hanya untuk bobot model dasar. Menggunakan kuantisasi AWQ atau GGUF (4-bit) memotong kebutuhan tersebut menjadi sekitar 0.5–0.6 byte per parameter (~4–5 GB untuk 7B), menyisakan ruang untuk KV Cache.
KV Cache bertumbuh secara linear seiring bertambahnya context window dan batch size:
KV Cache per token ≈ 2 × (layers) × (heads_kv) × (head_dim) × bytes_per_elementJika VRAM terlampaui (OOM), latensi inferensi anjlok akibat paging ke RAM sistem, membatasi throughput paralel lokal.
2. Profil Latensi: TTFT vs Inter-Token Latency
- Local SLM (vLLM/Ollama): Menghilangkan RTT (Round Trip Time) jaringan internet. Time To First Token (TTFT) sangat rendah (biasanya <50ms untuk prompt pendek) selama komputasi GPU lokal tidak mengalami antrean.
- Cloud Frontier API: Memiliki latensi jaringan internet tambahan (100–300ms baseline), ditambah waktu antrean multi-tenant penyedia. Namun, generation speed (tokens per second) sering kali lebih stabil untuk context window sangat besar (>32k token).
Pola Routing Berdasarkan Kompleksitas Tugas
Mekanisme penentuan jalur (routing) dapat dieksekusi melalui beberapa pendekatan:
- Heuristik Berbasis Aturan: Memeriksa panjang context, format output yang diharapkan (JSON murni vs analisis mendalam), atau metadata endpoint pengguna. Pendekatan ini memiliki overhead komputasi mendekati nol.
- Small Classifier/Embedding: Menggunakan model embedding atau fast classifier lokal (misal: DeBERTa/FastText) untuk memprediksi intent kompleks sebelum mengirim ke LLM utama.
Implementasi Semantic Proxy Router (Python)
Berikut implementasi proxy router asinkron berbasis FastAPI dan HTTP client (httpx). Sistem mengevaluasi kompleksitas input, merutekan tugas sederhana ke engine lokal, dan melakukan otomatis fallback ke Cloud API jika terjadi kegagalan sistem lokal.
import os
import time
import httpx
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI(title="Hybrid LLM Router")
LOCAL_LLM_URL = os.getenv("LOCAL_LLM_URL", "http://localhost:11434/api/generate")
CLOUD_LLM_URL = os.getenv("CLOUD_LLM_URL", "https://api.anthropic.com/v1/messages")
CLOUD_API_KEY = os.getenv("ANTHROPIC_API_KEY", "")
class QueryRequest(BaseModel):
prompt: str
force_cloud: bool = False
def is_complex_task(prompt: str) -> bool:
# Heuristik evaluasi kompleksitas task
triggers = ["analisis mendalam", "refactor architecture", "prove theorem", "synthesize"]
if len(prompt.split()) > 350:
return True
return any(trigger in prompt.lower() for trigger in triggers)
async def call_local_engine(client: httpx.AsyncClient, prompt: str) -> str:
payload = {
"model": "qwen2.5:7b",
"prompt": prompt,
"stream": False
}
resp = await client.post(LOCAL_LLM_URL, json=payload, timeout=8.0)
resp.raise_for_status()
return resp.json().get("response", "")
async def call_cloud_engine(client: httpx.AsyncClient, prompt: str) -> str:
headers = {
"x-api-key": CLOUD_API_KEY,
"anthropic-version": "2023-06-01",
"content-type": "application/json"
}
payload = {
"model": "claude-3-opus-20240229",
"max_tokens": 1024,
"messages": [{"role": "user", "content": prompt}]
}
resp = await client.post(CLOUD_LLM_URL, headers=headers, json=payload, timeout=30.0)
resp.raise_for_status()
return resp.json()["content"][0]["text"]
@app.post("/v1/chat")
async def route_inference(req: QueryRequest):
start_time = time.perf_counter()
routed_target = "local"
async with httpx.AsyncClient() as client:
# Tentukan rute eksekusi
if req.force_cloud or is_complex_task(req.prompt):
routed_target = "cloud"
try:
content = await call_cloud_engine(client, req.prompt)
except Exception as e:
raise HTTPException(status_code=502, detail=f"Cloud provider error: {str(e)}")
else:
try:
content = await call_local_engine(client, req.prompt)
except (httpx.RequestError, httpx.HTTPStatusError):
# Fallback ke cloud jika engine lokal down/OOM
routed_target = "cloud-fallback"
content = await call_cloud_engine(client, req.prompt)
duration = time.perf_counter() - start_time
return {
"response": content,
"target": routed_target,
"latency_ms": round(duration * 1000, 2)
}Operasional dan Maintainability
Memilih batas antara model lokal dan managed API bergantung pada beban kerja operasional tim Anda:
- Engine Lokal (Self-Hosted): Memerlukan observability mendalam terhadap alokasi VRAM, continuous batching scheduler (vLLM PagedAttention), dan penanganan worker crash. Kegagalan umum meliputi degradasi latensi bertahap akibat KV Cache fragmentation saat concurrent request melonjak.
- Cloud Managed API: Beban operasional zero-infra, tetapi rentan terhadap rate limiting (429 Too Many Requests), perubahan perilaku model antar-versi tanpa pemberitahuan, serta biaya per-token yang tidak dapat diprediksi saat lalu lintas melonjak tajam.
Rekomendasi Praktis: Tetapkan batas 80/20. Terapkan model lokal (7B–14B) untuk menangani setidaknya 80% lalu lintas query internal dan rutin, alokasikan sisa 20% query penalaran kritis ke model frontier berbayar.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!