Tutorial Layer-First Pattern: Mengurangi Overhead LLM dengan In-Memory Mapping
ND
Naufal Dev

Dipublikasikan 5 Juli 2026

Tutorial Layer-First Pattern: Mengurangi Overhead LLM dengan In-Memory Mapping

Salah satu masalah besar saat membangun aplikasi berbasis LLM adalah biaya token yang membengkak ketika model harus menjadi pipa data. Bayangkan kamu membangun sistem mapping yang mengolah wildfire data dan trail routes untuk dikirim ke user via SMS. GeoJSON untuk wildfire perimeter saja bisa mencapai 500KB, atau sekitar 125.000 token ketika dihitung dengan rasio 4 bytes per token. Melewatkan data sebesar itu melalui context window LLM adalah pemborosan yang signifikan, baik dari sisi biaya maupun latency. Artikel ini membahas layer-first pattern yang saya pelajari dari implementasi RidgeText, sebuah platform SMS AI yang berhasil mengurangi token overhead dari ratusan ribu menjadi ratusan saja.

Masalah: LLM sebagai Pipa Data

Pendekatan naif untuk sistem mapping berbasis LLM kira-kira seperti ini: LLM memanggil tool get_wildfire_data(), menerima 2.000 polygon GeoJSON, lalu meneruskannya ke tool render_map(). Masalahnya, LLM tidak bisa menyederhanakan GeoJSON tanpa kehilangan informasi penting, tidak bisa memvalidasi geometri dengan akurat, dan tetap membayar full context cost setiap kali tool dipanggil. LLM menjadi pipa data, bukan reasoning engine. Dalam arsitektur ini, LLM justru menjadi bottleneck karena context window-nya terisi oleh data mentah yang seharusnya tidak perlu ia pegang.

Langkah 1: Pahami Layer-First Architecture

Pattern ini terinspirasi dari cara kerja Mapbox: data source menyediakan data mentah, layer mendefinisikan cara merender data tersebut, dan layer dikomposit dalam declaration order. Bedanya, kita menjalankan abstraction ini di server-side, bukan di browser client. Hasil akhirnya adalah satu gambar map yang bisa dikirim ke user melalui SMS atau ditampilkan di aplikasi.

Alih-alih mengembalikan GeoJSON ke LLM, setiap data-fetching tool menyimpan hasilnya di server dan hanya mengembalikan acknowledgment ringan ke LLM. Berikut contoh interaksi yang ideal:

LLM calls retrieve_wildfire_layer(location: "Cascades")
-> { status: "queued", layerId: "wildfires-0", featureCount: 847 }

LLM calls retrieve_trail_layer(trailName: "PCT Section J")
-> { status: "queued", layerId: "trail-1", featureCount: 1 }

LLM calls generate_map()
-> { mapUrl: "https://cdn.example.com/map-abc123.jpg" }

Dengan pendekatan ini, LLM hanya melihat sekitar 150 token dari tool results, bukan 125.000+ token GeoJSON mentah. Penghematan ini sangat berarti, terutama untuk aplikasi production yang menangani banyak request per hari.

Langkah 2: Implementasi In-Memory Layer Queue

Buat ordered layer array yang disimpan dalam request context. Di Node.js, kamu bisa menggunakan in-process Map yang di-key oleh session ID dengan TTL 30 menit. Setiap panggilan retrieve_* menambahkan layer ke queue:

interface MapLayer {
  type: 'wildfire-perimeters' | 'trail' | 'heatmap';
  data: GeoJSON.FeatureCollection;
  style: LayerStyle;
}

const layerQueue: MapLayer[] = [];

Method generate_map membaca queue dalam insertion order, mengkomposit setiap layer di atas base map dari Mapbox Static API, lalu menghasilkan satu image URL. Layer yang di-queue lebih dulu akan berada di bawah layer yang di-queue belakangan, persis seperti perilaku CSS z-index atau Mapbox layer stack. Kamu bisa menggunakan library seperti sharp untuk komposit gambar secara efisien di server.

Langkah 3: Desain Tool yang LLM-Friendly

