Danh sách bài viết

Bài 26: Vì sao cần LangGraph khi đã có LangChain

LangGraph là framework graph-based của LangChain Inc., xây dựng trên cùng ecosystem LangChain nhưng giải quyết bài toán khác: stateful agent với vòng lặp, branching phức tạp, human-in-the-loop và checkpoint. Bài này phân tích cụ thể những gì LCEL không làm tốt và LangGraph tiếp cận thế nào.

27/05/2026
1 lượt xem
1

Mục tiêu bài học

Sau bài này bạn sẽ:

  • Hiểu rõ những tình huống LCEL xử lý không tốt khi agent phức tạp dần.
  • Biết LangGraph là gì, khác gì LangChain, và chúng coexist thế nào.
  • Nhận ra mô hình mental của Graph (node + edge + state).
  • Biết khi nào nên dùng LangGraph, khi nào LCEL hoặc SDK thuần là đủ.
  • Nhận biết được một số pitfall phổ biến trước khi đào sâu vào syntax.

Bài này là intro module — syntax và implementation chi tiết sẽ ở bài 27–31.

2

Giới hạn của LangChain LCEL với agent phức tạp

LCEL được thiết kế để compose các Runnable thành pipeline tuyến tính (hoặc parallel tĩnh). Điều này đủ dùng cho phần lớn use case RAG và chain đơn giản, nhưng khi agent cần nhiều bước hơn thì một số vấn đề xuất hiện:

Vòng lặp đa bước

Bài 25 đã minh họa vòng lặp agent thủ công: gọi LLM → nếu có tool_calls thì execute rồi gọi lại, lặp đến khi không còn tool call. Vòng lặp đó phải tự viết Python thuần (for + điều kiện break), nằm ngoài LCEL chain. LCEL không có khái niệm loop với điều kiện dừng — chain là tuyến tính theo thiết kế.

Branching nhiều cấp

LCEL có RunnableBranch để route theo điều kiện, nhưng chỉ phù hợp cho 1 điểm phân nhánh đơn giản. Nếu workflow có nhiều nhánh lồng nhau, mỗi nhánh lại có state khác nhau, code nhanh chóng trở thành nested lambda khó đọc và khó test.

State implicit và dễ lẫn key

LCEL truyền dữ liệu giữa các bước qua Python dict thông thường. Không có định nghĩa schema rõ ràng cho toàn bộ pipeline — key nào có ở bước nào, key nào có thể None, key nào được thêm bởi bước nào. Với chain 3–4 bước thì ổn, nhưng với workflow 10+ bước và nhiều nhánh thì rất khó trace bug "key bị overwrite từ đâu".

Human-in-the-loop

Một số workflow cần dừng lại, chờ con người xem xét rồi mới tiếp tục — ví dụ agent soạn email xong cần human approve trước khi gửi, hoặc agent tạo SQL query cần DBA review trước khi chạy trên production. LCEL không có khái niệm pauseresume — pipeline chạy thẳng từ đầu đến cuối.

Checkpoint và replay

Nếu agent đang chạy đến bước 8/12 thì lỗi network, toàn bộ workflow phải chạy lại từ đầu khi dùng LCEL. Không có cơ chế persist state giữa các bước để resume từ điểm thất bại. Với agent gọi LLM nhiều lần, điều này tốn cả token lẫn thời gian.

Multi-agent

Khi cần nhiều agent chạy song song hoặc tuần tự, giao tiếp qua shared state — ví dụ một planner agent tạo kế hoạch, nhiều executor agent thực hiện từng task, rồi một reviewer agent tổng hợp — LCEL không có abstraction phù hợp để mô hình hóa flow này.

3

LangGraph là gì

LangGraph là framework để xây dựng stateful workflow dưới dạng graph, được phát triển bởi LangChain Inc. — cùng team viết LangChain và LCEL. Package riêng biệt:

pip install langgraph
# phiên bản hiện tại: 0.2.x (tính đến 2025)

Hai khái niệm cốt lõi:

  • Node — function Python nhận state, trả về state update.
  • Edge — transition từ node này sang node khác; có thể là unconditional hoặc conditional (dựa trên state).

State không phải dict thông thường mà là TypedDict được khai báo tường minh. Mọi node đều nhìn thấy và có thể update cùng một object state đó.

