ในยุคที่ AI กลายเป็นหัวใจสำคัญของธุรกิจดิจิทัล การติดตามและบันทึกการใช้งาน LLM API ไม่ใช่ทางเลือกอีกต่อไป แต่เป็นความจำเป็นเชิงกฎหมาย ความปลอดภัย และการควบคุมต้นทุน บทความนี้จะพาคุณสร้างระบบ Audit Log ที่พร้อมสำหรับ Production ตั้งแต่ศูนย์
ทำไมต้องมี Audit Log สำหรับ LLM API
จากประสบการณ์การ Deploy ระบบ AI หลายสิบโปรเจกต์ ผมพบว่าบริษัทที่ไม่มี Audit Log มักเจอปัญหาหลายอย่าง:
- ค่าใช้จ่ายพุ่งสูงผิดปกติ — ไม่สามารถระบุว่า Token ถูกใช้ไปที่ไหน
- ปัญหาความปลอดภัยข้อมูล — ไม่รู้ว่าใครส่งข้อมูลอะไรไปยัง API
- การ Debug ยากเย็น — ไม่มี Log ต้องนั่งเดาแทนที่จะรู้แน่ชัด
- ไม่ผ่าน Compliance — PDPA, GDPR ต้องการ Traceability
กรณีศึกษา: ระบบ AI Customer Service ของร้าน E-Commerce
ร้านค้าออนไลน์แห่งหนึ่งใช้ LLM ตอบคำถามลูกค้า 24/7 แต่พบว่า:
- ค่าใช้จ่าย API เดือนเดียวพุ่งจาก $200 เป็น $2,000
- ลูกค้าบางคนได้รับคำตอบที่ไม่ถูกต้อง แต่ไม่มีใครตอบได้ว่า "ถามอะไร"
- ต้องการเก็บ Log ตาม พ.ร.บ.คุ้มครองข้อมูลส่วนบุคคล
การแก้ปัญหาคือสร้าง Audit Logging Middleware ที่บันทึกทุก Request และ Response อย่างเป็นระบบ
การสร้าง Audit Logger ด้วย Python
โค้ดด้านล่างนี้ใช้งานได้จริงกับ HolySheep AI ซึ่งให้บริการ API หลากหลาย Models ด้วยราคาที่ประหยัด (DeepSeek V3.2 เพียง $0.42/MTok) และ Latency ต่ำกว่า 50ms ทำให้เหมาะสำหรับ Production ที่ต้องการ Logging แบบ Real-time
import json
import logging
import hashlib
from datetime import datetime, timezone
from typing import Optional, Dict, Any, List
from dataclasses import dataclass, asdict, field
from pathlib import Path
import sqlite3
@dataclass
class AuditLogEntry:
"""โครงสร้างข้อมูลสำหรับบันทึกตรวจสอบ"""
log_id: str
timestamp: str
user_id: Optional[str]
session_id: str
model: str
provider: str
# Request Data
request_tokens: int
request_cost: float
prompt_preview: str # ตัดยาวให้เหลือ 200 ตัวอักษร
# Response Data
response_tokens: int
response_cost: float
response_preview: str
full_response_hash: str
# Metadata
latency_ms: float
status: str # success, error, timeout
error_message: Optional[str] = None
ip_address: Optional[str] = None
user_agent: Optional[str] = None
def __post_init__(self):
"""สร้าง Log ID อัตโนมัติถ้ายังไม่มี"""
if not self.log_id:
self.log_id = hashlib.sha256(
f"{self.timestamp}{self.session_id}{self.prompt_preview}".encode()
).hexdigest()[:16]
class LLMAuditLogger:
"""ระบบบันทึกตรวจสอบสำหรับ LLM API ทุกตัว"""
def __init__(self, db_path: str = "llm_audit.db"):
self.db_path = db_path
self._init_database()
# ตั้งค่า Logger
self.logger = logging.getLogger("LLMAudit")
self.logger.setLevel(logging.INFO)
# Handler สำหรับไฟล์
file_handler = logging.FileHandler("llm_audit.log")
file_handler.setFormatter(
logging.Formatter('%(asctime)s | %(levelname)s | %(message)s')
)
self.logger.addHandler(file_handler)
def _init_database(self):
"""สร้างตาราง SQLite สำหรับเก็บ Log"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS audit_logs (
log_id TEXT PRIMARY KEY,
timestamp TEXT NOT NULL,
user_id TEXT,
session_id TEXT NOT NULL,
model TEXT NOT NULL,
provider TEXT NOT NULL,
request_tokens INTEGER,
request_cost REAL,
prompt_preview TEXT,
response_tokens INTEGER,
response_cost REAL,
response_preview TEXT,
full_response_hash TEXT,
latency_ms REAL,
status TEXT,
error_message TEXT,
ip_address TEXT,
user_agent TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
# สร้าง Index เพื่อความเร็วในการ Query
cursor.execute('CREATE INDEX IF NOT EXISTS idx_timestamp ON audit_logs(timestamp)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_user ON audit_logs(user_id)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_session ON audit_logs(session_id)')
conn.commit()
conn.close()
def _calculate_cost(self, model: str, prompt_tokens: int, completion_tokens: int, provider: str) -> tuple[float, float]:
"""คำนวณค่าใช้จ่ายตาม Model และ Provider"""
# ราคาจาก HolySheep AI (USD per Million Tokens)
prices = {
"holysheep": {
"gpt-4.1": {"prompt": 8.0, "completion": 8.0},
"claude-sonnet-4.5": {"prompt": 15.0, "completion": 15.0},
"gemini-2.5-flash": {"prompt": 2.5, "completion": 2.5},
"deepseek-v3.2": {"prompt": 0.42, "completion": 0.42},
},
"openai": {
"gpt-4": {"prompt": 30.0, "completion": 60.0},
"gpt-4-turbo": {"prompt": 10.0, "completion": 30.0},
}
}
provider_prices = prices.get(provider, prices["holysheep"])
model_prices = provider_prices.get(model.lower(), {"prompt": 10.0, "completion": 10.0})
prompt_cost = (prompt_tokens / 1_000_000) * model_prices["prompt"]
completion_cost = (completion_tokens / 1_000_000) * model_prices["completion"]
return prompt_cost, completion_cost
def _hash_content(self, content: str) -> str:
"""สร้าง Hash ของเนื้อหาเพื่อไม่ต้องเก็บ Response ทั้งหมด"""
return hashlib.sha256(content.encode()).hexdigest()[:32]
def _truncate(self, text: str, length: int = 200) -> str:
"""ตัดข้อความยาวให้สั้นลง"""
if len(text) <= length:
return text
return text[:length-3] + "..."
def log_request(self,
session_id: str,
model: str,
provider: str,
prompt: str,
user_id: Optional[str] = None,
ip_address: Optional[str] = None,
user_agent: Optional[str] = None) -> AuditLogEntry:
"""บันทึก Request ที่กำลังจะส่งไป API"""
timestamp = datetime.now(timezone.utc).isoformat()
entry = AuditLogEntry(
log_id="", # จะถูกสร้างใน __post_init__
timestamp=timestamp,
user_id=user_id,
session_id=session_id,
model=model,
provider=provider,
request_tokens=0, # จะอัพเดทหลังได้ response
request_cost=0.0,
prompt_preview=self._truncate(prompt),
response_tokens=0,
response_cost=0.0,
response_preview="PENDING",
full_response_hash="",
latency_ms=0.0,
status="in_progress",
ip_address=ip_address,
user_agent=user_agent
)
return entry
def log_response(self,
entry: AuditLogEntry,
response: str,
prompt_tokens: int,
completion_tokens: int,
latency_ms: float,
status: str = "success",
error_message: Optional[str] = None):
"""บันทึก Response ที่ได้รับจาก API"""
prompt_cost, completion_cost = self._calculate_cost(
entry.model, prompt_tokens, completion_tokens, entry.provider
)
entry.request_tokens = prompt_tokens
entry.request_cost = prompt_cost
entry.response_tokens = completion_tokens
entry.response_cost = completion_cost
entry.response_preview = self._truncate(response)
entry.full_response_hash = self._hash_content(response)
entry.latency_ms = latency_ms
entry.status = status
entry.error_message = error_message
# บันทึกลง Database
self._save_to_db(entry)
# บันทึกลง Log file
log_msg = f"{entry.status} | {entry.model} | {entry.user_id or 'anonymous'} | "
log_msg += f"req:{prompt_tokens}tok ${prompt_cost:.4f} | "
log_msg += f"res:{completion_tokens}tok ${completion_cost:.4f} | "
log_msg += f"{latency_ms:.0f}ms"
if status == "error":
self.logger.error(log_msg + f" | ERROR: {error_message}")
else:
self.logger.info(log_msg)
def _save_to_db(self, entry: AuditLogEntry):
"""บันทึก Log Entry ลง SQLite"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
INSERT OR REPLACE INTO audit_logs
(log_id, timestamp, user_id, session_id, model, provider,
request_tokens, request_cost, prompt_preview,
response_tokens, response_cost, response_preview, full_response_hash,
latency_ms, status, error_message, ip_address, user_agent)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
entry.log_id, entry.timestamp, entry.user_id, entry.session_id,
entry.model, entry.provider, entry.request_tokens, entry.request_cost,
entry.prompt_preview, entry.response_tokens, entry.response_cost,
entry.response_preview, entry.full_response_hash, entry.latency_ms,
entry.status, entry.error_message, entry.ip_address, entry.user_agent
))
conn.commit()
conn.close()
def get_cost_summary(self,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
user_id: Optional[str] = None) -> Dict[str, Any]:
"""ดึงสรุปค่าใช้จ่าย"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
query = '''
SELECT model, provider,
SUM(request_tokens) as total_req_tokens,
SUM(response_tokens) as total_res_tokens,
SUM(request_cost + response_cost) as total_cost,
COUNT(*) as total_requests,
AVG(latency_ms) as avg_latency
FROM audit_logs
WHERE status = 'success'
'''
params = []
if start_date:
query += " AND timestamp >= ?"
params.append(start_date)
if end_date:
query += " AND timestamp <= ?"
params.append(end_date)
if user_id:
query += " AND user_id = ?"
params.append(user_id)
query += " GROUP BY model, provider ORDER BY total_cost DESC"
cursor.execute(query, params)
results = cursor.fetchall()
conn.close()
return {
"summary": [
{
"model": r[0],
"provider": r[1],
"total_prompt_tokens": r[2],
"total_completion_tokens": r[3],
"total_cost_usd": round(r[4], 4),
"total_requests": r[5],
"avg_latency_ms": round(r[6], 2)
}
for r in results
]
}
วิธีใช้งาน
logger = LLMAuditLogger("production_audit.db")
print("Audit Logger initialized successfully!")
Integration กับ HolySheep AI API
ด้านล่างคือโค้ดที่พร้อมใช้งานจริงสำหรับเชื่อมต่อกับ HolySheep AI ซึ่งรองรับ Models ยอดนิยมทั้ง GPT-4.1, Claude Sonnet 4.5, Gemini 2.5 Flash และ DeepSeek V3.2 โดยมีอัตราแลกเปลี่ยนที่คุ้มค่ามาก (¥1 = $1 หรือประหยัดกว่า 85% เมื่อเทียบกับราคาตลาดอื่น)
import openai
import time
import tiktoken
from typing import Optional
class HolySheepAIClient:
"""Client สำหรับเชื่อมต่อ HolySheep AI พร้อม Audit Logging"""
def __init__(self, api_key: str, model: str = "deepseek-v3.2"):
self.client = openai.OpenAI(
api_key=api_key,
base_url="https://api.holysheep.ai/v1" # URL ของ HolySheep AI เท่านั้น
)
self.model = model
self.encoding = tiktoken.get_encoding("cl100k_base") # สำหรับ GPT-4
self.audit_logger = LLMAuditLogger("holysheep_audit.db")
def _count_tokens(self, text: str) -> int:
"""นับจำนวน Token ในข้อความ"""
return len(self.encoding.encode(text))
def chat(self,
messages: list,
session_id: str,
user_id: Optional[str] = None,
temperature: float = 0.7,
max_tokens: int = 2048) -> dict:
"""ส่ง Chat Request พร้อมบันทึก Audit Log"""
# รวมข้อความสำหรับ Logging
full_prompt = "\n".join([f"{m['role']}: {m['content']}" for m in messages])
# สร้าง Log Entry ก่อน Request
log_entry = self.audit_logger.log_request(
session_id=session_id,
model=self.model,
provider="holysheep",
prompt=full_prompt,
user_id=user_id
)
start_time = time.time()
try:
# ส่ง Request ไปยัง HolySheep AI
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=temperature,
max_tokens=max_tokens
)
latency_ms = (time.time() - start_time) * 1000
# ดึงข้อมูล Response
assistant_message = response.choices[0].message.content
# นับ Tokens
prompt_tokens = self._count_tokens(full_prompt)
completion_tokens = self._count_tokens(assistant_message)
# บันทึก Response
self.audit_logger.log_response(
entry=log_entry,
response=assistant_message,
prompt_tokens=prompt_tokens,
completion_tokens=completion_tokens,
latency_ms=latency_ms,
status="success"
)
return {
"success": True,
"message": assistant_message,
"usage": {
"prompt_tokens": prompt_tokens,
"completion_tokens": completion_tokens,
"total_tokens": prompt_tokens + completion_tokens
},
"latency_ms": latency_ms,
"log_id": log_entry.log_id
}
except Exception as e:
latency_ms = (time.time() - start_time) * 1000
# บันทึก Error
self.audit_logger.log_response(
entry=log_entry,
response="",
prompt_tokens=self._count_tokens(full_prompt),
completion_tokens=0,
latency_ms=latency_ms,
status="error",
error_message=str(e)
)
return {
"success": False,
"error": str(e),
"latency_ms": latency_ms,
"log_id": log_entry.log_id
}
ตัวอย่างการใช้งาน
if __name__ == "__main__":
# สร้าง Client (ใช้ API Key จาก HolySheep AI)
client = HolySheepAIClient(
api_key="YOUR_HOLYSHEEP_API_KEY", # แทนที่ด้วย API Key จริง
model="deepseek-v3.2" # Model ราคาถูก แต่คุณภาพดี
)
# ทดสอบ Chat
result = client.chat(
messages=[
{"role": "system", "content": "คุณเป็นผู้ช่วยแนะนำสินค้า"},
{"role": "user", "content": "แนะนำโทรศัพท์มือถือราคา 10,000 บาท"}
],
session_id="user123-session456",
user_id="user123"
)
if result["success"]:
print(f"Response: {result['message']}")
print(f"Tokens used: {result['usage']['total_tokens']}")
print(f"Latency: {result['latency_ms']:.2f}ms")
print(f"Log ID: {result['log_id']}")
else:
print(f"Error: {result['error']}")
Dashboard สำหรับ Monitor ค่าใช้จ่ายแบบ Real-time
import streamlit as st
import pandas as pd
from datetime import datetime, timedelta
import plotly.express as px
def render_audit_dashboard(db_path: str = "holysheep_audit.db"):
"""สร้าง Dashboard สำหรับ Monitor การใช้งาน API"""
st.set_page_config(page_title="LLM API Audit Dashboard", layout="wide")
st.title("📊 LLM API Audit Dashboard")
st.markdown("ติดตามการใช้งานและค่าใช้จ่ายแบบ Real-time")
# เชื่อมต่อ Database
import sqlite3
conn = sqlite3.connect(db_path)
# Sidebar filters
st.sidebar.header("ตัวกรอง")
# เลือกช่วงเวลา
time_range = st.sidebar.selectbox(
"ช่วงเวลา",
["วันนี้", "7 วัน", "30 วัน", "ทั้งหมด"]
)
days_map = {"วันนี้": 1, "7 วัน": 7, "30 วัน": 30, "ทั้งหมด": 365}
days = days_map[time_range]
# ดึงข้อมูล Summary
df = pd.read_sql_query(f'''
SELECT
DATE(timestamp) as date,
model,
provider,
SUM(request_tokens + response_tokens) as total_tokens,
SUM(request_cost + response_cost) as total_cost,
COUNT(*) as total_requests,
AVG(latency_ms) as avg_latency,
SUM(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as success_count,
SUM(CASE WHEN status = 'error' THEN 1 ELSE 0 END) as error_count
FROM audit_logs
WHERE timestamp >= datetime('now', '-{days} days')
GROUP BY DATE(timestamp), model, provider
ORDER BY date DESC
''', conn)
# Metrics Cards
col1, col2, col3, col4 = st.columns(4)
total_cost = df['total_cost'].sum()
total_tokens = df['total_tokens'].sum()
total_requests = df['total_requests'].sum()
avg_latency = df['avg_latency'].mean()
with col1:
st.metric("💰 ค่าใช้จ่ายรวม", f"${total_cost:.2f}")
with col2:
st.metric("🔢 Tokens ที่ใช้", f"{total_tokens:,}")
with col3:
st.metric("📝 Requests", f"{total_requests:,}")
with col4:
st.metric("⚡ Latency เฉลี่ย", f"{avg_latency:.0f}ms")
# Charts
st.subheader("📈 กราฟค่าใช้จ่ายรายวัน")
if not df.empty:
# กราฟค่าใช้จ่ายตาม Model
fig1 = px.bar(
df.groupby('model')['total_cost'].sum().reset_index(),
x='model', y='total_cost',
title='ค่าใช้จ่ายแยกตาม Model',
color='model'
)
st.plotly_chart(fig1, use_container_width=True)
# กราฟ Requests ตามเวลา
fig2 = px.line(
df.groupby('date')['total_requests'].sum().reset_index(),
x='date', y='total_requests',
title='จำนวน Requests รายวัน'
)
st.plotly_chart(fig2, use_container_width=True)
# Recent Logs Table
st.subheader("📋 Log ล่าสุด")
recent_logs = pd.read_sql_query('''
SELECT
timestamp,
user_id,
model,
request_tokens,
response_tokens,
request_cost + response_cost as cost,
latency_ms,
status
FROM audit_logs
ORDER BY timestamp DESC
LIMIT 100
''', conn)
st.dataframe(recent_logs, use_container_width=True)
conn.close()
รัน Dashboard
if __name__ == "__main__":
render_audit_dashboard()
ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข
1. Error: "Connection timeout" หรือ Latency สูงผิดปกติ
สาเหตุ: การเชื่อมต่อ API โดยไม่มี Retry Logic หรือ Timeout ที่เหมาะสม
# โค้ดที่ผิด - ไม่มี Timeout
response = openai.ChatCompletion.create(
model="deepseek-v3.2",
messages=messages
)
โค้ดที่ถูกต้อง - มี Timeout และ Retry
from openai import OpenAI
from tenacity import retry, stop_after_attempt, wait_exponential
client = OpenAI(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1",
timeout=30.0, # Timeout 30 วินาที
max_retries=3 # Retry สูงสุด 3 ครั้ง
)
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def call_with_retry(messages):
return client.chat.completions.create(
model="deepseek-v3.2",
messages=messages,
timeout=30.0
)
2. Error: "Invalid API Key" หรือ Authentication Failed
สาเหตุ: API Key ไม่ถูกต้อง หรือถูก Limit Quota
# โค้ดที่ผิด - ไม่ตรวจสอบ Key ก่อนใช้งาน
client = OpenAI(
api_key="sk-xxx", # Key อาจหมดอายุ
base_url="https://api.holysheep.ai/v1"
)
โค้ดที่ถูกต้อง - ตรวจสอบ Key ก่อน
import os
def validate_api_key(api_key: str) -> bool:
"""ตรวจสอบความถูกต้องของ API Key"""
if not api_key or len(api_key) < 10:
return False
try:
test_client = OpenAI(
api_key=api_key,
base_url="https://api.holysheep.ai/v1"
)
# ทดสอบด้วย Request เล็กๆ
test_client.models.list()
return True
except Exception as e:
print(f"API Key validation failed: {e}")
return False
ใช้งาน
API_KEY = os.environ.get("HOLYSHEEP_API_KEY")
if validate_api_key(API_KEY):
client = OpenAI(
api_key=API_KEY,
base_url="https://api.holysheep.ai/v1"
)
else:
raise ValueError("Invalid or expired API Key")
3. Error: "Token limit exceeded" หรือ Context Overflow
สาเหตุ: Prompt หรือ History ยาวเกิน Context Window ของ Model
# โค้ดที่ผิด - ไม่จำกัด Context Length
def build_prompt(messages):
return "\n".join([f"{m['role']}: {m['content']}" for m in messages])
โค้ดที่ถูกต้อง - จำกัด Context และ Summarize
def build_prompt_safe(messages: list, max_tokens: int = 3000) -> str:
"""สร้าง Prompt ที่ควบคุม Context Length ได้"""
import tiktoken
encoding = tiktoken.get_encoding("cl100k_base")
# คำนวณ Token ที่เหลือสำหรับ History
system_tokens = 200 # เก็บไว้สำหรับ System Prompt
result = []
remaining_tokens = max_tokens - system_tokens
# วนจากข้อความล่าสุดขึ้นไป
for message in reversed(messages):
if message["role"] == "system":
continue
content_tokens = len(encoding.encode(message["content