Tool design untuk LLM harus mengikuti prinsip fundamental: jika LLM tidak membuat keputusan berdasarkan konten data, ia tidak perlu memegang data tersebut. Acknowledgment yang dikembalikan ke LLM harus cukup informatif untuk memungkinkan reasoning (contoh: featureCount memberi gambaran seberapa kompleks dataset-nya), tapi tidak perlu mengandung geometri lengkap.

Layer ordering dikontrol secara implisit oleh urutan tool call. Jika LLM memanggil retrieve_satellite_base sebelum retrieve_trail, maka trail akan digambar di atas satellite imagery secara otomatis. Pendekatan ini natural bagi LLM karena tidak membutuhkan parameter ordering eksplisit yang bisa membingungkan model.

Langkah 4: Render Pipeline yang Deterministik

Fungsi generate_map harus deterministik dan terpisah dari LLM. Ia tidak menerima GeoJSON dari LLM, hanya parameter opsional seperti zoom level atau map style. Implementasinya bisa seperti ini:

async function generateMap(options: MapOptions): Promise<string> {
  const layers = drainLayerQueue();
  const base = await fetchMapboxBase(options);
  const composed = await compositeLayers(base, layers);
  return await uploadToStorage(composed);
}

Karena render pipeline terpisah dari LLM, kamu bisa mengujinya secara independen tanpa perlu memanggil model sama sekali. Tambahkan unit test untuk setiap layer type, uji berbagai kombinasi layer, dan pastikan output gambar selalu konsisten. Ini adalah salah satu keuntungan utama dari pattern ini: separasi concern yang jelas antara orchestration (LLM) dan execution (render pipeline).

Langkah 5: Identifikasi Kasus Lain untuk Pattern Ini

Signal bahwa pattern ini dibutuhkan di sistemmu: Tool A mengambil data, LLM menerimanya, lalu LLM meneruskannya langsung ke Tool B tanpa melakukan transformasi atau reasoning berarti. Jika LLM tidak membuat keputusan berdasarkan konten, ia tidak perlu memegang konten tersebut.

Beberapa skenario lain di mana layer-first pattern bisa diterapkan:

  • Multi-source data enrichment: Setiap retrieval tool mengantri dataset server-side. Compositor menggabungkan data berdasarkan station ID. LLM hanya menerima summary berisi jumlah record dan ketersediaan field.

  • Log analysis: Log fetch berjalan sekali dan menyimpan hasil di temporary storage. Error-count tool dan root-cause tool membaca dari dataset yang sama secara independen. LLM tidak perlu melihat raw log lines.

  • ETL pipeline: LLM memutuskan source apa yang diambil dan mendeskripsikan hasil akhirnya, tapi tidak ikut dalam merge operation. Intermediate state antara source A dan source B berada di pipeline, bukan di context window.

Tradeoff yang Perlu Diperhatikan

Pattern ini bukan tanpa kekurangan. Pertama, LLM tidak bisa lagi melakukan reasoning tentang geometri underlying dari layer yang di-queue. Pertanyaan seperti kota terdekat dari trail ini tidak bisa dijawab dari queued layer data. Solusinya adalah menyediakan tool terpisah yang mengembalikan jawaban sebagai structured text tanpa melewatkan geometri penuh.

Kedua, layer queue bersifat ephemeral untuk satu LLM turn saja. Jika user meminta refinement multi-turn seperti zoom in atau ganti style, kamu perlu menyimpan layer reference ke database agar bisa di-rehydrate tanpa re-fetching dari API asli. Implementasi persistent queue memang menambah kompleksitas, tapi sangat diperlukan untuk UX yang mulus.

Kesimpulan

Layer-first pattern mengubah LLM dari pipa data menjadi orchestrator murni. Dengan menyimpan intermediate state di server dan hanya mengirim acknowledgment ringan ke LLM, kamu menghemat token secara drastis, meningkatkan reliability, dan membuat render pipeline lebih mudah diuji. Pattern ini tidak spesifik untuk mapping: ia berlaku untuk setiap sistem di mana LLM seharusnya mengatur alur kerja, bukan mengangkut data mentah.

Sumber referensi: RidgeText Blog: Mapping with In-Memory Layers to Reduce LLM Overload.