Back to News/Arsitektur AI Modern: End-to-End

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.

Faisal Affan
5/28/2026

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.

👤 User queryREST / UI / Voice / CLI🔌 Model GatewayLiteLLM — routing, fallback, cost tracking🔗 Orchestration / AgentLangGraph · LlamaIndex · Google ADK · CrewAI📄 RAG PipelineRetrieve → Rerank → Inject🧩 MemoryMem0 · Zep · Redis🧰 ToolsSearch · SQL · Browser · API⚡ LLM InferenceContext: query + docs + memory + tool results📊 LangFusetrace + eval🎯 Structured OutputInstructor + Pydantic validation + retry✅ ResponseJSON / stream / markdown① ENTRY② ROUTING③ ORCHESTRATION④ INFERENCE⑤ OUTPUT
Request flow end-to-end — setiap step bisa di-trace via LangFuse

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.

User querymasuk ke agent loop① ReasonLLM pikirkan langkah berikutnyaDone?Cukup info?Ya →Final Responsegenerate jawaban ke userTidak② ActPanggil tool / query DB / search webTooleksekusi③ Observeinject ke contextloop kembali
ReAct loop — semua agentic framework mengimplementasikan pola ini

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: f(tokens_in)probability_distribution(tokens_out)f(\text{tokens\_in}) \rightarrow \text{probability\_distribution}(\text{tokens\_out}). 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.

KomponenIsiToken BudgetSumber
System promptIdentitas, aturan, format output, batasan200–2.000hardcoded oleh developer
Retrieved docsChunk relevan dari vector DB500–4.000RAG pipeline
MemoryFakta dari sesi sebelumnya100–500Mem0 / Redis
Tool schemaJSON descriptor semua tool yang tersedia200–800tool registry
HistoryTurn percakapan sebelumnya500–8.000conversation state
User queryQuery saat ini50–200user 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 \rightarrow 🔍 Parse (Docling) \rightarrow ✂️ Chunk (~512 token, 50 overlap) \rightarrow 🧮 Embed (OpenAI / Jina) \rightarrow 💾 Store (pgvector / Qdrant)


RETRIEVAL (Online — Setiap Request)

🗣️ User query \rightarrow 🧮 Embed query \rightarrow 🔍 Similarity search (top-100) \rightarrow 📊 Rerank (Cohere) \rightarrow top-5 \rightarrow 💉 Inject ke context

SituasiPakai 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 trailYa (Hijau)Harus bisa cite sumber spesifik
Inventory forecasting + live dataHybrid (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 nyata

4.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) \rightarrow Span (unit kerja) \rightarrow Generation (satu LLM call) \rightarrow 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 feedback

Google 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).

KomponenFungsiAnalogi ke LangGraph
AgentUnit dasar. LlmAgent (reasoning) atau WorkflowAgent (deterministic)Node dalam graph
ToolsPython function yang bisa dipanggil agent. Auto-convert ke function calling schemaTool dalam LangGraph
RunnerEngine yang eksekusi agent loopgraph.invoke()
SessionState per user conversation, persistentCheckpointer
A2A ProtocolAgent-to-Agent communication. Sub-agent bisa dipanggil sebagai toolSubgraph
DeploymentLocal dev, Vertex AI (managed), atau self-hosted ADK serverLangGraph 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

FrameworkKelebihanTrade-offPilih kalau
Google ADKMulti-agent native, Vertex AI, A2A protocolPython only, community kecilButuh multi-agent production-grade di Google Cloud
LangGraphMature, graph state machine, checkpointingAbstraksi tebal, LangChain depComplex stateful agent, human-in-the-loop
CrewAIIntuitive, role-based, cepat prototypeKurang fleksibel untuk complex flowPrototype cepat, workshop
Pydantic AIType-safe, minimal, PythonicEkosistem terbatasSimple 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 parsing

Untuk 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: datetime

AI 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: str

Learning 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.

OpenAI SDKAnthropic SDKInstructorPydantic

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.

FastAPILiteLLMDockerSSE streaming

Bangun sistem Q&A atas dokumen. Ingest PDF \rightarrow chunk \rightarrow embed \rightarrow store di pgvector \rightarrow retrieve \rightarrow rerank \rightarrow inject ke prompt. LlamaIndex handle orchestration pipeline-nya. Ini skill yang paling banyak dicari di job posting AI.

LlamaIndexpgvectorDoclingembeddingsreranking

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.

LangGraphtool callingReActcheckpointing

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.

LangFusetracingRAGASLLM-as-judge

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.

Google ADKGemini 2.0multi-agentA2A protocol

Gabungkan semua konsep dalam satu project yang bisa di-demo. Contoh: inventory Q&A agent — user tanya natural language \rightarrow agent RAG + query DB + generate insight \rightarrow stream response. Deploy ke K8s dengan LangFuse tracing aktif.

full stackK8s deployportfolioproduction-ready

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 dict atau Any
  • Field nullable di-mark Optional / None eksplisit
  • Field numerik punya constraint (ge=0, le=1.0, dll)
  • Literal atau Enum untuk 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 retryable flag
  • request_id ada di setiap response untuk tracing
  • Fallback provider dikonfigurasi di LiteLLM

OBSERVABILITY

  • trace_id link ke LangFuse di setiap response
  • latency_ms di-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

STACK MINIMUM PRODUCTION · v1

FastAPI  ·  LiteLLM  ·  LlamaIndex  ·  LangGraph
pgvector  ·  LangFuse  ·  Instructor  ·  Kubernetes


Related Articles

Arsitektur AI Modern: End-to-End | Faisal Affan