เมื่อพัฒนาแอปพลิเคชันที่ใช้ AI API ในระดับ Production ปัญหาที่พบบ่อยที่สุดคือ คำขอซ้ำ (Duplicate Requests) และ การตอบกลับที่ไม่สอดคล้อง จากการเรียก API หลายครั้ง บทความนี้จะสอนวิธีออกแบบระบบให้รองรับการทำงานแบบ Idempotent หรือการที่การเรียก API หนึ่งครั้งหรือหลายครั้งจะได้ผลลัพธ์เหมือนกันเสมอ

ทำไมต้องกังวลเรื่อง Request Deduplication?

ในระบบ AI จริงมีหลายสถานการณ์ที่คำขออาจถูกส่งซ้ำโดยไม่ตั้งใจ

กรณีศึกษา: ระบบ Customer Service AI ของ E-Commerce

บริษัท E-Commerce แห่งหนึ่งใช้ HolySheep AI สำหรับแชทบอทตอบคำถามลูกค้า ปัญหาที่พบคือเมื่อลูกค้าส่งข้อความเดียวกัน 2 ครั้ง ระบบเรียก AI API 2 ครั้ง ทำให้เสียค่าใช้จ่ายเป็น 2 เท่า

การใช้ Idempotency Key

วิธีแก้ไขคือส่ง Idempotency Key ไปกับทุกคำขอ เพื่อให้ Server ตรวจสอบว่าคำขอนี้เคยถูกประมวลผลแล้วหรือไม่

const axios = require('axios');
const crypto = require('crypto');

// สร้าง Cache สำหรับเก็บผลลัพธ์ตาม Idempotency Key
const idempotencyCache = new Map();

// ฟังก์ชันสำหรับเรียก AI API แบบ Idempotent
async function callAIWithIdempotency(userId, message, conversationId) {
    // สร้าง Idempotency Key จาก userId + conversationId + message hash
    const idempotencyKey = crypto
        .createHash('sha256')
        .update(${userId}:${conversationId}:${message})
        .digest('hex')
        .substring(0, 32);

    // ตรวจสอบ Cache ก่อน
    if (idempotencyCache.has(idempotencyKey)) {
        console.log('พบคำขอซ้ำ ส่งผลลัพธ์จาก Cache');
        return idempotencyCache.get(idempotencyKey);
    }

    // ส่งคำขอไปยัง HolySheep AI
    const response = await axios.post('https://api.holysheep.ai/v1/chat/completions', {
        model: 'gpt-4.1',
        messages: [
            { role: 'system', content: 'คุณคือผู้ช่วยบริการลูกค้า' },
            { role: 'user', content: message }
        ],
        max_tokens: 500
    }, {
        headers: {
            'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
            'Content-Type': 'application/json',
            'X-Idempotency-Key': idempotencyKey
        },
        timeout: 30000
    });

    const result = response.data;

    // เก็บผลลัพธ์ลง Cache (TTL 1 ชั่วโมง)
    idempotencyCache.set(idempotencyKey, result);
    
    // ลบ entry เก่าออกถ้า Cache ใหญ่เกิน
    if (idempotencyCache.size > 10000) {
        const firstKey = idempotencyCache.keys().next().value;
        idempotencyCache.delete(firstKey);
    }

    return result;
}

// ตัวอย่างการใช้งาน
callAIWithIdempotency('user_123', 'สถานะสั่งซื้อของฉัน', 'conv_456')
    .then(result => console.log('ผลลัพธ์:', result.choices[0].message.content))
    .catch(err => console.error('เกิดข้อผิดพลาด:', err.message));

กรณีศึกษา: ระบบ RAG ขององค์กร

เมื่อเปิดตัวระบบ RAG (Retrieval-Augmented Generation) สำหรับค้นหาเอกสารภายในองค์กร ปัญหาที่พบคือ การ Embedding ซ้ำ เมื่อเอกสารเดียวกันถูกอัปโหลดหลายครั้ง วิธีแก้ไขคือใช้ Document Hash เพื่อตรวจสอบก่อนทำ Embedding

const crypto = require('crypto');

class DocumentDeduplicator {
    constructor() {
        this.processedDocuments = new Set();
    }

    // สร้าง Hash จากเนื้อหาเอกสาร
    static createDocumentHash(content, metadata = {}) {
        const hashInput = JSON.stringify({
            content: content.trim(),
            ...metadata
        });
        return crypto.createHash('sha256').update(hashInput).digest('hex');
    }

