Python & AI Tutorials Logo
LangChain & LangGraph

4. Merancang Prompt yang Dapat Digunakan Kembali dengan Template

Di Bab 3, kita membangun CLI chat streaming yang berfungsi di mana prompt disematkan langsung dalam kode Python kita. Ini berfungsi untuk prototipe cepat, tetapi seiring aplikasi AI Anda berkembang, prompt yang di-hardcode menjadi mimpi buruk pemeliharaan. Bayangkan memperbarui logika prompt yang sama di beberapa file, atau mencoba melakukan A/B testing variasi prompt yang berbeda tanpa melakukan redeploy kode.

Bab ini mengajarkan Anda cara merancang prompt yang dapat digunakan kembali dan mudah dipelihara menggunakan sistem template LangChain. Anda akan belajar memisahkan logika prompt dari kode aplikasi, memanfaatkan pesan berbasis peran untuk kontrol LLM yang lebih baik, mengeksternalisasi prompt ke file YAML untuk kolaborasi tim, dan memvalidasi template sebelum eksekusi untuk menangkap kesalahan lebih awal.

Apa yang Dicakup Bab Ini (dan Apa yang Tidak):

Di bab ini, kita akan bekerja dengan template dan prompt secara manual—Anda akan secara eksplisit merender template menjadi pesan, kemudian mengirim pesan tersebut ke LLM menggunakan llm.invoke(). Pendekatan langsung ini membantu Anda memahami dengan tepat apa yang dilakukan template dan bagaimana cara kerjanya.

Di Bab 6, Anda akan belajar LCEL (LangChain Expression Language), yang memungkinkan Anda menyusun template dan LLM menjadi pipeline menggunakan operator |. Untuk saat ini, kita fokus pada fundamental template tanpa lapisan orkestrasi tersebut.

Di akhir bab ini, Anda akan memiliki sistem manajemen prompt yang kuat yang dapat diskalakan dari chatbot sederhana hingga workflow multi-agen yang kompleks.

4.1) Pemisahan Kepentingan: Memisahkan Kode dari Prompt

Mengapa Memisahkan Prompt dari Kode?

Ketika Anda meng-hardcode prompt langsung dalam logika aplikasi Anda, Anda menciptakan coupling yang ketat yang mengarah pada beberapa masalah:

Beban Pemeliharaan: Mengubah prompt memerlukan modifikasi kode Python, menjalankan tes, dan melakukan redeploy. Perubahan prompt biasanya terjadi jauh lebih sering daripada perubahan kode, membuat siklus modifikasi-kode-tes-redeploy ini sangat tidak efisien untuk apa yang seharusnya hanya pengeditan teks sederhana.

Tantangan Version Control: Ketika kode dan prompt dicampur bersama, version control menjadi sulit. Konflik merge lebih mungkin terjadi, dan setiap konflik memerlukan resolusi manual dan refactoring.

Friksi Kolaborasi: Anggota tim non-teknis (product manager, ahli domain) tidak dapat langsung mengedit prompt yang ada di file .py dan harus bergantung pada bantuan developer. Ketergantungan ini membuat siklus perbaikan prompt menjadi jauh lebih lambat.

Kompleksitas Testing: Menguji variasi prompt yang berbeda berarti menyalin kode, memodifikasi string, dan mengelola beberapa branch—membuat eksperimen menjadi lambat dan rentan kesalahan.

Pikirkan prompt seperti query SQL dalam aplikasi tradisional. Anda tidak akan meng-hardcode string SQL di seluruh kode Python Anda—Anda akan menggunakan ORM atau setidaknya memusatkan query. Prompt layak mendapat disiplin arsitektur yang sama.

Sistem Template LangChain

LangChain menyediakan kelas PromptTemplate dan ChatPromptTemplate untuk memisahkan struktur tetap prompt Anda dari data yang berubah. Tulis prompt Anda sekali dengan {placeholders}, kemudian masukkan nilai yang berbeda setiap kali—tidak perlu lagi membangun ulang prompt dengan f-string atau concatenation.

Sintaks dan Penggunaan Template

Sintaks Placeholder

