Home Blog Series C C02
Series C: Prompt / Context / Harness / Loop Engineering · C02 AI & Agentic Systems 20 Oktober 2025 10 min read

Context Window Engineering — Apa yang Masuk, Apa yang Dibuang

Context window bukan hanya tentang panjang chat — tapi keputusan aktif apa yang masuk. Sliding window, relevance threshold, dan semantic caching untuk efisiensi biaya.

RM
Ryan Muliadi
Digital Systems Architect · Ryzen Digital Systems

Context window adalah "working memory" LLM — dan seperti working memory manusia, kapasitasnya terbatas. Yang membedakan developer biasa dan yang mahir adalah kemampuan memilih apa yang masuk dan apa yang dibuang dari window tersebut.

Context Window — Bukan Sekedar "Panjang Chat"

Definisi
Context window adalah total token yang bisa "dilihat" LLM dalam satu inferensi: system prompt + conversation history + retrieved documents + tool results + user message + expected output. Semua dihitung.
ModelContext WindowBiaya per 1M token (input)Sweet Spot
Claude 3 Haiku200K token$0.25High-volume triage, classification
Claude 3.5 Sonnet200K token$3.00Complex reasoning, agent tasks
GPT-4o mini128K token$0.15Budget-conscious production
GPT-4o128K token$2.50Frontier reasoning
Gemini 1.5 Flash1M token$0.075Very long document processing
Gemini 1.5 Pro2M token$1.25Extreme long-context tasks
⚠️ "Context Panjang = Tidak Perlu RAG" adalah Mitos

Walaupun Gemini bisa handle 2M token, memasukkan semua dokumen ke context bukan solusi yang baik: (1) biaya token sangat mahal, (2) LLM mengalami "lost in the middle" — attention berkurang untuk konten di tengah context window yang sangat panjang. RAG masih lebih efisien untuk sebagian besar use case.

Token Counting — Perlu Tahu Ini

Satu token ≈ 0.75 kata dalam Bahasa Inggris. Untuk Bahasa Indonesia, ratio-nya sedikit berbeda karena tokenizer dilatih lebih banyak dari data Inggris:

Python · Token Counter Praktis
import tiktoken  # pip install tiktoken

def count_tokens(text: str, model: str = "gpt-4o") -> int:
    enc = tiktoken.encoding_for_model(model)
    return len(enc.encode(text))

# Estimasi biaya sebelum run
def estimate_cost(messages: list, model: str = "claude-3-5-sonnet") -> float:
    PRICE_PER_M = {
        "claude-3-5-sonnet": 3.0,
        "claude-3-haiku": 0.25,
        "gpt-4o": 2.5,
        "gpt-4o-mini": 0.15,
    }
    total_tokens = sum(count_tokens(m["content"]) for m in messages)
    price = PRICE_PER_M.get(model, 1.0)
    return (total_tokens / 1_000_000) * price

# Rule of thumb untuk Bahasa Indonesia:
# 1000 kata Indonesia ≈ 1500-2000 token (lebih dari Inggris)
# PDF 10 halaman teks ≈ 5000-8000 token

Apa yang Masuk, Apa yang Dibuang

Ini keputusan terpenting dalam context engineering — setiap token yang masuk adalah biaya dan "perhatian" LLM yang terbagi:

01
System prompt — hanya yang relevan untuk sesi ini
Jangan masukkan semua dokumentasi produk ke system prompt. Hanya persona, rules, dan output format. Informasi spesifik domain → masuk via RAG saat diperlukan, bukan di system prompt.
02
Conversation history — sliding window, bukan semua
Untuk chatbot, jangan kirim seluruh history dari awal sesi. Gunakan sliding window (5–10 pesan terakhir) plus summary dari pesan lebih lama. Ini menghemat 60–80% token untuk sesi yang panjang.
03
RAG context — filter sebelum masuk
Jangan masukkan semua chunk yang di-retrieve. Tambahkan relevance threshold: hanya chunk dengan similarity score di atas 0.75 yang masuk. Chunk yang tidak relevan membuat LLM lebih mudah hallucinate.
04
Tool results — truncate yang panjang
Hasil tool (API response, database query) bisa sangat panjang. Buat wrapper yang truncate dan summarize hasil sebelum masuk ke context. LLM tidak butuh seluruh JSON response 50KB — cukup field yang relevan.

Teknik Context Compression

Python · Conversation Summary Pattern
class ContextManager:
    def __init__(self, llm, max_tokens: int = 4000):
        self.llm = llm
        self.max_tokens = max_tokens
        self.summary = ""          # ringkasan sesi
        self.recent_messages = []   # 5-10 pesan terakhir

    def add_message(self, role: str, content: str):
        self.recent_messages.append({"role": role, "content": content})

        # Kalau terlalu panjang, compress history lama ke summary
        if self._total_tokens() > self.max_tokens:
            old_messages = self.recent_messages[:-5]  # semua kecuali 5 terakhir
            self.recent_messages = self.recent_messages[-5:]
            self.summary = self._summarize(old_messages)

    def get_context(self) -> list:
        messages = []
        if self.summary:
            messages.append({
                "role": "system",
                "content": f"Ringkasan percakapan sebelumnya:\n{self.summary}"
            })
        return messages + self.recent_messages

    def _summarize(self, messages: list) -> str:
        return self.llm.invoke(
            f"Buat ringkasan singkat percakapan ini dalam 3-5 kalimat:\n{messages}"
        )

Semantic Caching — Hemat Biaya untuk Query Serupa

Kalau 40% pertanyaan user adalah variasi dari 10 pertanyaan yang sama, Anda bisa cache LLM response dan serve dari cache untuk query yang semantically similar:

Python · Semantic Cache dengan Redis
import numpy as np

class SemanticCache:
    def __init__(self, embedding_model, redis_client, threshold=0.92):
        self.embed = embedding_model
        self.redis = redis_client
        self.threshold = threshold  # similarity threshold untuk cache hit

    def get(self, query: str):
        query_vec = self.embed.encode(query)
        cached = self.redis.hgetall("semantic_cache")

        for cached_query, cached_data in cached.items():
            cached_vec = np.frombuffer(cached_data["embedding"])
            similarity = np.dot(query_vec, cached_vec)  # cosine similarity
            if similarity >= self.threshold:
                return cached_data["response"]  # cache hit!
        return None  # cache miss — perlu call LLM

    def set(self, query: str, response: str):
        query_vec = self.embed.encode(query)
        self.redis.hset("semantic_cache", query, {
            "embedding": query_vec.tobytes(),
            "response": response
        })

Context engineering adalah tentang signal-to-noise ratio. Setiap token yang masuk ke context adalah "perhatian" LLM yang harus dibagi. Lebih sedikit noise = output yang lebih fokus dan lebih murah.

Kesimpulan

Context window bukan hanya soal "berapa panjang chat yang bisa ditampung" — tapi soal keputusan aktif apa yang masuk dan apa yang tidak. Sliding window untuk history, relevance threshold untuk RAG, truncation untuk tool results, dan semantic caching untuk efisiensi biaya adalah empat teknik yang langsung bisa diterapkan.