Referensi praktis LangChain Python. Model, tools, agents, structured output, RAG, LangGraph, testing, tracing, dan keamanan.
LangChain Python cocok saat kamu perlu menyatukan chat model, tool, prompt, state percakapan, dan observability dalam satu aplikasi. Untuk loop agent standar, mulai dari create_agent. Untuk satu panggilan model tanpa tool, pakai init_chat_model atau kelas provider seperti ChatOpenAI. Untuk alur yang punya percabangan deterministik, approval manusia, pekerjaan paralel, atau state tahan lama, turun ke LangGraph.
Versi baru LangChain memakai gaya v1 dengan create_agent. Banyak tutorial lama masih memakai LLMChain, AgentExecutor, atau create_react_agent versi terdahulu. Jangan salin pola lama hanya karena hasil pencariannya tinggi. API LangChain berubah cukup cepat. Pin versi paket di proyekmu, baca dokumentasi resmi saat upgrade, lalu uji ulang contoh kode sebelum masuk produksi.
Rujukan utama yang layak dibuka saat bekerja adalah docs.langchain.com/oss/python/langchain dan API reference provider yang kamu pakai. Nama model juga berubah mengikuti provider. Contoh gpt-5-nano di halaman ini perlu kamu cocokkan lagi dengan model yang tersedia di akunmu.
| Kebutuhan | Titik awal | Catatan |
|---|---|---|
| Jawaban chat tunggal | ChatOpenAI atau init_chat_model | Tidak perlu agent bila tidak ada tool atau loop |
| Memanggil API, database, atau fungsi Python | @tool + create_agent | Deskripsi tool ikut memengaruhi keputusan model |
| Output JSON tervalidasi | with_structured_output() atau response_format= | Gunakan schema Pydantic |
| Q&A dari dokumen sendiri | loaders, splitter, embeddings, vector store, retriever | Uji kualitas chunk dan sumber jawaban |
| Alur agent yang rumit | LangGraph StateGraph | Tepat untuk route, retry khusus, approval, dan checkpoint |
Buat virtual environment terpisah. Simpan kunci API di environment variable atau secret manager, bukan di repository dan bukan di prompt. Paket inti tidak otomatis membawa integrasi setiap provider.
python -m venv .venv
source .venv/bin/activate
pip install -U langchain langchain-openai langchain-text-splitters
# Tambahkan saat benar-benar diperlukan
pip install -U langgraph pydantic
export OPENAI_API_KEY="isi-dari-secret-manager"Untuk dependency yang stabil, pin versi setelah kamu sudah memverifikasi aplikasi. Contoh berikut memakai batas mayor agar upgrade besar tidak masuk diam-diam:
langchain>=1,<2
langchain-openai>=1,<2
langchain-text-splitters>=1,<2
langgraph>=1,<2
pydantic>=2,<3Jangan anggap batas ini cukup untuk aplikasi yang sensitif. Di CI dan produksi, kunci versi lengkap lewat lockfile uv.lock, poetry.lock, atau requirements yang sudah dipin. Cek changelog LangChain dan provider sebelum menaikkan versi. Satu perubahan kecil pada format tool call bisa mematahkan alur agent.
init_chat_model memberi antarmuka umum untuk provider. Bentuk string biasanya mengikuti provider:model. Ini enak kalau kamu mau mengganti provider tanpa mengganti banyak kode aplikasi.
from langchain.chat_models import init_chat_model
model = init_chat_model(
"openai:gpt-5-nano",
temperature=0,
timeout=30,
max_retries=2,
)
response = model.invoke("Jelaskan perbedaan list dan tuple di Python.")
print(response.text)Untuk fitur spesifik OpenAI, gunakan ChatOpenAI dari paket langchain-openai. Contoh ini memakai stream_usage=True agar metadata penggunaan token dapat tersedia saat streaming, jika endpoint mendukungnya.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-5-nano",
temperature=0,
timeout=30,
max_retries=2,
stream_usage=True,
)
answer = llm.invoke("Tulis fungsi Python untuk mengecek bilangan prima.")
print(answer.text)
print(answer.usage_metadata)temperature=0 membantu output yang lebih konsisten, tapi bukan jaminan hasil identik. Untuk tugas kreatif, nilainya bisa dinaikkan. Untuk ekstraksi data, routing, dan tool call, mulai dari nilai rendah dulu. Atur timeout agar request tidak menggantung terlalu lama. Retry cocok untuk timeout, gangguan koneksi, atau rate limit, bukan untuk API key salah, model tidak ada, atau input yang ditolak provider.
Chat model bekerja dengan daftar pesan. Bentuk tuple ringkas cocok untuk banyak kasus. Role yang umum dipakai adalah system, human, dan ai. System message menjelaskan batas tugas dan gaya jawaban, bukan tempat aman untuk menyimpan rahasia.
messages = [
(
"system",
"Kamu tutor Python. Jawab dalam Bahasa Indonesia, singkat, dan beri contoh kecil.",
),
("human", "Kapan aku memakai generator expression?"),
]
response = llm.invoke(messages)
print(response.text)Kalau kamu perlu menyusun message sebagai objek, gunakan kelas message dari LangChain. Bentuk ini berguna saat perlu memeriksa tipe pesan atau menambahkan metadata.
from langchain.messages import HumanMessage, SystemMessage
messages = [
SystemMessage(content="Jawab tanpa menebak data yang tidak tersedia."),
HumanMessage(content="Apa risiko menyimpan API key di frontend?"),
]
response = llm.invoke(messages)
print(response.text)Pilih invoke() untuk hasil akhir sekali jalan, stream() untuk token bertahap, dan batch() untuk banyak input independen. Jangan memasukkan riwayat percakapan tanpa batas. Riwayat panjang menaikkan biaya, latensi, dan risiko context overflow. Ringkas pesan lama atau simpan fakta yang benar-benar perlu dipakai pada giliran berikutnya.
Teks JSON yang tampak benar belum tentu valid. Schema Pydantic memberi tipe, validasi, dan kontrak yang bisa diuji. Untuk panggilan model langsung, with_structured_output() adalah pilihan sederhana.
from pydantic import BaseModel, Field
class BugReport(BaseModel):
title: str = Field(description="Ringkasan masalah dalam satu kalimat")
severity: str = Field(description="Salah satu dari low, medium, high")
steps: list[str] = Field(description="Langkah reproduksi masalah")
structured_llm = llm.with_structured_output(BugReport)
report = structured_llm.invoke(
"Aplikasi crash ketika aku klik Simpan setelah mengosongkan email. "
"Itu mengganggu checkout pelanggan."
)
print(report.title)
print(report.severity)
print(report.steps)Gunakan field yang sempit bila aplikasi punya aturan ketat. Misalnya, ganti str dengan Literal["low", "medium", "high"] jika pilihan tidak boleh bebas. Validasi schema mengurangi kesalahan bentuk data, tapi tidak membuktikan fakta di dalam field. Model masih dapat mengisi nilai yang rapi namun keliru.
Pada agent, masukkan schema ke response_format. Hasil tervalidasi tersedia di key structured_response pada state agent.
from langchain.agents import create_agent
from pydantic import BaseModel
class AnswerCard(BaseModel):
answer: str
needs_human_review: bool
agent = create_agent(
model=llm,
tools=[],
response_format=AnswerCard,
system_prompt="Jawab berdasarkan informasi yang tersedia. Jangan mengarang sumber.",
)
result = agent.invoke(
{"messages": [{"role": "user", "content": "Apa itu dependency injection?"}]}
)
card = result["structured_response"]
print(card.answer)
print(card.needs_human_review)Jika provider mendukung structured output native, LangChain dapat memilih strategi provider. Jika tidak, LangChain bisa memakai tool calling. Perilaku detail ini dapat berubah antarprovider. Uji schema pada input normal, input kosong, input ambigu, dan input yang sengaja rusak.
@toolTool memberi model akses ke aksi yang nyata. Itu berarti tool punya dampak lebih besar dibanding prompt biasa. Fungsi, type hint, docstring, dan nilai balik perlu ditulis sangat jelas. Model memakai deskripsi tersebut untuk memutuskan kapan tool dipanggil dan parameter apa yang dikirim.
from langchain.tools import tool
ORDERS = {
"BK-1001": "diproses",
"BK-1002": "dikirim",
}
@tool
def get_order_status(order_id: str) -> str:
"""Ambil status pesanan berdasarkan ID seperti BK-1001."""
status = ORDERS.get(order_id)
if status is None:
return "Pesanan tidak ditemukan. Minta pengguna memeriksa ID pesanan."
return f"Status pesanan {order_id}: {status}"
print(get_order_status.invoke({"order_id": "BK-1001"}))Tool yang memanggil HTTP API perlu timeout, pembatasan domain, validasi parameter, dan pesan error yang aman. Jangan teruskan URL bebas atau SQL bebas dari pengguna ke tool. Validasi input dekat dengan aksi yang berisiko, bukan hanya di system prompt.
from urllib.parse import urlparse
import requests
from langchain.tools import tool
ALLOWED_HOSTS = {"status.example.com"}
@tool
def get_status_page(url: str) -> str:
"""Baca status layanan dari status.example.com saja."""
parsed = urlparse(url)
if parsed.scheme != "https" or parsed.netloc not in ALLOWED_HOSTS:
return "URL ditolak. Hanya https://status.example.com yang diizinkan."
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
return response.text[:4000]
except requests.Timeout:
return "Layanan status tidak merespons dalam lima detik."
except requests.RequestException:
return "Gagal mengambil status layanan. Coba lagi nanti."Untuk aksi mengirim email, menghapus data, transfer uang, atau mengubah hak akses, jangan biarkan model langsung mengeksekusi. Tampilkan detail tindakan dan minta persetujuan manusia. Middleware human-in-the-loop dapat membantu menerapkan pola ini, tetapi validasi otorisasi tetap harus ada di backend tool.
create_agentcreate_agent membangun loop model dan tool. Model membaca konteks, memilih tool bila perlu, menerima hasil tool, lalu menjawab saat tool tidak lagi dibutuhkan. Mulai dari tool sedikit. Terlalu banyak tool dengan nama mirip membuat model lebih mudah memilih tool yang salah.
from langchain.agents import create_agent
support_agent = create_agent(
model=llm,
tools=[get_order_status],
system_prompt=(
"Kamu menangani status pesanan. Gunakan get_order_status saat pengguna "
"memberi ID pesanan. Jangan mengaku sudah mengubah pesanan."
),
)
result = support_agent.invoke(
{
"messages": [
{"role": "user", "content": "Status pesanan BK-1002 bagaimana?"}
]
}
)
print(result["messages"][-1].text)State hasil biasanya memuat urutan messages, termasuk tool call dan ToolMessage. Jangan kirim seluruh state mentah ke frontend jika di dalamnya ada parameter internal, token, atau hasil tool yang sensitif. Bentuk respons API yang sengaja kamu pilih lebih aman.
Riwayat percakapan persisten membutuhkan checkpointer dan thread_id. thread_id mengidentifikasi percakapan. Data per-request seperti user ID, role, tenant, dan feature flag sebaiknya lewat context yang dibaca tool atau middleware. Jangan percaya user ID yang dikirim frontend tanpa autentikasi server.
from langgraph.checkpoint.memory import InMemorySaver
stateful_agent = create_agent(
model=llm,
tools=[get_order_status],
checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": "support-session-42"}}
result = stateful_agent.invoke(
{"messages": [{"role": "user", "content": "Cek BK-1001"}]},
config=config,
)InMemorySaver hanya cocok untuk eksperimen lokal karena isi state hilang saat proses berhenti. Produksi perlu checkpointer yang tahan restart, kebijakan retensi, isolasi per tenant, serta kontrol akses saat membaca checkpoint.
Middleware mengintervensi loop agent sebelum atau sesudah model serta tool berjalan. Ini tempat yang pas untuk retry, batas jumlah model call, logging, PII redaction, pemilihan tool dinamis, atau approval manusia. Jangan memakai middleware untuk menyembunyikan bug bisnis.
from langchain.agents.middleware import ModelRetryMiddleware, ToolRetryMiddleware
resilient_agent = create_agent(
model=llm,
tools=[get_order_status],
middleware=[
ModelRetryMiddleware(
max_retries=3,
backoff_factor=2.0,
initial_delay=1.0,
),
ToolRetryMiddleware(
max_retries=2,
retry_on=(ConnectionError, TimeoutError),
on_failure="continue",
),
],
)Retry harus idempotent. Tool GET yang membaca data biasanya aman diulang. Tool untuk membuat invoice, kirim pesan, atau charge kartu bisa menggandakan dampak bila retry terjadi setelah server sebenarnya berhasil namun respons hilang. Pakai idempotency key, catat request ID, dan minta approval sebelum aksi mahal atau destruktif.
Tangani error di batas aplikasi juga. Bedakan error yang bisa dicoba ulang dari error konfigurasi dan error input. Pesan untuk pengguna tidak perlu memuat stack trace, nama tabel, API key, atau URL internal. Stack trace tetap masuk log privat agar kamu bisa memperbaiki masalahnya.
Untuk chat sederhana, stream token langsung dari model. Frontend bisa menampilkan teks bertahap tanpa menunggu seluruh jawaban.
messages = [("human", "Jelaskan recursion dalam lima kalimat.")]
for chunk in llm.stream(messages):
print(chunk.text, end="", flush=True)Agent juga dapat mengirim progres tool dan output model. API streaming lama berbasis stream_mode masih ada pada banyak contoh. Untuk aplikasi baru, dokumentasi LangChain kini merekomendasikan event streaming karena projection untuk messages, tool calls, values, dan subgraph dipisah.
stream = support_agent.stream_events(
{"messages": [{"role": "user", "content": "Cek BK-1001"}]},
version="v3",
)
for message in stream.messages:
for delta in message.text:
print(delta, end="", flush=True)
final_state = stream.outputJangan menampilkan argument tool mentah atau hasil tool sensitif ke pengguna. Streaming juga butuh strategi pembatalan saat browser menutup koneksi, limit ukuran buffer, dan event error yang jelas. Kalau UI menunjukkan progres seperti "mencari pesanan", pastikan itu berasal dari event nyata, bukan teks dekoratif.
RAG mengambil konteks dari data eksternal ketika ada pertanyaan. Alurnya biasanya: dokumen dimuat, dipecah menjadi chunk, diubah menjadi embedding, disimpan pada vector store, lalu dicari saat query datang. Hasil retrieval tetap bahan bukti yang perlu disaring, bukan jawaban otomatis yang selalu benar.
from langchain_core.documents import Document
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
documents = [
Document(
page_content="Pengembalian barang bisa diajukan dalam 14 hari setelah pesanan diterima.",
metadata={"source": "kebijakan-pengembalian"},
),
Document(
page_content="Produk digital yang sudah diakses tidak dapat dikembalikan.",
metadata={"source": "kebijakan-produk-digital"},
),
]
splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=80,
add_start_index=True,
)
chunks = splitter.split_documents(documents)
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vector_store = InMemoryVectorStore(embeddings)
vector_store.add_documents(documents=chunks)
retriever = vector_store.as_retriever(search_kwargs={"k": 3})
found_docs = retriever.invoke("Apakah produk digital boleh dikembalikan?")
for doc in found_docs:
print(doc.metadata["source"])
print(doc.page_content)InMemoryVectorStore cocok untuk belajar dan test. Aplikasi nyata biasanya memerlukan penyimpanan persisten, metadata filter, penghapusan dokumen, versi indeks, dan audit siapa yang boleh mencari data tertentu. Jangan mencampur dokumen antar pelanggan dalam satu query tanpa filter tenant yang dipaksakan server.
Pilih arsitektur sesuai kebutuhan. Two-step RAG selalu retrieve lalu generate, sehingga alurnya lebih mudah diprediksi. Agentic RAG memberi agent tool retrieval dan membiarkannya memilih kapan mencari. Ini berguna bila pertanyaan perlu beberapa sumber, tetapi biaya dan jalurnya lebih bervariasi. Hybrid RAG menambah pemeriksaan relevansi atau validasi jawaban sebelum respons dikirim.
Kualitas RAG sering rusak bukan karena model. Penyebab yang sering muncul adalah chunk terlalu besar, chunk terlalu kecil, metadata sumber hilang, dokumen basi, query tanpa filter, atau prompt yang tidak mewajibkan jawaban berkata "tidak tahu" saat bukti tidak cukup. Simpan source, judul, versi dokumen, dan izin akses di metadata. Tampilkan kutipan sumber bila produkmu memang mendukungnya.
LangChain dan LangGraph saling terkait, tapi tugasnya berbeda. LangChain memberi integrasi model, tool, serta harness agent. Agent dari create_agent berjalan di atas LangGraph. LangGraph memberi kontrol lebih rendah untuk graph stateful: node, edge, routing, checkpoint, interrupt, dan langkah deterministik.
Gunakan create_agent saat alurmu cukup seperti ini: model memutuskan apakah perlu tool, tool berjalan, model memberi jawaban. Jangan buru-buru membuat graph manual untuk chatbot FAQ kecil.
Pilih LangGraph bila kamu perlu aturan seperti "klasifikasikan tiket, route ke agent billing atau teknis, minta approval sebelum refund, lalu tulis audit log". Bagian klasifikasi dan audit dapat kamu buat deterministik, sementara agent tetap menangani bahasa alami.
from langgraph.graph import END, START, MessagesState, StateGraph
def greet_node(state: MessagesState):
return {"messages": [{"role": "ai", "content": "Halo, ada yang bisa aku bantu?"}]}
graph = StateGraph(MessagesState)
graph.add_node("greet", greet_node)
graph.add_edge(START, "greet")
graph.add_edge("greet", END)
app = graph.compile()
result = app.invoke({"messages": [{"role": "user", "content": "Hai"}]})
print(result["messages"][-1].content)Jaga node tetap kecil dan punya kontrak input-output yang jelas. Node yang menerima semua state global lalu mengubah banyak key sulit diuji. Buat state schema, log transisi, dan identifikasi titik yang perlu idempotency. LangGraph membantu mengatur alur, tetapi tidak otomatis memperbaiki prompt injection, akses data, atau keputusan bisnis yang buruk.
Mulai dari test unit untuk tool. Tool perlu diuji tanpa API model supaya test cepat dan deterministik. Setelah itu, test integrasi untuk schema, permission, retrieval, dan jalur error. Test end-to-end ke model sungguhan dipisahkan karena lambat, berbayar, dan output dapat berubah.
from app.tools import get_order_status
def test_get_order_status_returns_known_order():
result = get_order_status.invoke({"order_id": "BK-1001"})
assert result == "Status pesanan BK-1001: diproses"
def test_get_order_status_rejects_unknown_order():
result = get_order_status.invoke({"order_id": "BK-9999"})
assert "tidak ditemukan" in resultUntuk test agent, inject model palsu atau rekam respons provider pada fixture jika kebijakan datamu mengizinkan. Assert perilaku yang penting: tool mana yang boleh dipanggil, user tanpa role admin ditolak, output mengikuti Pydantic schema, dan agent tidak mengirim aksi tanpa approval. Jangan assert setiap kata dalam respons LLM. Fokus pada kontrak, bukti sumber, dan efek samping.
Buat set evaluasi kecil dari pertanyaan nyata yang sudah dianonimkan. Masukkan kasus ambigu, typo, pertanyaan di luar data, percobaan prompt injection, dan request yang seharusnya ditolak. Ukur apakah retrieval menemukan sumber tepat, apakah jawaban didukung sumber, dan apakah tool aman dipakai.
Tracing membantu kamu melihat input model, tool call, latensi, error, dan urutan state. LangSmith adalah opsi resmi di dokumentasi LangChain. Aktifkan tracing dari environment, lalu jangan lupa menetapkan proyek terpisah untuk development dan produksi.
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="isi-dari-secret-manager"
export LANGSMITH_PROJECT="support-agent-dev"Trace dapat berisi prompt dan hasil tool. Redaksi PII sebelum trace bila data pengguna ikut dikirim. Batasi siapa yang bisa membuka trace, tentukan masa retensi, dan jangan log header otorisasi, password, nomor kartu, atau secret. Observability yang bocor sama berbahayanya dengan endpoint yang bocor.
Pantau angka yang punya arti operasional: error rate per tool, waktu respons, jumlah tool call per request, rate limit, biaya token, dan persentase jawaban tanpa sumber pada RAG. Lihat contoh trace gagal satu per satu. Rata-rata yang bagus dapat menyembunyikan satu jalur refund yang salah.
Prompt tidak dapat menggantikan autentikasi dan otorisasi. Anggap input pengguna, dokumen RAG, hasil web, dan hasil tool sebagai data yang mungkin membawa instruksi jahat. Model tidak punya hak akses. Backend tool yang menentukan apakah aksi boleh dilakukan.
OPENAI_API_KEY dan LANGSMITH_API_KEY di secret manager. Jangan masukkan ke JavaScript browser, file MDX, commit, atau log.requests.get ke URL arbitrer serta shell command dari input model.Agent: loop yang memakai model untuk memilih tool, membaca hasilnya, lalu menyusun respons.
Checkpoint: snapshot state graph atau agent yang memungkinkan percakapan dan pekerjaan dilanjutkan.
Embedding: vektor angka yang mewakili makna teks agar teks serupa dapat dicari.
LangGraph: runtime tingkat rendah untuk workflow stateful yang menggabungkan node deterministik dan langkah berbasis model.
Middleware: hook yang mengubah atau mengawasi langkah model dan tool dalam agent loop.
Pydantic schema: class Python bertipe yang memvalidasi bentuk data masuk atau keluar.
RAG: Retrieval-Augmented Generation, pola yang mengambil konteks eksternal sebelum atau saat model menjawab.
Retriever: antarmuka yang menerima query teks lalu mengembalikan dokumen relevan.
Structured output: respons model yang dipaksa mengikuti schema, bukan teks bebas saja.
Tool: fungsi dengan input dan output jelas yang dapat dipanggil model melalui agent.
Vector store: penyimpanan yang menaruh embedding dan menjalankan pencarian kemiripan.
Login atau daftar akun gratis untuk membaca cheat sheet ini.