Template menggunakan {variable_name} sebagai placeholder. Saat runtime, Anda menyediakan dictionary dengan kunci yang cocok:

python
from langchain_core.prompts import PromptTemplate
 
# Definisikan template dengan placeholder
template = PromptTemplate.from_template(
    "Translate {content} from {source_lang} to {target_lang}"
)
 
# Isi placeholder dengan dictionary
result = template.invoke({
    "content": "Hello world",
    "source_lang": "English", 
    "target_lang": "Korean"
})
 
print(result.text)

Output:

Translate Hello world from English to Korean

Aturan Kunci:

  • Nama placeholder harus cocok persis dengan kunci dictionary
  • Semua placeholder harus disediakan (kunci yang hilang akan memunculkan KeyError)
  • Kunci dictionary tambahan diabaikan
  • Gunakan invoke() untuk merender template dengan nilai Anda

PromptTemplate vs ChatPromptTemplate

PromptTemplate: Mengembalikan string biasa (dibungkus dalam StringPromptValue)

  • Untuk text completion sederhana atau model legacy
  • Output: String tunggal seperti "Summarize: {content}"

ChatPromptTemplate: Mengembalikan pesan terstruktur dengan peran (dibungkus dalam ChatPromptValue)

  • Untuk model chat modern (GPT-4, Claude, Gemini)
  • Output: Pesan yang dipisahkan berdasarkan peran (system/user/assistant)
  • Pilihan yang disukai: Lebih jelas dan lebih mudah dipelihara

Kapan menggunakan yang mana?

  • Default ke ChatPromptTemplate untuk model chat—lebih jelas dan lebih mudah dipelihara
  • Gunakan PromptTemplate hanya untuk completion sederhana atau ketika pemisahan peran tidak diperlukan
python
# PromptTemplate - output string tunggal
from langchain_core.prompts import PromptTemplate
 
template1 = PromptTemplate.from_template("Summarize: {content}")
result1 = template1.invoke({"content": "LangChain is a framework..."})  
print(result1)

Output:

text='Summarize: LangChain is a framework...'
python
# ChatPromptTemplate - pesan berbasis peran
from langchain_core.prompts import ChatPromptTemplate
 
template2 = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant"),
    ("user", "{question}")
])
result2 = template2.invoke({"question": "What is LangChain?"})
print(result2)

Output:

messages=[SystemMessage(content='You are a helpful assistant'), HumanMessage(content='What is LangChain?')]

Template didefinisikan sekali. Anda dapat menggunakannya kembali dengan nilai yang berbeda tanpa memodifikasi definisi template. Baik PromptTemplate.invoke() maupun ChatPromptTemplate.invoke() mengembalikan nilai prompt yang siap dikirim langsung ke LLM.

Dari String Formatting ke Template

Mari kita refactor prompt yang di-hardcode untuk menggunakan template. Berikut versi "sebelum" dari Bab 3:

python
# Pendekatan hardcoded (gaya Bab 3)
from langchain_openai import ChatOpenAI
 
llm = ChatOpenAI(model="gpt-4o-mini")
 
user_input = "Explain quantum computing"
# Logika prompt dicampur dengan kode
prompt = f"You are a helpful assistant. Answer this question: {user_input}"
 
response = llm.invoke(prompt)
print(response.content)

Sekarang dengan template—menggunakan pendekatan langkah-demi-langkah yang akan kita praktikkan di seluruh bab ini:

python
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
 
# Template didefinisikan secara terpisah
template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    ("user", "{user_input}")
])
 
# Logika aplikasi - eksekusi langkah-demi-langkah
llm = ChatOpenAI(model="gpt-4o-mini")
 
user_input = "Explain quantum computing"
 
# Langkah 1: Render template menjadi pesan
messages = template.invoke({"user_input": user_input})
 
# Langkah 2: Kirim pesan ke LLM
response = llm.invoke(messages)
print(response.content)

