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

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

6. Calendar, currency, units

Indonesian models default to Indonesian conventions:

7. Hallucination patterns specific to Indonesian content

Things the models hallucinate more frequently than for English:

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:

9. Epithre platform quirks

Behavior worth knowing about specifically on Epithre:

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