ผมเคยปฏิบัติกับ RAG pipeline เหมือนเป็นกล่องดำ (black box) คือใส่ Embeddings เข้าไป แล้วก็ได้คำตอบออกมา โดยที่ระหว่างนั้นค่าใช้จ่ายบนคลาวด์ของผมก็เพิ่มขึ้นเรื่อยๆ เหมือนกับนักพัฒนาส่วนใหญ่ที่ผมเคยคุยด้วย ผมทึกทักเอาเองว่าโมเดล Dense Vector คือตัวร้าย เพราะฟังดูเหมือนจะมีราคาแพง การแปลงเอกสารพันหน้าให้กลายเป็นค่า float มิติสูงให้ความรู้สึกเหมือนกระบวนการผลิตในโรงงานที่หนักหน่วง ผมจึงจัดการกับมันด้วยความระมัดระวังเป็นพิเศษ ถึงขั้นสร้างเลเยอร์การทำ Caching ขึ้นมาโดยเฉพาะเพื่อหลีกเลี่ยงการทำ Re-embedding ข้อมูลที่เคยประมวลผลไปแล้ว ผมเคยภูมิใจกับการปรับแต่ง (optimization) นั้นมาก จนกระทั่งผมเปิดใบแจ้งหนี้และลองคำนวณตัวเลขดู

ผมกำลังปรับแต่งผิดจุดอย่างสิ้นเชิง

กับดัก Embedding

นี่คือตัวเลขที่ทำลายสมมติฐานของผม: การทำ embedding เอกสาร 1,000 หน้า มีค่าใช้จ่ายเพียงประมาณ 18 เซนต์ (ประมาณ 6-7 บาท) นี่ไม่ใช่การพิมพ์ผิด ในราคาที่ถูกกว่ากาแฟหนึ่งแก้วในเมืองส่วนใหญ่ คุณสามารถทำ vectorization หนังสือได้ทั้งเล่ม และที่สำคัญกว่านั้นคือ ค่าใช้จ่ายนี้เกิดขึ้นเพียงครั้งเดียวตอนนำข้อมูลเข้า (ingestion) หลังจากผ่านขั้นตอนแรกไปแล้ว เวกเตอร์เหล่านั้นจะถูกเก็บไว้ในที่จัดเก็บข้อมูลเพื่อรอใช้งาน พวกมันไม่ได้เรียกเก็บค่าธรรมเนียมตามการใช้งานทุกครั้งที่ผู้ใช้เปิดแอปพลิเคชันของคุณ มันคือรายจ่ายฝ่ายทุน (capital expense) ไม่ใช่รายจ่ายที่ไหลออกอย่างต่อเนื่อง (recurring drain)

แต่ความเชื่อผิดๆ นี้ยังคงอยู่ ส่วนหนึ่งของความสับสนเกิดจากโครงสร้างการทำงาน ขั้นตอนการนำข้อมูลเข้า (ingestion pipeline) คือจุดที่วิศวกรทุ่มเทพลังงานในช่วงแรก คุณต้องเขียน Chunker, ต้องสู้กับ Tokenizer, และต้องนั่งเฝ้าแถบความคืบหน้าที่ค่อยๆ ขยับบน Terminal ความพยายามที่มองเห็นได้นี้สร้างภาพลวงตาเรื่องสัดส่วนของต้นทุน มันให้ความรู้สึกว่าเป็นส่วนที่แพงเพราะมันเป็นส่วนที่ต้องใช้แรงงานหนัก แต่แรงงานกับต้นทุนนั้นไม่ใช่สิ่งเดียวกัน และในระบบ RAG ทั้งสองอย่างนี้มักจะมีความสัมพันธ์แบบผกผันกัน

บิล 3 รูปแบบที่แตกต่างกันอย่างสิ้นเชิง

เมื่อผมแยกต้นทุนตามขั้นตอนแทนที่จะรวมกันเป็นก้อนเดียว ภาพทุกอย่างก็ชัดเจนขึ้น ระบบ RAG ทำงานบนโมเดลเศรษฐศาสตร์ที่แตกต่างกัน 3 รูปแบบ และการเข้าใจความแตกต่างนี้เป็นสิ่งจำเป็นหากคุณต้องการควบคุมงบประมาณให้คงที่