Apa yang berubah?

  1. Definisi Template: Struktur prompt didefinisikan sekali dalam template, terpisah dari logika eksekusi.
  2. Sintaks Placeholder: {user_input} adalah placeholder yang diisi saat runtime.
  3. Eksekusi Langkah-demi-Langkah: Kita secara eksplisit merender template (template.invoke()), kemudian mengirim hasilnya ke LLM (llm.invoke()). Proses dua langkah ini membantu Anda memahami apa yang sebenarnya dilakukan template.
  4. Reusability: template yang sama dapat digunakan untuk pertanyaan pengguna apa pun tanpa modifikasi.
  5. Struktur Pesan: template.invoke() mengembalikan ChatPromptValue yang diformat dengan benar yang diharapkan oleh LLM.

Mengapa Pendekatan Langkah-demi-Langkah?

Di seluruh bab ini, Anda akan melihat pola ini berulang kali:

python
messages = template.invoke(inputs)  # Langkah 1: Render template
response = llm.invoke(messages)     # Langkah 2: Kirim ke LLM

Kita menggunakan pendekatan dua langkah ini dengan sengaja untuk pembelajaran—ini menunjukkan dengan tepat apa yang dilakukan template: mengubah data input menjadi pesan terstruktur. Di Bab 6, Anda akan belajar pola produksi dunia nyata: menggabungkan langkah-langkah ini dengan pipeline LCEL (template | llm). Tetapi memahami setiap langkah secara terpisah terlebih dahulu membangun fondasi yang solid.

Validasi Template

Template menangkap kesalahan lebih awal. Jika Anda mereferensikan placeholder yang tidak ada, LangChain memunculkan error sebelum melakukan API call:

python
template = PromptTemplate.from_template("Summarize: {text}")
 
# Ini akan gagal - kunci 'text' hilang
try:
    template.invoke({"content": "Some text"})  # Nama kunci salah
except KeyError as e:
    print(f"Template error: {e}")

Output:

Template error: "Input to PromptTemplate is missing variables {'text'}.  Expected: ['text'] Received: ['content']

Validasi ini terjadi pada waktu rendering template, bukan selama eksekusi LLM—menghemat waktu dan biaya API Anda.

4.2) Template Prompt yang Sadar Peran (System, User, Assistant)

Memahami Peran Pesan

LLM modern (GPT-4, GPT-5, Claude, Gemini) memahami struktur percakapan melalui peran pesan. Setiap pesan memiliki peran spesifik yang memberi tahu model cara menginterpretasinya.

Tiga Peran Inti:

System: Mendefinisikan bagaimana AI harus berperilaku

  • Tujuan: Mengatur kepribadian AI, keahlian, dan aturan operasional
  • Contoh: "You are a Python expert who writes concise code examples"
  • Kapan berlaku: Diatur sekali di awal, memengaruhi semua respons
  • Anggap sebagai: Manual instruksi AI

User: Mewakili input manusia

  • Tujuan: Mengajukan pertanyaan atau membuat permintaan
  • Contoh: "How do I read a file in Python?"
  • Kapan berlaku: Setiap kali manusia mengirim pesan
  • Anggap sebagai: Pertanyaan yang Anda ajukan

Assistant: Mewakili respons AI sebelumnya

  • Tujuan: Menyediakan riwayat percakapan
  • Contoh: "You can use the open() function to read files"
  • Kapan berlaku: Ketika Anda memerlukan percakapan multi-turn
  • Anggap sebagai: Memori AI tentang jawaban sebelumnya

Pesan System: Mekanisme Kontrol

Pesan system memberi tahu AI siapa dirinya dan bagaimana ia harus beroperasi—sebelum interaksi pengguna apa pun.

Apa yang Dapat Anda Kontrol:

  1. Keahlian: "You are a senior Python developer"
  2. Format Output: "Always respond in JSON format"
  3. Aturan Perilaku: "If unsure, say 'I don't know'"
  4. Gaya Respons: "Be concise and technical"

Mengapa Ini Penting:

Tanpa pesan system → respons generik dan verbose

Dengan pesan system → perilaku yang konsisten dan disesuaikan

Pesan System dalam Aksi

Mari kita lihat dampak nyata dari pesan system dengan membandingkan pertanyaan yang sama dengan dan tanpa pesan system. Perhatikan bagaimana respons berubah secara dramatis—tidak hanya dalam panjang, tetapi dalam nada, kompleksitas, dan pendekatan pengajaran.

