🔗 LangGraph Cơ bản
LangGraph là framework từ LangChain team để build complex, stateful agent workflows. Bài này sẽ giúp bạn master các concepts cốt lõi của LangGraph.
Tại sao cần LangGraph?
Vấn đề với simple agents
Agents đơn giản gặp khó khăn với:
- Complex multi-step workflows
- Conditional logic và branching
- State management across steps
- Error handling và retries
- Human-in-the-loop
LangGraph giải quyết những vấn đề này bằng cách model agents như graphs:
Diagram
graph TD
Start([Start]) --> A[Gather Info]
A --> B{Enough Info?}
B -->|Yes| C[Generate Response]
B -->|No| D[Ask Clarifying Question]
D --> A
C --> End([End])Core Concepts
1. State
State là "bộ nhớ" của graph, được truyền qua các nodes:
Python
1from typing import TypedDict, Annotated2import operator34class AgentState(TypedDict):5 # Messages accumulate với operator.add6 messages: Annotated[list, operator.add]7 8 # Simple values được overwrite9 current_step: str10 user_query: str11 12 # Optional fields13 search_results: list | None14 final_answer: str | None2. Nodes
Nodes là functions xử lý state:
Python
1def gather_info_node(state: AgentState):2 """Node thu thập thông tin"""3 messages = state["messages"]4 query = state["user_query"]5 6 # Do something7 response = llm.invoke(messages)8 9 # Return state updates10 return {11 "messages": [response],12 "current_step": "gathered"13 }1415def generate_response_node(state: AgentState):16 """Node tạo response cuối cùng"""17 context = state.get("search_results", [])18 19 response = llm.invoke([20 SystemMessage("Tạo response dựa trên context"),21 HumanMessage(f"Context: {context}")22 ])23 24 return {25 "final_answer": response.content,26 "messages": [response]27 }3. Edges
Edges connect nodes và define flow:
Python
1from langgraph.graph import StateGraph, END23# Create graph4workflow = StateGraph(AgentState)56# Add nodes7workflow.add_node("gather", gather_info_node)8workflow.add_node("respond", generate_response_node)910# Simple edge: gather → respond11workflow.add_edge("gather", "respond")1213# End edge: respond → END14workflow.add_edge("respond", END)1516# Set start17workflow.set_entry_point("gather")4. Conditional Edges
Branching logic dựa trên state:
Python
1def should_continue(state: AgentState) -> str:2 """Quyết định bước tiếp theo"""3 messages = state["messages"]4 last_message = messages[-1]5 6 # Nếu có tool call, đi đến action node7 if hasattr(last_message, "tool_calls") and last_message.tool_calls:8 return "action"9 10 # Không có tool call, kết thúc11 return "end"1213# Add conditional edge14workflow.add_conditional_edges(15 "reasoning", # From node16 should_continue, # Router function17 {18 "action": "action_node", # If returns "action"19 "end": END # If returns "end"20 }21)Build một Graph hoàn chỉnh
Ví dụ: Research Agent
Python
1from langgraph.graph import StateGraph, END2from langchain_openai import ChatOpenAI3from langchain_core.messages import SystemMessage, HumanMessage, AIMessage4from typing import TypedDict, Annotated, Literal5import operator67# 1. Define State8class ResearchState(TypedDict):9 messages: Annotated[list, operator.add]10 topic: str11 search_results: list12 outline: str13 draft: str14 final_report: str1516# 2. Define Nodes17llm = ChatOpenAI(model="gpt-4o")1819def search_node(state: ResearchState):20 """Tìm kiếm thông tin về topic"""21 topic = state["topic"]22 23 # Giả lập search24 results = [25 f"Result 1 about {topic}",26 f"Result 2 about {topic}",27 f"Result 3 about {topic}"28 ]29 30 return {31 "search_results": results,32 "messages": [AIMessage(content=f"Found {len(results)} results")]33 }3435def outline_node(state: ResearchState):36 """Tạo outline từ search results"""37 results = state["search_results"]38 topic = state["topic"]39 40 response = llm.invoke([41 SystemMessage("Tạo outline cho research report"),42 HumanMessage(f"Topic: {topic}\nResults: {results}")43 ])44 45 return {46 "outline": response.content,47 "messages": [response]48 }4950def draft_node(state: ResearchState):51 """Viết draft dựa trên outline"""52 outline = state["outline"]53 results = state["search_results"]54 55 response = llm.invoke([56 SystemMessage("Viết draft report dựa trên outline"),57 HumanMessage(f"Outline:\n{outline}\n\nSources:\n{results}")58 ])59 60 return {61 "draft": response.content,62 "messages": [response]63 }6465def review_node(state: ResearchState):66 """Review và finalize report"""67 draft = state["draft"]68 69 response = llm.invoke([70 SystemMessage("Review và polish report này"),71 HumanMessage(draft)72 ])73 74 return {75 "final_report": response.content,76 "messages": [response]77 }7879# 3. Build Graph80workflow = StateGraph(ResearchState)8182workflow.add_node("search", search_node)83workflow.add_node("outline", outline_node)84workflow.add_node("draft", draft_node)85workflow.add_node("review", review_node)8687# Linear flow: search → outline → draft → review → END88workflow.add_edge("search", "outline")89workflow.add_edge("outline", "draft")90workflow.add_edge("draft", "review")91workflow.add_edge("review", END)9293workflow.set_entry_point("search")9495# 4. Compile96graph = workflow.compile()9798# 5. Run99result = graph.invoke({100 "topic": "AI Agents in 2024",101 "messages": [],102 "search_results": [],103 "outline": "",104 "draft": "",105 "final_report": ""106})107108print(result["final_report"])Visualize Graph
Python
1# Tạo diagram của graph2from IPython.display import Image, display34display(Image(graph.get_graph().draw_mermaid_png()))Output:
Diagram
graph TD
__start__ --> search
search --> outline
outline --> draft
draft --> review
review --> __end__Checkpointing (Persistence)
Lưu state để resume later:
Python
1from langgraph.checkpoint.memory import MemorySaver23# Memory checkpointer4checkpointer = MemorySaver()56# Compile với checkpointer7graph = workflow.compile(checkpointer=checkpointer)89# Run với thread_id để track10config = {"configurable": {"thread_id": "research-123"}}11result = graph.invoke(initial_state, config=config)1213# Resume later với same thread_id14state = graph.get_state(config)Human-in-the-Loop
Pause để chờ human input:
Python
1from langgraph.graph import StateGraph, END2from langgraph.checkpoint.memory import MemorySaver34def human_review_node(state):5 """Node chờ human review"""6 draft = state["draft"]7 8 # Node này chỉ format output9 # Human sẽ review và provide feedback10 return {11 "awaiting_review": True,12 "messages": [AIMessage(f"Draft ready for review:\n{draft}")]13 }1415# Add interrupt before human_review16graph = workflow.compile(17 checkpointer=MemorySaver(),18 interrupt_before=["human_review"] # Pause trước node này19)2021# Run until interrupt22result = graph.invoke(initial_state, config)23# Graph pauses at human_review2425# Human provides feedback26graph.update_state(config, {27 "human_feedback": "Please add more details about X"28})2930# Continue from interrupt31result = graph.invoke(None, config) # None = continue from checkpointStreaming
Stream outputs real-time:
Python
1# Stream all events2for event in graph.stream(initial_state):3 print(event)45# Stream specific events6for event in graph.stream(initial_state, stream_mode="values"):7 print(f"Current state: {event}")89# Stream với updates mode10for node_name, output in graph.stream(initial_state, stream_mode="updates"):11 print(f"{node_name}: {output}")Bài tập thực hành
Hands-on Exercise
Build một Customer Support Graph:
-
Nodes:
classify: Phân loại query (billing/technical/general)billing_handler: Xử lý billing questionstechnical_handler: Xử lý technical issuesgeneral_handler: Xử lý general queriesrespond: Tạo final response
-
Flow:
- classify → (conditional) → handler nodes → respond → END
-
Test với các queries:
- "Tôi muốn hủy subscription"
- "App không hoạt động"
- "Giờ làm việc của công ty"
Python
1# Starter code2from langgraph.graph import StateGraph, END3from typing import TypedDict, Annotated, Literal4import operator56class SupportState(TypedDict):7 messages: Annotated[list, operator.add]8 query: str9 category: Literal["billing", "technical", "general"] | None10 response: str | None1112def classify_node(state: SupportState):13 # TODO: Implement classification14 pass1516def route_by_category(state: SupportState) -> str:17 # TODO: Return category name18 pass1920# TODO: Build the graphTiếp theo
Trong bài tiếp theo, chúng ta sẽ build First Agent - một agent hoàn chỉnh sử dụng tools với LangGraph.