Built-in features của LangGraph 0.2.x:

  • Checkpointer — persist state sau mỗi node, cho phép replay/resume.
  • Interrupt — dừng graph tại node chỉ định, chờ input bên ngoài rồi tiếp tục (interrupt_before, interrupt_after).
  • Parallel branches — nhiều node chạy song song, kết quả merge lại.
  • Streaming — stream từng event trong quá trình graph chạy (mỗi node update state là 1 event).
  • Cycle — graph có thể quay lại node cũ (khác DAG thuần).

LangGraph integrate hoàn toàn với mọi LangChain Runnable: mỗi node bên trong có thể là một LCEL chain, một ChatModel, một Retriever hoặc bất kỳ callable nào.

4

Mô hình mental: Graph có cycle

Một graph LangGraph gồm:

  • State — TypedDict định nghĩa toàn bộ data workflow cần. Shared giữa tất cả nodes.
  • Nodes — function Python (hoặc callable) nhận state: State, trả về dict chứa các key muốn update.
  • Edges — khai báo luồng đi giữa nodes. Có thể cố định (add_edge) hoặc có điều kiện (add_conditional_edges).
  • START / END — hai node đặc biệt; START là điểm vào, END là điểm kết thúc.

Điểm quan trọng nhất: cycle được phép. Một node có thể có edge trỏ ngược về node trước đó, tạo vòng lặp. Đây chính là điều LCEL chain không hỗ trợ và là nền tảng để implement agent loop (LLM gọi tool → nhận kết quả → LLM quyết định gọi tiếp hay dừng → ...).

Sơ đồ đơn giản một ReAct agent:

START
  │
  ▼
[llm_node]  ← ─────────────────────┐
  │                                 │
  ├─ (có tool_calls?) ─── YES ──► [tool_node]
  │
  └─ NO ──► END

Node llm_node gọi LLM. Nếu LLM trả về tool call, edge conditional route sang tool_node để execute, sau đó quay lại llm_node. Nếu LLM trả về câu trả lời cuối, route sang END. Đây là cycle — graph không phải DAG thuần.

Mỗi lần node chạy, LangGraph gọi checkpointer persist state. Nếu workflow fail ở tool_node, có thể resume từ đúng điểm đó thay vì chạy lại từ llm_node đầu tiên.

5

So sánh LCEL và LangGraph

Tiêu chí LangChain LCEL LangGraph
Mô hình Chain tuyến tính (Runnable pipe) Graph có cycle (node + edge)
State Implicit dict, pass qua từng bước Explicit TypedDict, shared toàn graph
Branching RunnableBranch — đơn giản, 1 cấp add_conditional_edges — đầy đủ, lồng được
Loop Không có native — phải tự viết Python Native — edge có thể trỏ về node trước
Human-in-the-loop Không có khái niệm pause/resume interrupt_before / interrupt_after
Checkpoint Không có MemorySaver, SqliteSaver, PostgresSaver, RedisSaver
Use case phù hợp Pipeline ngắn, RAG, chain 1–3 bước Agent stateful, multi-agent, workflow phức tạp

LangGraph không thay thế LCEL. Chúng coexist: node bên trong LangGraph graph có thể là một LCEL chain. LangChain cung cấp component (ChatModel, Tool, Retriever), LangGraph cung cấp orchestration (state, loop, checkpoint).

6

Hello world LangGraph

Ví dụ tối giản — graph 2 node, không có LLM, chỉ để thấy cấu trúc:

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

# 1. Khai báo State — TypedDict là schema của toàn bộ graph
class State(TypedDict):
    messages: list[str]

# 2. Định nghĩa nodes — function nhận state, trả dict update
def greet(state: State) -> dict:
    return {"messages": state["messages"] + ["Hello!"]}

def farewell(state: State) -> dict:
    return {"messages": state["messages"] + ["Goodbye!"]}

# 3. Build graph
builder = StateGraph(State)
builder.add_node("greet", greet)
builder.add_node("farewell", farewell)
builder.add_edge(START, "greet")
builder.add_edge("greet", "farewell")
builder.add_edge("farewell", END)

graph = builder.compile()

# 4. Invoke — truyền initial state
result = graph.invoke({"messages": []})
print(result)
# {"messages": ["Hello!", "Goodbye!"]}

Quan sát:

  • State là TypedDict — schema rõ ràng, IDE có thể type-check.
  • Mỗi node trả dict chứa các key muốn update — không phải toàn bộ state. LangGraph merge update vào state.
  • STARTEND là constant import từ langgraph.graph.
  • Gọi builder.compile() mới tạo ra graph chạy được — bước này cũng là lúc validate cấu trúc (thiếu END, node không được kết nối...).

