หากคุณกำลังพัฒนา AI Agent ที่ต้องการความซับซ้อนในการจัดการสถานะ (Stateful) และ workflow ที่ยืดหยุ่น LangGraph คือเครื่องมือที่ GitHub มี stars เกิน 90,000 ครั้ง และถูกใช้งานจริงใน production ขององค์กรชั้นนำทั่วโลก ในบทความนี้ผมจะพาคุณเจาะลึกการทำงาน พร้อมตัวอย่างโค้ดที่ใช้งานได้จริง และวิเคราะห์ต้นทุนอย่างละเอียด
ทำไมต้อง LangGraph? ทำความเข้าใจ Stateful vs Stateless Agent
AI Agent พื้นฐานที่ใช้ prompt ธรรมดาเป็น Stateless — ทุกครั้งที่ส่ง request ใหม่ ระบบจะ "ลืม" ทุกอย่างที่เคยคุยมา แต่ในโลกจริง AI Agent ต้องการ:
- จำสถานะการสนทนายาว (Long-term memory)
- ตัดสินใจตามข้อมูลที่สะสมมา (Context-aware decisions)
- ทำงานหลายขั้นตอนต่อเนื่องกัน (Multi-step workflow)
- รองรับการย้อนกลับและแก้ไข (Rollback & retry)
LangGraph สร้างมาเพื่อแก้ปัญหานี้โดยเฉพาะ ด้วยสถาปัตยกรรม Graph-based ที่ทำให้การจัดการ state สะอาดและ predictable
ตารางเปรียบเทียบต้นทุน LLM APIs ปี 2026
ก่อนจะเข้าสู่โค้ด มาดูต้นทุนที่สำคัญสำหรับการ deploy AI Agent ใน production กันก่อน:
| Model | Output Price ($/MTok) | 10M Tokens/เดือน | DeepSeek ประหยัด |
|---|---|---|---|
| GPT-4.1 | $8.00 | $80.00 | 95% |
| Claude Sonnet 4.5 | $15.00 | $150.00 | 97% |
| Gemini 2.5 Flash | $2.50 | $25.00 | 83% |
| DeepSeek V3.2 | $0.42 | $4.20 | — |
จะเห็นได้ว่า DeepSeek V3.2 มีราคาถูกกว่า GPT-4.1 ถึง 95% ซึ่งสำหรับ workflow ที่ต้องเรียก LLM หลายครั้งต่อการทำงานหนึ่งครั้ง (เช่น multi-step agent) ต้นทุนนี้จะส่งผลต่อ ROI อย่างมาก
สถาปัตยกรรมของ LangGraph: Graph, Nodes, และ Edges
LangGraph ใช้ concept ง่ายๆ คือทุกอย่างคือ Graph ที่ประกอบด้วย:
- Nodes — หน่วยการทำงาน (functions ที่รับ state เข้า และ return state ออก)
- Edges — เส้นทางการไหลของ state ระหว่าง nodes
- State — shared memory ที่ nodes ทั้งหมดเข้าถึงได้
┌─────────────────────────────────────────────────────────────┐
│ LangGraph Flow │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ START │───▶│ Node 1 │───▶│ Node 2 │ │
│ └──────────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │Condition │ │ Node 3 │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ ┌────────┴────────┐ │ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌────────┐│ END │
│ │ Node A │ │ Node B ││ │
│ └────┬───┘ └────┬───┘│ │
│ └────────┬────────┬─┘ │
│ ▼ │
│ ┌────────┐ │
│ │ END │ │
│ └────────┘ │
└─────────────────────────────────────────────────────────────┘
การติดตั้งและ Setup Environment
pip install langgraph langchain-core langchain-holysheep
ตัวอย่างที่ 1: Customer Support Agent พื้นฐาน
มาเริ่มกันง่ายๆ ด้วย Customer Support Agent ที่จำสถานะการสนทนาและตัดสินใจ route ปัญหาไปยัง department ที่เหมาะสม:
import os
from typing import TypedDict, Annotated
from langgraph.graph import StateGraph, END
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
from langchain_holysheep import ChatHolySheep
Setup HolySheep API - ราคาถูกกว่า 85%+ เมื่อเทียบกับ official API
os.environ["HOLYSHEEP_API_KEY"] = "YOUR_HOLYSHEEP_API_KEY"
llm = ChatHolySheep(
model="deepseek-v3.2",
base_url="https://api.holysheep.ai/v1",
api_key=os.environ["HOLYSHEEP_API_KEY"],
temperature=0.7
)
Define State Schema - กำหนดโครงสร้างข้อมูลที่ agent จะจำ
class SupportAgentState(TypedDict):
messages: list
intent: str | None
department: str | None
resolution_status: str
def classify_intent(state: SupportAgentState) -> SupportAgentState:
"""Node 1: วิเคราะห์ว่าลูกค้าต้องการอะไร"""
messages = state["messages"]
last_message = messages[-1].content
prompt = f"""Classify customer intent into one of these categories:
- billing: ปัญหาเกี่ยวกับบิลหรือการชำระเงิน
- technical: ปัญหาทางเทคนิคหรือ bug
- sales: สอบถามเกี่ยวกับ product ใหม่
- complaint: ร้องเรียนหรือแจ้งปัญหาบริการ
Customer message: {last_message}
Return only the category name."""
response = llm.invoke([HumanMessage(content=prompt)])
intent = response.content.strip().lower()
return {"intent": intent}
def route_to_department(state: SupportAgentState) -> str:
"""Edge: ตัดสินใจว่าจะ route ไป department ไหน"""
intent = state.get("intent", "unknown")
routes = {
"billing": "handle_billing",
"technical": "handle_technical",
"sales": "handle_sales",
"complaint": "handle_complaint"
}
return routes.get(intent, "handle_general")
def handle_billing(state: SupportAgentState) -> SupportAgentState:
"""Node 2a: จัดการปัญหา billing"""
messages = state["messages"]
system_msg = SystemMessage(content="""You are a billing specialist.
Help customers with invoice issues, payment problems, or refund requests.
Be clear about policies and timelines.""")
response = llm.invoke([system_msg] + messages)
return {
"messages": messages + [response],
"department": "billing",
"resolution_status": "in_progress"
}
def handle_technical(state: SupportAgentState) -> SupportAgentState:
"""Node 2b: จัดการปัญหาทางเทคนิค"""
messages = state["messages"]
system_msg = SystemMessage(content="""You are a technical support specialist.
Help troubleshoot technical issues, bugs, or integration problems.
Ask clarifying questions to pinpoint the exact issue.""")
response = llm.invoke([system_msg] + messages)
return {
"messages": messages + [response],
"department": "technical",
"resolution_status": "in_progress"
}
def handle_sales(state: SupportAgentState) -> SupportAgentState:
"""Node 2c: จัดการคำถามขาย"""
messages = state["messages"]
system_msg = SystemMessage(content="""You are a sales representative.
Provide product information, pricing details, and help with purchasing decisions.
Be enthusiastic but not pushy.""")
response = llm.invoke([system_msg] + messages)
return {
"messages": messages + [response],
"department": "sales",
"resolution_status": "completed"
}
def handle_complaint(state: SupportAgentState) -> SupportAgentState:
"""Node 2d: จัดการร้องเรียน"""
messages = state["messages"]
system_msg = SystemMessage(content="""You are a customer relations specialist.
Handle complaints with empathy. Acknowledge the issue, apologize sincerely,
and propose solutions. Escalate if customer remains unsatisfied.""")
response = llm.invoke([system_msg] + messages)
return {
"messages": messages + [response],
"department": "customer_relations",
"resolution_status": "escalated" if "unsatisfied" in response.content.lower() else "resolved"
}
def handle_general(state: SupportAgentState) -> SupportAgentState:
"""Node 2e: จัดการกรณีทั่วไป"""
messages = state["messages"]
system_msg = SystemMessage(content="""You are a general customer support agent.
Help with any questions or concerns. If you cannot resolve the issue,
collect details and promise a callback.""")
response = llm.invoke([system_msg] + messages)
return {
"messages": messages + [response],
"department": "general",
"resolution_status": "pending"
}
Build the Graph
workflow = StateGraph(SupportAgentState)
เพิ่ม nodes
workflow.add_node("classify_intent", classify_intent)
workflow.add_node("handle_billing", handle_billing)
workflow.add_node("handle_technical", handle_technical)
workflow.add_node("handle_sales", handle_sales)
workflow.add_node("handle_complaint", handle_complaint)
workflow.add_node("handle_general", handle_general)
เพิ่ม edges
workflow.set_entry_point("classify_intent")
workflow.add_conditional_edges(
"classify_intent",
route_to_department,
{
"handle_billing": "handle_billing",
"handle_technical": "handle_technical",
"handle_sales": "handle_sales",
"handle_complaint": "handle_complaint",
"handle_general": "handle_general"
}
)
ทุก department node จบที่ END
for node in ["handle_billing", "handle_technical", "handle_sales",
"handle_complaint", "handle_general"]:
workflow.add_edge(node, END)
Compile
app = workflow.compile()
Run the agent
initial_state = {
"messages": [HumanMessage(content="ผมได้รับบิลเกินมา 500 บาท ช่วยตรวจสอบให้หน่อยได้ไหมครับ")],
"intent": None,
"department": None,
"resolution_status": ""
}
result = app.invoke(initial_state)
print(f"Department: {result['department']}")
print(f"Status: {result['resolution_status']}")
print(f"Last Response: {result['messages'][-1].content}")
ตัวอย่างที่ 2: Multi-Agent Collaboration ด้วย LangGraph
ใน production จริง คุณอาจต้องการหลาย specialized agents ทำงานร่วมกัน มาดูตัวอย่าง Research & Writing Team:
import os
from typing import TypedDict, List
from langgraph.graph import StateGraph, END, START
from langgraph.prebuilt import ToolNode
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage, BaseMessage
from langchain_holysheep import ChatHolySheep
os.environ["HOLYSHEEP_API_KEY"] = "YOUR_HOLYSHEEP_API_KEY"
Initialize multiple specialized LLMs via HolySheep
research_llm = ChatHolySheep(
model="deepseek-v3.2",
base_url="https://api.holysheep.ai/v1",
api_key=os.environ["HOLYSHEEP_API_KEY"]
)
writer_llm = ChatHolySheep(
model="gpt-4.1", # ใช้ GPT-4.1 สำหรับงานเขียนที่ต้องการคุณภาพสูง
base_url="https://api.holysheep.ai/v1",
api_key=os.environ["HOLYSHEEP_API_KEY"]
)
reviewer_llm = ChatHolySheep(
model="claude-sonnet-4.5", # Claude สำหรับงาน review ที่ต้องการ critical thinking
base_url="https://api.holysheep.ai/v1",
api_key=os.environ["HOLYSHEEP_API_KEY"]
)
class TeamResearchState(TypedDict):
topic: str
research_notes: str
draft: str
feedback: str
final_version: str
iteration: int
messages: List[BaseMessage]
def researcher(state: TeamResearchState) -> TeamResearchState:
"""Agent 1: ทำหน้าที่ค้นคว้าและรวบรวมข้อมูล"""
topic = state["topic"]
system_msg = SystemMessage(content="""You are a thorough research analyst.
Your task is to gather comprehensive information about the given topic.
Structure your findings with:
1. Key concepts and definitions
2. Important facts and statistics
3. Different perspectives or approaches
4. Notable examples or case studies
Be objective and cite sources conceptually (not real URLs).""")
prompt = f"""Research the following topic and provide structured notes:
Topic: {topic}
Focus on recent developments and practical applications."""
response = research_llm.invoke([system_msg, HumanMessage(content=prompt)])
return {
"research_notes": response.content,
"iteration": state.get("iteration", 0),
"messages": state.get("messages", []) + [
{"agent": "researcher", "content": response.content}
]
}
def writer(state: TeamResearchState) -> TeamResearchState:
"""Agent 2: เขียนบทความจากข้อมูลที่ได้รับ"""
research = state.get("research_notes", "")
previous_feedback = state.get("feedback", "")
system_msg = SystemMessage(content="""You are a skilled technical writer.
Transform research notes into a well-structured, engaging article.
Use appropriate headings, examples, and maintain consistent tone.
If there's previous feedback, incorporate it into the revision.""")
prompt = f"""Write an article based on the following research:
Research Notes:
{research}
Previous Feedback (if any):
{previous_feedback}
Write a comprehensive, publication-ready article."""
response = writer_llm.invoke([system_msg, HumanMessage(content=prompt)])
return {
"draft": response.content,
"messages": state.get("messages", []) + [
{"agent": "writer", "content": response.content}
]
}
def reviewer(state: TeamResearchState) -> TeamResearchState:
"""Agent 3: ตรวจสอบและให้ feedback"""
draft = state["draft"]
iteration = state.get("iteration", 0)
system_msg = SystemMessage(content="""You are a critical reviewer and editor.
Evaluate the draft for:
1. Accuracy and factual correctness
2. Logical flow and structure
3. Clarity and readability
4. Completeness of coverage
Provide specific, actionable feedback. If the draft is good enough,
say 'APPROVED - ready for publication'.""")
prompt = f"""Review this draft and provide detailed feedback:
Draft:
{draft}
Iteration: {iteration}"""
response = reviewer_llm.invoke([system_msg, HumanMessage(content=prompt)])
needs_revision = "APPROVED" not in response.content.upper()
return {
"feedback": response.content,
"iteration": iteration + 1 if needs_revision else iteration,
"final_version": draft if not needs_revision else state["draft"]
}
def should_revise(state: TeamResearchState) -> str:
"""Decision edge: ตรวจสอบว่าต้องแก้ไขหรือจบ"""
feedback = state["feedback"]
iteration = state.get("iteration", 0)
if "APPROVED" in feedback.upper():
return "publish"
elif iteration >= 3: # Max 3 iterations
return "publish"
else:
return "revise"
Build Team Workflow
workflow = StateGraph(TeamResearchState)
workflow.add_node("researcher", researcher)
workflow.add_node("writer", writer)
workflow.add_node("reviewer", reviewer)
workflow.add_edge(START, "researcher")
workflow.add_edge("researcher", "writer")
workflow.add_edge("writer", "reviewer")
workflow.add_conditional_edges(
"reviewer",
should_revise,
{
"revise": "writer", # ส่งกลับไปให้ writer แก้ไข
"publish": END
}
)
app = workflow.compile()
Run the team
initial_state = {
"topic": "ความแตกต่างระหว่าง Stateless และ Stateful AI Agents",
"research_notes": "",
"draft": "",
"feedback": "",
"final_version": "",
"iteration": 0,
"messages": []
}
result = app.invoke(initial_state)
print(f"Final Version:\n{result['final_version']}")
print(f"\nTotal Iterations: {result['iteration']}")
print(f"Team Messages: {len(result['messages'])}")
Memory Persistence: เก็บ State ลง Database
ใน production คุณต้องการเก็บ state ไว้ใช้งานต่อเนื่อง มาดูวิธีใช้ Redis หรือ PostgreSQL:
from langgraph.checkpoint.postgres import PostgresSaver
from langgraph.checkpoint.memory import MemorySaver
import json
from datetime import datetime
Option 1: In-memory (เหมาะสำหรับ dev)
checkpointer = MemorySaver()
Option 2: PostgreSQL (เหมาะสำหรับ production)
checkpointer = PostgresSaver.from_conn_string("postgresql://user:pass@localhost/db")
class PersistentAgentState(TypedDict):
user_id: str
session_id: str
conversation_history: List[dict]
user_preferences: dict
current_task: str | None
task_progress: dict
def create_session(user_id: str, session_id: str) -> PersistentAgentState:
"""สร้าง session ใหม่"""
return {
"user_id": user_id,
"session_id": session_id,
"conversation_history": [],
"user_preferences": {},
"current_task": None,
"task_progress": {}
}
def process_message(state: PersistentAgentState, new_message: str) -> PersistentAgentState:
"""ประมวลผลข้อความใหม่พร้อมจดจำ context"""
# ดึง system prompt ที่รวม conversation history
history_text = "\n".join([
f"{'User' if m['role']=='user' else 'Assistant'}: {m['content']}"
for m in state["conversation_history"][-10:] # last 10 messages
])
system_msg = SystemMessage(content=f"""You are an AI assistant with long-term memory.
Conversation History (recent):
{history_text}
User Preferences:
{json.dumps(state.get('user_preferences', {}), ensure_ascii=False)}
Current Task: {state.get('current_task', 'None')}
Always consider the context from previous conversations.""")
response = llm.invoke([system_msg, HumanMessage(content=new_message)])
# อัพเดท state
updated_history = state["conversation_history"] + [
{"role": "user", "content": new_message, "timestamp": datetime.now().isoformat()},
{"role": "assistant", "content": response.content, "timestamp": datetime.now().isoformat()}
]
return {
"conversation_history": updated_history,
"messages": state.get("messages", []) + [response]
}
Recompile with checkpointer
app = workflow.compile(checkpointer=checkpointer)
สร้าง config สำหรับ thread/session
config = {
"configurable": {
"thread_id": "user_123_session_456"
}
}
ส่งข้อความแรก
state1 = {"messages": [HumanMessage(content="ผมชอบอ่านบทความเกี่ยวกับ AI")]}
app.invoke(state1, config)
ส่งข้อความที่สอง - agent จะจำได้ว่าผู้ใช้ชอบ AI
state2 = {"messages": [HumanMessage(content="แนะนำบทความให้หน่อย")]}
app.invoke(state2, config) # จะใช้ context จากข้อความก่อนหน้า
Error Handling และ Retry Logic
Production agent ต้องจัดการ error อย่าง graceful ให้ดูวิธีเพิ่ม retry และ fallback:
from tenacity import retry, stop_after_attempt, wait_exponential
from langchain_core.outputs import LLMResult
import time
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def robust_llm_call(messages, model="deepseek-v3.2", temperature=0.7):
"""LLM call ที่มี retry logic ในตัว"""
try:
llm = ChatHolySheep(
model=model,
base_url="https://api.holysheep.ai/v1",
api_key=os.environ["HOLYSHEEP_API_KEY"],
temperature=temperature,
max_retries=0 # disable langchain's default retry
)
response = llm.invoke(messages)
return response
except Exception as e:
print(f"Error occurred: {type(e).__name__}")
if "rate_limit" in str(e).lower():
print("Rate limited - waiting before retry...")
time.sleep(5)
raise # Re-raise to trigger retry
def process_with_fallback(state: AgentState) -> AgentState:
"""Process พร้อม fallback ไป model อื่นหาก fail"""
messages = state["messages"]
models_to_try = ["deepseek-v3.2", "gemini-2.5-flash", "gpt-4.1"]
last_error = None
for model in models_to_try:
try:
response = robust_llm_call(messages, model=model)
return {"messages": messages + [response], "model_used": model}
except Exception as e:
last_error = e
print(f"Model {model} failed: {e}")
continue
# ทุก model ล้มเหลว - return graceful error message
error_msg = AIMessage(content="ขออภัยครับ ระบบไม่สามารถประมวลผลได้ในขณะนี้ กรุณาลองใหม่อีกครั้งในอีกสักครู่")
return {"messages": messages + [error_msg], "error": str(last_error)}
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
กรณีที่ 1: "Connection timeout" เมื่อเรียก HolySheep API
# ❌ วิธีผิด - ไม่มี timeout handling
response = llm.invoke(messages)
✅ วิธีถูก - เพิ่ม timeout และ retry
from langchain_holysheep import ChatHolySheep
from langchain_core.utils import get_from_dict_or_env
class TimeoutHolySheep(ChatHolySheep):
def _generate(self, messages, stop=None, run_manager=None, **kwargs):
import signal
def timeout_handler(signum, frame):
raise TimeoutError("API call exceeded 30 seconds")
# Set timeout for 30 seconds
signal.signal(signal.SIGALRM, timeout_handler)
signal.alarm(30)
try:
result = super()._generate(messages, stop, run_manager, **kwargs)
signal.alarm(0) # Cancel alarm
return result
except TimeoutError:
signal.alarm(0)
raise
Usage
llm = TimeoutHolySheep(
model="deepseek-v3.2",
base_url="https://api.holysheep.ai/v1",
api_key="YOUR_HOLYSHEEP_API_KEY"
)
กรณีที่ 2: "State not persisting" - State หายระหว่าง nodes
# ❌ วิธีผิด - return state ไม่ครบ
def bad_node(state):
new_content = process(state["messages"][-1])
return {"result": new_content} # ไม่ได้ return messages กลับไป!
✅ วิธีถูก - ต้อง merge state อย่างถูกต้อง
def correct_node(state: AgentState) -> AgentState:
# สร้าง state ใหม่โดย copy ทุก field
new_state = dict(state)
new_content = process(state["messages"][-1])
# Option 1: Append to existing list
new_state["messages"] = state["messages"] + [AIMessage(content=new_content)]
# Option 2: ใช้ state.update() สำหรับ partial update
new_state.update({
"last_result": new_content,
"processed": True
})
return new_state
Alternative: ใช้ Annotated สำหรับ automatic state merging
from typing import Annotated
import operator
class AgentState(TypedDict):
messages: Annotated[list, operator.add] # automatic append
context: dict
def auto_append_node(state: AgentState) -> AgentState:
return {"messages": [AIMessage(content="new message")]} # will auto-merge!
กรณีที่ 3: "Maximum iterations exceeded" - Infinite loop ใน conditional edges
# ❌ วิธีผิด - ไม่มี exit condition
def bad_router(state):
if some_condition:
return "continue_processing" # infinite loop!
return "end"
✅ วิธีถูก - เพิ่ม iteration counter และ max limit
class SafeAgentState(TypedDict):
iteration: int
max_iterations: int
def safe_router(state: SafeAgentState) -> str:
iteration = state.get("iteration", 0)
max_iter = state.get("max_iterations", 5)
# Force exit if max iterations reached
if iteration >= max_iter:
return "end"
if some_condition:
return "continue_processing"
return "end"
def increment_iteration(state: SafeAgentState) -> SafeAgentState:
return {"iteration": state.get("iteration", 0) + 1}
Add iteration node in the loop
workflow.add_edge("continue_processing", "increment_iteration")
workflow.add_edge("increment_iteration", "safe_router") # loop back
กรณีที่ 4: "Invalid base_url" - ใช้ URL ผิด
# ❌ วิธีผิด - URL จาก official API (ห้ามใช้!)
llm = ChatHolySheep(
model="deepseek-v3.2",
base_url="https://api.openai.com/v1", # ❌ ผิด!
api_key="sk-xxx"
)
❌