ข้ามไปยังเนื้อหาหลัก
ProgrammerThailand

AI & Vibe Coding

เลือกโมเดล AI ให้เหมาะงาน: ใหญ่ เล็ก เร็ว ถูก

เลือกโมเดล AI ให้เหมาะงาน: ใหญ่ เล็ก เร็ว ถูก

เมื่อเริ่มทำฟีเจอร์ AI คำถามที่ตามมาเสมอคือ "ใช้โมเดลไหนดี" คำตอบที่พบบ่อยคือเลือกตัวที่ดังที่สุดหรือตัวที่ใหญ่ที่สุดไว้ก่อน ซึ่งอาจทำให้จ่ายแพงเกินจำเป็นและช้ากว่าที่ผู้ใช้รับได้ หรือกลับกัน เลือกตัวถูกที่สุดแล้วพบว่าตอบภาษาไทยไม่ดี โมเดลใหม่ออกมาเร็วมากจนคำแนะนำแบบ "ใช้ตัวนี้" ล้าสมัยภายในไม่กี่เดือน บทความนี้จึงไม่บอกว่าควรใช้โมเดลไหน แต่ให้เกณฑ์และวิธีเลือกที่ใช้ได้ตลอด ตั้งแต่คุณภาพ ความเร็ว ราคา ขนาด context ภาษาไทย การรันเอง ไปจนถึงการตัดสินด้วย eval ของเราเองพร้อมตัวอย่างโค้ด PHP

เริ่มจากงาน ไม่ใช่จากโมเดล

ก่อนดูรายชื่อโมเดล ให้เขียนลักษณะงานให้ชัดก่อน เพราะเกณฑ์แต่ละข้อมีน้ำหนักต่างกันตามงาน

  • ความยากของงาน จัดหมวดคำร้อง ดึงเลขที่เอกสารจากข้อความ หรือสรุปสั้น เป็นงานที่โมเดลเล็กทำได้ดีพอ ส่วนการวิเคราะห์เอกสารยาวหลายฉบับหรือเขียนโค้ดซับซ้อน มักต้องใช้โมเดลที่ความสามารถสูงกว่า
  • ผู้ใช้รอคำตอบหรือไม่ chatbot ต้องเร็ว ส่วนงานประมวลผลเอกสารตอนกลางคืนรอได้
  • ปริมาณ วันละสิบครั้งกับวันละหมื่นครั้ง ทำให้เรื่องราคาสำคัญต่างกันมาก
  • ความอ่อนไหวของข้อมูล ข้อมูลส่งออกไปบริการภายนอกได้หรือไม่ ต้องอยู่ในประเทศหรือในองค์กรหรือเปล่า
  • ราคาของความผิดพลาด ตอบผิดแล้วผู้ใช้แค่กดถามใหม่ หรือตอบผิดแล้วเกิดความเสียหาย

เกณฑ์หลักในการเลือก

เกณฑ์คำถามที่ต้องตอบวิธีวัด
คุณภาพตอบถูกตามเกณฑ์ของงานเราบ่อยแค่ไหนeval ชุดของเราเอง ไม่ใช่ตัวเลขจากที่อื่น
ความเร็วเวลาถึงคำตอบแรกและเวลาจนตอบจบเป็นเท่าไรวัด latency จริงจากเครือข่ายของเรา ช่วงเวลาที่ใช้งานจริง
ราคาต้นทุนต่อหนึ่งงานเป็นเท่าไรจำนวน token เข้าและออกเฉลี่ยต่องาน คูณราคาปัจจุบันของผู้ให้บริการ
ขนาด contextต้องส่งข้อความยาวแค่ไหนในครั้งเดียววัดความยาวของ prompt จริง รวม system prompt และเอกสารที่แนบ
ภาษาไทยเข้าใจและเขียนไทยเป็นธรรมชาติไหมชุดทดสอบที่เป็นข้อความไทยจริง รวมคำเฉพาะของธุรกิจ
ความสามารถเสริมต้องใช้ structured output, tool use, รับภาพ หรือไม่ทดสอบฟีเจอร์ที่ต้องใช้จริง
การรันเองและข้อมูลต้องรันในองค์กรหรือส่งออกได้นโยบายข้อมูลขององค์กร และเงื่อนไขของผู้ให้บริการ
ไลเซนส์และเงื่อนไขใช้เชิงพาณิชย์ได้ไหม มีข้อห้ามอะไรอ่านเงื่อนไขการใช้งานของโมเดลหรือบริการ