Tanpa Pesan System:

python
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
 
template = ChatPromptTemplate.from_messages([
    ("user", "What is Python?")
])
 
llm = ChatOpenAI(model="gpt-4o-mini")
messages = template.invoke({})
response = llm.invoke(messages)
print(response.content)

Output:

Python is a high-level, interpreted programming language known for its readability and simplicity. 
It was created by Guido van Rossum and first released in 1991. 
Python emphasizes code readability, allowing programmers to express concepts in fewer lines of code compared to languages such as C++ or Java.
 
Key features of Python include:
...

Dengan Pesan System:

python
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
 
# Kontrol persona dan gaya output dengan pesan System
template = ChatPromptTemplate.from_messages([
    ("system", """You are a senior Python instructor with 15 years of teaching experience.
Your students are complete beginners who have never programmed before.
 
Teaching style:
- Use simple, everyday analogies
- Avoid technical jargon
- Show practical examples from daily life
- Be encouraging and patient"""),
    ("user", "What is Python?")
])
 
llm = ChatOpenAI(model="gpt-4o-mini")
messages = template.invoke({})
response = llm.invoke(messages)
print(response.content)

Output:

Great question! Think of Python like a really helpful tool in your toolbox. 
Just like a hammer or a screwdriver helps you build or fix things around the house, Python helps you create software or automate tasks on a computer.
 
Imagine you wanted to bake a cake. 
You need a recipe to follow, right? In this analogy, Python is like that recipe. 
It tells the computer what steps to take to achieve a goal, whether it's doing math, organizing files, or even running a game.
...

Perbedaannya:

Tanpa Pesan System:

  • AI menggunakan perilaku default-nya: sopan, informatif, tetapi generik
  • Respons ensiklopedis dan formal—dioptimalkan untuk audiens luas
  • Tidak ada persona yang konsisten: setiap respons mungkin bervariasi dalam nada dan gaya
  • Tidak ada batasan: AI memutuskan sendiri seberapa detail atau teknis

Dengan Pesan System:

  • AI mengikuti instruksi spesifik Anda: persona, gaya, dan aturan yang Anda definisikan
  • Respons konsisten dan dapat diprediksi—setiap jawaban sesuai dengan persyaratan Anda
  • Persona yang jelas dipertahankan: bertindak sebagai peran yang Anda tetapkan (guru, ahli, asisten)
  • Batasan eksplisit diterapkan: format output, tingkat bahasa, dan batasan perilaku yang Anda tetapkan

Wawasan Kunci: Tanpa pesan system, Anda mendapatkan mode default AI. Dengan pesan system, Anda mendapatkan AI Anda—disesuaikan dengan kebutuhan aplikasi Anda. Pesan system mengubah AI dari alat serbaguna menjadi asisten khusus yang berperilaku persis seperti yang Anda inginkan, setiap saat.

Peran User dan Assistant: Membangun Percakapan

Pertanyaan Tunggal (User Saja):

python
template = ChatPromptTemplate.from_messages([
    ("system", "You are a Python expert."),
    ("user", "{question}")
])
 
llm = ChatOpenAI(model="gpt-4o-mini")
messages = template.invoke({"question": "How do I read a CSV?"})
response = llm.invoke(messages)

Berfungsi baik untuk pertanyaan independen.

Multi-Turn dengan Konteks (User + Assistant):

Tanpa riwayat:

python
template = ChatPromptTemplate.from_messages([
    ("system", "You are a Python expert."),
    ("user", "How does it work?")  # "it" = ???
])

AI tidak tahu apa yang dimaksud dengan "it".

Dengan riwayat:

python
template = ChatPromptTemplate.from_messages([
    ("system", "You are a Python expert."),
    ("user", "What's the pandas library?"),
    ("assistant", "Pandas is a data analysis library."),
    ("user", "How does it work?")  # Sekarang "it" = pandas
])

Riwayat percakapan (pertanyaan user sebelumnya + respons assistant) menyediakan konteks. AI sekarang memahami "it" berarti pandas.

Contoh: Membangun Percakapan dengan Riwayat

