v1.0.0-011 : [DRAFT] Optimasi System Prompt — Native Separation & Ollama Modelfile
Memisahkan system prompt hardcode dari user input menggunakan field API yang tepat (systemInstruction untuk Gemini, system untuk Ollama) dan membuat Ollama Custom Modelfile agar system prompt nol token saat runtime di jalur Ollama.
Setiap request ke LLM saat ini menggabungkan system prompt statis (hardcode ratusan baris) dengan user input dinamis menjadi satu string fullPrompt yang dikirim sekaligus ke model. Pola ini boros token karena system prompt tidak pernah berubah:
| System Prompt | Ukuran | Estimasi Token Terbuang |
|---|---|---|
transactionParser.ts |
~9 KB | ~2.275 token / request |
ocrTool.ts |
~10 KB | ~2.500 token / request |
pricingParser.ts |
~2,4 KB | ~600 token / request |
vibeOrchestrator.ts |
~2 KB | ~500 token / request |
Selain itu, log monitoring di mcp_request_logs menyimpan fullPrompt sehingga isi teks transaksi user tenggelam dan terpotong di tengah ratusan baris system prompt.
Prinsip: Alih-alih menggabungkan menjadi satu string, kirim system prompt dan user input melalui field terpisah yang sudah didukung natively oleh Gemini SDK dan Ollama API.
Gemini — pindah system prompt ke getGenerativeModel:
// SEBELUM (bermasalah):const fullPrompt = `${systemPrompt}\n\nUser: ${prompt}`;const model = genAI.getGenerativeModel({ model: modelName });await model.generateContent(fullPrompt); // dikirim campur jadi satu
// SESUDAH (bersih):const model = genAI.getGenerativeModel({ model: modelName, ...(systemPrompt ? { systemInstruction: systemPrompt } : {})});await model.generateContent(prompt); // hanya user inputOllama — gunakan field system yang sudah ada di API:
// SEBELUM:{ model: modelName, prompt: fullPrompt, stream: false }
// SESUDAH:{ model: modelName, system: systemPrompt || '', prompt: prompt, stream: false }Dampak langsung Tier 1:
- ✅ Log monitoring bersih — hanya menyimpan teks transaksi user
- ✅ Arsitektur lebih benar secara semantik
- ✅ Model memproses system instruction lebih akurat
- ⚠️ Token dihitung tetap sama di Gemini (belum ada penghematan biaya nyata)
Prinsip: Membuat model turunan di VPS Ollama yang sudah “hafal” system prompt via Modelfile. Saat runtime, tidak ada system prompt yang dikirim.
#!/bin/bashcat > /tmp/Modelfile.accounting << 'MODELEOF'FROM qwen2.5:3bSYSTEM """[isi penuh parseTransactionSystemPrompt]"""PARAMETER num_ctx 8192PARAMETER temperature 0.1MODELEOF
docker exec ollama ollama create blonjo-accounting -f /tmp/Modelfile.accountingOLLAMA_ACCOUNTING_MODEL=blonjo-accountingconst accountingModel = process.env.OLLAMA_ACCOUNTING_MODEL;if (accountingModel && ollamaAlive) { // 0 token system — sudah baked ke model return await AiProviderService.generateText(userInput, undefined, 'accounting_bot');} else { // Fallback Tier 1: Gemini dengan systemInstruction return await AiProviderService.generateText(userInput, parseTransactionSystemPrompt, 'accounting_bot');}| Skenario | Token Input Sekarang | Token Input Setelah |
|---|---|---|
| Parse via Gemini (Tier 1) | ~2.325 tok | ~2.325 tok (arsitektur bersih) |
| Parse via Ollama (Tier 1) | ~2.325 tok | ~2.325 tok (arsitektur bersih) |
| Parse via Ollama (Tier 2) | ~2.325 tok | ~50 tok 🎉 |
| Log monitoring | Terpotong ❌ | Input user bersih ✅ |
Request Transaksi: "beli gula 2kg 20rb" │ ├─► Gemini (Tier 1) │ systemInstruction = parseTransactionSystemPrompt [~2.275 tok] │ generateContent("beli gula 2kg 20rb") [~10 tok] │ Log: "beli gula 2kg 20rb" ✅ │ └─► Ollama blonjo-accounting (Tier 2) system = (sudah baked ke model, 0 token dikirim) prompt = "beli gula 2kg 20rb" [~10 tok] Log: "beli gula 2kg 20rb" ✅- Gemini Free Tier: Token masih dihitung di Tier 1. Penghematan nyata di Gemini hanya via Context Caching (butuh billing aktif).
- Model drift Tier 2: Jika
parseTransactionSystemPromptdiupdate di kode tapi model VPS tidak diperbarui → Ollama masih pakai prompt lama. Perlu SOP update. - ocrTool adalah model vision (multimodal) — tidak bisa di-bake ke Ollama text model → cukup Tier 1.
- Kompatibilitas:
systemInstructionsudah didukung di@google/generative-aiv0.3.0+.
- Tier 1 saja atau Tier 1 + Tier 2?
- Selain
transactionParser, apakahpricingParserdanvibeOrchestratorjuga perlu model baked?