ก้าวข้าม RAG แบบพื้นฐาน
ข้อจำกัดของการดึงข้อมูลพื้นฐาน
ก้าวข้าม RAG แบบพื้นฐาน เป็นบทเรียน AI Prompt Engineering ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Prompt Engineering และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
สิ่งที่ RAG แบบพื้นฐานทำ
RAG แบบพื้นฐานคือแนวทางพื้นฐาน: แบ่งเอกสารเป็นชิ้น สร้างเวกเตอร์แทนเอกสาร จัดเก็บเวกเตอร์ สร้างเวกเตอร์แทนคำค้น ค้นคืนชิ้นข้อมูล k อันดับแรกตามความคล้ายคลึงแบบโคไซน์ ยัดชิ้นข้อมูลลงในพรอมต์ แล้วสร้างคำตอบ วิธีนี้เป็นจุดเริ่มต้นที่แข็งแกร่ง และมีรูปแบบความล้มเหลวที่คาดเดาได้เมื่อใช้งานในขนาดใหญ่
การทำความเข้าใจรูปแบบความล้มเหลวเหล่านี้เป็นพื้นฐานที่จำเป็นสำหรับเทคนิคขั้นสูง เช่น การจัดอันดับใหม่ การบีบอัด และการเขียนคำค้นใหม่ ซึ่งจะกล่าวถึงในหลักสูตรนี้
def naive_rag(query, k=5):
q = embed(query)
chunks = vector_store.search(q, k) # top-k by cosine
context = '\n\n'.join(c.text for c in chunks)
return llm('Context:\n' + context + '\n\nQ: ' + query)ความครอบคลุมเทียบกับความแม่นยำของการค้นคืน
การค้นคืน k อันดับแรกแบบพื้นฐานปรับให้เหมาะกับ ความคล้ายคลึง ของเวกเตอร์ดิบ ซึ่งปะปนความเกี่ยวข้องเข้ากับความใกล้เคียงทางความหมายบนผิวภาษา จึงเกิดความขัดแย้งระหว่างสองด้าน: ค่า k ที่น้อยเสี่ยงพลาดคำตอบ (ความครอบคลุมต่ำ) ส่วนค่า k ที่มากทำให้บริบทเต็มไปด้วยสิ่งรบกวน (ความแม่นยำต่ำ)
ความคล้ายคลึงของเวกเตอร์ฝังที่ใช้ขับเคลื่อนการค้นคืนเป็นเพียงตัวแทนความเกี่ยวข้องแบบหยาบ และเป็นต้นเหตุของปัญหาต่อเนื่องหลายประการ
# The core dilemma
# small k -> may miss the gold chunk (recall problem)
# large k -> distractors crowd context (precision + cost problem)
# Advanced RAG decouples 'retrieve many' from 'use few'ปัญหาความไม่ตรงกันของเวกเตอร์ฝัง
คำค้นและเอกสารมักอยู่ใน ระดับภาษาที่แตกต่างกัน: คำถามสั้น ๆ เทียบกับข้อความบอกเล่าที่ยาว ตัวเข้ารหัสแบบคู่อาจวางคำตอบที่เกี่ยวข้องไว้ห่างจากคำถาม เพราะทั้งสองถูกเขียนด้วยถ้อยคำต่างกัน ซึ่งเป็นปัญหาความไม่ตรงกันของคำศัพท์
ปัญหานี้เป็นที่มาของเทคนิคต่าง ๆ เช่น การเขียนคำค้นใหม่และ HyDE ซึ่งปรับรูปคำค้นให้เข้ากับพื้นที่ของเอกสารก่อนการค้นคืน
# Query: 'how do I revoke a token?'
# Doc: 'Token invalidation is performed via the /sessions endpoint.'
# Lexically and semantically distant -> bi-encoder may miss it
sim = cos(embed('how do I revoke a token?'),
embed('Token invalidation via /sessions')) # may be lowข้อมูลตรงกลางถูกมองข้าม
แม้จะค้นคืนชิ้นข้อมูลที่ถูกต้องได้แล้ว การยัดชิ้นข้อมูลจำนวนมากลงไปก็ทำให้เกิด ผลกระทบจากการหลงลืมข้อมูลตรงกลาง: โมเดลให้ความสนใจกับเนื้อหาที่อยู่ตรงกลางของบริบทยาว ๆ น้อยลง ชิ้นข้อมูลที่ถูกต้องแต่ถูกฝังอยู่ในอันดับ 3 จาก 10 อาจถูกมองข้ามไปโดยสิ้นเชิง
นี่เป็นเหตุผลที่ต้องจัดอันดับใหม่ (วางชิ้นข้อมูลที่ดีที่สุดไว้ในตำแหน่งที่โมเดลให้ความสนใจ) และบีบอัดบริบท (ลดขนาดบริบทเพื่อไม่ให้มีสิ่งใดถูกฝังอยู่ตรงกลาง)
# Retrieval rank != attention rank
# Place the highest-relevance chunk at the START or END,
# never stranded in the middle of a large concatenation.ความไวต่อสิ่งรบกวน
LLM มีความไวต่อ บริบทที่ไม่เกี่ยวข้อง การเพิ่มชิ้นข้อมูลที่ดูน่าเชื่อถือแต่ผิดอาจทำให้คำตอบออกนอกแนวทาง แม้จะมีชิ้นข้อมูลที่ถูกต้องอยู่ด้วยก็ตาม บริบทที่ค้นคืนมาได้มากขึ้นไม่ได้ดีกว่าเสมอไป
นี่คือเหตุผลที่ความแม่นยำมีความสำคัญ บริบทที่กระชับ จัดอันดับใหม่ และบีบอัดแล้ว มักให้ผลดีกว่าการเทชิ้นข้อมูลจำนวนมากที่เกี่ยวข้องกันอย่างหลวม ๆ ลงไป
# Empirically: appending a single highly-similar but WRONG chunk
# can flip a previously-correct answer. RAG quality depends on
# keeping distractors OUT, not just getting the gold chunk IN.ปัญหาจากการแบ่งชิ้นข้อมูล
การแบ่งเป็นชิ้นขนาดคงที่อาจตัดแนวคิดกลางประโยค แยกข้ออ้างออกจากหลักฐาน และตัดบริบทเชิงโครงสร้างออกไป เช่น อยู่ในส่วนใดหรือเอกสารใด ชิ้นข้อมูลที่อ่านรู้เรื่องเมื่ออยู่ลำพังอาจไร้ประโยชน์หรือทำให้เข้าใจผิดเมื่อไม่มีบริบทโดยรอบ
กระบวนการขั้นสูงใช้การแบ่งชิ้นโดยคำนึงถึงโครงสร้าง ส่วนทับซ้อน การขยายไปยังเอกสารแม่ และข้อมูลเมตา เพื่อรักษาความหมายไว้
def structure_aware_chunks(doc, max_tokens=400, overlap=50):
sections = split_by_headings(doc) # respect document structure
chunks = []
for sec in sections:
for c in sliding_window(sec.text, max_tokens, overlap):
chunks.append(Chunk(c, meta={'section': sec.title}))
return chunksช่องว่างของการค้นคืนเชิงความหมายเพียงอย่างเดียว
การค้นคืนแบบหนาแน่นเพียงอย่างเดียวพลาดความต้องการจับคู่แบบตรงตัว เช่น ตัวระบุ รหัสข้อผิดพลาด ชื่อเฉพาะที่พบไม่บ่อย และชื่อส่วนเชื่อมต่อโปรแกรมประยุกต์ ซึ่งเป็นกรณีที่ผู้ใช้คาดหวังความแม่นยำตามตัวอักษรโดยเฉพาะ การค้นคืนแบบผสมจะรวมสัญญาณแบบหนาแน่น (เชิงความหมาย) และแบบเบาบาง (BM25/คำสำคัญ) เพื่อรองรับทั้งสองด้าน
การผสานอันดับแบบส่วนกลับเป็นวิธีที่เรียบง่ายและทนทานสำหรับรวมรายการที่จัดอันดับแล้วสองรายการโดยไม่ต้องปรับน้ำหนัก
def rrf(dense_ranks, sparse_ranks, k0=60):
scores = {}
for ranks in (dense_ranks, sparse_ranks):
for rank, doc_id in enumerate(ranks):
scores[doc_id] = scores.get(doc_id, 0) + 1.0 / (k0 + rank)
return sorted(scores, key=scores.get, reverse=True)บริบทล้าสมัยและตรวจสอบที่มาไม่ได้
RAG แบบพื้นฐานไม่มีแนวคิดเรื่อง ความใหม่ หรือ ที่มา อาจค้นคืนเอกสารที่ล้าสมัย และไม่มีวิธีในตัวสำหรับระบุข้ออ้างว่าอ้างอิงจากแหล่งใด ซึ่งบั่นทอนความน่าเชื่อถือและทำให้ตรวจจับภาพหลอนได้ยาก
ระบบขั้นสูงจะเพิ่มข้อมูลเมตา เช่น เวลา แหล่งที่มา และรุ่น กรองข้อมูลตามข้อมูลเหล่านั้น และกำหนดให้ตัวสร้างอ้างอิงรหัสชิ้นข้อมูล เพื่อให้ตรวจสอบคำตอบได้
def filtered_retrieve(q, after_date):
cands = vector_store.search(embed(q), k=50)
fresh = [c for c in cands if c.meta['date'] >= after_date]
return fresh # then re-rank; generator must cite c.idไม่มีข้อมูลป้อนกลับก็ไม่มีการปรับตัว
RAG แบบพื้นฐานค้นคืนโดยไม่ตรวจสอบ: ไม่สามารถบอกได้ว่าการค้นคืนล้มเหลว ไม่สามารถตัดสินใจว่าไม่จำเป็นต้องค้นคืน และไม่สามารถทำซ้ำเป็นรอบ ๆ ได้ รูปแบบขั้นสูงเพิ่ม การตรวจสอบความเกี่ยวข้อง การค้นคืนตามเงื่อนไข และการค้นคืนหลายขั้นตอนแบบตัวแทน ซึ่งจะปรับรูปคำค้นใหม่เมื่อผลลัพธ์ดูอ่อนแอ
กระบวนการจึงกลายเป็นวงรอบที่ประเมินตนเอง แทนที่จะเป็นการประมวลผลไปข้างหน้าเพียงรอบเดียว
def adaptive_rag(q):
chunks = retrieve(q)
if relevance_score(q, chunks) < 0.4:
q2 = rewrite_query(q) # reformulate and retry
chunks = retrieve(q2)
if relevance_score(q, chunks) < 0.4:
return 'I could not find this in the sources.'
return generate(q, chunks)ชุดองค์ประกอบ RAG ขั้นสูง
เมื่อนำความล้มเหลวทั้งหมดมาพิจารณาร่วมกัน กระบวนการขั้นสูงจะประกอบด้วยหลายชั้น ได้แก่ การแบ่งชิ้นโดยคำนึงถึงโครงสร้างพร้อมข้อมูลเมตา การค้นคืนแบบผสมที่มีความครอบคลุมสูง ตัวจัดอันดับใหม่แบบตัวเข้ารหัสข้ามเพื่อเพิ่มความแม่นยำ การบีบอัดบริบทเพื่อให้พอดีและมุ่งเน้น การเขียนคำค้นใหม่ / HyDE เพื่อแก้ปัญหาความไม่ตรงกัน และกลไกคัดกรองความเกี่ยวข้องพร้อมการอ้างอิง
บทเรียนถัดไปจะสร้างแต่ละชั้นขึ้นมา แนวคิดหลักคือ ค้นคืนให้กว้างก่อน แล้วจึงกรองและปรับปรุงอย่างเข้มข้น
def advanced_rag(q):
cands = hybrid_retrieve(rewrite_query(q), k=50) # high recall
top = rerank(q, cands)[:8] # precision
ctx = compress(q, top) # focus + fit
return generate_with_citations(q, ctx) # verifiableวัดผลก่อนปรับให้เหมาะสม
วินิจฉัยก่อนว่าคุณกำลังพบความล้มเหลวแบบใดจริง ๆ ก่อนเพิ่มกลไกต่าง ๆ วัด ความครอบคลุมของการค้นคืนที่อันดับ k ว่าค้นคืนชิ้นข้อมูลอ้างอิงได้หรือไม่ แยกจาก ความแม่นยำของคำตอบ ว่าตัวสร้างนำชิ้นข้อมูลนั้นไปใช้หรือไม่ ปัญหาด้านความครอบคลุมกับปัญหาด้านความแม่นยำต้องใช้วิธีแก้ต่างกัน
ติดตามผลทั้งสองส่วน และอย่ารีบเพิ่มตัวจัดอันดับใหม่หากปัญหาที่แท้จริงอยู่ที่การแบ่งชิ้นข้อมูลหรือความไม่ตรงกันของคำค้น
def diagnose(eval_set):
return {
'recall@5': recall_at_k(eval_set, k=5), # retrieval health
'recall@50': recall_at_k(eval_set, k=50), # ceiling with rerank
'answer_acc': answer_accuracy(eval_set), # generation health
}ตรวจสอบอย่างรวดเร็ว
วินิจฉัยรูปแบบความล้มเหลวของ RAG
สรุปทบทวน
ประเด็นสำคัญ:
- RAG แบบพื้นฐาน (แบ่งชิ้น สร้างเวกเตอร์แทน ค้นคืน k อันดับแรก ยัดลงพรอมต์ แล้วสร้างคำตอบ) เป็นพื้นฐานที่แข็งแกร่งและมีความล้มเหลวที่คาดเดาได้
- ความคล้ายคลึงของตัวเข้ารหัสแบบคู่เป็นเพียงตัวแทนความเกี่ยวข้องแบบหยาบ ความไม่ตรงกันของระดับภาษาระหว่างคำค้นกับเอกสารทำให้ความครอบคลุมลดลง
- บริบทที่มากขึ้นไม่ได้ดีกว่าเสมอไป เพราะความไวต่อสิ่งรบกวนและการหลงลืมข้อมูลตรงกลางทำให้คำตอบแย่ลงเมื่อค่า k เพิ่มขึ้น
- ปัญหาจากการแบ่งชิ้นข้อมูล ช่องว่างของการค้นคืนเชิงความหมายเพียงอย่างเดียว ความล้าสมัย และการขาดข้อมูลป้อนกลับ ล้วนจำกัด RAG แบบพื้นฐาน
- RAG ขั้นสูงค้นคืนให้กว้างแล้วจึงกรอง ได้แก่ การค้นคืนแบบผสม การจัดอันดับใหม่ การบีบอัด การเขียนคำค้นใหม่ และการคัดกรองความเกี่ยวข้อง ควรวัดความครอบคลุมกับความแม่นยำของคำตอบแยกกันก่อนปรับปรุงระบบ
คำถามที่พบบ่อย
บทเรียน “ก้าวข้าม RAG แบบพื้นฐาน” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ก้าวข้าม RAG แบบพื้นฐาน” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Prompt Engineering ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ก้าวข้าม RAG แบบพื้นฐาน”
ข้อจำกัดของการดึงข้อมูลพื้นฐาน คุณปฏิบัติ AI Prompt Engineering ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Prompt Engineering หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Prompt Engineering บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “ก้าวข้าม RAG แบบพื้นฐาน” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Prompt Engineering นี้ได้ไหม
ได้ บทเรียน AI Prompt Engineering ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ก้าวข้าม RAG แบบพื้นฐาน
- การจัดอันดับชิ้นส่วนข้อมูลที่ดึงมาใหม่
- การบีบอัดบริบท
- การเขียนคำสืบค้นใหม่และ HyDE