เมื่อพัฒนาแอปพลิเคชันที่ใช้ AI API ในระดับ Production ปัญหาหนึ่งที่นักพัฒาต้องเจอคือ Content Filter หรือการกรองเนื้อหาที่ไม่เหมาะสม บทความนี้จะพาคุณเข้าใจกลไกการทำงาน วิธีจัดการเมื่อเนื้อหาถูก Filter และเทคนิคการ Optimize สำหรับ Production Environment
Content Filter คืออะไรและทำงานอย่างไร
Content Filter เป็นระบบความปลอดภัยที่ทำงานขณะประมวลผล Prompt และ Response มันจะสแกนเนื้อหาทั้ง Input และ Output หากตรวจพบเนื้อหาที่ละเอียดอ่อน เช่น ความรุนแรง เนื้อหาทางเพศ หรือข้อมูลที่เป็นอันตราย ระบบจะส่งคืน Error Response แทนที่จะเป็นข้อมูลจริง
โครงสร้าง Response เมื่อถูก Filter
เมื่อเนื้อหาถูก Filter คุณจะได้รับ Response ที่มีโครงสร้างเฉพาะ ซึ่งแตกต่างจาก Error ปกติ
# Response ปกติ (สำเร็จ)
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1735689600,
"model": "gpt-4",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "ผลลัพธ์ปกติ"
},
"finish_reason": "stop"
}],
"usage": {"prompt_tokens": 10, "completion_tokens": 5, "total_tokens": 15}
}
Response เมื่อถูก Filter
{
"error": {
"message": "Content filter triggered",
"type": "content_filter",
"code": "content_filter",
"param": null,
"error": {
"code": "content_filter",
"innererror": {
"content_filter_reason": "violence",
"filtered_reason": "violence",
"prompt_filter_results": [...]
}
}
}
}
การ Implement ระบบตรวจจับและจัดการ Content Filter
Architecture สำหรับ Production
การออกแบบระบบที่ดีต้องมี Layer การตรวจสอบหลายชั้น เริ่มจาก Pre-filter ฝั่ง Client ไปจนถึง Error Handling ฝั่ง Server
import openai
from typing import Optional, Dict, Any, Callable
from dataclasses import dataclass
from enum import Enum
import time
import logging
Configuration
client = openai.OpenAI(
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1", # ใช้ HolySheep API เท่านั้น
timeout=30.0,
max_retries=3
)
class ContentFilterReason(Enum):
VIOLENCE = "violence"
SEXUAL = "sexual"
HATE = "hate"
SELF_HARM = "self-harm"
ILLEGAL = "illegal"
UNKNOWN = "unknown"
@dataclass
class FilterResult:
is_filtered: bool
reason: Optional[ContentFilterReason]
error_message: str
retry_allowed: bool
fallback_message: str
class ContentFilterHandler:
"""
Handler สำหรับจัดการ Content Filter ในระดับ Production
รองรับ: Detection, Retry Logic, Fallback Strategy, Logging
"""
def __init__(self, logger: Optional[logging.Logger] = None):
self.logger = logger or logging.getLogger(__name__)
self.fallback_responses = {
ContentFilterReason.VIOLENCE: "ขออภัย ฉันไม่สามารถตอบคำถามเกี่ยวกับความรุนแรงได้",
ContentFilterReason.SEXUAL: "ขออภัย เนื้อหานี้ไม่เหมาะสมสำหรับการสนทนา",
ContentFilterReason.HATE: "ขออภัย ฉันไม่สนับสนุนเนื้อหาที่เกลียดชัง",
ContentFilterReason.SELF_HARM: "หากคุณกำลังมีความคิดที่จะทำร้ายตัวเอง กรุณาติดต่อสายด่วนสุขภาพจิต",
ContentFilterReason.ILLEGAL: "ขออภัย ฉันไม่สามารถช่วยในเรื่องที่ผิดกฎหมายได้",
ContentFilterReason.UNKNOWN: "ขออภัย เกิดข้อผิดพลาดในการประมวลผล กรุณาลองใหม่อีกครั้ง"
}
def parse_filter_error(self, error: Exception) -> FilterResult:
"""แยกวิเคราะห์ Error Response จาก Content Filter"""
error_dict = vars(error)
error_msg = str(error)
# ตรวจหา Content Filter Error
if "content_filter" in error_msg.lower() or "content filter" in error_msg.lower():
# ดึง Filter Reason จาก Response
reason = self._extract_filter_reason(error_dict)
return FilterResult(
is_filtered=True,
reason=reason,
error_message=error_msg,
retry_allowed=False, # Content Filter ไม่ควร Retry
fallback_message=self.fallback_responses.get(
reason,
self.fallback_responses[ContentFilterReason.UNKNOWN]
)
)
# Network Error หรือ Server Error - สามารถ Retry ได้
return FilterResult(
is_filtered=False,
reason=None,
error_message=error_msg,
retry_allowed=True,
fallback_message="เกิดข้อผิดพลาดในการเชื่อมต่อ กรุณาลองใหม่อีกครั้ง"
)
def _extract_filter_reason(self, error_dict: Dict[str, Any]) -> ContentFilterReason:
"""ดึง Filter Reason จาก Error Structure"""
try:
# ลองหาใน nested error structure
if 'error' in error_dict:
inner = error_dict['error']
if isinstance(inner, dict):
if 'innererror' in inner:
reason_str = inner['innererror'].get('content_filter_reason', '')
else:
reason_str = inner.get('content_filter_reason', '')
for reason in ContentFilterReason:
if reason.value in reason_str.lower():
return reason
except Exception:
pass
return ContentFilterReason.UNKNOWN
async def chat_with_filter_handling(
prompt: str,
model: str = "gpt-4o",
system_prompt: Optional[str] = None,
max_retries: int = 3
) -> Dict[str, Any]:
"""
Function หลักสำหรับ Chat พร้อมระบบจัดการ Content Filter
Features:
- Automatic Filter Detection
- Retry with Exponential Backoff (สำหรับ Network Error เท่านั้น)
- Graceful Fallback
- Comprehensive Logging
"""
handler = ContentFilterHandler()
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.append({"role": "user", "content": prompt})
last_error = None
for attempt in range(max_retries):
try:
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=0.7,
max_tokens=1000
)
# สำเร็จ - คืนค่า Response
return {
"success": True,
"content": response.choices[0].message.content,
"usage": response.usage.model_dump() if response.usage else None,
"filter_triggered": False
}
except openai.APIError as e:
last_error = e
filter_result = handler.parse_filter_error(e)
if filter_result.is_filtered:
# Content Filter - ไม่ Retry แต่ Fallback
return {
"success": False,
"content": filter_result.fallback_message,
"error_type": "content_filter",
"filter_reason": filter_result.reason.value if filter_result.reason else None,
"filter_triggered": True
}
# Network Error - Retry ด้วย Exponential Backoff
if filter_result.retry_allowed and attempt < max_retries - 1:
wait_time = 2 ** attempt # 1s, 2s, 4s
logging.warning(f"Retry {attempt + 1}/{max_retries} after {wait_time}s")
time.sleep(wait_time)
continue
# Error อื่นๆ
return {
"success": False,
"content": filter_result.fallback_message,
"error_type": "api_error",
"filter_triggered": False
}
# หลังจาก Retry หมดแล้วยังไม่สำเร็จ
return {
"success": False,
"content": "เกิดข้อผิดพลาดหลังจากพยายามหลายครั้ง กรุณาลองใหม่ภายหลัง",
"error_type": "max_retries_exceeded",
"filter_triggered": False
}
การ Implement Retry Strategy ที่ชาญฉลาด
สำหรับ Production คุณต้องแยกแยะระหว่าง Error ที่สามารถ Retry ได้ (Network Timeout, Rate Limit) กับ Content Filter ที่ไม่ควร Retry เพราะจะได้ผลลัพธ์เดิมเสมอ
import asyncio
from typing import TypeVar, Callable, Any
from dataclasses import dataclass, field
from datetime import datetime, timedelta
import hashlib
T = TypeVar('T')
@dataclass
class RetryConfig:
max_retries: int = 3
base_delay: float = 1.0
max_delay: float = 60.0
exponential_base: float = 2.0
jitter: bool = True
@dataclass
class RequestMetrics:
request_id: str
timestamp: datetime
model: str
prompt