ข้อสังเกตเรื่องภาษาไทย: โมเดลหลายตัวแบ่งข้อความไทยเป็น token มากกว่าข้อความอังกฤษที่ความยาวใกล้กัน ทำให้ทั้งราคาและการใช้ context สูงกว่าที่คำนวณจากตัวอย่างภาษาอังกฤษ ควรวัดจำนวน token จากข้อความไทยจริงที่ API ส่งกลับมา

ใหญ่ เล็ก เร็ว ถูก: ไม่จำเป็นต้องเลือกตัวเดียว

ระบบจริงหลายระบบใช้มากกว่าหนึ่งโมเดล โดยเลือกตามงาน รูปแบบที่พบบ่อย:

  • แยกตามงาน ใช้โมเดลเล็กกับงานจัดหมวดและดึงข้อมูล ใช้โมเดลใหญ่กับงานวิเคราะห์ที่ซับซ้อน
  • Cascade ให้โมเดลเล็กตอบก่อน ถ้าผลไม่ผ่านการตรวจ (เช่น JSON ไม่ตรง schema หรือโมเดลบอกว่าไม่มั่นใจ) ค่อยส่งต่อให้โมเดลใหญ่
  • แยกตามความอ่อนไหวของข้อมูล ข้อมูลภายในใช้โมเดลที่รันในองค์กร ข้อมูลทั่วไปใช้บริการ cloud ได้
  • ลดงานก่อนถึงโมเดล หลายงานไม่ต้องใช้ LLM เลย เช่น ค้นหาด้วย full-text search หรือตรวจรูปแบบด้วย regex ก่อน ใช้ LLM เฉพาะส่วนที่จำเป็น

เพื่อให้สลับโมเดลได้ง่าย ให้แอปเรียกผ่าน interface กลาง ไม่ผูกโค้ดกับผู้ให้บริการรายใดรายหนึ่ง

<?php

namespace common\ai;

interface ModelClient
{
    /** ชื่อที่ใช้แสดงในรายงาน */
    public function name(): string;

    /**
     * @param array<int, array{role: string, content: string}> $messages
     */
    public function complete(array $messages): ModelResult;
}

final class ModelResult
{
    public function __construct(
        public readonly string $text,
        public readonly int $inputTokens,
        public readonly int $outputTokens,
        public readonly float $latencySeconds,
    ) {
    }
}

แต่ละผู้ให้บริการหรือ Ollama บนเครื่องเป็นคลาสหนึ่งที่ implement interface นี้ ชื่อโมเดลและ API key อ่านจาก config หรือ environment ทำให้เปลี่ยนโมเดลได้โดยไม่ต้องแก้ business logic

ตัดสินด้วย eval ของเราเอง

ผล benchmark สาธารณะบอกภาพกว้างได้ แต่ไม่ได้วัดงานของเรา ข้อความภาษาไทยของเรา หรือรูปแบบคำตอบที่ระบบเราต้องการ วิธีที่เชื่อถือได้คือสร้างชุดทดสอบจากงานจริงแล้วรันกับทุกโมเดลที่สนใจ (รายละเอียดการสร้างชุดทดสอบอยู่ในบทความ "Evals: วัดคุณภาพคำตอบ AI ก่อนขึ้น Production" ของซีรีส์นี้) ตัวอย่าง runner ที่เทียบหลายโมเดลพร้อมกัน วัดทั้งอัตราผ่าน เวลา และต้นทุนโดยประมาณ

<?php

namespace common\ai;

final class ModelComparison
{
    /**
     * @param ModelClient[] $clients
     * @param array<string, array{input: float, output: float}> $pricePerMillion ราคาต่อ 1 ล้าน token ที่เรากรอกเองจากหน้าราคาปัจจุบัน
     * @param array<int, array{prompt: string, check: callable(string): bool}> $cases
     * @return array<string, array<string, float|int>>
     */
    public function run(array $clients, array $pricePerMillion, array $cases, string $systemPrompt): array
    {
        $report = [];
        foreach ($clients as $client) {
            $passed = 0;
            $latencies = [];
            $cost = 0.0;
            $price = $pricePerMillion[$client->name()] ?? ['input' => 0.0, 'output' => 0.0];

            foreach ($cases as $case) {
                $result = $client->complete([
                    ['role' => 'system', 'content' => $systemPrompt],
                    ['role' => 'user', 'content' => $case['prompt']],
                ]);
                if (($case['check'])($result->text)) {
                    $passed++;
                }
                $latencies[] = $result->latencySeconds;
                $cost += $result->inputTokens / 1_000_000 * $price['input']
                    + $result->outputTokens / 1_000_000 * $price['output'];
            }

            sort($latencies);
            $count = max(count($cases), 1);
            $report[$client->name()] = [
                'pass_rate' => round($passed / $count * 100, 1),
                'median_latency' => $latencies[intdiv(count($latencies), 2)] ?? 0.0,
                'cost_per_case' => round($cost / $count, 6),
            ];
        }
        return $report;
    }
}

