ในโลกของ AI API การพัฒนาแชทบอทที่เชื่อถือได้ หนึ่งในความท้าทายที่ใหญ่ที่สุดคือการจัดการการขาดการเชื่อมต่อระหว่างการสนทนา ฉันเคยเจอสถานการณ์จริงที่ ConnectionError: timeout เกิดขึ้นกลางคันในขณะที่ผู้ใช้กำลังสนทนากับ AI ครั้งแรก ทำให้บริบททั้งหมดสูญหายและผู้ใช้ต้องเริ่มต้นใหม่ทั้งหมด

บทความนี้จะอธิบายกลไกการเชื่อมต่อใหม่ (Reconnection) และกลยุทธ์การกู้คืนบริบท (Context Recovery) อย่างละเอียด เหมาะสำหรับนักพัฒนาที่ต้องการสร้าง AI แชทบอทที่เสถียรและไม่สูญเสียข้อมูลการสนทนา รวมถึงการใช้งาน HolySheep AI ที่รองรับ Streaming API พร้อม latency ต่ำกว่า 50ms

ปัญหาการขาดการเชื่อมต่อของ Streaming API

Streaming API เป็นเทคโนโลยีที่ช่วยให้ AI ตอบสนองได้เร็วโดยส่งข้อมูลทีละส่วน (chunk) แทนที่จะรอจนได้คำตอบเต็ม ซึ่งทำให้ผู้ใช้เห็นการตอบสนองแบบเรียลไทม์ อย่างไรก็ตาม การเชื่อมต่อแบบนี้มีความเสี่ยงสูงที่จะขาดหายเมื่อเครือข่ายไม่เสถียร

ข้อผิดพลาดที่พบบ่อยที่สุด

สถาปัตยกรรมการจัดการการเชื่อมต่อใหม่

การออกแบบระบบที่ดีต้องมี 3 ชั้นในการจัดการความผิดพลาด

┌─────────────────────────────────────────────────────────┐
│                    ชั้นที่ 1: การตรวจจับความผิดพลาด        │
├─────────────────────────────────────────────────────────┤
│  - Heartbeat mechanism (ping ทุก 30 วินาที)             │
│  - Timeout detection (< 10 วินาที สำหรับ HolySheep)    │
│  - Automatic retry with exponential backoff            │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│                    ชั้นที่ 2: การกู้คืนบริบท              │
├─────────────────────────────────────────────────────────┤
│  - Message queue persistence                            │
│  - Conversation ID tracking                             │
│  - Partial response assembly                            │
└─────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────┐
│                    ชั้นที่ 3: การเชื่อมต่อใหม่อัตโนมัติ    │
├─────────────────────────────────────────────────────────┤
│  - Max 3 retry attempts                                 │
│  - Session state restoration                            │
│  - Graceful degradation                                 │
└─────────────────────────────────────────────────────────┘

การติดตั้ง Exponential Backoff

Exponential Backoff คือเทคนิคการรอก่อนลองใหม่ โดยเพิ่มเวลารอเป็นเท่าตัวทุกครั้ง ช่วยป้องกันไม่ให้เซิร์ฟเวอร์รับโหลดเกิน

import time
import asyncio
from typing import Optional, List, Dict, Any