Sekarang mari kita bangun contoh yang mengingat pertukaran sebelumnya. Fungsi ini mempertahankan riwayat percakapan dan meneruskannya ke AI dengan setiap pertanyaan baru:

python
llm = ChatOpenAI(model="gpt-4o-mini")
 
def chat_with_history(user_input: str, history: list):
    messages = [("system", "You are a Python expert.")]
    
    # Tambahkan riwayat
    for msg in history:
        messages.append((msg["role"], msg["content"]))
    
    # Tambahkan input saat ini
    messages.append(("user", user_input))
    
    # Gunakan format mustache untuk menghindari error ketika konten mengandung {kurung kurawal}
    template = ChatPromptTemplate.from_messages(messages, template_format="mustache")
    
    formatted = template.format()
    response = llm.invoke(formatted)
    return response.content
 
# Penggunaan
history = []
 
# Turn 1
resp1 = chat_with_history("What's a Python dictionary?", history)
print(resp1)
 
history.append({"role": "user", "content": "What's a Python dictionary?"})
history.append({"role": "assistant", "content": resp1})
 
# Turn 2 - menggunakan konteks
resp2 = chat_with_history("Show an example.", history)
print(resp2)

Aturan Urutan Pesan

LLM mengharapkan struktur percakapan spesifik: System → User → Assistant → User → Assistant → ...

Mengapa Urutan Ini?

Pola ini mencerminkan percakapan manusia-AI yang alami:

  1. System datang pertama (opsional): Karena ini menetapkan aturan perilaku yang berlaku untuk seluruh percakapan, ini harus didefinisikan sebelum interaksi apa pun dimulai. Sama seperti Anda memberi briefing kepada seseorang sebelum mereka mulai bekerja, bukan di tengah tugas.

  2. User kemudian Assistant bergantian: Dalam percakapan nyata, manusia berbicara (User), AI merespons (Assistant), manusia menindaklanjuti (User), AI merespons lagi (Assistant). Pola bergantian ini adalah bagaimana AI dilatih, jadi ia mengharapkan struktur ini.

  3. Harus diakhiri dengan User: AI menghasilkan respons untuk pesan User terakhir. Jika percakapan diakhiri dengan Assistant, tidak ada yang bisa direspons oleh AI.

Contoh Valid:

python
# System + User tunggal
[("system", "..."), ("user", "...")]
 
# System + percakapan
[("system", "..."), ("user", "..."), ("assistant", "..."), ("user", "...")]

Pola Bermasalah:

python
# Assistant sebelum User - AI bingung tentang konteks
[("system", "..."), ("assistant", "..."), ("user", "...")]
# AI melihat respons tanpa pertanyaan. Ia mungkin berhalusinasi pertanyaan apa 
# yang dijawab ini, yang mengarah pada respons yang tidak relevan atau bingung.
python
# Dua pesan User berturut-turut - respons AI hilang
[("system", "..."), ("user", "..."), ("user", "...")]
# AI tidak tahu pesan User mana yang harus direspons, atau mungkin menggabungkannya 
# dengan canggung. Kehilangan alur percakapan.
python
# Diakhiri dengan Assistant - tidak ada yang bisa direspons
[("system", "..."), ("user", "..."), ("assistant", "...")]
# Percakapan sudah selesai. AI tidak memiliki apa pun untuk dihasilkan karena tidak ada 
# pertanyaan User yang tertunda. Kemungkinan akan menghasilkan error atau respons kosong.

Poin Kunci: Pola-pola ini tidak selalu menyebabkan error keras, tetapi mereka membingungkan AI karena mereka melanggar logika percakapan yang dilatih padanya. AI mungkin menghasilkan respons, tetapi mereka akan tidak dapat diandalkan atau tidak masuk akal. Selalu ikuti pola yang diharapkan untuk perilaku yang dapat diprediksi.

Di Luar Riwayat Sederhana: Pola Produksi (Preview)

Catatan Penting: Pola riwayat percakapan yang baru saja Anda pelajari adalah fondasi yang bagus, tetapi sistem produksi menggunakan pendekatan yang lebih canggih.

Masalah dengan Riwayat Mentah:

Hanya meneruskan semua riwayat percakapan ke AI memiliki keterbatasan:

  1. Pemborosan token: Setiap pesan (bahkan yang lama) dihitung terhadap batas token Anda dan biaya
  2. Kehilangan fokus: AI mungkin terganggu oleh percakapan sebelumnya yang tidak relevan
  3. Tidak ada tugas eksplisit: AI menyimpulkan apa yang harus dilakukan dari riwayat, daripada menerima instruksi yang jelas

Pendekatan yang Lebih Baik:

Sistem produksi memisahkan konteks dari instruksi:

Pendekatan riwayat sederhana (yang baru kita pelajari):

python
messages = [
    ("system", "You are a Python expert."),
    ("user", "What's a dictionary?"),
    ("assistant", "A dictionary is a key-value data structure."),
    ("user", "Show an example.")
]

Pendekatan produksi (akan datang di bab-bab selanjutnya):

python
messages = [
    ("system", "You are a Python expert."),
    ("user", """Context: The user previously asked about Python dictionaries and learned they are key-value structures.
 
Task: Provide a code example demonstrating dictionary usage.""")
]

Perbedaannya:

  • Riwayat mentah: AI melihat percakapan lengkap dan mencari tahu apa yang harus dilakukan
  • Pola produksi: AI menerima konteks yang dirangkum + instruksi eksplisit

Manfaat pemisahan:

  • Token lebih sedikit (biaya lebih rendah, respons lebih cepat)
  • Perilaku lebih dapat diandalkan (instruksi yang jelas)
  • Kontrol lebih baik (Anda memutuskan konteks apa yang penting)

Di mana Anda akan mempelajari ini:

  • Bab 8: Mengelola state dan memori percakapan
  • Bab 11: Contextual Retrieval (menggabungkan RAG dengan memori percakapan)
  • Bab 16: Routing dinamis berdasarkan konteks percakapan

Untuk saat ini, memahami riwayat mentah sangat penting—ini adalah fondasi untuk pola-pola lanjutan ini. Tetapi ingat: apa yang baru saja Anda pelajari adalah alat pengajaran, bukan solusi akhir.

4.3) Mengeksternalisasi Prompt: Mengelola File Template (.yaml)

Mengapa Mengeksternalisasi Prompt?

Seiring aplikasi AI Anda berkembang, mengelola prompt dalam kode Python menjadi tidak praktis. Mengeksternalisasi prompt ke file YAML menyediakan:

Kolaborasi Non-teknis: Product manager, ahli domain, dan prompt engineer dapat mengedit file YAML tanpa menyentuh kode Python atau memahami konsep pemrograman.

Kejelasan Version Control: Lacak perubahan prompt secara terpisah dari perubahan kode. Tidak ada lagi commit campuran di mana tweak prompt dan pembaruan logika muncul bersama.

Prompt Spesifik Lingkungan: Prompt yang berbeda untuk development, staging, dan production tanpa perubahan kode.

A/B Testing: Uji variasi prompt dengan memuat file yang berbeda—tidak perlu perubahan kode.

Pikirkan file prompt YAML sebagai file konfigurasi dalam aplikasi tradisional—mereka mendefinisikan perilaku tanpa memerlukan perubahan kode atau redeploy.

Apa itu YAML?

YAML adalah format data yang dapat dibaca manusia yang umum digunakan untuk file konfigurasi. Jika Anda belum pernah melihat YAML sebelumnya, anggap saja sebagai alternatif yang lebih bersih untuk JSON—ia menggunakan indentasi alih-alih tanda kurung dan lebih mudah dibaca dan diedit.

Struktur Prompt YAML

LangChain mendefinisikan struktur file YAML standar untuk prompt. Mari kita lihat contohnya:

Contoh 1: Prompt tanpa variabel

Ketika prompt tidak memerlukan nilai runtime apa pun, atur input_variables ke list kosong:

yaml
# prompts/system_prompt.yaml
_type: prompt
input_variables: []
template: |
  You are a helpful assistant.
  Please answer in a friendly and encouraging tone.

Simbol | memungkinkan Anda menulis teks multi-baris, dan line break dipertahankan.

Contoh 2: Prompt dengan variabel