ข้อควรจำเมื่อรันเทียบ:

  • ใช้ prompt และชุดทดสอบเดียวกันทุกโมเดล แต่ยอมให้ปรับ prompt ให้เหมาะกับแต่ละโมเดลได้ในรอบถัดไป เพราะบางโมเดลตอบสนองต่อรูปแบบ prompt ต่างกัน
  • ราคาให้กรอกเองจากหน้าราคาของผู้ให้บริการ ณ วันที่ทดสอบ และบันทึกวันที่ไว้ เพราะราคาเปลี่ยนได้
  • รันซ้ำมากกว่าหนึ่งรอบ คำตอบของ LLM ไม่คงที่ ผลที่ต่างกันเล็กน้อยระหว่างโมเดลอาจเป็นแค่ความแปรปรวน
  • อย่าใส่ข้อมูลส่วนบุคคลจริงในชุดทดสอบที่ส่งไปบริการภายนอก ให้ทำข้อมูลให้เป็นนิรนามก่อน

ตัดสินใจและทบทวนเป็นรอบ

เมื่อได้ผล eval แล้ว ให้กำหนดเกณฑ์ขั้นต่ำก่อน แล้วเลือกตัวที่ถูกและเร็วที่สุดในกลุ่มที่ผ่านเกณฑ์ ไม่ใช่เลือกตัวที่คะแนนสูงสุดเสมอ ตัวอย่างเกณฑ์: "อัตราผ่านอย่างน้อยตามที่ทีมตกลง, median latency ไม่เกินที่หน้าจอรับได้, ต้นทุนต่อเดือนตามปริมาณที่คาดไม่เกินงบ" จากนั้น

  1. เขียนเหตุผลการเลือกไว้ใน decision record ของโปรเจกต์ พร้อมผล eval และวันที่
  2. ติดตามคุณภาพหลังขึ้นจริง ด้วยการสุ่มตรวจคำตอบและเก็บกรณีที่ผู้ใช้ร้องเรียนเข้าชุดทดสอบ
  3. ทบทวนเป็นรอบ เช่น ทุกไตรมาส หรือเมื่อผู้ให้บริการประกาศเปลี่ยนรุ่นหรือเลิกให้บริการรุ่นที่ใช้
  4. เตรียมแผนสำรอง ถ้าบริการหลักล่ม จะ fallback ไปโมเดลไหน หรือจะปิดฟีเจอร์อย่างไรให้ผู้ใช้เข้าใจ

เมื่อมี interface กลางและ eval ชุดเดิม การเปลี่ยนโมเดลในอนาคตจะเป็นการตัดสินใจจากข้อมูล ไม่ใช่การเดา

สรุป

  • เริ่มจากลักษณะงาน: ความยาก ความเร่งด่วน ปริมาณ ความอ่อนไหวของข้อมูล และราคาของความผิดพลาด
  • เกณฑ์หลักคือคุณภาพ ความเร็ว ราคา ขนาด context ภาษาไทย ความสามารถเสริม การรันเอง และไลเซนส์
  • ไม่ต้องใช้โมเดลเดียว ใช้การแยกตามงานหรือ cascade และเรียกผ่าน interface กลาง
  • ตัดสินด้วย eval จากงานจริงของเรา วัดทั้งอัตราผ่าน latency และต้นทุนต่องาน
  • เลือกตัวที่ถูกและเร็วที่สุดในกลุ่มที่ผ่านเกณฑ์ บันทึกเหตุผล และทบทวนเป็นรอบ

ลองทำ

เลือกงาน AI หนึ่งงานในระบบของคุณ เขียนชุดทดสอบ 15 ข้อจากข้อมูลจริงที่ทำเป็นนิรนามแล้ว พร้อมฟังก์ชันตรวจผลแต่ละข้อ จากนั้น implement ModelClient อย่างน้อยสองตัว (เช่น โมเดลจากบริการที่ใช้อยู่ และโมเดลบนเครื่องผ่าน Ollama) รัน ModelComparison สองรอบ แล้วเขียน decision record สั้น ๆ ว่าจะเลือกตัวไหนเพราะอะไร

ติดปัญหาตอนทำตาม? ถามในชุมชน

ความคิดเห็น (0)

ยังไม่มีความคิดเห็น — เริ่มคุยเป็นคนแรก ถามสิ่งที่สงสัย หรือแชร์ประสบการณ์ของคุณ