การพัฒนา AI Agent ที่ซับซ้อนในยุคปัจจุบันต้องการมากกว่าแค่การเรียก LLM ผ่าน API เพียงอย่างเดียว ทีมพัฒนาต้องออกแบบ flow การตัดสินใจที่ชาญฉลาด จัดการ state ของ conversation ได้อย่างแม่นยำ และ orchestrate API calls หลายตัวพร้อมกัน ในบทความนี้เราจะมาเรียนรู้วิธีใช้ LangGraph เพื่อสร้าง state machine ที่ทรงพลัง พร้อมกรณีศึกษาจริงจากทีมสตาร์ทอัพ AI ในกรุงเทพฯ ที่ปรับปรุงประสิทธิภาพจาก 420ms เหลือ 180ms และประหยัดค่าใช้จ่ายจาก $4,200 เหลือ $680 ต่อเดือน
กรณีศึกษา: ทีมสตาร์ทอัพ AI ในกรุงเทพฯ
ทีมพัฒนา AI สตาร์ทอัพแห่งหนึ่งในกรุงเทพฯ ต้องการสร้าง AI customer service agent ที่สามารถจัดการคำถามลูกค้าหลายประเภท ตั้งแต่การตอบคำถามทั่วไป การประมวลผลออเดอร์ จนถึงการ escalate ปัญหาที่ซับซ้อนไปยังมนุษย์ ระบบเดิมใช้ if-else chain ที่ยาวมากและไม่สามารถจัดการ conversation state ที่ซับซ้อนได้ ทำให้เกิดปัญหา context lost และ response ที่ไม่สอดคล้องกับ conversation flow
จุดเจ็บปวดของระบบเดิมคือความหน่วง (latency) สูงถึง 420ms ต่อการตอบสนองหนึ่งครั้ง เนื่องจากต้องเรียก API หลายรอบอย่าง sequential และค่าใช้จ่ายรายเดือนสูงถึง $4,200 จากการใช้ GPT-4 ผ่าน OpenAI API ทีมงานตัดสินใจย้ายมาใช้ HolySheep AI ซึ่งให้บริการ API ที่เข้ากันได้กับ OpenAI format ใช้งานง่าย ราคาประหยัดกว่า 85% และมี latency เฉลี่ยต่ำกว่า 50ms
ขั้นตอนการย้ายระบบ
การย้ายระบบจาก OpenAI ไปยัง HolySheep AI ทำได้ง่ายมากเพราะ API format เข้ากันได้กัน 100% ทีมงานเพียงแค่เปลี่ยน base_url และ API key ก็สามารถใช้งานได้ทันที นี่คือขั้นตอนที่ทีมใช้:
- การเปลี่ยน base_url: เปลี่ยนจาก api.openai.com/v1 เป็น api.holysheep.ai/v1
- การหมุนคีย์ (key rotation): สร้าง API key ใหม่จาก HolySheep dashboard และนำไปใช้แทน key เดิม
- Canary deployment: เริ่มจากการ route traffic 10% ไปยัง HolySheep ก่อน จากนั้นค่อยๆ เพิ่มเป็น 50%, 80% และ 100%
- Performance monitoring: วัดผล latency, error rate และ cost อย่างต่อเนื่อง
ตัวชี้วัดหลังการย้าย 30 วัน
หลังจากย้ายระบบมาใช้ HolySheep AI สำเร็จ ตัวชี้วัดหลักของทีมดีขึ้นอย่างเห็นได้ชัด:
- Latency: 420ms → 180ms (ปรับปรุงได้ 57%)
- ค่าใช้จ่ายรายเดือน: $4,200 → $680 (ประหยัด 84%)
- Error rate: ลดลงจาก 2.3% เป็น 0.4%
- ความพึงพอใจของลูกค้า: เพิ่มขึ้น 23%
พื้นฐาน LangGraph State Machine
LangGraph เป็น library ที่สร้างขึ้นบน LangChain เพื่อให้สามารถสร้าง graph-based workflow ได้ โดยแต่ละ node ใน graph จะรับผิดชอบ task เฉพาะ และ edges จะกำหนด flow การเปลี่ยน state ระหว่าง nodes สิ่งที่ทำให้ LangGraph แตกต่างจาก simple chain คือความสามารถในการ maintain state ข้ามหลาย steps และรองรับ branching, looping และ conditional routing
แนวคิดหลักของ LangGraph State Machine ประกอบด้วย State ที่เป็น dictionary ที่เก็บข้อมูลทุกอย่างที่ agents ต้องการรู้, Nodes ที่เป็น Python functions ที่รับ state และ return state ที่อัพเดต, Edges ที่กำหนดว่าจะไป node ไหนถัดไป, และ Graph ที่รวม nodes และ edges เข้าด้วยกันเพื่อสร้างเป็น workflow สมบูรณ์
การติดตั้งและ Setup
ก่อนเริ่มต้น เราต้องติดตั้ง dependencies ที่จำเป็น คุณสามารถใช้ pip เพื่อติดตั้งได้เลย สำหรับ API endpoint เราจะใช้ HolySheep AI ที่ให้บริการ API ที่เข้ากันได้กับ OpenAI format ใช้งานง่าย และราคาประหยัดมาก
pip install langgraph langchain-core langchain-holysheep openai python-dotenv
สำหรับ environment setup เราจะใช้ไฟล์ .env เพื่อเก็บ API key อย่างปลอดภัย:
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
การสร้าง AI Agent แบบ State Machine พื้นฐาน
เรามาเริ่มสร้าง AI Agent ที่มี state machine เพื่อจัดการ customer service flow กัน เราจะใช้ HolySheep AI เป็น LLM provider เพราะราคาประหยัดมาก (เริ่มต้นเพียง $0.42 ต่อล้าน tokens สำหรับ DeepSeek V3.2) และ latency ต่ำกว่า 50ms ซึ่งเหมาะมากสำหรับ real-time application
from typing import TypedDict, Annotated, Sequence
from langgraph.graph import StateGraph, END
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
from openai import OpenAI
import os
from dotenv import load_dotenv
load_dotenv()
Initialize HolySheep AI client
client = OpenAI(
api_key=os.getenv("HOLYSHEEP_API_KEY"),
base_url="https://api.holysheep.ai/v1"
)
class AgentState(TypedDict):
"""State หลักของ Agent ที่จะถูก pass ผ่านทุก node"""
messages: Sequence[BaseMessage]
intent: str | None
needs_human: bool
context: dict
def classify_intent(state: AgentState) -> AgentState:
"""Node แรก: จำแนกประเภทของคำถามลูกค้า"""
last_message = state["messages"][-1].content
response = client.chat.completions.create(
model="gpt-4.1",
messages=[
{"role": "system", "content": """จำแนกคำถามลูกค้าเป็นหนึ่งในประเภทต่อไปนี้:
- product_inquiry: สอบถามข้อมูลสินค้า
- order_status: ติดตามสถานะออเดอร์
- complaint: ร้องเรียนหรือปัญหา
- billing: ปัญหาเกี่ยวกับการเงินหรือการชำระเงิน
- human_escalation: ต้องการพูดคุยกับมนุษย์
ตอบกลับเฉพาะประเภทเท่านั้น"""},
{"role": "user", "content": last_message}
],
temperature=0
)
intent = response.choices[0].message.content.strip().lower()
return {
**state,
"intent": intent,
"needs_human": intent == "human_escalation"
}
def route_based_on_intent(state: AgentState) -> str:
"""Edge function: ตัดสินใจว่าจะไป node ไหนถัดไป"""
intent = state.get("intent", "")
if intent == "product_inquiry":
return "handle_product"
elif intent == "order_status":
return "handle_order"
elif intent == "complaint":
return "handle_complaint"
elif intent == "billing":
return "handle_billing"
elif intent == "human_escalation":
return "escalate_to_human"
else:
return "general_response"
def handle_product(state: AgentState) -> AgentState:
"""จัดการคำถามเกี่ยวกับสินค้า"""
last_message = state["messages"][-1].content
response = client.chat.completions.create(
model="gpt-4.1",
messages=[
{"role": "system", "content": "คุณคือ AI ที่ช่วยตอบคำถามเกี่ยวกับสินค้า จงให้ข้อมูลที่เป็นประโยชน์และชัดเจน"},
*state["messages"]
]
)
ai_response = response.choices[0].message.content
return {
**state,
"messages": [*state["messages"], AIMessage(content=ai_response)],
"context": {**state.get("context", {}), "last_handler": "product"}
}
สร้าง Graph
workflow = StateGraph(AgentState)
เพิ่ม nodes
workflow.add_node("classify", classify_intent)
workflow.add_node("handle_product", handle_product)
workflow.add_node("handle_order", handle_order)
workflow.add_node("handle_complaint", handle_complaint)
workflow.add_node("handle_billing", handle_billing)
workflow.add_node("escalate_to_human", escalate_to_human)
workflow.add_node("general_response", general_response)
เพิ่ม edges
workflow.add_edge("classify", END)
graph = workflow.compile()
จากตัวอย่างข้างต้น เราได้สร้าง state machine พื้นฐานที่มีหลาย nodes และใช้ conditional routing เพื่อส่ง request ไปยัง handler ที่เหมาะสม สิ่งสำคัญคือ state จะถูก pass ผ่านทุก node ทำให้เราสามารถ maintain context ตลอด conversation ได้
การจัดการ API Call Orchestration
ใน real-world application AI Agent มักจะต้องเรียก API หลายตัวพร้อมกันหรือเรียกตามลำดับ เรามาดูวิธีการ orchestrate API calls อย่างมีประสิทธิภาพ โดยใช้ parallel execution และ async patterns ซึ่งจะช่วยลด latency ได้มาก
import asyncio
from typing import List, Dict, Any
from concurrent.futures import ThreadPoolExecutor
class APICallOrchestrator:
"""จัดการการเรียก API หลายตัวพร้อมกัน"""
def __init__(self):
self.client = OpenAI(
api_key=os.getenv("HOLYSHEEP_API_KEY"),
base_url="https://api.holysheep.ai/v1"
)
async def fetch_multiple_contexts(
self,
customer_id: str,
order_id: str | None = None
) -> Dict[str, Any]:
"""เรียก API หลายตัวพร้อมกันเพื่อดึง context"""
async def get_customer_info():
# Simulate API call to get customer info
return await asyncio.to_thread(
self._get_customer_from_db, customer_id
)
async def get_order_history():
if not order_id:
return None
return await asyncio.to_thread(
self._get_orders_from_db, customer_id
)
async def get_product_catalog():
return await asyncio.to_thread(
self._get_product_catalog
)
# Execute all API calls in parallel
results = await asyncio.gather(
get_customer_info(),
get_order_history(),
get_product_catalog(),
return_exceptions=True
)
customer_info, order_history, product_catalog = results
return {
"customer": customer_info if not isinstance(customer_info, Exception) else None,
"orders": order_history if not isinstance(order_history, Exception) else [],
"products": product_catalog if not isinstance(product_catalog, Exception) else []
}
def generate_response_with_context(
self,
user_message: str,
context: Dict[str, Any]
) -> str:
"""สร้าง response โดยใช้ context ที่ได้มา"""
context_summary = f"""
ข้อมูลลูกค้า: {context.get('customer', {})}
ประวัติการสั่งซื้อ: {context.get('orders', [])}
แคทตาล็อกสินค้า: {context.get('products', [])}
"""
response = self.client.chat.completions.create(
model="gpt-4.1",
messages=[
{"role": "system", "content": f"""คุณคือ AI customer service agent
ใช้ข้อมูลต่อไปนี้เพื่อตอบคำถามลูกค้า:
{context_summary}"""},
{"role": "user", "content": user_message}
],
temperature=0.7,
max_tokens=500
)
return response.choices[0].message.content
# Helper methods (simulated database calls)
def _get_customer_from_db(self, customer_id: str) -> Dict:
return {
"id": customer_id,
"name": "สมชาย ใจดี",
"tier": "gold",
"join_date": "2024-01-15"
}
def _get_orders_from_db(self, customer_id: str) -> List[Dict]:
return [
{"id": "ORD001", "status": "shipped", "total": 2500},
{"id": "ORD002", "status": "processing", "total": 1800}
]
def _get_product_catalog(self) -> List[Dict]:
return [
{"id": "P001", "name": "สินค้า A", "price": 500},
{"id": "P002", "name": "สินค้า B", "price": 1200}
]
async def run_agent_flow(user_message: str, customer_id: str):
"""ตัวอย่างการ run agent flow แบบเต็ม"""
orchestrator = APICallOrchestrator()
# 1. Fetch all contexts in parallel (ลดเวลาจาก 3 API calls เหลือ 1 round trip)
context = await orchestrator.fetch_multiple_contexts(customer_id)
# 2. Generate response with full context
response = orchestrator.generate_response_with_context(
user_message,
context
)
return response
วิธีใช้งาน
result = asyncio.run(run_agent_flow(
"สถานะออเดอร์ล่าสุดของฉันเป็นอย่างไร?",
"CUST123"
))
ในตัวอย่างนี้เราใช้ asyncio.gather เพื่อเรียก API หลายตัวพร้อมกัน ซึ่งช่วยลดเวลา response ได้อย่างมาก แทนที่จะต้องรอ API call แต่ละตัวตามลำดับ (sequential) ตอนนี้เราสามารถทำทุกอย่างในรอบเดียว (parallel)
Advanced Pattern: Conditional Branching และ Looping
ในบางกรณี AI Agent ต้องมี ability ในการวน loop เพื่อ retry หรือ refine response หรือ branching ตามเงื่อนไขที่ซับซ้อน เรามาดู advanced pattern ที่จะช่วยให้สร้าง logic ที่ยืดหยุ่นได้
def should_retry(state: AgentState) -> bool:
"""ตรวจสอบว่าควรจะ retry หรือไม่"""
retry_count = state.get("context", {}).get("retry_count", 0)
last_success = state.get("context", {}).get("last_success", True)
return retry_count < 3 and not last_success
def evaluation_node(state: AgentState) -> AgentState:
"""ประเมินผล response ก่อนที่จะส่งกลับให้ลูกค้า"""
messages = state.get("messages", [])
if not messages:
return {**state, "context": {**state.get("context", {}), "last_success": False}}
last_response = messages[-1]
response_quality = check_response_quality(last_response.content)
return {
**state,
"context": {
**state.get("context", {}),
"last_success": response_quality >= 0.7,
"quality_score": response_quality
}
}
def retry_with_feedback(state: AgentState) -> AgentState:
"""Retry โดยให้ feedback จาก response ก่อนหน้า"""
messages = state.get("messages", [])
retry_count = state.get("context", {}).get("retry_count", 0)
last_response = messages[-1].content if messages else ""
response = client.chat.completions.create(
model="gpt-4.1",
messages=[
{"role": "system", "content": """ปรับปรุง response ก่อนหน้าให้ดีขึ้น
โดยคำนึงถึงปัญหาต่อไปนี้:
- ความชัดเจนของคำตอบ
- ความถูกต้องของข้อมูล
- ความเป็นมิตรในการสื่อสาร"""},
{"role": "assistant", "content": last_response},
{"role": "user", "content": "กรุณาปรับปรุงคำตอบนี้ให้ดีขึ้น"}
]
)
new_response = response.choices[0].message.content
return {
**state,
"messages": [*messages[:-1], AIMessage(content=new_response)],
"context": {
**state.get("context", {}),
"retry_count": retry_count + 1,
"improvement_applied": True
}
}
def build_advanced_workflow():
"""สร้าง workflow ที่ซับซ้อนขึ้น"""
workflow = StateGraph(AgentState)
# Nodes
workflow.add_node("classify", classify_intent)
workflow.add_node("process", handle_product)
workflow.add_node("evaluate", evaluation_node)
workflow.add_node("retry", retry_with_feedback)
workflow.add_node("escalate", escalate_to_human)
# Edges with conditional logic
workflow.add_edge("classify", "process")
workflow.add_edge("process", "evaluate")
# Conditional edge: ถ้า evaluate ว่าไม่ดีพอ ให้ retry
workflow.add_conditional_edges(
"evaluate",
should_retry,
{
True: "retry",
False: END
}
)
# Loop back to evaluate after retry
workflow.add_edge("retry", "evaluate")
return workflow.compile()
วิธีใช้งาน workflow ที่ซับซ้อน
graph = build_advanced_workflow()
initial_state = {
"messages": [HumanMessage(content="ขอสถานะออเดอร์หมายเลข 12345")],
"intent": None,
"needs_human": False,
"context": {"retry_count": 0}
}
Run the graph
final_state = graph.invoke(initial_state)
print(final_state["messages"][-1].content)
Pattern นี้มีประโยชน์มากสำหรับการสร้าง AI Agent ที่ต้องการ quality control ในตัว เช่น customer service agent ที่ต้องตรวจสอบว่า response มีคุณภาพเพียงพอก่อนที่จะส่งกลับให้ลูกค้า ถ้าไม่ดีพอก็จะ retry โดยอัตโนมัติจนกว่าจะได้ response ที่acceptable
การ Monitor และ Debug Agent Flow
การ monitor LangGraph workflow สามารถทำได้หลายวิธี วิธีที่ง่ายที่สุดคือใช้ LangSmith หรือสร้าง custom logging system ขึ้นมาเอง เรามาดูวิธีการ trace execution flow เพื่อ debug และ optimize performance
import logging
from datetime import datetime
from typing import Optional
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class AgentDebugger:
"""Debug และ monitor LangGraph workflow"""
def __init__(self):
self.execution_history = []
def trace_node_execution(
self,
node_name: str,
input_state: dict,
output_state: dict
):
"""บันทึกการ execute แต่ละ node"""
execution = {
"timestamp": datetime.now().isoformat(),
"node": node_name,
"input_keys": list(input_state.keys()),
"output_keys": list(output_state.keys()),
"state_changes": self._compute_state_diff(input_state, output_state)
}
self.execution_history.append(execution)
logger.info(f"Node '{node_name}' executed - State changes: {execution['state_changes']}")
def _compute_state_diff(self, before: dict, after: dict) -> dict:
"""คำนวณความแตกต่างของ state"""
diff = {}
for key in set(before.keys()) | set(after.keys()):
before_val = before.get(key)
after_val = after.get(key)
if before_val != after_val:
diff[key] = {
"before": str(before_val)[:100], # Truncate for readability
"after": str(after_val)[:100]
}
return diff
def get_execution_summary(self) -> dict:
"""สรุปการ execute ทั้งหมด"""
if not self.execution_history:
return {"total_nodes": 0, "total_time": 0}
return {
"total_nodes": len(self.execution_history),
"nodes_executed": [e["node"] for e in self.execution_history],