    // ตรวจสอบว่าเอกสารเคยถูกประมวลผลหรือไม่
    isAlreadyProcessed(documentHash) {
        return this.processedDocuments.has(documentHash);
    }

    // ประมวลผลเอกสารแบบ Idempotent
    async processDocument(content, metadata = {}) {
        const docHash = DocumentDeduplicator.createDocumentHash(content, metadata);

        // ตรวจสอบก่อน
        if (this.isAlreadyProcessed(docHash)) {
            return {
                status: 'duplicate',
                message: 'เอกสารนี้เคยถูกประมวลผลแล้ว',
                hash: docHash
            };
        }

        // เรียก Embedding API จาก HolySheep AI
        const response = await fetch('https://api.holysheep.ai/v1/embeddings', {
            method: 'POST',
            headers: {
                'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                model: 'text-embedding-3-large',
                input: content.substring(0, 8000) // จำกัดความยาว
            })
        });

        if (!response.ok) {
            throw new Error(Embedding API Error: ${response.status});
        }

        const embeddingResult = await response.json();

        // ทำเครื่องหมายว่าประมวลผลแล้ว
        this.processedDocuments.add(docHash);

        return {
            status: 'success',
            hash: docHash,
            embedding: embeddingResult.data[0].embedding,
            tokenUsage: embeddingResult.usage.total_tokens
        };
    }
}

// ตัวอย่างการใช้งาน
const deduplicator = new DocumentDeduplicator();

async function main() {
    const documentContent = 'รายงานประจำปี 2568 ของบริษัท...';
    
    // ครั้งที่ 1
    const result1 = await deduplicator.processDocument(documentContent);
    console.log('ครั้งที่ 1:', result1.status);
    
    // ครั้งที่ 2 - จะ return duplicate
    const result2 = await deduplicator.processDocument(documentContent);
    console.log('ครั้งที่ 2:', result2.status);
}

main().catch(console.error);

รูปแบบการออกแบบ Idempotency ที่แนะนำ

1. ใช้ Database Transaction

สำหรับระบบที่ต้องการความถูกต้องสูง ใช้ Transaction เพื่อตรวจสอบและบันทึกพร้อมกัน

async function processAIGenerationWithTransaction(requestId, userId, prompt) {
    const pool = require('./db-pool'); // PostgreSQL/MySQL connection pool

    const client = await pool.connect();
    
    try {
        await client.query('BEGIN');

        // ตรวจสอบว่ามี requestId นี้ในฐานข้อมูลหรือไม่
        const existingRequest = await client.query(
            'SELECT result FROM idempotent_requests WHERE request_id = $1',
            [requestId]
        );

        if (existingRequest.rows.length > 0) {
            await client.query('COMMIT');
            console.log('พบคำขอที่ประมวลผลแล้ว ส่งผลลัพธ์เดิม');
            return JSON.parse(existingRequest.rows[0].result);
        }

        // สร้าง record ว่ากำลังประมวลผล
        await client.query(
            'INSERT INTO idempotent_requests (request_id, user_id, status) VALUES ($1, $2, $3)',
            [requestId, userId, 'processing']
        );

        await client.query('COMMIT');

        // เรียก AI API
        const aiResponse = await fetch('https://api.holysheep.ai/v1/chat/completions', {
            method: 'POST',
            headers: {
                'Authorization': Bearer ${process.env.HOLYSHEEP_API_KEY},
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                model: 'claude-sonnet-4.5',
                messages: [{ role: 'user', content: prompt }],
                max_tokens: 1000
            })
        });

        const result = await aiResponse.json();

        // อัปเดตผลลัพธ์
        const updateClient = await pool.connect();
        await updateClient.query('BEGIN');
        await updateClient.query(
            'UPDATE idempotent_requests SET status = $1, result = $2 WHERE request_id = $3',
            ['completed', JSON.stringify(result), requestId]
        );
        await updateClient.query('COMMIT');
        updateClient.release();

        return result;

    } catch (error) {
        await client.query('ROLLBACK');
        throw error;
    } finally {
        client.release();
    }
}

ข้อผิดพลาดที่พบบ่อยและวิธีแก้ไข

ข้อผิดพลาดที่ 1: "429 Too Many Requests" หรือ Rate Limit

สาเหตุ: ส่งคำขอเร็วเกินไปเก