class HolySheepStreamingClient:
    """
    Streaming API Client พร้อมกลไกการเชื่อมต่อใหม่อัตโนมัติ
    รองรับ context preservation และ graceful error handling
    """
    
    def __init__(
        self,
        api_key: str,
        base_url: str = "https://api.holysheep.ai/v1",
        max_retries: int = 3,
        timeout: float = 30.0
    ):
        self.api_key = api_key
        self.base_url = base_url
        self.max_retries = max_retries
        self.timeout = timeout
        self.conversation_history: List[Dict[str, str]] = []
        self.conversation_id: Optional[str] = None
        
    def _calculate_backoff(self, attempt: int) -> float:
        """
        คำนวณเวลารอแบบ Exponential Backoff
        สูตร: min(base * (2 ** attempt), max_delay)
        """
        base_delay = 1.0  # 1 วินาที
        max_delay = 30.0  # สูงสุด 30 วินาที
        jitter = 0.5  # สุ่ม ±0.5 วินาทีเพื่อป้องกัน thundering herd
        
        delay = min(base_delay * (2 ** attempt), max_delay)
        delay += time.time() % jitter  # เพิ่ม jitter
        
        return delay

    async def send_with_retry(
        self,
        messages: List[Dict[str, str]],
        model: str = "gpt-4.1"
    ) -> str:
        """
        ส่งคำขอพร้อมกลไก retry อัตโนมัติ
        """
        last_error = None
        
        for attempt in range(self.max_retries):
            try:
                response = await self._make_streaming_request(
                    messages=messages,
                    model=model
                )
                return response
                
            except ConnectionError as e:
                last_error = e
                if attempt < self.max_retries - 1:
                    wait_time = self._calculate_backoff(attempt)
                    print(f"ความพยายาม {attempt + 1} ล้มเหลว: {str(e)}")
                    print(f"รอ {wait_time:.2f} วินาทีก่อนลองใหม่...")
                    await asyncio.sleep(wait_time)
                    
            except Exception as e:
                # ข้อผิดพลาดอื่นๆ เช่น 401 ให้หยุดทันที
                raise RuntimeError(f"ข้อผิดพลาดร้ายแรง: {str(e)}")
        
        raise RuntimeError(
            f"ล้มเหลวหลังจาก {self.max_retries} ความพยายาม: {str(last_error)}"
        )

การกู้คืนบริบทการสนทนา (Context Recovery)

หัวใจสำคัญของการเชื่อมต่อใหม่คือการไม่สูญเสียบริบทการสนทนา ต้องเก็บรักษาประวัติข้อความทั้งหมดไว้แม้การเชื่อมต่อจะขาดหาย

import json
import hashlib
from datetime import datetime
from dataclasses import dataclass, asdict
from typing import Optional, List
import redis
import aiohttp

@dataclass
class ConversationContext:
    """โครงสร้างข้อมูลบริบทการสนทนา"""
    session_id: str
    messages: List[Dict[str, str]]
    created_at: str
    updated_at: str
    partial_response: str = ""
    last_message_id: Optional[str] = None
    
    def to_json(self) -> str:
        return json.dumps(asdict(self), ensure_ascii=False)
    
    @classmethod
    def from_json(cls, json_str: str) -> 'ConversationContext':
        data = json.loads(json_str)
        return cls(**data)
    
    def add_message(self, role: str, content: str) -> str:
        """เพิ่มข้อความและคืนค่า message_id"""
        message_id = hashlib.md5(
            f"{self.session_id}{len(self.messages)}{datetime.now().isoformat()}".encode()
        ).hexdigest()[:16]
        
        self.messages.append({
            "role": role,
            "content": content,
            "message_id": message_id
        })
        self.last_message_id = message_id
        self.updated_at = datetime.now().isoformat()
        
        return message_id