Bài 28 sẽ xây agent thực sự (LLM + tools) với conditional edge và tool execution loop. Bài này chỉ minh họa cấu trúc cơ bản.

7

Patterns và helpers có sẵn

LangGraph 0.2.x cung cấp sẵn một số abstraction để không phải viết lại từ đầu:

create_react_agent

Factory tạo ReAct agent từ LLM và danh sách tools trong 1 dòng. Không cần tự khai báo StateGraph, node, edge:

from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """Cộng 2 số nguyên."""
    return a + b

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
agent = create_react_agent(llm, tools=[add])

result = agent.invoke({"messages": [{"role": "user", "content": "5 + 7 bằng bao nhiêu?"}]})
# result["messages"] chứa toàn bộ conversation kể cả tool call và kết quả

create_react_agent vẫn trả về một CompiledStateGraph — vẫn có thể thêm checkpointer, gọi .stream(), dùng interrupt. Bài 28 sẽ đào chi tiết.

MessagesState

TypedDict có sẵn dành cho chatbot pattern — state chỉ cần 1 key messages: list[BaseMessage]:

from langgraph.graph import MessagesState

# Thay vì tự khai báo:
# class State(TypedDict):
#     messages: Annotated[list, add_messages]
#
# Dùng sẵn:
builder = StateGraph(MessagesState)

add_messages reducer

Mặc định khi node trả {"messages": new_list}, LangGraph overwrite key đó (replace). Dùng add_messages reducer để append thay vì replace:

from typing import Annotated
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage

class State(TypedDict):
    # Annotated với add_messages → append thay vì overwrite
    messages: Annotated[list[BaseMessage], add_messages]

Đây là một pitfall phổ biến — xem mục 11.

Checkpointers

Pass vào compile() để persist state:

from langgraph.checkpoint.memory import MemorySaver
# hoặc
from langgraph.checkpoint.sqlite import SqliteSaver
# hoặc (cần cài thêm package)
# from langgraph.checkpoint.postgres import PostgresSaver
# from langgraph.checkpoint.redis import RedisSaver

memory = MemorySaver()
graph = builder.compile(checkpointer=memory)

# Mỗi invoke với thread_id riêng = session riêng
config = {"configurable": {"thread_id": "user-123"}}
result = graph.invoke({"messages": [...]}, config=config)
8

Tooling và ecosystem

Ba công cụ thường đi kèm khi dùng LangGraph:

LangGraph Studio

Desktop app (macOS, Windows) visualize graph runtime. Hiển thị graph dưới dạng sơ đồ tương tác, cho phép step qua từng node, xem state tại từng bước, edit state rồi replay. Hữu ích khi debug agent chạy sai nhánh hoặc loop vô hạn.

LangSmith

Tracing và observability platform. LangGraph tích hợp tracing vào LangSmith theo mặc định nếu set LANGCHAIN_TRACING_V2=true. Mỗi graph run tạo ra một trace gồm tất cả node calls, state update, LLM calls bên trong. Không cần instrumentation code thủ công.

LangGraph Platform

Managed deployment service của LangChain Inc. — deploy graph như API, tự động handle scaling, checkpointing, streaming. Là tùy chọn paid; không bắt buộc để dùng LangGraph (vẫn có thể tự deploy qua FastAPI + bất kỳ infrastructure nào).

9

Khi nào dùng LangGraph, khi nào không

Nên dùng LangGraph khi

  • Agent có loop — ReAct pattern, plan-and-execute, bất kỳ workflow nào cần LLM → tool → LLM → ... lặp không cố định số lần.
  • Branching phức tạp nhiều cấp — routing khác nhau dựa trên giá trị state, có thể lồng nhau.
  • Human-in-the-loop — cần pause để con người xem xét (approve, edit, reject) trước khi tiếp tục.
  • Checkpoint / debug — muốn replay từ giữa workflow khi agent fail, hoặc cần so sánh kết quả khi thay đổi một node.
  • Multi-agent — 2+ agent cần collaborate qua shared state (planner + executor, writer + reviewer...).
  • Long-running workflow — workflow chạy nhiều phút, cần persist state giữa các LLM call.

