3. Membangun Chat CLI Streaming Pertama Anda
Di Bab 1, kamu membuat panggilan LLM pertamamu dan melihat respons lengkap muncul sekaligus. Di Bab 2, kamu mempelajari fondasi konseptual agentic AI dan kenapa LangChain ada. Sekarang saatnya membangun sesuatu yang praktis: aplikasi chat streaming yang terasa responsif dan profesional.
Kenapa streaming itu penting: Saat kamu bertanya ke LLM pertanyaan yang kompleks, menunggu 10–30 detik untuk respons lengkap terasa seperti rusak. Streaming membuat token muncul saat dihasilkan, menciptakan alur percakapan yang natural. Bab ini membangun aplikasi chat CLI dengan output streaming, manajemen konfigurasi yang benar, kemampuan debugging, dan penanganan error yang tangguh.
Apa yang akan kamu bangun: Di akhir bab ini, kamu akan punya skrip chat.py yang berfungsi dan:
- Men-stream respons LLM token demi token ke terminal
- Memuat API key secara aman dari environment variable
- Menangani tipe model yang berbeda (chat vs reasoning models) dengan parameter yang sesuai
- Menyediakan alat debugging untuk memeriksa apa yang benar-benar dikirim ke LLM
- Menangani error umum dengan baik (API key hilang, kegagalan jaringan, input tidak valid)
3.1) Buat Folder Kerja dan Instal Paket
Sebelum menulis kode apa pun, kamu butuh struktur proyek yang rapi dan dependensi yang tepat. Bagian ini membangun fondasi untuk proyek Python yang mudah dipelihara.
Struktur Proyek
Buat direktori baru untuk aplikasi chat kamu:
mkdir langchain-chat
cd langchain-chatSetup Environment Python
Buat virtual environment untuk mengisolasi dependensi:
# Buat virtual environment
python -m venv venv
# Aktifkan (macOS/Linux)
source venv/bin/activate
# Aktifkan (Windows)
venv\Scripts\activateKenapa virtual environment? LangChain punya banyak dependensi (misalnya OpenAI SDK, Pydantic, library async). Virtual environment memastikan:
- Python sistem kamu tetap bersih
- Proyek yang berbeda bisa memakai versi LangChain yang berbeda
- Dependensi dapat direproduksi (melalui
requirements.txt)
Kamu akan melihat (venv) di prompt terminal saat sudah aktif.
Menginstal LangChain
Instal paket inti LangChain:
pip install langchain-core==1.2.7 langchain-openai==1.1.7 python-dotenvRincian paket:
langchain-core: Abstraksi inti (messages, prompts, chains, runnables)langchain-openai: Implementasi spesifik OpenAI (ChatOpenAI, embeddings)python-dotenv: Memuat environment variable dari file.env
Catatan versi: Buku ini memakai LangChain 1.2.x per Januari 2026. Jika kamu membaca ini di masa depan, cek dokumentasi LangChain untuk versi terbaru.
Verifikasi Instalasi
Buat tes sederhana untuk memastikan semuanya berjalan:
# test_install.py
try:
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI
print("✓ langchain-core: OK")
print("✓ langchain-openai: OK")
print("\nInstalasi berhasil!")
except ImportError as e:
print(f"✗ Import gagal: {e}")
print("Pastikan virtual environment kamu sudah diaktifkan.")Jalankan:
python test_install.pyOutput yang diharapkan:
✓ langchain-core: OK
✓ langchain-openai: OK
Instalasi berhasil!Jika kamu melihat "Instalasi berhasil!", kamu siap lanjut. Jika kamu mendapat import error, cek ulang bahwa:
- Virtual environment kamu aktif (lihat
(venv)di prompt) - Paket terinstal dengan sukses (coba jalankan
pip list)
Membuat requirements.txt
Kamu baru saja menginstal paket dengan perintah pip install. Walaupun ini oke untuk belajar, ada cara yang lebih baik: file requirements.txt. Ini praktik standar di proyek Python karena beberapa alasan:
Kenapa memakai requirements.txt?
- Reproducibility: Orang lain (atau kamu 6 bulan lagi) bisa menginstal versi paket yang persis sama
- Manajemen dependensi yang jelas: Sekilas terlihat paket apa saja yang dibutuhkan proyekmu
- Kolaborasi tim: Anggota tim memakai versi yang identik, menghindari masalah "works on my machine"
- Otomasi: Server atau pipeline CI/CD bisa menyiapkan environment dengan satu baris:
pip install -r requirements.txt
Buat file requirements.txt di root proyek:
# requirements.txt
langchain-core==1.2.7
langchain-openai==1.1.7
python-dotenvPerhatikan sintaksnya:
==1.2.7mengunci ke versi yang tepat (direkomendasikan untuk reproducibility)- Tanpa spesifier versi (seperti
python-dotenv) akan menginstal versi stabil terbaru - Baris yang diawali
#adalah komentar
Sekarang siapa pun bisa menginstal semua dependensi dengan satu perintah:
pip install -r requirements.txtIni jauh lebih baik dibanding mengetik setiap paket satu per satu. Kalau rekan tim meng-clone proyekmu, mereka hanya perlu:
- Membuat virtual environment
- Menjalankan
pip install -r requirements.txt
Tidak perlu mengingat nama paket atau versinya—semuanya ada di file.
Struktur Proyek Kamu
Setelah menyelesaikan bagian ini, folder kamu seharusnya terlihat seperti:
langchain-chat/
├── venv/ # Virtual environment (jangan commit ke git)
├── requirements.txt # Daftar dependensi
└── test_install.py # Skrip verifikasi instalasiBerikutnya: Bagian 3.2 menunjukkan cara memuat API key secara aman menggunakan file .env.
3.2) Environment Variable dengan .env
API key adalah rahasia. Men-hardcode-nya di kode adalah risiko keamanan (terutama kalau kamu commit ke git). Bagian ini menunjukkan pendekatan standar: environment variable yang dimuat dari file .env.
Kenapa Environment Variable?
Masalah dengan key yang di-hardcode:
# ❌ JANGAN PERNAH LAKUKAN INI
llm = ChatOpenAI(api_key="sk-proj-abc123...")Jika kamu commit kode ini ke GitHub, API key kamu jadi publik. Siapa pun bisa memakainya, menimbulkan biaya di akunmu, atau membuat key kamu dicabut.
Solusinya: Simpan rahasia di environment variable, muat saat runtime.
Membuat File .env
Buat file .env di root proyek:
# .env
OPENAI_API_KEY=sk-proj-your-actual-key-hereDapatkan API key kamu:
- Buka platform.openai.com/api-keys
- Buat secret key baru
- Salin segera (kamu tidak bisa melihatnya lagi)
- Tempel ke file
.envkamu, menggantisk-proj-your-actual-key-here
Langkah keamanan yang kritis: Sebelum melakukan apa pun, lindungi API key kamu agar tidak ter-commit ke git.
Buat file .gitignore di root proyek dan tambahkan baris-baris ini:
# .gitignore
venv/
__pycache__/
*.pyc
.envBaris .env memberitahu git untuk mengabaikan file API key kamu. Ini mencegah rahasia ter-commit ke version control secara tidak sengaja.
Struktur proyek kamu sekarang:
langchain-chat/
├── venv/
├── .env # API key kamu (diabaikan oleh git)
├── .gitignore # Berisi: .env, venv/, dll.
├── requirements.txt
└── test_install.pyMemuat Environment Variable
Paket python-dotenv memuat file .env ke os.environ:
# chat.py
import os
from dotenv import load_dotenv
# Muat file .env
load_dotenv()
# Akses environment variable
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
raise ValueError("OPENAI_API_KEY tidak ditemukan di environment")
print(f"API key dimuat: {api_key[:8]}...") # Tampilkan 8 karakter pertama sajaCara kerja load_dotenv():
- Mencari file
.envmulai dari lokasi kamu menjalankan skrip - Membaca setiap baris dengan format
KEY=value - Menambahkan setiap variabel ke
os.environ - Jika sebuah variabel sudah diset (misalnya oleh platform hosting), variabel itu tidak akan ditimpa—nilai yang ada tetap dipakai
Menggunakan API Key dengan LangChain
Implementasi OpenAI di LangChain (ChatOpenAI, dll.) secara otomatis mencari OPENAI_API_KEY di os.environ:
from langchain_openai import ChatOpenAI
load_dotenv()
# Ini otomatis memakai os.environ["OPENAI_API_KEY"]
llm = ChatOpenAI(model="gpt-4o-mini")Konvensi LangChain: Saat kamu membuat ChatOpenAI() tanpa parameter api_key, ia otomatis mencari OPENAI_API_KEY di environment. Ini adalah pola standar di seluruh integrasi LangChain.
API key eksplisit (untuk pengujian atau banyak key):
llm = ChatOpenAI(
model="gpt-4o-mini",
api_key=os.environ.get("OPENAI_API_KEY")
)Ini berguna saat kamu punya beberapa API key (development vs production) atau ingin eksplisit tentang key mana yang dipakai.
Environment Variable di Production
Di lingkungan production (platform cloud, container Docker), kamu tidak memakai file .env. Sebagai gantinya, kamu mengonfigurasi environment variable lewat pengaturan platform:
- Docker: Gunakan flag
-esaat menjalankan container - Platform cloud: Set environment variable di dashboard konfigurasi
- CI/CD: Gunakan alat manajemen secrets
Bagian pentingnya: kode kamu tidak berubah. os.environ.get("OPENAI_API_KEY") bekerja dengan cara yang sama apakah variabelnya berasal dari file .env atau platform cloud. Kita akan membahas deployment secara detail di bab-bab berikutnya.
Verifikasi Setup Kamu
Untuk memastikan semuanya bekerja, kamu bisa menguji kode pemuatan environment variable yang ditunjukkan sebelumnya. Jika file .env kamu dikonfigurasi dengan benar, os.environ.get("OPENAI_API_KEY") akan mengembalikan API key kamu.
Jika os.environ.get("OPENAI_API_KEY") mengembalikan None, pastikan bahwa:
- Kamu memanggil
load_dotenv()sebelum mengakses environment variable .envada di root proyekOPENAI_API_KEY=sk-proj-...ditulis dengan benar di.env- Kamu menjalankan dari direktori root proyek
Berikutnya: Bagian 3.3 mengimplementasikan chat loop yang sebenarnya dengan output streaming.
3.3) Mengimplementasikan Chat Loop dengan Output Streaming
Sekarang kamu akan membangun chat loop inti. Bagian ini memperkenalkan streaming - perbedaan kunci antara chatbot yang lamban dan yang responsif.
Memahami Streaming
Tanpa streaming (pendekatan Bab 1):
response = llm.invoke("Tulis esai 500 kata tentang AI")
print(response.content) # Tunggu 20 detik, lalu seluruh esai munculDengan streaming:
for chunk in llm.stream("Tulis esai 500 kata tentang AI"):
print(chunk.content, end="", flush=True) # Token muncul saat dihasilkanKenapa streaming itu penting:
- Feedback langsung: Alih-alih menatap layar kosong 20 detik, kamu langsung melihat kata-kata muncul
- Terasa seperti percakapan natural: Sama seperti ngobrol dengan orang—respons datang bertahap, bukan sekaligus
- Hemat waktu dan uang: Jika LLM mulai memberi jawaban yang salah, kamu bisa menghentikannya lebih awal daripada menunggu respons lengkap (yang tidak berguna)
- Debugging lebih baik: Saat membangun aplikasi, kamu bisa melihat masalah (seperti error format) saat itu juga, bukan setelah menunggu lama
Apa sebenarnya streaming itu: Streaming adalah pengiriman bertahap dari teks respons yang sama. Ini tidak membuka reasoning tersembunyi atau proses internal model—ini hanya menunjukkan output parsial saat tersedia dari API. Bayangkan seperti mengunduh file: kamu melihat progres saat potongan (chunk) datang, tetapi isi file sama baik kamu mengunduh sekaligus maupun bertahap.
Catatan tentang batas chunk: Chunk tidak dijamin selaras dengan kata atau kalimat. API mengirim token dalam batch kecil untuk efisiensi, jadi sebuah chunk bisa berupa "Hel", "lo! How", " can I", " help you", "?". Ini normal dan memang diharapkan—jangan mencoba menafsirkan makna dari tiap chunk secara terpisah.
Chat Loop Dasar
Ini adalah chat loop streaming yang minimal:
# chat.py
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
def main():
load_dotenv()
llm = ChatOpenAI(model="gpt-4o-mini")
print("Chat dimulai. Ketik 'quit' atau 'exit' untuk berhenti.\n")
while True:
user_input = input("Kamu: ")
if user_input.lower() in ["quit", "exit"]:
print("Sampai jumpa!")
break
print("Asisten: ", end="", flush=True)
for chunk in llm.stream([HumanMessage(content=user_input)]):
print(chunk.content, end="", flush=True)
print("\n")
if __name__ == "__main__":
main()Cara kerjanya:
while True:: Loop tak hingga untuk percakapan terus-menerusinput("You: "): Ambil input pengguna dari terminalllm.stream([HumanMessage(...)]): Stream respons LLM- Output streaming dengan parameter khusus:
end="": Jangan tambah newline setelah tiap chunk (menjaga output tetap di baris yang sama)flush=True: Paksa output langsung ke terminal tanpa buffering
Kenapa [HumanMessage(content=user_input)]?
Model chat LangChain mengharapkan list of messages, bukan string mentah. Setiap message punya role:
- HumanMessage: Input pengguna
- AIMessage: Respons LLM
- SystemMessage: Instruksi untuk LLM (dibahas di Bab 4)
Bahkan untuk satu message pengguna, kamu mengirim list: [HumanMessage(content="Hello")].
Keterbatasan utama - Percakapan single-turn: Chat loop ini sengaja dibuat stateless. Setiap request hanya mengirim message saat ini, bukan riwayat percakapan sebelumnya. Ini berarti:
- LLM tidak akan mengingat apa yang kamu tanyakan sebelumnya
- Pertanyaan lanjutan seperti "Bagaimana dengan populasinya?" tidak akan bekerja setelah bertanya "Apa ibu kota Prancis?"
- Ini adalah karakteristik fundamental LLM—mereka tidak punya memori kecuali kamu secara eksplisit memberi konteks
Contoh keterbatasannya:
Kamu: Apa ibu kota Prancis?
Asisten: Paris.
Kamu: Berapa populasinya?
Asisten: Saya tidak punya cukup konteks. Kota mana yang kamu maksud?Loop while True memberi kontinuitas UX (kamu bisa terus chat), tetapi tiap turn berdiri sendiri. Akan dibahas di Bab 8: Kita akan mengimplementasikan memori percakapan dengan menyimpan dan mengirim ulang riwayat message pada tiap request.
Menjalankan Chat Loop
python chat.pyContoh interaksi:
Chat dimulai. Ketik 'quit' atau 'exit' untuk berhenti.
Kamu: Apa itu LangChain?
Asisten: LangChain adalah kerangka kerja untuk mengembangkan aplikasi yang ditenagai oleh model bahasa. Ini menyediakan alat untuk manajemen prompt, chain, agen, dan memori.
Kamu: Beri saya contoh sederhana
Asisten: Berikut contoh dasarnya: ...
Kamu: quit
Sampai jumpa!Memahami Streaming API
Apa itu "chunk"?
Setiap chunk adalah objek AIMessageChunk dengan:
content: Token teks yang dihasilkanresponse_metadata: Info model, jumlah token, dll.
for chunk in llm.stream([HumanMessage(content="Hello")]):
print(f"Chunk: {chunk}")
print(f"Content: {chunk.content}")
print(f"Type: {type(chunk)}")Output:
Chunk: content='Hello' response_metadata={'model_provider': 'openai', ...}
Content: Hello
Type: <class 'langchain_core.messages.ai.AIMessageChunk'>
Chunk: content='!' response_metadata={...}
Content: !
Type: <class 'langchain_core.messages.ai.AIMessageChunk'>
Chunk: content=' How' response_metadata={...}
Content: How
Type: <class 'langchain_core.messages.ai.AIMessageChunk'>Mengakumulasi Respons Lengkap
Kadang kamu butuh respons lengkap (untuk logging, testing, atau pemrosesan lanjutan):
def chat_with_accumulation():
load_dotenv()
llm = ChatOpenAI(model="gpt-4o-mini")
user_input = input("Kamu: ")
full_response = ""
print("Assistant: ", end="", flush=True)
for chunk in llm.stream([HumanMessage(content=user_input)]):
print(chunk.content, end="", flush=True)
full_response += chunk.content
print("\n")
# Sekarang kamu punya respons lengkapnya
print(f"[DEBUG] Panjang respons penuh: {len(full_response)} chars")
return full_responsePola ini umum saat kamu perlu:
- Menyimpan percakapan ke database
- Mem-parsing respons untuk data terstruktur
- Menghitung penggunaan token atau biaya
Struktur proyek kamu setelah bagian ini:
langchain-chat/
├── venv/
├── .env
├── .gitignore
├── requirements.txt
├── test_install.py
└── chat.py # Chat loop streaming (baru!)Berikutnya: Bagian 3.4 menunjukkan cara menangani tipe model yang berbeda dengan konfigurasi parameter yang cerdas.
3.4) Konfigurasi Cerdas: Menangani Parameter untuk Reasoning vs Chat Models
OpenAI menawarkan dua tipe model dengan kapabilitas dan mekanisme kontrol yang berbeda:
Chat models (gpt-4o, gpt-4o-mini):
- Cepat dan conversational
- Mendukung
temperatureuntuk mengontrol randomness dan kreativitas - Terbaik untuk tugas umum, penulisan kreatif, coding rutin
Reasoning models (o1, o3, GPT-5):
- Lebih lambat tetapi lebih logis dan konsisten
- TIDAK mendukung
temperature(menggunakan internal reasoning) - Terbaik untuk matematika kompleks, perencanaan multi-langkah, analisis formal
Perbedaan kunci: Chat models memakai sampling probabilistik (kamu mengontrol randomness), sedangkan reasoning models memakai logika internal yang deterministik (model mengontrol proses reasoning-nya sendiri).
Memahami Temperature (Hanya Chat Models)
Apa itu temperature?
Temperature adalah angka antara 0.0 dan 2.0 yang mengontrol seberapa kreatif respons model. Pada nilai rendah (mendekati 0), kamu mendapat jawaban yang konsisten dan dapat diprediksi. Pada nilai tinggi (mendekati 2.0), kamu mendapat respons yang kreatif dan bervariasi. Anggap saja seperti "tombol pengatur kreativitas".
Cara kerjanya: Saat menghasilkan tiap kata, model melihat banyak kemungkinan kata berikutnya dengan probabilitas yang berbeda. Temperature memengaruhi bagaimana model memilih:
- Temperature rendah (0.0): Hampir selalu memilih kata dengan probabilitas tertinggi → respons konsisten dan fokus
- Temperature tinggi (2.0): Lebih mungkin memilih kata dengan probabilitas lebih rendah → respons beragam dan kreatif
Penting: Temperature hanya bekerja dengan chat models (gpt-4o, gpt-4o-mini). Temperature tidak berlaku untuk reasoning models (GPT-5, o1, o3), yang memakai logika internal alih-alih sampling probabilistik.
Panduan nilai temperature:
-
0.0: Sangat deterministik, fokus, dan konsisten
- Gunakan untuk: Q&A faktual, pembuatan kode rutin, output terstruktur
- Input yang sama → output hampir identik setiap kali
- Contoh: "What is 2+2?" → Selalu "4"
-
0.7–1.0: Perilaku sampling standar (default adalah 1.0)
- Gunakan untuk: percakapan umum, penjelasan, respons seimbang
- Variasi moderat dalam frasa dan contoh
- Contoh: "Explain photosynthesis" → Kata-kata berbeda tiap kali, info inti sama
-
1.2–2.0: Lebih kreatif dan beragam, lebih sulit diprediksi
- Gunakan untuk: penulisan kreatif, brainstorming, ideasi
- Variasi tinggi pada tone, struktur, dan kata-kata
- Contoh: "Write a poem about the moon" → Gaya sangat berbeda tiap kali
Catatan: Nilai di atas 1.0 meningkatkan kreativitas tetapi bisa menurunkan akurasi faktual dan koherensi. Nilai maksimum adalah 2.0.
Contoh: Dampak temperature (hanya chat models)
# Temperature 0.0 - deterministik, jawaban sama setiap kali
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.0)
response = llm.invoke([HumanMessage(content="Berapa 2+2?")])
print(response.content) # Output: 4
# Temperature 1.0 - perilaku default, kemungkinan variasi kecil
llm = ChatOpenAI(model="gpt-4o-mini", temperature=1.0)
response = llm.invoke([HumanMessage(content="Berapa 2+2?")])
print(response.content) # Output: 4 (mungkin disertai penjelasan singkat)Untuk pertanyaan tertutup yang faktual, temperature hanya sedikit berpengaruh terhadap kebenaran.
Untuk tugas open-ended atau kreatif, temperature sangat memengaruhi keberagaman, tone, dan gaya.
Bagaimana Jika Kamu Memakai Parameter Chat Model pada Reasoning Models?
Tergantung modelnya - beberapa menolak, yang lain diam-diam mengabaikan:
# ❌ Ini akan gagal pada model o3
llm = ChatOpenAI(model="o3-mini", temperature=0.7)Error:
BadRequestError: Temperature is not supported with this modelModel berbeda, kebijakan berbeda:
- Model o1 / o3: Secara eksplisit menolak parameter yang tidak didukung. Jika temperature disertakan, API langsung mengembalikan error 400 BadRequest.
- Model GPT-5: Lebih permisif—parameter diterima tetapi diam-diam diabaikan. Request kamu berhasil, tetapi temperature tidak berpengaruh.
Kenapa ini penting: Selalu cek model mana yang kamu gunakan dan konfigurasikan parameter dengan sesuai. Memakai parameter yang salah bisa menyebabkan error atau gagal diam-diam, membuang waktu debugging.
Cara Mengontrol Perilaku Reasoning Model
Sekarang kamu tahu chat models memakai temperature dan reasoning models tidak. Jadi bagaimana mengontrol reasoning models?
Reasoning models di-tune lewat desain prompt, bukan parameter:
- Reasoning models tidak mengekspos
temperatureatau kontrol serupa - Sebagai gantinya, kamu mengarahkan perilaku lewat cara kamu menulis prompt:
- Instruksi eksplisit: "Think step-by-step", "Show your work"
- Constraint sebagai aturan: "You must not assume...", "Always verify..."
- Kebutuhan terstruktur: "Output in JSON format", "Include reasoning before answer"
- Logika keputusan: "If condition A, then do X, otherwise do Y"
Contoh: Parameter chat vs prompt reasoning
# ❌ Pendekatan chat - tidak akan bekerja untuk reasoning models
llm = ChatOpenAI(model="o3-mini", temperature=0.5)
# Error: BadRequestError: Temperature is not supported
# ✅ Pendekatan reasoning - arahkan lewat struktur prompt
prompt = """
Selesaikan masalah ini langkah demi langkah:
1. Nyatakan apa yang kamu ketahui
2. Tunjukkan perhitunganmu
3. Verifikasi jawabanmu
Soal: Jika x + 5 = 12, berapa nilai x?
"""
llm = ChatOpenAI(model="o3-mini")
response = llm.invoke([HumanMessage(content=prompt)])
print(response.content)Output:
1. Yang saya ketahui: x + 5 = 12
2. Perhitungan: x = 12 - 5 = 7
3. Verifikasi: 7 + 5 = 12 ✓
Jawaban: x = 7Insight kunci: Chat models dikontrol dengan parameter, reasoning models dikontrol dengan prompt.
Tabel Keputusan Pemilihan Model
Sekarang kamu paham cara mengontrol kedua tipe model, ini kapan harus memakai masing-masing:
| Tipe Tugas | Model yang Direkomendasikan | Kenapa |
|---|---|---|
| Percakapan umum | gpt-4o-mini | Cepat, murah, conversational |
| Q&A sederhana | gpt-4o-mini | Cukup untuk lookup faktual |
| Penulisan kreatif | gpt-4o-mini (temp 0.8–1.0) | Temperature memungkinkan kreativitas |
| Pembuatan kode | GPT-5 | Perencanaan logis lebih baik |
| Reasoning kompleks | GPT-5 | Dioptimalkan untuk logika multi-langkah |
| Soal matematika | o3 / o1 | Reasoning models khusus |
| Perencanaan multi-langkah | GPT-5 | Kuat untuk perencanaan jangka panjang |
| Analisis formal (legal/kebijakan) | o3 | Deterministik secara ketat |
Trade-off Biaya dan Latensi
Memahami trade-off praktis membantu kamu memilih model yang tepat untuk use case kamu:
| Tipe Model | Kecepatan (Latensi Tipikal) | Biaya (Relatif) | Terbaik Untuk |
|---|---|---|---|
| gpt-4o-mini | Sangat cepat (<2s) | Sangat rendah | Percakapan umum, tugas sederhana |
| gpt-4o | Cepat (1–4s) | Menengah | Chat kualitas lebih tinggi, tugas multimodal |
| GPT-5 | Sedang (3–8s) | Tinggi | Reasoning kompleks, perencanaan |
| o1 / o3 | Paling lambat (5–15s+) | Paling tinggi | Reasoning deterministik, logika formal |
Catatan:
- Kecepatan mencerminkan latensi respons tipikal (bervariasi tergantung panjang prompt dan kompleksitas)
- Biaya adalah perbandingan relatif—cek harga terbaru di website OpenAI
- Reasoning models menukar kecepatan dan biaya untuk konsistensi dan ketepatan
- Chat models memprioritaskan responsivitas dan efisiensi
Kapan memakai reasoning models (GPT-5, o1, o3):
- Soal matematika multi-langkah dan masalah STEM(Science, Technology, Engineering, Mathematics) yang membutuhkan langkah intermediate yang benar
- Analisis logis kompleks dengan dependensi dan constraint
- Debugging kode dengan banyak penyebab yang saling berinteraksi
- Tugas perencanaan dengan banyak aturan, edge case, atau trade-off
- Workflow agen yang membutuhkan konsistensi dan pemikiran jangka panjang
Kapan memakai chat models (gpt-4o, gpt-4o-mini):
- Percakapan umum dan chat interaktif
- Q&A sederhana dengan kedalaman reasoning terbatas
- Pembuatan konten (blog, ringkasan, penulisan kreatif)
- Pembuatan kode rutin dan tugas boilerplate
- Aplikasi di mana kecepatan dan biaya lebih penting daripada reasoning mendalam
Berikutnya: Bagian 3.5 menunjukkan teknik debugging untuk memeriksa apa yang benar-benar dikirim ke LLM.
3.5) Debugging: Memeriksa Respons dan Penggunaan Token
Saat LLM kamu berperilaku tidak seperti yang diharapkan, kamu perlu melihat persis apa yang dikirim dan diterima. Bagian ini menunjukkan cara memeriksa panggilan LLM dan men-debug masalah.
Kenapa Debugging Itu Penting
Skenario debugging yang umum:
- "Kenapa LLM memberi jawaban ini?" → Cek prompt yang persis
- "Berapa biaya request ini?" → Cek penggunaan token
- "Kenapa ini lambat sekali?" → Ukur latensi
- "Apakah format message saya benar?" → Inspeksi struktur message
Tantangannya: Saat kamu memanggil llm.invoke(), kamu mendapat objek respons. Tapi sebenarnya apa isinya? Informasi apa yang tersedia untuk debugging?
Memahami Objek Respons
Sebelum debugging, kamu perlu paham apa yang dikembalikan llm.invoke().
Struktur dasar:
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
llm = ChatOpenAI(model="gpt-4o-mini")
response = llm.invoke([HumanMessage(content="Hello")])
# Apa isi responsnya?
print(type(response)) # AIMessage
print(response.content) # Teks sebenarnya
print(response.response_metadata) # Penggunaan token, info model, dll.Output:
<class 'langchain_core.messages.ai.AIMessage'>
Hello! How can I assist you today?
{
'token_usage': {
'completion_tokens': 9,
'prompt_tokens': 8,
'total_tokens': 17
},
'model_name': 'gpt-4o-mini-2024-07-18',
'finish_reason': 'stop',
...
}Bagian kunci dari respons:
response.content: Teks yang dihasilkan LLMresponse.response_metadata: Dictionary yang berisi:token_usage: Berapa token yang dipakai (untuk perhitungan biaya)model_name: Versi model persis yang meresponsfinish_reason: Kenapa generasi berhenti (lihat bagian Debug Mode untuk detail)
Mengakses penggunaan token:
token_usage = response.response_metadata['token_usage']
print(f"Prompt tokens: {token_usage['prompt_tokens']}")
print(f"Response tokens: {token_usage['completion_tokens']}")
print(f"Total: {token_usage['total_tokens']}")Output:
Prompt tokens: 8
Response tokens: 9
Total: 17Kenapa ini penting: Kamu butuh nilai-nilai ini untuk debugging, pelacakan biaya, dan mengoptimalkan prompt kamu.
Menghitung Biaya dari Penggunaan Token
Penggunaan token menentukan biaya. Setiap model punya harga yang berbeda:
GPT-4o-mini (per Januari 2026):
- Input: $0.15 per 1M token
- Output: $0.60 per 1M token
GPT-4o:
- Input: $2.50 per 1M token
- Output: $10.00 per 1M token
Fungsi perhitungan biaya:
def calculate_cost(token_usage, model_name):
"""Menghitung biaya berdasarkan penggunaan token."""
prompt_tokens = token_usage.get('prompt_tokens', 0)
completion_tokens = token_usage.get('completion_tokens', 0)
# Harga per 1M token (per Januari 2026)
pricing = {
'gpt-4o-mini': {'input': 0.15, 'output': 0.60},
'gpt-4o': {'input': 2.50, 'output': 10.00},
'gpt-5': {'input': 1.25, 'output': 10.00},
}
if model_name not in pricing:
return None
input_cost = (prompt_tokens / 1_000_000) * pricing[model_name]['input']
output_cost = (completion_tokens / 1_000_000) * pricing[model_name]['output']
return input_cost + output_cost
# Contoh
response = llm.invoke([HumanMessage(content="Jelaskan komputasi kuantum")])
token_usage = response.response_metadata['token_usage']
cost = calculate_cost(token_usage, "gpt-4o-mini")
print(f"Cost: ${cost:.6f}")Output:
Cost: $0.000123Kenapa ini penting: Aplikasi production bisa menangani 50.000+ request/hari. Dengan $0.002 per request, itu $3.000/bulan. Memakai model yang salah atau prompt yang terlalu bengkak, biayanya melonjak jadi $30.000/bulan. Bug retry loop bisa membakar ribuan dolar semalam. Lacak penggunaan token sejak hari pertama.
Mengaktifkan Debug Mode (Saat Kamu Butuh Detail Raw API)
Objek respons dan wrapper kustom menangani sebagian besar kebutuhan debugging. Tapi kadang kamu perlu melihat persis apa yang LangChain kirim ke OpenAI—request dan response JSON mentah.
Kapan kamu mungkin butuh ini:
- Men-debug format message LangChain
- Memverifikasi parameter API diset dengan benar
- Menginvestigasi error API yang tidak terduga
- Memahami payload API yang persis
LangChain punya debug logging bawaan via langchain_core.globals:
from langchain_core.globals import set_debug
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
set_debug(True)
# Sekarang semua panggilan LLM akan mencetak info debug
llm = ChatOpenAI(model="gpt-4o-mini")
response = llm.invoke([HumanMessage(content="Hello")])Output:
[llm/start] [llm:ChatOpenAI] Entering LLM run with input:
{
"prompts": [
"Human: Hello"
]
}
[llm/end] [llm:ChatOpenAI] [1.45s] Exiting LLM run with output:
{
"generations": [
[
{
"text": "Hello! How can I assist you today?",
"generation_info": {
"finish_reason": "stop",
"logprobs": null
},
"type": "ChatGeneration",
...
}
]
],
"llm_output": {
"token_usage": {
"completion_tokens": 9,
"prompt_tokens": 8,
"total_tokens": 17,
...
},
"model_provider": "openai",
"model_name": "gpt-4o-mini-2024-07-18",
...
},
}Catatan: Format output bervariasi tergantung provider LLM. Contoh ini menunjukkan struktur OpenAI.
Apa yang ditunjukkan output debug:
Debug mode menunjukkan alur komunikasi LangChain → OpenAI secara lengkap:
1. Transformasi format message:
# Kode kamu
[HumanMessage(content="Hello")]
# Yang kamu lihat di output debug
{
"prompts": ["Human: Hello"]
}Debug mode menunjukkan bagaimana LangChain merepresentasikan message kamu secara internal sebelum mengirim ke LLM.
2. Status penyelesaian generasi:
"finish_reason": "stop"Kenapa generasi berakhir:
"stop": Model menyelesaikan respons secara natural"length": Respons terpotong karena mencapai batas max_tokens"tool_calls": Model mengakhiri generasi dengan menghasilkan instruksi pemanggilan alat (tool call) alih-alih respons teks final (Bab 12)"content_filter": Respons diblokir atau ditekan karena aturan safety atau moderasi konten
Jika kamu melihat "length", naikkan max_tokens untuk mendapatkan respons lengkap.
3. Rincian penggunaan token:
"token_usage": {
"completion_tokens": 9,
"prompt_tokens": 8,
"total_tokens": 17,
"completion_tokens_details": {
"reasoning_tokens": 0 # Untuk reasoning models (o1/o3, dll.)
},
"prompt_tokens_details": {
"cached_tokens": 0 # Prompt caching (menghemat biaya)
}
}Selain hitungan dasar, kamu bisa melihat:
- reasoning_tokens: Langkah reasoning internal (hanya untuk reasoning models)
- cached_tokens: Berapa token prompt yang dilayani dari cache (mengurangi biaya)
4. Versi model dan fingerprint:
"model_name": "gpt-4o-mini-2024-07-18",
"system_fingerprint": "fp_8bbc38b4db"- model_name: Versi snapshot yang persis (menjelaskan kenapa respons berubah dari waktu ke waktu)
- system_fingerprint: ID konfigurasi backend OpenAI (berubah saat mereka meng-update sistem)
5. Timing request:
[llm/end] [llm:ChatOpenAI] [1.56s][1.45s] menunjukkan total durasi request—berguna untuk mengidentifikasi query yang lambat.
Berikutnya: Bagian 3.6 menunjukkan cara menangani error umum dengan baik.
3.6) Menangani Kegagalan (Simulasikan dan perbaiki error umum)
Aplikasi LLM production menghadapi mode kegagalan yang dapat diprediksi: kredensial hilang, network timeout, rate limit, dan input tidak valid. Bagian ini menunjukkan cara menangani error ini dengan baik dan membangun aplikasi yang tangguh sejak hari pertama.
Enam Error yang Umum
1. API Key Hilang
Kapan ini terjadi: Kamu mencoba membuat instance ChatOpenAI, tetapi OPENAI_API_KEY tidak diset di environment kamu.
Contoh:
# File .env tidak ada, atau OPENAI_API_KEY tidak didefinisikan
llm = ChatOpenAI(model="gpt-4o-mini")
response = llm.invoke([HumanMessage(content="Hello")])Error yang akan kamu lihat:
OpenAIError: The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variableCara memperbaiki:
- Cek file
.envada di root proyek - Pastikan nama key persis
OPENAI_API_KEY(typo umum:OPENAPI_KEY) - Pastikan
load_dotenv()dipanggil sebelum membuat LLM
2. API Key Salah
Kapan ini terjadi: File .env kamu berisi API key yang tidak valid, kedaluwarsa, atau salah salin.
Contoh:
# .env berisi: OPENAI_API_KEY=sk-invalid-key-12345
llm = ChatOpenAI(model="gpt-4o-mini")
response = llm.invoke([HumanMessage(content="Hello")])Error yang akan kamu lihat:
AuthenticationError: Incorrect API key providedCara memperbaiki:
- Buka https://platform.openai.com/api-keys
- Pastikan key kamu masih aktif (tidak dicabut atau kedaluwarsa)
- Buat key baru jika diperlukan
- Salin seluruh key dengan teliti (kesalahan umum: karakter awal/akhir hilang)
- Tempel ke
.envtanpa spasi tambahan:
OPENAI_API_KEY=sk-proj-exactkeyhere3. Kegagalan Jaringan
Kapan ini terjadi: Koneksi internet kamu putus, atau server OpenAI sementara tidak bisa dijangkau saat request.
Contoh:
# WiFi putus di tengah request, atau OpenAI API sedang down
response = llm.invoke([HumanMessage(content="Hello")])Error yang akan kamu lihat:
APIConnectionError: Connection errorCara memperbaiki:
- Cek koneksi internet kamu
- Verifikasi status OpenAI di https://status.openai.com
4. Rate Limits
Kapan ini terjadi: Kamu mengirim terlalu banyak request dalam waktu singkat dan melampaui kuota API.
Contoh:
# Mengirim 1000 request secara instan
for i in range(1000):
llm.invoke([HumanMessage(content=f"Request {i}")])Error yang akan kamu lihat:
RateLimitError: Rate limit reached for requestsCara memperbaiki:
- Cek rate limit kamu di https://platform.openai.com/account/limits
- Upgrade plan kamu jika butuh limit lebih tinggi
- Gunakan batch processing untuk workload besar (dibahas di Bab 6)
5. Nama Model Tidak Valid
Kapan ini terjadi: Kamu menentukan nama model yang tidak ada atau tidak tersedia di plan kamu.
Contoh:
llm = ChatOpenAI(model="gpt-99-ultra") # Tidak ada
response = llm.invoke([HumanMessage(content="Hello")])Error yang akan kamu lihat:
NotFoundError: The model `gpt-99-ultra` does not exist or you do not have access to itCara memperbaiki:
- Cek model yang tersedia pada plan kamu di https://platform.openai.com/docs/models
6. Batas Token Terlampaui
Kapan ini terjadi: Prompt kamu terlalu panjang dan melebihi context window maksimum model.
Contoh:
# Membuat prompt 1 juta karakter
huge_prompt = "x" * 1_000_000
response = llm.invoke([HumanMessage(content=huge_prompt)])Error yang akan kamu lihat:
BadRequestError: This model's maximum context length is 128000 tokens. However, your messages resulted in 250000 tokens.Cara memperbaiki:
- Cek panjang input sebelum mengirim
- Ketahui batas model kamu:
- gpt-4o-mini: 128K token
- gpt-4o: 128K token
- gpt-5: 400K token
- Untuk dokumen panjang, gunakan chunking atau summarization (dibahas di Bab 9)
Langkah berikutnya: Bab 4 menunjukkan cara mendesain prompt template yang reusable yang memisahkan prompt engineering dari kode aplikasi.