
Cerita di balik layar kenapa gue ninggalin linear chains tradisional dan beralih ke LangGraph untuk membangun AI Agent berbasis state yang lebih andal.
Gue awalnya mikir membangun AI Agent itu gampang. Tinggal panggil LLM, suruh dia nge-output JSON, parsing hasilnya, panggil tool Python yang sesuai, kelar.
Tapi begitu agen yang gue rancang butuh logika yang lebih kompleks—misalnya harus ada perulangan (loops) di mana agen mencoba suatu tugas, memeriksa hasilnya, dan kalau salah dia harus memperbaiki kodenya sendiri sebelum nanya ke gue—script Python gue mulai berubah jadi sarang laba-laba (spaghetti code).
Gue nyoba nulis state manager sendiri. Ngirim list messages bolak-balik lewat argumen fungsi, nge-handle error tool call secara manual, sampai nyoba nge-jeda eksekusi buat nunggu persetujuan gue (human-in-the-loop). Hasilnya? Pusing sendiri. Kodenya jadi rapuh, susah di-debug, dan rawan kena infinite loop yang bikin kuota API key gue ludes dalam semalam.
Di sinilah gue nabrak batasan LangChain biasa dan mutusin buat migrasi ke LangGraph.
Awalnya gue skeptis, "Ah, paling ini cuma wrapper LangChain lainnya yang bikin ribet." Tapi setelah gue coba refaktor logic asisten gue (Nouva) pake library ini, gue sadar kalau konsep graf berbasis state yang mereka tawarkan adalah solusi paling masuk akal buat masalah gue.
LangGraph itu gampangnya cuma memetakan alur kerja agen lu jadi sebuah diagram alur (graf) yang punya memori bersama (state). Ada tiga komponen utama yang wajib lu pahami:
State saat ini, kerja, lalu nge-kembalikan perubahan (update) untuk ditulis ke State.Mari kita buat agen sederhana yang bisa melakukan operasi matematika dasar menggunakan sebuah tool. Kalau pengguna nanya soal matematika, agen bakal diarahkan ke node tool kalkulator; kalau cuma ngobrol biasa, agen bakal langsung menjawab tanpa manggil tool.
Instal dulu library-nya. Di sini kita pake OpenAI sebagai LLM-nya:
pip install langgraph langchain-openai
Kita definisikan AgentState yang bakal melacak daftar pesan percakapan kita. Kita pake add_messages biar pesan baru otomatis ditambahkan ke daftar lama, bukan menimpanya.
from typing import Annotated, Sequence
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
class AgentState(TypedDict):
# add_messages bertindak sebagai reducer untuk menggabungkan pesan baru
messages: Annotated[Sequence[BaseMessage], add_messages]
Kita bikin satu tool sederhana bernama multiply untuk mengalikan angka, lalu hubungkan tool ini ke model LLM.
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Mengalikan dua bilangan bulat."""
return a * b
tools = [multiply]
# Kita bind tools ke model agar LLM tahu dia punya akses ke tool perkalian
model = ChatOpenAI(model="gpt-4o-mini", temperature=0).bind_tools(tools)
Kita butuh dua node: satu untuk manggil LLM (call_model), dan satu lagi untuk nge-run tool (tool_node). LangGraph udah nyediain ToolNode bawaan biar kita gak perlu nulis fungsi eksekusi tool manual.
from langchain_core.messages import ToolMessage
from langgraph.prebuilt import ToolNode
# Node 1: Manggil LLM
def call_model(state: AgentState):
messages = state["messages"]
response = model.invoke(messages)
# Kita kembalikan pesan respons LLM untuk diupdate ke State
return {"messages": [response]}
# Node 2: Eksekutor Tool
tool_node = ToolNode(tools)
Ini adalah otak penentu alur. Kita cek pesan terakhir dari LLM. Apakah LLM butuh manggil tool? Kalau iya, lanjut ke node tools. Kalau gak butuh, stop workflow.
def should_continue(state: AgentState):
last_message = state["messages"][-1]
# Coba cek apakah ada tool_calls di respons terakhir LLM
if last_message.tool_calls:
return "tools"
# Kalau gak ada, kita arahkan ke node spesial '__end__' untuk berhenti
return "__end__"
Sekarang kita rakit semuanya menggunakan StateGraph. Di sinilah keindahan LangGraph kelihatan: alur kerja agen didefinisikan secara deklaratif dan sangat mudah dibaca.
from langgraph.graph import StateGraph, START, END
# 1. Inisialisasi graf dengan State yang udah kita rancang
workflow = StateGraph(AgentState)
# 2. Daftarkan node-node pekerja kita
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)
# 3. Tentukan titik mulai (START) langsung masuk ke node agent
workflow.add_edge(START, "agent")
# 4. Tambahkan logika percabangan dari node agent
workflow.add_conditional_edges(
"agent",
should_continue,
{
# formatnya: "kondisi": "node tujuan"
"tools": "tools",
"__end__": END
}
)
# 5. Setelah tool selesai dieksekusi, oper balik hasilnya ke node agent
# Ini yang disebut siklus (cycle/loop)
workflow.add_edge("tools", "agent")
# 6. Compile graf menjadi aplikasi siap pakai
app = workflow.compile()
Mari kita tes jalankan graf yang sudah kita compile tadi:
from langchain_core.messages import HumanMessage
# Kita coba kirim pertanyaan matematika yang butuh tool perkalian
events = app.stream(
{"messages": [HumanMessage(content="Berapa hasil dari 23 dikali 45?")]}
)
for event in events:
for value in event.values():
print("Assistant:", value["messages"][-1].content)
Gue gak bakal bilang LangGraph itu library yang sempurna tanpa cela. Library ini punya learning curve yang lumayan bikin dahi mengkerut di awal, terutama kalau lu gak biasa dengan konsep Graph Theory atau sintaksis LangChain Expression Language (LCEL) yang kadang terasa terlalu bertele-tele.
Tapi untuk project agen yang kompleks, keuntungan yang didapat sebanding dengan repotnya belajar di awal:
while True manual yang rawan infinite loop. Alur berputar (LLM -> Tool -> LLM) ditangani secara native dan aman oleh graf.Kalau agen lu cuma butuh alur linear sekali jalan (tanya -> cari DB -> jawab), pake LangChain biasa atau script Python raw itu udah lebih dari cukup. Jangan over-engineer.
Tapi begitu agen lu butuh otak yang bisa mikir berulang kali, butuh pakai tools secara dinamis, dan butuh pengawasan manusia sebelum mengeksekusi perintah bahaya, LangGraph adalah pilihan paling pragmatis saat ini untuk menyelamatkan lu dari neraka spaghetti code.