Embeddings คือต้นทุนการผลิตแบบจ่ายครั้งเดียว คุณจ่ายเพื่อแปลงเอกสารให้เป็นเวกเตอร์ แล้วก็จบกันไป หากเอกสารของคุณเป็นข้อมูลแบบคงที่ (static) รายการนี้แทบจะไม่ปรากฏในใบแจ้งหนี้รายเดือนของคุณเลย

Vector databases คือค่าเช่าโครงสร้างพื้นฐาน คุณจ่ายเพื่อให้ระบบทำงานได้ตลอด 24 ชั่วโมง คุณจ่ายสำหรับ SSD ที่เก็บข้อมูลชิ้นส่วน (chunks) นับล้าน, จ่ายสำหรับ CPU cores ที่คอยรักษา index, และจ่ายสำหรับเครือข่ายที่ทำให้การค้นหาใช้เวลาไม่ถึง 100 มิลลิวินาที ต้นทุนนี้มีอยู่จริงและจะเพิ่มขึ้นตามปริมาณข้อมูล แต่โดยทั่วไปแล้วมันคาดการณ์ได้ มันทำงานเหมือนค่าสมาชิกยิม ไม่ว่าคุณจะ Query หนึ่งครั้งหรือหนึ่งหมื่นครั้ง ต้นทุนโครงสร้างพื้นฐานพื้นฐานก็ยังคงใกล้เคียงเดิม

Large language models คือภาษีตามการใช้งาน ทุกคำถามของผู้ใช้จะกระตุ้นให้เกิดบิล ทุกๆ token ที่ออกจากชั้นการดึงข้อมูล (retrieval layer) และเข้าสู่ Prompt จะมีค่าใช้จ่าย ทุกขั้นตอนของการใช้เหตุผล, ทุกคำสั่งในการจัดรูปแบบ, และทุกการอ้างอิงที่คุณสั่งให้โมเดลสร้างขึ้น ล้วนเพิ่มน้ำหนักเล็กๆ น้อยๆ แต่ค่าใช้จ่ายเล็กๆ เหล่านั้นจะทวีคูณตามจำนวน Session และจำนวน Session ก็มีแนวโน้มเพิ่มขึ้นเรื่อยๆ นี่คือจุดที่ความหน่วง (latency) จะมาบรรจบกับการใช้จ่าย การ Query ที่ช้าไม่ใช่แค่เรื่องน่ารำคาญสำหรับผู้ใช้ แต่มันคือการเผาเงินทิ้งในขณะที่ผู้ใช้กำลังรอ

สิ่งเหล่านี้ไม่ใช่ความแปรผันของปัญหาเดียวกัน แต่มันคือสามปัญหาที่แยกจากกัน คุณไม่สามารถแก้ปัญหาการใช้จ่ายตอน Query ได้ด้วยการทำให้ขั้นตอน Ingestion ถูกลง นั่นเหมือนกับการจูนเครื่องยนต์รถเพื่อประหยัดค่าจอดรถ

เงินไหลไปที่ไหนกันแน่

หากคุณกำลังรันแอปพลิเคชัน RAG ในระดับ Production ให้ลองเปิด Cost Explorer ของคุณแล้วกรองตามประเภทการใช้งาน (usage type) ผมกล้าพนันได้เลยว่างาน Embedding ของคุณจะเป็นเส้นตรงราบเรียบวันละครั้ง ในขณะที่ Endpoint ของ LLM จะดูเหมือนกราฟชีพจรที่พุ่งสูงขึ้นตามปริมาณทราฟฟิก รูปแบบนั้นบอกเรื่องราวทั้งหมด เวกเตอร์ของคุณกำลังนอนหลับ แต่โมเดลของคุณตื่นขึ้นมาทุกครั้งที่มีคนถามคำถาม

การตระหนักรู้นี้เปลี่ยนวิธีที่ผมจัดลำดับความสำคัญของงานวิศวกรรม ผมเลิกถามว่าจะทำให้ Ingestion ถูกลงได้อย่างไร และเริ่มถามว่าจะทำให้แต่ละคำถามถูกลงได้อย่างไร การเปลี่ยนมุมมองนี้ฟังดูเหมือนเป็นเรื่องชัดเจน แต่ทีมส่วนใหญ่ยังคงทำงานตามสัญชาตญาณ พวกเขาสร้างตรรกะการทำ Deduplication ที่ซับซ้อนสำหรับขั้นตอน Embedding แต่กลับป้อน Context window ที่บวมและไม่ตรงประเด็นให้กับ LLM โดยไม่หยุดคิด พวกเขากำลังขัดพื้นในขณะที่หลังคากำลังรั่ว