Không cần LangGraph khi

  • Chain đơn giản: prompt → LLM → parser — LCEL gọn hơn đáng kể.
  • RAG chuẩn: retrieve → rerank → 1 LLM call — LCEL.
  • 1-shot LLM call không cần tool, không cần lịch sử — gọi SDK provider trực tiếp.
  • Batch inference offline — không cần state management, chỉ cần pipeline xử lý data.

LangGraph có learning curve và thêm dependency. Với bài toán đơn giản, overhead của nó không đem lại lợi ích tương xứng.

10

Alternatives

LangGraph không phải lựa chọn duy nhất cho orchestration agent phức tạp:

Framework Model Điểm khác biệt
LangGraph 0.2 Graph (node + edge + state) Control flow rõ ràng, coexist với LangChain, checkpoint sẵn
CrewAI Role-based agent Abstraction cao hơn — khai báo Agent, Task, Crew; ít code boilerplate hơn với multi-agent đơn giản
AutoGen (Microsoft) Conversational agent Agent giao tiếp qua message như người dùng; phù hợp multi-agent chat-style
Code thuần State machine + asyncio Không dependency, full control; phù hợp khi requirement đơn giản và team muốn tự kiểm soát

Với lộ trình này, Module 5 tập trung vào LangGraph vì nó integrate trực tiếp với LangChain ecosystem (Module 4), có checkpoint và human-in-the-loop built-in, và kiến trúc graph rõ ràng dễ debug hơn so với agent message-based.

11

Pitfalls thường gặp

1. Hiểu nhầm LangGraph là LangChain v2

LangGraph là package riêng biệt (langgraph), không phải version mới của LangChain. Cả hai cùng tồn tại — LangGraph sử dụng LangChain components bên trong node, không thay thế chúng. Import từ langgraph.graphlangchain_core/langchain_openai đều cần thiết.

2. Lạm dụng LangGraph cho chain đơn giản

Không cần StateGraph cho prompt → LLM → parser. LCEL chain = prompt | llm | parser ngắn hơn, dễ test hơn, không có overhead graph. Dùng LangGraph khi thực sự cần loop hoặc checkpoint.

3. State update bị overwrite thay vì append

Khi node trả {"messages": [new_message]}, mặc định LangGraph replace key messages bằng list mới — toàn bộ lịch sử bị mất. Để append, cần dùng Annotated[list[BaseMessage], add_messages] hoặc dùng MessagesState:

# Sai — mỗi node call xóa messages cũ
class BadState(TypedDict):
    messages: list[str]

# Đúng — messages được append
from typing import Annotated
from langgraph.graph.message import add_messages
from langchain_core.messages import BaseMessage

class GoodState(TypedDict):
    messages: Annotated[list[BaseMessage], add_messages]

4. Quên kết nối node với END

Nếu không có edge từ node cuối đến END, graph sẽ raise lỗi khi compile hoặc chạy vô hạn. builder.compile() validate cấu trúc — đọc kỹ error message nếu nó fail.

5. Conditional edge return sai giá trị

Function trong add_conditional_edges phải return một string khớp với key trong mapping. Nếu return giá trị không có trong mapping, graph raise ValueError lúc runtime (không phải lúc compile). Bài 29 sẽ trình bày chi tiết pattern này.

12

Tóm tắt

  • LCEL chain tuyến tính — phù hợp pipeline ngắn, RAG, chain không cần loop hay checkpoint.
  • LangGraph giải quyết 5 vấn đề LCEL không có: loop, branching nhiều cấp, state explicit, human-in-the-loop, checkpoint/replay.
  • LangGraph không thay thế LangChain — node bên trong vẫn dùng LangChain component (ChatModel, Tool, Retriever).
  • Mô hình mental: node (function) + edge (transition) + state (TypedDict shared). Cycle được phép — đây là nền tảng của agent loop.
  • Built-in: create_react_agent, MessagesState, add_messages reducer, MemorySaver/SqliteSaver/PostgresSaver.
  • Pitfall quan trọng nhất: state update mặc định là overwrite, không phải append — dùng reducer add_messages khi cần giữ lịch sử messages.
  • Nếu workflow đơn giản, LCEL hoặc SDK thuần vẫn là lựa chọn gọn hơn.
13

Bài tiếp theo

Bài 27: State, Node, Edge — 3 khái niệm cốt lõi — đào sâu vào từng khái niệm: cách định nghĩa State với reducer, cách viết Node đúng chuẩn, các loại Edge và cách compile graph.