เมื่อวานผมเจอปัญหาที่ทำให้หงุดหงิดมาก — เมื่อรัน production pipeline บน LangChain มี API call หายไป 3 ครั้งโดยไม่มี error message แสดงเลย แค่เห็นแค่ ConnectionError: timeout after 30s ตอนเรียกใช้ GPT-4.1 model ผ่าน HolySheheep AI พอผมเปิด debug mode ด้วย Callback mechanism ถึงรู้ว่า request ที่หายไปมันไปติดที่ rate limit แต่ไม่มี retry logic เลย
บทความนี้ผมจะสอนวิธีใช้ LangChain Callback อย่างละเอียด ครอบคลุมตั้งแต่พื้นฐานจนถึง advanced monitoring พร้อมโค้ดที่ใช้งานได้จริง ประหยัดค่าใช้จ่ายได้มากเพราะ HolySheep AI มีราคาถูกกว่าวงในถึง 85%+ และ latency ต่ำกว่า 50ms
LangChain Callback คืออะไรและทำไมต้องใช้
Callback ใน LangChain คือ event system ที่ช่วยให้เราตรวจสอบทุกขั้นตอนของ LLM chain — ตั้งแต่เริ่ม request, ได้ response, เกิด error, จนถึงจบการทำงาน ถ้าไม่มี callback คุณจะบอกได้แค่ว่า "มันพัง" แต่ไม่รู้ว่า "ทำไม" หรือ "เกิดตรงไหน"
ใน production environment การมี monitoring ที่ดีจะช่วยลดค่าใช้จ่ายได้มหาศาล — ผมเคยเสียเงินไปกับ retry loop ที่ผิดพลาดเกือบ 200 ดอลลาร์ก่อนจะติดตั้ง callback เต็มรูปแบบ
การติดตั้งและเริ่มต้นใช้งาน
ก่อนอื่นติดตั้ง dependencies ที่จำเป็น:
pip install langchain langchain-community langchain-core holyhsheep-ai python-dotenv
สร้างไฟล์ .env เพื่อเก็บ API key อย่างปลอดภัย:
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
LOG_LEVEL=DEBUG
Custom Callback Handler แบบเต็มรูปแบบ
นี่คือโค้ด callback handler ที่ผมใช้ใน production จริง — มันจะ log ทุกอย่างตั้งแต่ token usage, latency, errors, จนถึง cost estimation:
import os
import time
import json
from datetime import datetime
from typing import Any, Dict, List, Optional
from langchain_core.callbacks import BaseCallbackHandler
from langchain_core.messages import BaseMessage
from langchain_core.outputs import LLMResult
class ProductionCallbackHandler(BaseCallbackHandler):
"""Custom callback handler สำหรับ monitoring และ logging"""
def __init__(self, project_name: str = "default"):
self.project_name = project_name
self.start_time = None
self.request_count = 0
self.error_count = 0
self.total_tokens = 0
self.cost_tracker = {}
def on_llm_start(
self, serialized: Dict[str, Any], prompts: List[str], **kwargs
) -> None:
self.start_time = time.time()
self.request_count += 1
print(f"[{datetime.now().isoformat()}] 🔄 LLM Request #{self.request_count}")
print(f" Model: {serialized.get('name', 'unknown')}")
print(f" Prompt length: {len(prompts[0]) if prompts else 0} chars")
def on_llm_end(self, response: LLMResult, **kwargs) -> None:
elapsed = time.time() - self.start_time
print(f"[{datetime.now().isoformat()}] ✅ LLM Response")
print(f" Latency: {elapsed*1000:.2f}ms")
if response.llm_output:
token_usage = response.llm_output.get('token_usage', {})
prompt_tokens = token_usage.get('prompt_tokens', 0)
completion_tokens = token_usage.get('completion_tokens', 0)
total_tokens = token_usage.get('total_tokens', 0)
self.total_tokens += total_tokens
print(f" Tokens: {total_tokens} (prompt={prompt_tokens}, completion={completion_tokens})")
# คำนวณค่าใช้จ่าย (ตัวอย่างสำหรับ GPT-4.1)
cost = self._calculate_cost(prompt_tokens, completion_tokens, "gpt-4.1")
print(f" Estimated cost: ${cost:.4f}")
def on_llm_error(
self, error: Exception, **kwargs
) -> None:
self.error_count += 1
elapsed = time.time() - self.start_time if self.start_time else 0
print(f"[{datetime.now().isoformat()}] ❌ LLM Error (#{self.error_count})")
print(f" Error type: {type(error).__name__}")
print(f" Error message: {str(error)}")
print(f" Time before failure: {elapsed*1000:.2f}ms")
# Log error ไปยัง file สำหรับวิเคราะห์
self._log_error(error, elapsed)
def _calculate_cost(self, prompt_tokens: int, completion_tokens: int, model: str) -> float:
"""คำนวณค่าใช้จ่ายตาม model (ราคาจาก HolySheep AI)"""
rates = {
"gpt-4.1": (0.000008, 0.000032), # $8/MTok in, $32/MTok out
"claude-sonnet-4.5": (0.000015, 0.000075), # $15/MTok
"gemini-2.5-flash": (0.00000125, 0.000005), # $2.50/MTok
"deepseek-v3.2": (0.00000042, 0.00000168), # $0.42/MTok
}
if model in rates:
in_rate, out_rate = rates[model]
return (prompt_tokens * in_rate) + (completion_tokens * out_rate)
return 0.0
def _log_error(self, error: Exception, elapsed: float) -> None:
"""บันทึก error ลง log file"""
log_entry = {
"timestamp": datetime.now().isoformat(),
"project": self.project_name,
"error_type": type(error).__name__,
"error_message": str(error),
"latency_ms": elapsed * 1000,
"request_count": self.request_count
}
with open(f"error_log_{self.project_name}.jsonl", "a") as f:
f.write(json.dumps(log_entry) + "\n")
def get_summary(self) -> Dict[str, Any]:
"""สรุปสถิติทั้งหมด"""
return {
"total_requests": self.request_count,
"total_errors": self.error_count,
"total_tokens": self.total_tokens,
"error_rate": self.error_count / self.request_count if self.request_count > 0 else 0
}
การเชื่อมต่อกับ HolySheep AI API
ต่อไปคือการสร้าง LLM instance ที่เชื่อมต่อกับ HolySheep API ซึ่งมี latency เฉลี่ยต่ำกว่า 50ms และราคาถูกกว่าที่อื่นมาก:
import os
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage
from langchain_core.callbacks import StdOutCallbackHandler
ตั้งค่า HolySheep AI base URL
os.environ["OPENAI_API_BASE"] = "https://api.holysheep.ai/v1"
os.environ["OPENAI_API_KEY"] = "YOUR_HOLYSHEEP_API_KEY"
สร้าง ChatOpenAI instance พร้อม callback handler
callback_handler = ProductionCallbackHandler(project_name="holyhsheep-monitoring")
callbacks = [callback_handler]
เลือก model ตามความต้องการ (GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash, DeepSeek V3.2)
llm = ChatOpenAI(
model_name="gpt-4.1", # $8/MTok (ประหยัด 85%+ เทียบกับ OpenAI)
temperature=0.7,
max_tokens=2000,
callbacks=callbacks
)
ทดสอบการทำงาน
try:
response = llm.invoke([HumanMessage(content="อธิบายเรื่อง LangChain Callback")])
print(f"\n📝 Response: {response.content[:100]}...")
except Exception as e:
print(f"\n💥 Error occurred: {type(e).__name__}: {e}")
แสดงสรุปสถิติ
summary = callback_handler.get_summary()
print(f"\n📊 Summary: {summary}")
การใช้งาน Callback ใน Chain และ Agent
สำหรับ LangChain Expression Language (LCEL) chains คุณสามารถส่ง callback ผ่าน method chaining ได้เลย:
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser
from langchain_core.callbacks import BaseCallbackHandler
class DebugCallback(BaseCallbackHandler):
"""Lightweight callback สำหรับ chain debugging"""
def on_chain_start(self, serialized, inputs, **kwargs):
print(f"🔗 Chain started with inputs: {list(inputs.keys())}")
def on_chain_end(self, outputs, **kwargs):
print(f"🔗 Chain completed, outputs: {list(outputs.keys())}")
สร้าง chain พร้อม debug callback
prompt = ChatPromptTemplate.from_messages([
("system", "คุณคือผู้ช่วย AI ที่ตอบเป็นภาษาไทย"),
("human", "{question}")
])
chain = prompt | ChatOpenAI(
model_name="gemini-2.5-flash", # $2.50/MTok — ราคาถูกมาก!
callbacks=[DebugCallback()]
) | StrOutputParser()
รัน chain
result = chain.invoke(
{"question": "LangChain Callback ทำงานอย่างไร?"},
config={"callbacks": [ProductionCallbackHandler()]}
)
print(f"\n✨ Result: {result}")
การติดตาม Token Usage และ Cost
นี่คือสคริปต์ที่ผมใช้ติดตามค่าใช้จ่ายจริงในโปรเจกต์ — มันจะบันทึก usage ทุกครั้งและสรุปเป็นรายวัน:
import csv
from datetime import datetime, timedelta
from collections import defaultdict
class CostTracker:
"""ติดตามค่าใช้จ่ายจริงและวิเคราะห์การใช้งาน"""
# ราคาจาก HolySheep AI (อัปเดต 2026)
MODEL_RATES = {
"gpt-4.1": {"prompt": 0.000008, "completion": 0.000032},
"claude-sonnet-4.5": {"prompt": 0.000015, "completion": 0.000075},
"gemini-2.5-flash": {"prompt": 0.00000125, "completion": 0.000005},
"deepseek-v3.2": {"prompt": 0.00000042, "completion": 0.00000168},
}
def __init__(self, csv_file: str = "cost_report.csv"):
self.csv_file = csv_file
self.daily_usage = defaultdict(lambda: {
"requests": 0, "prompt_tokens": 0, "completion_tokens": 0, "cost": 0
})
self._init_csv()
def _init_csv(self):
with open(self.csv_file, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow([
"timestamp", "model", "prompt_tokens", "completion_tokens",
"total_tokens", "cost_usd", "latency_ms"
])
def record_usage(
self, model: str, prompt_tokens: int, completion_tokens: int,
cost_usd: float, latency_ms: float
):
today = datetime.now().strftime("%Y-%m-%d")
self.daily_usage[today]["requests"] += 1
self.daily_usage[today]["prompt_tokens"] += prompt_tokens
self.daily_usage[today]["completion_tokens"] += completion_tokens
self.daily_usage[today]["cost"] += cost_usd
with open(self.csv_file, 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow([
datetime.now().isoformat(), model, prompt_tokens,
completion_tokens, prompt_tokens + completion_tokens,
cost_usd, latency_ms
])
def get_daily_report(self, days: int = 7) -> str:
report_lines = ["📊 Cost Report (Last 7 days)"]
report_lines.append("=" * 50)
total_cost = 0
for i in range(days):
date = (datetime.now() - timedelta(days=i)).strftime("%Y-%m-%d")
usage = self.daily_usage.get(date, {})
if usage["requests"] > 0:
report_lines.append(f"\n📅 {date}")
report_lines.append(f" Requests: {usage['requests']}")
report_lines.append(f" Tokens: {usage['prompt_tokens'] + usage['completion_tokens']:,}")
report_lines.append(f" Cost: ${usage['cost']:.4f}")
total_cost += usage["cost"]
report_lines.append(f"\n💰 Total (7 days): ${total_cost:.4f}")
return "\n".join(report_lines)
ใช้งาน
tracker = CostTracker()
บันทึก usage หลังจากเรียก API
tracker.record_usage(
model="deepseek-v3.2",
prompt_tokens=150,
completion_tokens=280,
cost_usd=0.000218, # $0.42/MTok = ประหยัดมาก!
latency_ms=38.5
)
print(tracker.get_daily_report())
Retry Logic พร้อม Callback
นี่คือ pattern ที่ผมแนะนำสำหรับ handling rate limit และ timeout — มันใช้ exponential backoff และ callback สำหรับ logging:
import time
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
from langchain_core.callbacks import BaseCallbackHandler
class RetryCallback(BaseCallbackHandler):
"""Callback สำหรับติดตาม retry attempts"""
def __init__(self):
self.attempts = {}
def on_llm_retry(self, attempt_number: int, error: Exception, **kwargs):
wait_time = 2 ** attempt_number # exponential backoff
print(f"🔁 Retry #{attempt_number} after {wait_time}s")
print(f" Error: {type(error).__name__}: {str(error)[:100]}")
if attempt_number not in self.attempts:
self.attempts[attempt_number] = []
self.attempts[attempt_number].append({
"error": str(error),
"timestamp": datetime.now().isoformat()
})
Retry decorator
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10),
retry=retry_if_exception_type((ConnectionError, TimeoutError, RateLimitError)),
before_sleep=lambda retry_state: print(f"⏳ Waiting {retry_state.next_action.sleep}s before retry...")
)
def call_llm_with_retry(prompt: str, model: str = "gpt-4.1") -> str:
llm = ChatOpenAI(
model_name=model,
callbacks=[RetryCallback()],
request_timeout=30
)
response = llm.invoke([HumanMessage(content=prompt)])
return response.content
ทดสอบ
try:
result = call_llm_with_retry("ทดสอบ retry logic")
print(f"✅ Success: {result[:50]}...")
except Exception as e:
print(f"❌ All retries failed: {type(e).__name__}: {e}")
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
1. ConnectionError: timeout after 30s
สาเหตุ: Default timeout ของ LangChain อยู่ที่ 30 วินาที ซึ่งอาจไม่พอสำหรับ cold start หรือ high load
# วิธีแก้: เพิ่ม timeout และใช้ retry
llm = ChatOpenAI(
model_name="gpt-4.1",
max_retries=3,
request_timeout=120, # เพิ่ม timeout เป็น 120 วินาที
callbacks=[ProductionCallbackHandler()]
)
หรือตั้งค่าผ่าน environment variable
os.environ["OPENAI_TIMEOUT"] = "120"
2. 401 Unauthorized / Invalid API Key
สาเหตุ: API key ไม่ถูกต้องหรือไม่ได้ตั้งค่า environment variable
# วิธีแก้: ตรวจสอบว่า base_url และ api_key ถูกต้อง
os.environ["OPENAI_API_BASE"] = "https://api.holysheep.ai/v1"
os.environ["OPENAI_API_KEY"] = "YOUR_HOLYSHEEP_API_KEY" # ตรวจสอบว่าไม่มีช่องว่าง
หรือส่ง trực tiếp ใน constructor
llm = ChatOpenAI(
openai_api_base="https://api.holysheep.ai/v1",
openai_api_key="YOUR_HOLYSHEEP_API_KEY",
model_name="gpt-4.1"
)
ตรวจสอบว่าใช้งานได้
import os
print(f"API Base: {os.environ.get('OPENAI_API_BASE')}")
print(f"API Key set: {'Yes' if os.environ.get('OPENAI_API_KEY') else 'No'}")
3. RateLimitError: 429 Too Many Requests
สาเหตุ: เรียก API เร็วเกินไปเกิน rate limit ของ plan
# วิธีแก้: ใช้ rate limiter และ retry with backoff
import asyncio
from collections import defaultdict
from time import time
class RateLimiter:
def __init__(self, max_requests: int = 100, window_seconds: int = 60):
self.max_requests = max_requests
self.window = window_seconds
self.requests = defaultdict(list)
async def acquire(self):
now = time()
# ลบ requests ที่เก่ากว่า window
self.requests["default"] = [
r for r in self.requests["default"] if now - r < self.window
]
if len(self.requests["default"]) >= self.max_requests:
sleep_time = self.window - (now - self.requests["default"][0])
print(f"⏳ Rate limit reached, sleeping {sleep_time:.1f}s")
await asyncio.sleep(sleep_time)
self.requests["default"].append(time())
ใช้งาน
rate_limiter = RateLimiter(max_requests=100, window_seconds=60)
async def bounded_llm_call(prompt: str):
await rate_limiter.acquire()
llm = ChatOpenAI(model_name="deepseek-v3.2") # ประหยัดที่สุด: $0.42/MTok
return await llm.ainvoke([HumanMessage(content=prompt)])
รัน multiple requests
asyncio.run(bounded_llm_call("ทดสอบ rate limiting"))
สรุป
LangChain Callback mechanism เป็นเครื่องมือที่จำเป็นสำหรับทุกคนที่ใช้ LLM ใน production — ช่วยให้ตรวจสอบได้ว่าเกิดอะไรขึ้น เกิดที่ไหน และทำไม ลดค่าใช้จ่ายจากการ retry ที่ผิดพลาด และช่วยวิเคราะห์ปัญหาได้รวดเร็ว
สำหรับการใช้งานจริง ผมแนะนำให้ใช้ HolySheep AI เพราะมี latency เฉลี่ยต่ำกว่า 50ms และราคาประหยัดกว่าถึง 85%+ เทียบกับ OpenAI โดยเฉพาะ DeepSeek V3.2 ที่ราคาเพียง $0.42/MTok เหมาะมากสำหรับ high-volume applications
อย่าลืมติดตั้ง callback handler และ retry logic ก่อนนำไปใช้ใน production — มันจะช่วยประหยัดเวลาและเงินได้มากในระยะยาว
👉 สมัคร HolySheep AI — รับเครดิตฟรีเมื่อลงทะเบียน