Arsitektur AI Modern: End-to-End
Dari query user pertama hingga response tersimpan ke database. Panduan lengkap layer, tools, request flow, learning roadmap, dan penerapan nyata di production — termasuk Google ADK yang baru rilis.
- Arsitektur AI Modern: End-to-End
- Mengapa Perlu Memahami Ini?
- Layer Stack — 8 Lapisan Arsitektur
- Request Flow — Perjalanan Satu Query
- Konsep Fundamental
- 4.1 ReAct Loop — Pola Dasar Semua Agent
- 4.2 Context Window — Apa yang Dilihat LLM
- 4.3 RAG Pipeline — Cara Kerja Detail
- 4.4 Tool Calling — Mekanisme Lengkap
- 4.5 Structured Output — Dari Teks ke Data
- 4.6 Observability dengan LangFuse
- Google ADK — Framework Multi-Agent Baru
- ADK vs Framework Lain
- Format Response AI di Production
- Learning Roadmap — 8 Minggu
- Production Readiness Checklist
- SCHEMA
- DELIVERY
- ERROR HANDLING
- OBSERVABILITY
- SECURITY
Arsitektur AI Modern: End-to-End
Dari query user pertama hingga response tersimpan ke database. Panduan lengkap layer, tools, request flow, learning roadmap, dan penerapan nyata di production — termasuk Google ADK yang baru rilis.
PRINSIP UTAMA
Yang membuat AI sistem production-grade bukan kualitas model — tapi kualitas arsitektur di sekitar model. Model bisa diganti kapan saja. Arsitektur yang baik tetap solid.
Mengapa Perlu Memahami Ini?
LLM hanya bisa melakukan satu hal: text in → text out. Ia tidak bisa ingat percakapan sebelumnya, akses database, eksekusi kode, atau ambil keputusan multi-step. Semua "kecanggihan" AI yang kamu lihat di production bukan karena model-nya pintar sendirian — tapi karena ada arsitektur di sekitar model yang mengkoordinasikan semua kemampuan itu.
Memahami arsitektur ini memberi kamu kemampuan untuk: memilih tool yang tepat untuk problem yang tepat, mendesain sistem AI yang bisa di-maintain, dan debug ketika sesuatu tidak bekerja seperti yang diharapkan.
Layer Stack — 8 Lapisan Arsitektur
Sistem AI modern terdiri dari 8 layer yang bekerja bersama. Klik setiap layer di bawah ini untuk melihat detail penjelasan dan tools-nya.
Request Flow — Perjalanan Satu Query
Berikut adalah perjalanan lengkap satu query user dari awal hingga response diterima. Tidak ada step yang terjadi secara ajaib — semuanya eksplisit dan bisa di-trace.
Konsep Fundamental
Sebelum masuk ke framework spesifik, ini 6 konsep yang harus benar-benar dipahami. Semua framework — LangGraph, Google ADK, CrewAI — dibangun di atas konsep ini.
4.1 ReAct Loop — Pola Dasar Semua Agent
ReAct (Reason + Act) adalah pola fundamental yang dipakai semua agentic framework. Agent loop ini terus berulang sampai agent yakin jawabannya cukup.
POIN KUNCI
Tool calling bukan magic. LLM output JSON descriptor {"name": "check_stock", "args": {...}}. Orchestration layer yang eksekusi Python function-nya, inject hasilnya kembali ke context, lalu LLM dipanggil lagi. Ini satu cycle ReAct.
4.2 Context Window — Apa yang Dilihat LLM
LLM adalah fungsi matematika: . Tidak ada memori, tidak ada state. Setiap call, ia membaca seluruh context dari awal. Semua "pengetahuan" LLM dalam satu request ada di dalam context window ini.
| Komponen | Isi | Token Budget | Sumber |
|---|---|---|---|
| System prompt | Identitas, aturan, format output, batasan | 200–2.000 | hardcoded oleh developer |
| Retrieved docs | Chunk relevan dari vector DB | 500–4.000 | RAG pipeline |
| Memory | Fakta dari sesi sebelumnya | 100–500 | Mem0 / Redis |
| Tool schema | JSON descriptor semua tool yang tersedia | 200–800 | tool registry |
| History | Turn percakapan sebelumnya | 500–8.000 | conversation state |
| User query | Query saat ini | 50–200 | user input |
| Total | — | ~4k–15k | — |
LOST-IN-THE-MIDDLE PROBLEM
LLM lebih "perhatian" ke awal dan akhir context. Taruh instruksi penting di system prompt (awal) dan user query tepat sebelum generate (akhir). Retrieved chunks di tengah rawan diabaikan kalau terlalu banyak.
4.3 RAG Pipeline — Cara Kerja Detail
RAG terdiri dari dua fase yang terpisah: Indexing (offline, sekali jalan) dan Retrieval (online, setiap request).
INDEXING (Offline — Sekali Jalan)
📥 Load dokumen 🔍 Parse (Docling) ✂️ Chunk (~512 token, 50 overlap) 🧮 Embed (OpenAI / Jina) 💾 Store (pgvector / Qdrant)
RETRIEVAL (Online — Setiap Request)
🗣️ User query 🧮 Embed query 🔍 Similarity search (top-100) 📊 Rerank (Cohere) top-5 💉 Inject ke context
| Situasi | Pakai RAG? | Alasan |
|---|---|---|
| Q&A atas dokumen internal (SOP, katalog) | Ya (Hijau) | Data tidak ada di training LLM |
| Data real-time (harga, stok sekarang) | Tool call (Kuning) | Perlu query DB langsung, bukan RAG |
| Pertanyaan umum (cara pakai Python) | Tidak (Abu-abu) | LLM sudah tahu |
| Compliance & audit trail | Ya (Hijau) | Harus bisa cite sumber spesifik |
| Inventory forecasting + live data | Hybrid (Biru) | RAG untuk historical docs, tool call untuk data live |
4.4 Tool Calling — Mekanisme Lengkap
Ini yang membuat LLM bisa berinteraksi dengan dunia nyata. Bukan magic — ini sequence yang eksplisit dan deterministic dari sisi orchestration.
# Step 1: Define tool sebagai Python function biasa
@tool
def check_inventory(product_id: str) -> dict:
"""Cek stok produk dari database. Args: product_id (str)"""
return db.query("SELECT * FROM products WHERE id = %s", product_id)
# Step 2: LLM menerima tool schema di context
# {"name": "check_inventory", "description": "Cek stok...", "parameters": {...}}
# Step 3: LLM output (bukan eksekusi!) — JSON tool call
# {"type": "tool_call", "name": "check_inventory", "args": {"product_id": "A"}}
# Step 4: Orchestration layer eksekusi fungsi Python
result = check_inventory(product_id="A") # {"stock": 142, "safety_stock": 200}
# Step 5: Inject hasil sebagai tool_result ke context
# {"type": "tool_result", "content": {"stock": 142, "safety_stock": 200}}
# Step 6: LLM dipanggil LAGI dengan context lengkap + tool result
# Kali ini LLM bisa generate jawaban final berdasarkan data nyata4.5 Structured Output — Dari Teks ke Data
Tanpa structured output, LLM adalah sumber teks. Dengan structured output, LLM menjadi fungsi yang bisa dipanggil seperti API — output-nya langsung bisa diproses kode tanpa parsing manual.
import instructor
from pydantic import BaseModel, Field
from typing import Literal
# 1. Define schema yang diinginkan
class InventoryAlert(BaseModel):
product_id: str
current_stock: int = Field(ge=0)
status: Literal["ok", "low", "critical", "stockout"]
reorder_suggested: bool
suggested_quantity: int | None = None
reason: str = Field(max_length=200)
# 2. Instructor wrap LLM client
client = instructor.from_anthropic(Anthropic())
# 3. Response langsung berupa Python object — bukan string
alert = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=500,
response_model=InventoryAlert, # inject schema ke tool calling
messages=[{"role": "user", "content": context}]
)
# alert.status == "low" — type-safe, langsung pakai
if alert.reorder_suggested:
trigger_purchase_order(alert.product_id, alert.suggested_quantity)KENAPA INSTRUCTOR, BUKAN JSON MODE?
JSON mode hanya menjamin output adalah valid JSON — schema field masih bisa hilang atau salah tipe. Instructor inject Pydantic schema ke tool calling mechanism, validasi output, dan auto-retry 3x kalau output tidak sesuai schema. Ini yang bikin reliable di production.
4.6 Observability dengan LangFuse
LangFuse adalah observability layer khusus AI — analoginya Grafana untuk infra, tapi untuk LLM calls. Hierarki datanya: Trace (satu end-to-end request) Span (unit kerja) Generation (satu LLM call) Score (evaluasi).
# Cara paling simple: LiteLLM integration (1 baris)
import os
os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..."
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..."
litellm.success_callback = ["langfuse"] # semua LLM call auto-traced
# Atau via decorator untuk custom spans
from langfuse.decorators import observe
@observe(name="inventory-analysis")
def analyze_inventory(query: str) -> str:
chunks = retrieve_docs(query) # jadi child span
answer = generate_answer(query, chunks) # jadi child span
return answer
# Yang di-capture per generation:
# latency, input/output tokens, cost, faithfulness score, user feedbackGoogle ADK — Framework Multi-Agent Baru
GOOGLE AGENT DEVELOPMENT KIT
Framework open-source dari Google untuk build, test, dan deploy AI agent. Native Gemini, tapi support model lain. Dirancang untuk multi-agent production use case dengan protocol A2A (Agent-to-Agent).
| Komponen | Fungsi | Analogi ke LangGraph |
|---|---|---|
| Agent | Unit dasar. LlmAgent (reasoning) atau WorkflowAgent (deterministic) | Node dalam graph |
| Tools | Python function yang bisa dipanggil agent. Auto-convert ke function calling schema | Tool dalam LangGraph |
| Runner | Engine yang eksekusi agent loop | graph.invoke() |
| Session | State per user conversation, persistent | Checkpointer |
| A2A Protocol | Agent-to-Agent communication. Sub-agent bisa dipanggil sebagai tool | Subgraph |
| Deployment | Local dev, Vertex AI (managed), atau self-hosted ADK server | LangGraph Cloud / self-host |
from google.adk.agents import LlmAgent
from google.adk.tools import tool
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
# 1. Define tool
@tool
def check_stock(product_id: str) -> dict:
"""Cek stok produk dari inventory database"""
return db.get_stock(product_id)
# 2. Create agent
inventory_agent = LlmAgent(
name="inventory-analyst",
model="gemini-2.0-flash",
tools=[check_stock],
instruction="Kamu adalah analis inventory. Bantu user memahami kondisi stok."
)
# 3. Run
session_service = InMemorySessionService()
runner = Runner(agent=inventory_agent, session_service=session_service)
response = runner.run(
user_id="user_123",
session_id="session_abc",
message="Berapa stok produk A sekarang?"
)ADK vs Framework Lain
| Framework | Kelebihan | Trade-off | Pilih kalau |
|---|---|---|---|
| Google ADK | Multi-agent native, Vertex AI, A2A protocol | Python only, community kecil | Butuh multi-agent production-grade di Google Cloud |
| LangGraph | Mature, graph state machine, checkpointing | Abstraksi tebal, LangChain dep | Complex stateful agent, human-in-the-loop |
| CrewAI | Intuitive, role-based, cepat prototype | Kurang fleksibel untuk complex flow | Prototype cepat, workshop |
| Pydantic AI | Type-safe, minimal, Pythonic | Ekosistem terbatas | Simple agent dengan type safety ketat |
Format Response AI di Production
Format response yang baik bukan tentang estetika — tapi tentang predictability, parsability, dan contract yang tidak berubah saat model di-update.
Untuk data pipeline, background job, analisis dokumen. Type-safe penuh via Instructor + Pydantic.
class InventoryInsight(BaseModel):
product_id: str
action: Literal["reorder", "hold", "liquidate"]
urgency: Literal["immediate", "this_week", "this_month"]
confidence: float = Field(ge=0.0, le=1.0)
suggested_quantity: int | None = None
insight = client.messages.create(
response_model=InventoryInsight,
messages=[{"role": "user", "content": context}]
)
# insight.action == "reorder" — langsung gunakan, no parsingUntuk chat interface. SSE (Server-Sent Events) via FastAPI. TTFT (Time to First Token) < 500ms untuk perceived performance yang baik.
@app.post("/chat/stream")
async def chat_stream(request: ChatRequest):
async def generate():
with client.messages.stream(
model="claude-sonnet-4-6",
messages=request.messages
) as stream:
for text in stream.text_stream:
yield f"data: {json.dumps({'token': text})}\n\n"
yield "data: [DONE]\n\n"
return StreamingResponse(generate(), media_type="text/event-stream",
headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"})Wrapper metadata di sekitar setiap AI response. Penting untuk observability, audit trail, dan debugging production.
class AIResponse[T](BaseModel):
request_id: str # untuk tracing
trace_id: str | None # LangFuse trace ID
model: str
latency_ms: int
input_tokens: int
output_tokens: int
cost_usd: float
data: T # payload utama (InventoryInsight, dll)
confidence: float
fallback_used: bool = False
retry_count: int = 0
context_sources: list[str] = [] # chunk ID dari RAG (audit trail)
generated_at: datetimeAI endpoint gagal dengan cara berbeda dari API biasa. Perlu error taxonomy khusus dengan retryable flag agar frontend bisa handle dengan benar.
class AIErrorCode(str, Enum):
VALIDATION_FAILED = "validation_failed" # Instructor retry habis
CONTEXT_TOO_LONG = "context_too_long" # melebihi context window
MODEL_UNAVAILABLE = "model_unavailable" # semua provider down
RATE_LIMITED = "rate_limited" # quota habis
TIMEOUT = "timeout" # inference terlalu lama
class AIErrorResponse(BaseModel):
error_code: AIErrorCode
retryable: bool # True = rate_limited/timeout; False = validation
retry_after_seconds: int | None
request_id: strLearning Roadmap — 8 Minggu
Urutan belajar yang optimal berdasarkan dependency antar konsep. Tidak ada shortcut — tiap minggu membangun fondasi untuk minggu berikutnya.
Pahami cara panggil LLM via API, perbedaan model, token pricing. Kuasai Instructor + Pydantic — ini fondasi semua tool AI lainnya. Tanpa ini, kamu tidak akan bisa debug masalah di layer atasnya.
Bungkus LLM call dalam REST API pakai FastAPI. Tambah LiteLLM untuk routing multi-provider. Implement streaming endpoint. Deploy via Docker. Skill ini langsung masuk ke CV dan bisa langsung dipakai di project nyata.
Bangun sistem Q&A atas dokumen. Ingest PDF chunk embed store di pgvector retrieve rerank inject ke prompt. LlamaIndex handle orchestration pipeline-nya. Ini skill yang paling banyak dicari di job posting AI.
Bangun agent yang bisa reason, memanggil tool (search, SQL, API), dan loop sampai task selesai. LangGraph adalah graph state machine untuk agent workflow kompleks. Pelajari checkpointing dan human-in-the-loop pattern.
Integrasikan LangFuse ke semua LLM call. Track latency, token cost, kualitas output per request. Setup RAGAS untuk evaluasi RAG pipeline. Tanpa ini kamu buta di production. Self-hosted gratis, UI bagus, integrate dengan K8s.
Pelajari Google ADK untuk orchestrasi multi-agent di atas Gemini. Konsep: sub-agent, tool registry, session management, A2A protocol. Cocok untuk portofolio karena paling baru dan makin banyak dicari employer yang pakai Google Cloud.
Gabungkan semua konsep dalam satu project yang bisa di-demo. Contoh: inventory Q&A agent — user tanya natural language agent RAG + query DB + generate insight stream response. Deploy ke K8s dengan LangFuse tracing aktif.
PRIORITY STACK V1
FastAPI + LiteLLM + LlamaIndex + LangGraph + pgvector + LangFuse + Instructor. Ini cukup untuk 90% job requirement AI engineer level mid. Kuasai 7 tool ini production-depth sebelum expand ke yang lain.
Production Readiness Checklist
Gunakan ini sebelum deploy AI feature ke production. Setiap item yang terlewat adalah potensi incident.
SCHEMA
- Semua field typed, tidak ada
dictatauAny - Field nullable di-mark
Optional/Noneeksplisit - Field numerik punya constraint (
ge=0,le=1.0, dll) -
LiteralatauEnumuntuk field yang nilainya terbatas
DELIVERY
- Batch endpoint untuk data pipeline (JSON + Pydantic)
- Streaming endpoint untuk chat interface (SSE)
- SSE header benar:
Cache-Control: no-cache,X-Accel-Buffering: no - Timeout di-set (bukan infinite wait)
- Max tokens di-set eksplisit di setiap LLM call
ERROR HANDLING
- Validation error ter-catch sebelum masuk DB
- Retry logic ada (Instructor 3x default, atau manual)
- Error response punya
retryableflag -
request_idada di setiap response untuk tracing - Fallback provider dikonfigurasi di LiteLLM
OBSERVABILITY
-
trace_idlink ke LangFuse di setiap response -
latency_msdi-log per request - Input/output tokens di-log untuk cost monitoring
-
context_sources(chunk ID dari RAG) di-log untuk audit trail - PII masking dikonfigurasi di LangFuse sebelum go-live
SECURITY
- Prompt injection protection — validasi input user sebelum masuk ke system prompt
- Rate limiting per user / per endpoint
- API key tidak hardcoded — gunakan env var atau secret manager
- Output validation — AI output yang masuk ke DB harus melalui Pydantic
FastAPI · LiteLLM · LlamaIndex · LangGraph
pgvector · LangFuse · Instructor · Kubernetes