Ketika prompt memerlukan nilai runtime, cantumkan mereka di input_variables:

yaml
# prompts/user_prompt.yaml
_type: prompt
input_variables:
  - user_input
template: |
  User question: {user_input}
  Please provide a clear answer.

Saat runtime, placeholder {user_input} diganti dengan nilai aktual.

Komponen kunci:

  • _type: prompt: Mengidentifikasi ini sebagai template prompt
  • input_variables: Mencantumkan semua placeholder yang digunakan dalam template (list kosong [] jika tidak ada)
  • template: Teks prompt aktual dengan {placeholders}

Memuat dan Menggunakan Prompt YAML

Pemuatan Dasar:

Sekarang mari kita muat file YAML yang kita buat dan gunakan dengan LLM:

python
from langchain_core.prompts import load_prompt, ChatPromptTemplate
from langchain_openai import ChatOpenAI
 
# Muat prompt dari file YAML
system_prompt_template = load_prompt("prompts/system_prompt.yaml")
user_prompt_template = load_prompt("prompts/user_prompt.yaml")
 
# Gabungkan prompt yang dimuat menjadi template chat
chat_template = ChatPromptTemplate.from_messages([
    ("system", system_prompt_template.template),
    ("user", user_prompt_template.template)
])
 
llm = ChatOpenAI(model="gpt-4o-mini")
 
# Langkah 1: Render template dengan nilai runtime
messages = chat_template.invoke({"user_input": "What is LangChain?"})
 
# Langkah 2: Kirim ke LLM
response = llm.invoke(messages)
print(response.content)

Memverifikasi Template yang Dimuat:

Sebelum menggunakan template, verifikasi bahwa ia dimuat dengan benar:

python
from langchain_core.prompts import load_prompt
 
# Muat template
user_prompt_template = load_prompt("prompts/user_prompt.yaml")
 
# Periksa variabel apa yang diharapkan
print("Input variables:", user_prompt_template.input_variables)
 
# Lihat teks template
print("Template:", user_prompt_template.template)

Output:

Input variables: ['user_input']
Template: User question: {user_input}
Please provide a clear answer.

Kesalahan YAML Umum

Kesalahan 1: Indentasi tidak konsisten

YAML memerlukan indentasi yang konsisten (biasanya 2 spasi). Setiap level harus menggunakan jumlah spasi yang sama:

Salah:

yaml
_type: prompt
input_variables:
- user_input      # Salah: item list harus diindentasi
  - question      # Salah: level indentasi campuran

Benar:

yaml
_type: prompt
input_variables:
  - user_input    # Benar: kedua item pada level indentasi yang sama
  - question

Kesalahan 2: Ketidakcocokan placeholder

Placeholder dalam template harus cocok dengan input_variables:

Salah:

yaml
input_variables:
  - user_input
template: "Question: {question}"  # 'question' tidak ada di input_variables!

Benar:

yaml
input_variables:
  - user_input
template: "Question: {user_input}"

LangChain akan memunculkan error jika placeholder tidak cocok dengan variabel yang dideklarasikan.

4.4) Melihat Preview dan Memvalidasi Template sebelum Eksekusi

Mengapa Preview Template?

Rekayasa prompt bersifat iteratif. Anda mengubah kata-kata, menyesuaikan struktur, menambahkan contoh—dan setiap iterasi memerlukan token API dan waktu. Melihat preview template sebelum eksekusi memungkinkan Anda:

Menghemat Waktu dan Uang: Tangkap kesalahan sebelum melakukan API call yang mahal.

Memverifikasi Kebenaran: Pastikan variabel diisi dengan benar dan formatting sesuai yang diharapkan.

Debug Secara Efisien: Lihat prompt yang tepat yang dikirim ke LLM, dengan semua variabel diisi dan formatting diterapkan.

Pikirkan preview template sebagai print debugging—Anda memeriksa state perantara sebelum eksekusi untuk memverifikasi kebenaran.

Preview Template Dasar

Memeriksa Struktur Template:

Sebelum menggunakan template dengan LLM, periksa strukturnya dan preview bagaimana ia merender dengan data sampel:

python
from langchain_core.prompts import ChatPromptTemplate
 
