Khi mới xây agent, đa số chúng ta viết một vòng while gọi LLM, parse output, rồi dùng if/else để quyết định bước tiếp theo. Cách này chạy được với demo, nhưng vỡ trận khi agent thật cần: quay lại bước cũ để thử lại (retry), chờ người duyệt, chạy song song, hoặc khôi phục sau khi tiến trình crash. Lúc đó code biến thành một mớ cờ (flag) chằng chịt mà không ai dám sửa, mỗi lần thêm tính năng lại kéo theo vài bug ẩn.
LangGraph giải quyết vấn đề này bằng cách mô hình hóa agent thành state machine: một đồ thị (graph) gồm các node (việc cần làm) nối với nhau bằng edge (luồng đi), cùng một khối state dùng chung được truyền qua từng node. Bạn mô tả agent như một sơ đồ, và LangGraph lo phần chạy, lưu, khôi phục.
Ba khái niệm nền tảng
- State: một cấu trúc dữ liệu (thường là
TypedDict) chứa toàn bộ thông tin agent cần — tin nhắn, kết quả tool, biến điều khiển. Mỗi node đọc state, trả về phần cập nhật. - Node: một hàm Python nhận state, làm đúng một việc (gọi LLM, gọi API, xử lý dữ liệu), trả về dict cập nhật state.
- Edge: đường nối quyết định node nào chạy tiếp. Có edge cố định (luôn đi một hướng) và edge có điều kiện (conditional, tự chọn hướng theo state).
Ví dụ cụ thể: agent trả lời câu hỏi có tra cứu
Hãy hình dung agent hỗ trợ khách hàng. Luồng nghiệp vụ:
- Node
classify: phân loại câu hỏi (hỏi giá, khiếu nại, chào hỏi...). - Node
search: tra cứu tài liệu nếu câu hỏi cần dữ liệu. - Node
answer: soạn câu trả lời cuối. - Edge có điều kiện: sau
classify, nếu là câu hỏi cần dữ liệu thì đisearch, nếu chỉ chào hỏi thì đi thẳnganswer.
if.from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class State(TypedDict):
question: str
category: str
context: str
answer: str
def classify(state: State) -> dict:
# gọi LLM để phân loại; ở đây minh họa đơn giản
cat = "faq" if "giá" in state["question"] else "chat"
return {"category": cat}
Mỗi node ngắn gọn, một trách nhiệm. Khi cần sửa cách phân loại, bạn chỉ đụng vào classify mà không sợ ảnh hưởng phần soạn câu trả lời.
Các bước tư duy khi thiết kế agent bằng graph
- Liệt kê các "việc" agent phải làm — mỗi việc là một node ứng viên.
- Xác định dữ liệu chung cần truyền giữa các việc — đó chính là state.
- Vẽ luồng giữa các việc: đâu là đường thẳng, đâu là ngã rẽ (conditional edge), đâu là vòng lặp.
- Đánh dấu điểm dừng: nơi cần chờ người, nơi có thể lặp lại.
- Chỉ khi sơ đồ đã rõ mới bắt tay code từng node.
Khung tư duy: "Node làm, Edge quyết, State nhớ"
Ghi nhớ câu này. Mỗi khi bí, tự hỏi: dữ liệu này thuộc State hay là logic của Node? Quyết định rẽ nhánh này là Edge có điều kiện hay là việc bên trong Node? Ranh giới rõ ràng giúp graph dễ đọc và cho phép test từng phần độc lập — điều gần như bất khả thi với vòng while khổng lồ.
So sánh nhanh
| Cách viết vòng lặp thủ công | Cách state machine (LangGraph) |
|---|---|
| Logic trộn lẫn trong một hàm | Mỗi node một trách nhiệm |
| Khó lưu/khôi phục giữa chừng | Checkpoint có sẵn |
| Human-in-loop phải tự chế | Có cơ chế interrupt |
| Khó test từng bước | Test từng node dễ dàng |
| Vòng lặp khó kiểm soát | Cycle có ngưỡng rõ ràng |
Sai lầm thường gặp
- Nhồi mọi thứ vào một node: node "god function" gọi LLM, parse, gọi tool và quyết định — đánh mất toàn bộ lợi ích của graph. Hãy chia nhỏ.
- Đặt logic rẽ nhánh bên trong node thay vì dùng conditional edge, khiến luồng bị ẩn và khó theo dõi khi vẽ sơ đồ.
- Cho state chứa dữ liệu tạm không cần thiết, làm state phình to, khó debug và tốn token khi truyền cho LLM.
- Bắt đầu code trước khi vẽ sơ đồ: bạn sẽ liên tục refactor. Vẽ trước, code sau.