Prompt engineering for Bahasa Indonesia
The single biggest differentiator of Epithre models is that they treat Bahasa Indonesia as a first-class language, not a translation target. This guide covers concrete patterns that work specifically well on Indonesian text, and the failure modes we've seen so you don't have to learn them the painful way.
If you've used English-tuned models for Indonesian work before, half of what you're used to is no longer necessary here. The other half still matters.
1. Register matters more than you think
Indonesian has at least four practically-distinct registers your model will respond to differently:
| Register | When to use | Example phrase |
|---|---|---|
| Formal baku | Official docs, government communication, business writing | "Sehubungan dengan permohonan Saudara..." |
| Profesional neutral | News, customer support, B2B emails | "Mohon konfirmasi terkait jadwal..." |
| Casual / sehari-hari | Chat, social, internal team | "Bro, jadinya jadi gak nih?" |
| Code-switched ID-EN | Tech industry, urban Jakarta | "Tolong follow-up sama PIC marketing." |
Set the register explicitly in your system prompt. If you don't, the model will pick based on the user's message, which is usually fine but unpredictable.
# Casual chatbot
system = "Kamu asisten chat yang menjawab pake bahasa sehari-hari, santai, gak baku."
# B2B customer support
system = "Kamu customer support resmi. Gunakan bahasa profesional, sopan, tapi tidak kaku."
# Legal assistant
system = ("Kamu asisten hukum. Gunakan bahasa Indonesia baku. Sebutkan dasar hukum "
"(UU/PP/Permen + nomor + pasal) untuk setiap klaim faktual.")
A common mistake: setting temperature=0.7 and expecting consistent register across turns. Lower to 0.3-0.5 if register stability matters more than variety.
2. Code-switching ID-EN is a real feature
In Indonesian tech / urban contexts, users mix English freely: "Tolong summarize hasil meeting tadi", "Bisa deploy ke staging dulu?", "Update timeline-nya gimana?". Epithre models handle this natively. You don't need to translate or normalize.
But if you want to prevent code-switching (e.g. for formal output), tell the model:
system = ("Jawab dalam bahasa Indonesia baku tanpa istilah Inggris. "
"Kalau ada konsep yang biasanya disebut dalam bahasa Inggris, "
"berikan padanan bahasa Indonesia. Contoh: 'rapat' bukan 'meeting', "
"'tenggat' bukan 'deadline', 'penyebaran' bukan 'deployment'.")
To encourage code-switching (more natural for tech audiences):
system = ("Jawab dalam bahasa Indonesia campur sama istilah Inggris yang umum "
"dipake di industri tech. Boleh pake kata kayak 'deploy', 'meeting', "
"'sprint', 'pull request' tanpa diterjemahin.")
3. Domain registers: legal, medical, finance
Each Indonesian professional domain has its own terminological discipline. The models recognize and reproduce these, but you need to invoke them explicitly.
Legal: use formal markers like "Pasal", "ayat", "huruf", "butir", and cite by full title.
# Bad prompt
user = "Apa hukuman buat penebang hutan ilegal?"
# Good prompt
user = ("Berdasarkan UU 41/1999 tentang Kehutanan, jelaskan ancaman pidana "
"untuk perusakan hutan lindung. Sebutkan pasal yang relevan dan ayat-ayatnya.")
The good prompt gets you back content like "Pasal 50 ayat (3) huruf e jo. Pasal 78 ayat (5)..." which is properly citable. The bad prompt gets you a generic summary that you'd have to fact-check from scratch.
Medical: invoke Permenkes / IDI guidelines, use both Indonesian and Latin terms.
system = ("Kamu asisten edukasi pasien. Sebutkan istilah medis dalam bahasa "
"Indonesia dan Latin (contoh: tekanan darah tinggi / hipertensi / "
"hypertension). WAJIB sertakan disclaimer untuk konsultasi dokter "
"untuk diagnosis atau pengobatan.")
Finance: terms come in three flavors (formal Indonesian, English, Arabic/syariah). Pick one and stick.
# Formal Indonesian banking
system = "Gunakan istilah perbankan Indonesia: 'kredit', 'angsuran', 'tenor', 'cicilan'."
# Syariah banking
system = ("Gunakan istilah perbankan syariah: 'akad murabahah', 'wakalah', "
"'mudharabah', 'wadiah'. Hindari istilah konvensional 'bunga' atau 'kredit'.")
4. Few-shot examples are gold
For any non-trivial Indonesian task, give the model 2-3 input/output pairs. Indonesian is full of regional variation, register ambiguity, and domain-specific phrasing - examples remove the guesswork.
system = """Kamu klasifikator sentimen review produk Tokopedia.
Output: hanya satu kata: positif, netral, atau negatif.
Contoh:
Review: "Barangnya bagus, sesuai foto. Pengiriman cepet, packing rapi."
Output: positif
Review: "Barang nyampe tapi kemasan agak penyok. Isinya ok."
Output: netral
Review: "Salah kirim. Komplain 2 minggu gak direspon. Refund lama banget."
Output: negatif"""
Three examples covers ~80% of variation. Five covers 95%. Beyond 5 you're investing more in tokens than in accuracy.
5. Anti-patterns: things that work in English but fail or backfire in Indonesian
-
Negative-only prompts: "Jangan jawab dalam bahasa Inggris. Jangan pakai istilah teknis. Jangan kasih disclaimer." -> the model frequently does exactly the listed things, because Indonesian sentence structure makes negation contextually ambiguous in long lists. Use positive framing: "Jawab dalam bahasa Indonesia santai tanpa istilah teknis."
-
Reasoning chain in English: asking the model to "Think step by step:" in English when the actual task is Indonesian causes it to switch its internal reasoning to English mid-task, then translate back. Output quality drops. Either prompt the chain in Indonesian ("Pikirkan langkah demi langkah:") or skip chain-of-thought entirely and use
chat_template_kwargs={"enable_thinking": True}for native model-side reasoning. -
JSON keys in Indonesian: if you use structured output with Indonesian field names (e.g.
"nama_lengkap","alamat"), accuracy is fine but slightly slower because tokenization is denser. English keys ("full_name","address") tokenize tighter. Pick the convention your codebase uses; don't switch for the model's sake. -
Overly polite prefixes: "Mohon dengan hormat, saya ingin meminta..." adds tokens without affecting output quality. The model treats it as register signal (formal -> formal output) but doesn't reward politeness with better content. Be direct.
6. Calendar, currency, units
Indonesian models default to Indonesian conventions:
- Dates:
5 Mei 2026,Senin, 5 Mei 2026. The model also understands2026-05-05and USMay 5, 2026but outputs Indonesian by default. Specify if you need ISO 8601. - Currency:
Rp 1.500.000,00(dot for thousands, comma for decimal).IDR 1,500,000.00works too if you ask. - Time: 24-hour by default:
14:30. Add "AM/PM" if you want 12-hour. - Phone numbers:
+62 812-3456-7890or0812-3456-7890. Both natural. - Hijri calendar: the model knows Hijri dates and converts both ways. Ask "Hari ini tanggal berapa Hijriah?" for an answer.
7. Hallucination patterns specific to Indonesian content
Things the models hallucinate more frequently than for English:
- Specific Indonesian legal citations: it'll make up plausible-looking UU numbers if you ask without grounding. Always ground with
/v1/retrievalover your own corpus, or pass the relevant statute text in the system prompt. - Government regulation hierarchy: the model occasionally confuses Permenkes / Permendag / Permendagri / Perpres / Inpres hierarchy. If hierarchy matters, cite explicitly: "berdasarkan Permendag No. 76/2020".
- City / district administrative names: post-2022 there are several new provinces (Papua Pegunungan, Papua Tengah, etc). The model knows them, but for hyper-specific kelurahan / kecamatan names, ground from BPS or your own data.
- Indonesian historical events: famous events are fine. Obscure events ("peristiwa di kota X tahun Y") get fabricated. Always verify or ground.
The fix is the same for all of these: don't ask the model for facts you can ground from your own data. Use retrieval or pass relevant context inline.
8. Stylistic guidance for output
Common needs and the prompts that get them:
- Punchy / pendek: "Jawab dalam 1-2 kalimat. Tidak ada disclaimer, tidak ada salam pembuka."
- Bullet point friendly: "Format jawaban sebagai bullet point bahasa Indonesia. Maksimal 5 poin, tiap poin satu kalimat."
- No emoji: most users assume English-tuned models default to emoji-heavy output. Epithre models default to no emoji unless asked. To enforce: "Jangan gunakan emoji."
- WhatsApp-friendly: "Format untuk WhatsApp: maksimal 3 paragraf pendek, tanpa markdown, tanpa heading."
- Email-friendly: "Format sebagai email: 'Yth.' / nama, isi 2-3 paragraf, salam penutup 'Hormat saya'."
9. Epithre platform quirks
Behavior worth knowing about specifically on Epithre:
chat_template_kwargs={"enable_thinking": False}is the default. To get extended reasoning, opt in withTrue. Meaningful onepithre-omniandepithre-prme. See chat reference.tool_choice="required"(updated May 2026): the prior long-prompt stall onepithre-omniis resolved — bare"required"now works reliably across all backends regardless of prompt length."auto"still has slightly lower TTFT for latency-sensitive paths; use named tool choice{"type": "function", "function": {"name": "your_tool"}}when you need to force a specific function.response_formatwithjson_schemastrict mode works onepithre-omniandepithre-prme. Detailed semantics in the structured output guide.
10. Worked example: end-to-end customer support bot
A realistic Indonesian customer support prompt that combines everything above:
system = """Kamu Sari, customer support PT Hijau Indah, distributor pupuk pertanian.
REGISTER:
- Bahasa Indonesia profesional, sopan, tidak kaku.
- Boleh pake istilah pertanian umum (NPK, urea, dolomit, dst).
- Jangan pake emoji kecuali user pake duluan.
GAYA:
- Jawaban langsung ke poin, maksimal 3 paragraf pendek.
- Kalau pertanyaan tentang ketersediaan stok, harga, atau pengiriman:
WAJIB minta nomor telepon dan kota tujuan dulu.
- Kalau pertanyaan teknis pertanian: jawab langsung tapi sertakan
disclaimer "Untuk kondisi tanah spesifik, konsultasi ke penyuluh pertanian setempat".
OUT OF SCOPE:
- Diagnosis penyakit tanaman dari foto: bilang "Maaf, untuk diagnosis
kami sarankan kirim foto ke @hijauindah_pertanian di Instagram, tim
agronomi kami yang langsung respon."
- Pertanyaan di luar pupuk dan pertanian: arahkan ke topik kita."""
# few-shot example (one is usually enough for tone)
examples = [
{"role": "user", "content": "halo, stok pupuk urea masih ada gak?"},
{"role": "assistant", "content": (
"Halo, kak. Stok pupuk urea kami tersedia. Boleh saya minta nomor "
"telepon dan kota tujuan, supaya saya bisa cek estimasi pengiriman "
"dan harga termasuk ongkir?"
)},
]
Pass system + examples + the new user message as the messages array. Set temperature=0.3 for register stability and max_tokens=300 to keep replies short. Done.
Further reading
- Structured output - getting JSON back reliably.
- Tool use - function calling patterns.
- Streaming - SSE specifics.
- Cookbook: classification - few-shot patterns in action.
- Cookbook: legal doc analysis - grounded answers from Indonesian regulations.