template = ChatPromptTemplate.from_messages([
    ("system", "You are a {role}."),
    ("user", "{user_input}")
])
 
# Preview struktur template
print("Input variables:", template.input_variables)
print("Message count:", len(template.messages))
 
# Preview dengan data sampel
prompt_value = template.invoke({
    "role": "Python programming expert",
    "user_input": "What is Python?"
})
 
print("\nPreview:")
for msg in prompt_value.to_messages():
    print(f"{msg.type}: {msg.content}")

Output:

Input variables: ['role', 'user_input']
Message count: 2
 
Preview:
system: You are a Python programming expert.
human: What is Python?

Ini menunjukkan dengan tepat apa yang akan dikirim ke LLM, memungkinkan Anda memverifikasi prompt sebelum eksekusi.

Memvalidasi Template: Menangkap Variabel yang Hilang

Kesalahan template yang paling umum adalah variabel yang diperlukan hilang. Berikut fungsi validasi yang dapat digunakan kembali yang menangkap variabel yang hilang:

python
from langchain_core.prompts import ChatPromptTemplate
 
def preview_template(template: ChatPromptTemplate, inputs: dict):
    """Preview template dengan input yang diberikan, menangkap error."""
    try:
        prompt_value = template.invoke(inputs)
        
        print("TEMPLATE PREVIEW")
        print("=" * 60)
        
        for i, msg in enumerate(prompt_value.to_messages(), 1):
            print(f"Message {i} ({msg.type.upper()}):")
            print(msg.content)
            print("-" * 60)
                
    except KeyError as e:
        print(f"ERROR: {e}")
        print(f"Required variables: {template.input_variables}")
 
# Penggunaan
template = ChatPromptTemplate.from_messages([
    ("system", "You are a {role}."),
    ("user", "{user_input}")
])
 
# Input valid
preview_template(template, {
    "role": "Python programming expert",
    "user_input": "What is Python?"
})
 
# Variabel hilang
preview_template(template, {
    "user_input": "What is Python?"  # 'role' hilang
})

Output:

TEMPLATE PREVIEW
============================================================
Message 1 (SYSTEM):
You are a Python programming expert.
------------------------------------------------------------
Message 2 (HUMAN):
What is Python?
------------------------------------------------------------
 
ERROR: "Input to ChatPromptTemplate is missing variables {'role'}.
Expected: ['role', 'user_input'] Received: ['user_input']
...
Required variables: ['role', 'user_input']

Workflow Validasi:

Berikut proses validasi template yang khas:

Error

Valid

Tidak

Ya

Definisikan Template

Muat Data Sampel

Validasi Input

Perbaiki Template/Data

Preview Pesan

Siap?

Eksekusi dengan LLM

Proses iteratif ini membantu menangkap kesalahan sebelum LLM call yang mahal.

Checklist Pra-Eksekusi

Sebelum mengirim template ke production:

  • Semua input_variables dideklarasikan di YAML/template
  • Data sampel merender tanpa error
  • Prompt multi-baris ditampilkan dengan benar
  • Placeholder cocok dengan nama variabel persis
  • Uji dengan edge case (string kosong, teks panjang)

Ringkasan Bab:

Anda telah belajar merancang prompt yang mudah dipelihara dan dapat digunakan kembali menggunakan sistem template LangChain:

  1. Pemisahan Kepentingan: Pisahkan prompt dari kode untuk pemeliharaan dan iterasi yang lebih mudah
  2. Template Sadar Peran: Gunakan pesan system, user, dan assistant untuk interaksi LLM terstruktur dengan hierarki instruksi yang tepat
  3. Prompt yang Dieksternalisasi: Kelola prompt dalam file YAML untuk kolaborasi non-teknis dan version control
  4. Preview dan Validasi: Tangkap kesalahan lebih awal dan verifikasi template sebelum eksekusi

Langkah Selanjutnya:

Di Bab 5, Anda akan melihat bagaimana template memungkinkan pengambilan keputusan otonom dalam contoh agen preview. Kemudian di Bab 6, Anda akan belajar LCEL (LangChain Expression Language) untuk menyusun template ini menjadi pipeline yang kuat menggunakan operator |.