วิธีลดต้นทุนโดยไม่ทำให้ Pipeline พัง

การประหยัดเงินในระบบ RAG จำเป็นต้องใช้กลยุทธ์ให้สอดคล้องกับโมเดลต้นทุน และนี่คือสิ่งที่ได้ผลจริง

ทำ Deduplication ก่อนเริ่มประมวลผล

ฐานความรู้ส่วนใหญ่ในองค์กรมักจะมีการเคลื่อนไหวที่ล่าช้า นโยบาย, คู่มือ, ไฟล์ PDF งานวิจัย และรายงานที่จัดเก็บไว้ มักจะถูกปล่อยทิ้งไว้โดยไม่มีการแตะต้องเป็นเวลาหลายเดือน ในหลายๆ pipeline เอกสารต้นทางประมาณ 80% มักจะเหมือนเดิมระหว่างรอบการนำเข้าข้อมูล (ingestion runs) ทั้งที่เป็นเช่นนี้ แต่หลายระบบกลับลบข้อมูลทั้งหมด (corpus) ทิ้งแล้วสร้างดัชนี (index) ใหม่ทั้งหมดตามตารางเวลาที่กำหนด อย่าทำแบบนั้น ให้สร้าง "ด่านตรวจ" (gate) ไว้ที่จุดเริ่มต้นของ pipeline ของคุณ ทำการ Hash ไฟล์ที่เข้ามา เปรียบเทียบ timestamps ของการแก้ไขล่าสุด หากเอกสารไม่มีการเปลี่ยนแปลง ให้ข้ามไปเลยทั้งฉบับ การประมวลผลไฟล์ที่ไม่มีการเปลี่ยนแปลงซ้ำอีกครั้งคือการสิ้นเปลืองโดยเปล่าประโยชน์ มันทำให้เสียทรัพยากรการคำนวณ (compute) ทำให้ SSD สึกหรอโดยไม่จำเป็น และทำให้ log การนำเข้าข้อมูลบวมขึ้นด้วยกิจกรรมที่ไม่มีความหมาย

ในทางปฏิบัติ ให้จัดเก็บ manifest ขนาดเล็กที่จับคู่เส้นทางไฟล์ (file paths) กับ checksums เมื่อ scheduler เริ่มทำงาน ให้มันตรวจสอบ manifest ก่อน ควรมีเพียงไฟล์ส่วนน้อยที่เปลี่ยนแปลงเท่านั้นที่จะถูกส่งไปยัง chunker

แก้ไขเฉพาะจุด (Patch) อย่าแทนที่ทั้งฉบับ

เมื่อเอกสารมีการเปลี่ยนแปลง อย่าเผลอทำตามสัญชาตญาณที่อยากจะปฏิบัติกับมันเหมือนเป็นไฟล์ใหม่แกะกล่อง เอกสารข้อกำหนดทางเทคนิค (technical spec) จำนวน 50 หน้า อาจมีการแก้ไขเพียงแค่สองย่อหน้าในส่วนที่สี่ หาก pipeline ของคุณแทนที่ไฟล์ทั้งฉบับ คุณจะต้องเสียเวลาทำ re-chunk และ re-embed อีก 49 หน้าที่สมบูรณ์ดีอยู่แล้วโดยไม่มีเหตุผล

แทนที่จะทำแบบนั้น ให้เปรียบเทียบเวอร์ชันใหม่กับเวอร์ชันเก่า ระบุส่วนที่แตกต่าง (delta) จากนั้นจึงทำ re-chunk และ re-embed เฉพาะส่วนที่มีการเปลี่ยนแปลงเท่านั้น ใช้ metadata เช่น เลขหน้า, section IDs, header anchors หรือช่วงของย่อหน้า เพื่อติดตามขอบเขตของข้อมูล หากกลยุทธ์การ chunking ของคุณเคารพโครงสร้างเอกสาร เรื่องนี้ก็จะเป็นเรื่องง่าย แต่ถ้าไม่ การปรับปรุง chunker ของคุณให้ดีขึ้นเป็นการลงทุนที่คุ้มค่ากว่าการซื้อ inference cluster ที่ใหญ่ขึ้น ต้นทุนทางวิศวกรรมในการดูแลรักษา pipeline ที่รับรู้ความแตกต่าง (diff-aware) จะคืนทุนภายในไม่กี่สัปดาห์เมื่อจำนวนเอกสารของคุณเพิ่มมากขึ้น

