12 วิธีลด Latency และต้นทุนการรัน LLM ในระดับ Production อย่างมีประสิทธิภาพ

บทนำ
แอปพลิเคชันโมเดลภาษาขนาดใหญ่ (LLM) มักจะทำงานช้าลงและมีค่าใช้จ่ายพุ่งสูงขึ้นเร็วกว่าที่คาดไว้ ในช่วงตัวต้นแบบ (prototype) ทุกอย่างดูราบรื่นเพราะมีผู้ใช้ไม่กี่คน prompt สั้น และแทบไม่มีดีเลย์ แต่ในสภาพแวดล้อมใช้งานจริง (production) นั้นต่างออกไป เมื่อทราฟฟิกพุ่งสูงขึ้นจนเกิดคิวรอ บทสนทนายาวขึ้น ระบบ RAG เพิ่มบริบทขนาดใหญ่เข้าไปในทุกคำสั่ง หรือเอเจนต์ที่ต้องเรียกใช้เครื่องมือหลายครั้ง ปัจจัยเหล่านี้ล้วนเพิ่ม latency และต้นทุนแบบเงียบๆ
สิ่งที่น่าสนใจคือ ทางออกมักไม่ใช่การเปลี่ยนไปใช้โมเดลที่ฉลาดกว่าหรือเพิ่ม GPU ให้มากขึ้น แต่ผลลัพธ์ที่ดีที่สุดมาจากการ "ตัดงานที่ไม่จำเป็น" เช่น การใช้ token ให้น้อยลง ลดความถี่ในการเรียกใช้โมเดล ใช้โมเดลขนาดเล็กสำหรับงานง่ายๆ นำ cache กลับมาใช้ใหม่ และลดเวลารอในคิว คู่มือนี้จะสรุป 12 วิธีปฏิบัติเพื่อลด latency และต้นทุน inference ของ LLM ในการใช้งานจริง
1. วัดค่า Latency ที่ถูกต้องก่อน
ก่อนจะเริ่มปรับแต่ง คุณต้องรู้ก่อนว่าความล่าช้าเกิดขึ้นที่จุดใด
ค่า Latency แบบ End-to-end บอกผลลัพธ์รวมแต่ไม่ได้บอกสาเหตุ ระบบ LLM ในสายการผลิตควรติดตามตัวเลขเหล่านี้เป็นอย่างน้อย:
- Queue time: ระยะเวลาที่คำร้องรอในคิวก่อนเริ่มประมวลผล
- Time to first token (TTFT): เวลาที่ใช้จนกระทั่งผู้ใช้เห็นตัวอักษรแรก (ในโหมด streaming)
- Inter-token latency: ความเร็วในการสร้างตัวอักษรแต่ละตัวต่อจากตัวแรก
- End-to-end latency: เวลารวมทั้งหมดตั้งแต่ส่งคำสั่งจนจบการประเมินผล
- จำนวน Input และ Output token: ตัวแปรหลักที่กำหนดต้นทุน
- Cache hit rate: ความถี่ที่ระบบนำข้อมูลเดิมมาใช้ใหม่เพื่อเลี่ยงการคำนวณซ้ำ
- Tool และ retrieval latency: เวลาที่เสียไปกับการเรียกเครื่องมือภายนอกหรือดึงข้อมูล
- P50, P95, และ P99 latency: ค่าความล่าช้าในระดับเปอร์เซ็นไทล์ ซึ่งสำคัญกว่าค่าเฉลี่ยทั่วไป
ตัวอย่างเช่น หาก TTFT สูง อาจหมายถึง prompt ยาวเกินไปหรือระบบดึงข้อมูลช้า แต่ถ้า inter-token latency ช้า อาจแปลว่าโมเดลใหญ่เกินไปหรือ GPU ทำงานหนักเกินไป การวัดผลที่แม่นยำจะช่วยให้แก้ปัญหาได้ถูกจุด
2. ลด Output Tokens อย่างจริงจัง
Output token คือตัวการหลักของทั้งความช้าและค่าใช้จ่าย
ยิ่งคำตอบยาว โมเดลยิ่งต้องใช้เวลาสร้างนานขึ้นแบบแปรผันตรง ลองปรับแนวทางดังนี้:
- ตั้งค่า
max_tokensให้เหมาะสมกับความต้องการจริง - สั่งให้โมเดลตอบกระชับในกรณีที่ไม่ต้องการคำอธิบายละเอียด
- ใช้ stop sequences เพื่อตัดจบคำตอบในจุดที่ควร
- ไม่ต้องให้โมเดลทวนคำถามของผู้ใช้ซ้ำ
- ใช้ JSON schemas ที่กะทัดรัดและตั้งชื่อ field ให้สั้น
- ตัดส่วนที่เป็นน้ำหรือคำสรุปฟุ่มเฟือยออก
- เพิ่มตัวเลือกใน UI ให้ผู้ใช้เลือกระหว่าง "คำตอบสั้น" หรือ "คำอธิบายละเอียด"
กฎเหล็กคือ: อย่าจ่ายเงินค่า token ให้กับข้อความที่ผู้ใช้จะไม่อ่าน
3. ส่งคำร้องไปยังโมเดลที่เล็กที่สุดที่ทำงานนั้นได้
ไม่ใช่ทุกงานที่ต้องใช้โมเดลรุ่นท็อปที่มีราคาแพง
งานที่ซ้ำซ้อนและมีโครงสร้างชัดเจน เช่น การวิเคราะห์ทางอารมณ์ (Sentiment analysis), การดึงข้อมูล (Data extraction), หรือการตอบ FAQ พื้นฐาน สามารถรันบนโมเดลขนาดเล็กได้ดีพอๆ กันแต่เร็วกว่าและประหยัดกว่ามาก
เทคนิคที่นิยมคือการใช้ Model Routing:
- ส่งคำร้องง่ายๆ ไปยังโมเดลขนาดเล็ก
- ประเมินความมั่นใจหรือคุณภาพของคำตอบ
- ยกระดับคำร้องไปยังโมเดลที่เก่งกว่าเฉพาะในกรณีที่จำเป็นเท่านั้น
4. ลดจำนวนการเรียกใช้ LLM
หลีกเลี่ยงการสร้าง Workflow ที่เรียกใช้โมเดลต่อกันหลายครั้งเกินจำเป็น เช่น การเรียกโมเดลเพื่อจัดประเภท เขียนใหม่ ดึงข้อมูล สรุป ตรวจสอบ และเขียนใหม่อีกครั้ง ซึ่งทุกขั้นตอนเพิ่มทั้ง latency และความเสี่ยง
ลองออกแบบ prompt เดียวที่จัดการได้หลายขั้นตอนในครั้งเดียว หรือใช้โค้ดคอมพิวเตอร์แบบปกติ (deterministic code) ในงานที่ไม่ต้องใช้ AI เช่น การจัดฟอร์แมตวันที่, การคำนวณตัวเลข หรือการตรวจสอบสิทธิ์
5. ออกแบบ Prompt สำหรับ Prefix Caching
Prefix caching ช่วยลดต้นทุนในตอนที่ต้องส่ง prompt ยาวๆ ที่มีเนื้อหาบางส่วนซ้ำเดิม
ควรนำเนื้อหาที่คงที่ไว้ที่ส่วนต้นของ prompt เสมอ เช่น:
- คำแนะนำระบบ (System instructions)
- ตัวอย่าง Few-shot
- เอกสารประกอบคงที่
และนำข้อมูลที่เปลี่ยนแปลงบ่อยไว้ท้ายสุด เช่น คำถามของผู้ใช้หรือประวัติการสนทนาล่าสุด เพราะหากข้อมูลในช่วงต้นเปลี่ยน จะทำให้ cache เดิมกลายเป็นโมฆะและต้องเสียเงินประมวลผลใหม่ทั้งหมด
6. เพิ่มชั้น Cache หลายระดับ
นอกจากการแคชที่ตัวโมเดลแล้ว ควรมีระบบแคชในระดับแอปพลิเคชันด้วย:
- Exact Response Cache: เก็บคำตอบสำหรับคำถามที่เหมือนกันเป๊ะ
- Semantic Cache: นำคำตอบเดิมมาใช้เมื่อคำถามใหม่มีความหมายใกล้เคียงกันมาก
- Retrieval Cache: แคชผลการค้นหาหรือเอกสารที่ดึงมาบ่อยๆ
- Tool Result Cache: แคชผลลัพธ์จาก API หรือฐานข้อมูลที่ข้อมูลไม่ได้เปลี่ยนบ่อย
7. ควบคุมงบประมาณบริบท (Context Budget) ในการทำ RAG
การใส่ข้อมูลดิบหรือเอกสารจำนวนมากลงใน prompt ของ RAG ทำให้ระบบช้าและแพง ควรใช้วิธี "จำกัดงบประมาณ" ดังนี้:
- ดึงเฉพาะเอกสารที่เกี่ยวข้องที่สุดให้น้อยชิ้นลง
- ใช้การจัดลำดับใหม่ (Reranking) ก่อนส่งให้โมเดล
- ตัดข้อความที่ไม่จำเป็น เช่น HTML tag หรือข้อมูลซ้ำซ้อนออก
- สรุปใจความสำคัญของประวัติการสนทนาเก่าๆ แทนการใส่ไปทั้งหมด
8. ย้ายงานที่ไม่ด่วนไปยัง Batch Processing
งานประเภทการติดป้ายกำกับข้อมูล (labeling), การสรุปรายงานจำนวนมาก หรือการประมวลผลหลังบ้าน ควรใช้ Batch API ซึ่งมักมีราคาถูกกว่าและไม่ไปแย่งทรัพยากรผู้ใช้ที่ต้องการการโต้ตอบแบบเรียลไทม์
9. ปรับแต่ง Batching เพื่อ Latency ไม่ใช่แค่ Throughput
การรวมคำร้องมาประมวลผลพร้อมกัน (Batching) ช่วยให้ GPU ทำงานคุ้มค่าขึ้น แต่อย่าทำให้ batch ใหญ่เกินไปจนผู้ใช้ต้องรอนานในคิว เป้าหมายคือการหาจุดสมดุลที่ทำให้ GPU ทำงานเต็มประสิทธิภาพโดยที่ค่า P95 latency ยังอยู่ในเกณฑ์ที่ยอมรับได้
10. จัดการ Key-Value Cache และความยาวบริบทอย่างระมัดระวัง
KV Cache คือหน่วยความจำที่ LLM ใช้ขณะสร้างคำตอบ หากคำสั่งยาวเกินไปหรือมีคนใช้พร้อมกันมาก หน่วยความจำ GPU จะเต็มจนเกิดข้อผิดพลาด OOM (Out-of-memory)
ควรตั้งขีดจำกัดสูงสุด (Max context window) ที่สอดคล้องกับการใช้งานจริง อย่าเปิดกว้างไว้เพียงเพราะโมเดลรองรับได้ เพราะจะส่งผลเสียต่อเสถียรภาพของระบบ
11. วัดผล Servicing Optimization กับทราฟฟิกจริง
ฟีเจอร์ช่วยเพิ่มความเร็วอย่าง Quantization หรือ Speculative decoding อาจไม่ได้ผลดีเสมอไปในทุกกรณี ควรทดสอบ (Benchmark) ด้วยทราฟฟิกจริงที่มีความยาว prompt และพฤติกรรมการเรียกใช้ที่ใกล้เคียงกับผู้ใช้ของคุณมากที่สุด อย่าหลงเชื่อเพียงตัวเลขโฆษณาเรื่อง token-per-second
12. เพิ่มการควบคุมการรับคำร้อง (Admission Control) และการลดประสิทธิภาพอย่างสง่างาม
ในช่วงที่ทราฟฟิกพุ่งสูง ระบบควรมีการจำกัดอัตราการใช้ (Rate limits) หรือมีระบบลำดับความสำคัญ (Priority queues)
หากระบบรับภาระหนักเกินไป ควรมีกลไกตัดบางขั้นตอนที่ไม่จำเป็นออกชั่วคราว หรือสลับไปใช้โมเดลที่เล็กกว่า (fallback) เพื่อให้ระบบยังคงทำงานได้ แทนที่จะปล่อยให้ล่มไปทั้งหมด
สรุปส่งท้าย
กลยุทธ์การปรับแต่ง LLM ที่ดีที่สุดคือการออกแบบระบบให้ "ทำงานที่จำเป็นน้อยที่สุด" เมื่อคุณเริ่มลดขนาด output, นำ cache มาใช้, และจัดการบริบทได้อย่างมีประสิทธิภาพ แอปพลิเคชันของคุณจะเร็วขึ้น เสถียรขึ้น และราคาถูกลง โดยที่ยังคงคุณภาพที่ดีเยี่ยมไว้ได้
ความคิดเห็น (0)
เข้าสู่ระบบเพื่อร่วมแสดงความเห็น
สมัครสมาชิกมาเป็นคนแรกที่แสดงความเห็นกันเลยโบร