class ContextRecoveryManager:
    """
    จัดการการกู้คืนบริบทเมื่อการเชื่อมต่อขาดหาย
    รองรับการเก็บข้อมูลใน Redis หรือไฟล์
    """
    
    def __init__(self, redis_client: Optional[redis.Redis] = None):
        self.redis = redis_client
        self.local_cache: Dict[str, ConversationContext] = {}
        
    def save_context(self, context: ConversationContext) -> bool:
        """บันทึกบริบทลง storage"""
        try:
            # ลองบันทึกใน Redis ก่อน
            if self.redis:
                self.redis.setex(
                    f"context:{context.session_id}",
                    86400,  # หมดอายุใน 24 ชั่วโมง
                    context.to_json()
                )
            else:
                #  fallback เป็น local cache
                self.local_cache[context.session_id] = context
                
            return True
            
        except Exception as e:
            print(f"ไม่สามารถบันทึกบริบท: {e}")
            return False
    
    def load_context(self, session_id: str) -> Optional[ConversationContext]:
        """โหลดบริบทจาก storage"""
        try:
            if self.redis:
                data = self.redis.get(f"context:{session_id}")
                if data:
                    return ConversationContext.from_json(data)
            else:
                return self.local_cache.get(session_id)
                
        except Exception as e:
            print(f"ไม่สามารถโหลดบริบท: {e}")
            return None
        
        return None
    
    async def streaming_with_context_recovery(
        self,
        client: HolySheepStreamingClient,
        session_id: str,
        new_message: str
    ) -> tuple[str, str]:
        """
        ส่งข้อความใหม่พร้อมกู้คืนบริบท
        
        คืนค่า: (full_response, session_id)
        """
        # ขั้นตอนที่ 1: โหลดบริบทเดิม
        context = self.load_context(session_id)
        
        if context is None:
            # สร้างบริบทใหม่ถ้าไม่มี
            context = ConversationContext(
                session_id=session_id,
                messages=[],
                created_at=datetime.now().isoformat(),
                updated_at=datetime.now().isoformat()
            )
        
        # ขั้นตอนที่ 2: เพิ่มข้อความใหม่
        context.add_message("user", new_message)
        
        # ขั้นตอนที่ 3: ส่งคำขอพร้อม retry
        try:
            response = await client.send_with_retry(
                messages=context.messages,
                model="gpt-4.1"
            )
            
            # ขั้นตอนที่ 4: เพิ่มคำตอบลงบริบท
            context.add_message("assistant", response)
            self.save_context(context)
            
            return response, session_id
            
        except Exception as e:
            # ถ้าล้มเหลว ให้บันทึกบริบทก่อนข้อความใหม่เพื่อกู้คืนภายหลัง
            self.save_context(context)
            raise RuntimeError(
                f"การสนทนาขาดหาย บริบทถูกบันทึกแล้ว: {session_id}"
            ) from e

WebSocket Implementation สำหรับ Real-time Streaming

สำหรับการใช้งานที่ต้องการความเร็วสูงสุด ควรใช้ WebSocket แทน HTTP Streaming เพราะสามารถรักษาการเชื่อมต่อได้ดีกว่าและรองรับ bidirectional communication

import websockets
import asyncio
import json
from websockets.exceptions import ConnectionClosed
from typing import Callable, Optional

class HolySheepWebSocketClient:
    """
    WebSocket Client สำหรับ HolySheep API
    รองรับ auto-reconnect และ context preservation
    """
    
    def __init__(
        self,
        api_key: str,
        wss_url: str = "wss://api.holysheep.ai/v1/stream",
        ping_interval: int = 30,
        reconnect_delay: float = 1.0,
        max_reconnect_attempts: int = 5
    ):
        self.api_key = api_key
        self.wss_url = wss_url
        self.ping_interval = ping_interval
        self.reconnect_delay = reconnect_delay
        self.max_reconnect_attempts = max_reconnect_attempts
        
        self.websocket: Optional[websockets.WebSocketClientProtocol] = None
        self.session_id: Optional[str] = None
        self.context_buffer: list = []
        self.is_connected = False
        
    async def connect(self) -> bool:
        """สร้างการเชื่อมต่อ WebSocket"""
        try:
            headers = {
                "Authorization": f"Bearer {self.api_key}",
                "X-Session-ID": self.session_id or ""
            }
            
            self.websocket = await websockets.connect(
                self.wss_url,
                extra_headers=headers,
                ping_interval=self.ping_interval
            )
            
            self.is_connected = True
            print(f"เชื่อมต่อ WebSocket สำเร็จ")
            return True
            
        except Exception as e:
            print(f"ไม่สามารถเชื่อมต่อ: {e}")
            self.is_connected = False
            return False
    
    async def reconnect(self) -> bool:
        """
        