จัดการกับต้นทุนที่เกิดขึ้นซ้ำๆ อย่างตรงจุด

เนื่องจากมีการเรียกใช้ LLM ในทุกๆ query การลดจำนวน token ลงเพียงเล็กน้อยหรือการทำ caching คำตอบบางส่วนไว้ จะให้ผลตอบแทนที่คุ้มค่าอย่างมหาศาล เริ่มต้นด้วย prompt caching หากผู้ใช้คนหนึ่งถามเกี่ยวกับนโยบายการคืนเงิน และอีกคนถามคำถามเดียวกันในอีกสิบนาทีต่อมา ก็ไม่มีเหตุผลที่จะต้องเรียกใช้ model ซ้ำเป็นครั้งที่สอง จัดเก็บคู่ query-response ล่าสุดโดยใช้การจับคู่ความคล้ายคลึงกันทางความหมาย (semantic similarity matching) เมื่อคำถามใหม่มีความคล้ายคลึงกับคำถามที่ทำ cache ไว้ภายในเกณฑ์ที่กำหนด (similarity threshold) ให้ส่งคำตอบที่จัดเก็บไว้กลับไปโดยตรง ไม่ต้องสร้าง token ใหม่ และไม่ต้องเสียเงินเพิ่ม

ต่อไป ให้พิจารณาคุณภาพการดึงข้อมูล (retrieval quality) ของคุณอย่างจริงจัง ตัวดึงข้อมูล (retriever) ที่ไม่มีประสิทธิภาพจะบังคับให้ LLM ต้องอ่านกองฟางเพื่อหาเข็มเพียงเล่มเดียว หากคุณยัดเยียด chunk ที่ไม่เกี่ยวข้องจำนวน 20 chunks ลงใน prompt เพียงเพราะตั้งค่า top-k cutoff ไว้กว้างเกินไป คุณกำลังจ่ายเงินให้ model เพื่ออ่านข้อมูลขยะ (noise) ปรับการ retrieval ให้แม่นยำขึ้น ลดจำนวน top-k ลง และบีบอัด (compress) chunks ก่อนที่จะส่งไป ลบส่วนหัวและส่วนท้ายที่เป็น boilerplate ออกในระหว่างการนำเข้าข้อมูล เพื่อไม่ให้ข้อมูลเหล่านั้นหลุดเข้าไปใน prompt ทุกๆ token ที่คุณตัดออกจาก context window คือเศษเสี้ยวของเซนต์ที่ประหยัดได้ และเศษเสี้ยวเหล่านั้นจะสะสมรวมกันจากการใช้งานหลายพัน query ในแต่ละวัน

การดึงข้อมูลที่ดีขึ้นยังช่วยลด latency ซึ่งเป็นต้นทุนอีกรูปแบบหนึ่ง ผู้ใช้มักจะเลิกใช้งานอินเทอร์เฟซที่ทำงานช้า คำตอบที่รวดเร็วกว่านั้นทั้งประหยัดต้นทุนในการผลิตและช่วยรักษาผู้ใช้งาน (retention) ได้ดีกว่า

บทสรุปที่แท้จริง

เลิกปรับแต่งสิ่งที่ "รู้สึกว่า" แพง และเริ่มปรับแต่งสิ่งที่ "ใบแจ้งหนี้" บอกว่าแพง วัดผลในแต่ละขั้นตอนอย่างเป็นอิสระต่อกัน คุณน่าจะพบว่า embeddings เป็นส่วนที่ราคาถูก, vector storage เป็นส่วนที่มีค่าใช้จ่ายคงที่ และ LLM inference คือส่วนที่ทำให้เงินรั่วไหล ทุ่มเทพลังงานของคุณไปที่ประสิทธิภาพในช่วงเวลา query, การอัปเดตแบบเพิ่มส่วนต่าง (incremental updates) และการกำจัดข้อมูลซ้ำแบบเจาะจง (surgical deduplication) จงสร้างระบบเพื่อรองรับคำถามของผู้ใช้คนที่หนึ่งพัน ไม่ใช่เพื่อการอัปโหลดเอกสารฉบับที่ห้าสิบ คอขวด (bottleneck) มักจะไม่ใช่จุดที่คุณคิดไว้เสมอไป

ที่มา: Where Does RAG Actually Cost You Money? I Decided to Stop Guessing

เข้าร่วมการสนทนาใน GyaanSetu AI learning community.