การบีบอัดบริบท
ตัดบริบทให้เหลือเฉพาะส่วนสำคัญ
การบีบอัดบริบท เป็นบทเรียน AI Prompt Engineering ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Prompt Engineering และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องบีบอัดบริบท
ชิ้นส่วนที่เรียกคืนมามีสัญญาณรบกวน ชิ้นส่วนที่เกี่ยวข้องอาจประกอบด้วยข้อความสำเร็จรูปเกือบทั้งหมดและมีเพียงประโยคสำคัญที่รองรับคำตอบหนึ่งประโยค การบีบอัดบริบทจะตัดข้อความที่เรียกคืนมาให้เหลือเฉพาะส่วนที่ตอบคำค้นได้จริง ก่อนส่งต่อไปยังตัวสร้างผลลัพธ์
ประโยชน์จะสะสมกัน ได้แก่ ลดต้นทุนโทเค็น ลดเวลาแฝง ลดข้อมูลที่ชวนเขว และบรรเทาปัญหาข้อมูลตรงกลางบริบทถูกลืมด้วยการทำให้บริบทที่โมเดลต้องประมวลผลมีขนาดเล็กลง
def compress(query, chunks):
# Goal: keep only spans that bear on the query,
# dropping boilerplate, navigation, and off-topic sentences.
return [extract_relevant(query, c) for c in chunks]แบบสกัดกับแบบสรุปสร้างใหม่
การบีบอัดแบบสกัดเลือกช่วงข้อความตามต้นฉบับ (ประโยคหรือข้อความตอนหนึ่ง) ที่เกี่ยวข้องกับคำค้น จึงรักษาถ้อยคำและที่มาเดิมไว้ได้ การบีบอัดแบบสรุปสร้างใหม่จะถอดความหรือสรุป ทำให้บีบอัดได้มากกว่าแต่เสี่ยงต่อการสูญเสียข้อมูลและการเพิ่มข้อผิดพลาด
สำหรับ RAG เชิงข้อเท็จจริงที่มีการอ้างอิง ควรเลือกแบบสกัดเพื่อให้ตรวจสอบคำกล่าวอ้างย้อนกลับไปยังแหล่งที่มาได้ ใช้แบบสรุปสร้างใหม่เฉพาะเมื่อสามารถตรวจสอบความสอดคล้องกับต้นฉบับได้
def extractive(query, chunk):
sents = split_sentences(chunk.text)
scored = [(s, relevance(query, s)) for s in sents]
kept = [s for s, r in scored if r > TAU]
return ' '.join(kept) or top1(scored) # never return emptyการกรองระดับประโยค
เทคนิคที่มีน้ำหนักเบาและแข็งแกร่งคือ ให้คะแนนแต่ละประโยคของแต่ละชิ้นส่วนเทียบกับคำค้นด้วยตัวเข้ารหัสไขว้ขนาดเล็กหรือความคล้ายคลึงของเวกเตอร์ฝัง แล้วทิ้งประโยคที่ได้คะแนนต่ำ วิธีนี้เก็บประโยคที่มีคุณค่าสูงไว้และตัดข้อความเติมออก
เก็บบริบทขั้นต่ำในแต่ละชิ้นส่วนไว้ เพื่อไม่ให้ตัดประโยคแวดล้อมที่ทำให้ข้อเท็จจริงมีความหมายออกไป
def sentence_filter(query, chunk, keep_ratio=0.4):
sents = split_sentences(chunk.text)
scores = embed_sim_batch(query, sents)
n_keep = max(1, int(len(sents) * keep_ratio))
idx = sorted(range(len(sents)), key=lambda i: -scores[i])[:n_keep]
return ' '.join(sents[i] for i in sorted(idx)) # keep original orderการบีบอัดบริบทด้วย LLM
LLM สามารถบีบอัดทีละชิ้นส่วนได้ โดยกำหนดพรอมต์ให้ดึงเฉพาะส่วนของข้อความตอนหนึ่งที่เกี่ยวข้องกับคำค้น และส่งคืนชิ้นส่วนที่ตัดส่วนไม่เกี่ยวข้องออกแต่ยังคงข้อความตามต้นฉบับ หรือส่งเครื่องหมายว่างหากไม่มีส่วนใดเกี่ยวข้อง
นี่คือรูปแบบ ContextualCompressionRetriever ของ LangChain ซึ่งแม่นยำกว่าตัวกรองเวกเตอร์ฝัง แต่เพิ่มการเรียกใช้ LLM ในแต่ละชิ้นส่วน จึงควรสงวนไว้สำหรับ pipeline ที่มีความสำคัญสูงหรือประมวลผลเป็นชุด
def llm_compress(query, chunk):
prompt = (
'Extract ONLY sentences from the passage relevant to the query. '
'If none are relevant, output NONE. Do not paraphrase.\n'
'Query: ' + query + '\nPassage: ' + chunk.text
)
out = llm(prompt, temperature=0).strip()
return None if out == 'NONE' else outการตัดโทเค็นระดับโทเค็น (LLMLingua)
วิธีการอย่าง LLMLinguaจะบีบอัดในระดับโทเค็น โดยใช้โมเดลขนาดเล็กประเมินว่าโทเค็นให้ข้อมูลมากน้อยเพียงใด แล้วทิ้งโทเค็นที่ให้ข้อมูลน้อย วิธีเหล่านี้ทำให้อัตราการบีบอัดสูงได้ โดยยังรักษาสัญญาณที่โมเดลขนาดใหญ่ต้องใช้ไว้
ข้อแลกเปลี่ยนคือ ข้อความที่บีบอัดแล้วจะอ่านเข้าใจได้ยากขึ้น จึงเหมาะกับบริบทที่ใช้โดยเครื่องเท่านั้น ไม่เหมาะกับการแสดงผลต่อผู้ใช้
def token_prune(context, target_ratio=0.3):
# small LM estimates per-token information (perplexity-based);
# drop the least informative tokens down to target_ratio length
scores = small_lm_token_importance(context)
return keep_top_fraction(context, scores, target_ratio)แบบคำนึงถึงคำค้นกับแบบไม่ขึ้นกับคำค้น
การบีบอัดแบบคำนึงถึงคำค้นจะเก็บสิ่งที่เกี่ยวข้องกับคำค้นนี้ไว้ ทำให้ได้บริบทที่กระชับที่สุด แต่ต้องทำงานทุกครั้งที่มีคำขอ การบีบอัดแบบไม่ขึ้นกับคำค้น (บทสรุปชิ้นส่วนที่คำนวณไว้ล่วงหน้า) มีต้นทุนต่ำกว่าในขณะรับคำขอ แต่ไม่สามารถมุ่งเน้นไปที่คำถามเฉพาะได้
แนวทางไฮบริดจะจัดเก็บชิ้นส่วนฉบับย่อไว้ออฟไลน์ และใช้การตัดแต่งแบบคำนึงถึงคำค้นเล็กน้อยขณะให้บริการ
# Offline: precompute a dense summary per chunk (query-agnostic)
chunk.summary = summarize(chunk.text)
# Online: query-aware trim over summaries (cheap) then verify on full
ctx = [sentence_filter(query, Chunk(c.summary)) for c in top_chunks]การป้องกันการสูญเสียข้อมูล
การบีบอัดอย่างรุนแรงอาจลบข้อย่อยเพียงข้อเดียวที่มีความสำคัญได้ ให้ป้องกันด้วย การตรวจสอบความครอบคลุม: ตรวจสอบว่าบริบทที่บีบอัดแล้วยังรองรับคำตอบได้ หรือเก็บทางเลือกสำรองเป็นชิ้นส่วนที่ยังไม่บีบอัดไว้เมื่อผลลัพธ์จากตัวบีบอัดมีเนื้อน้อยอย่างน่าสงสัย
อย่าปล่อยให้การบีบอัดทำให้ชิ้นส่วนว่างเปล่าเมื่อตัวจัดอันดับใหม่ประเมินว่าชิ้นส่วนนั้นเกี่ยวข้องสูง เพราะนั่นบ่งชี้ว่าตัวบีบอัดทำงานผิดพลาด ไม่ใช่ชิ้นส่วนไม่เกี่ยวข้อง
def safe_compress(query, chunk):
out = llm_compress(query, chunk)
if out is None and chunk.rerank_score > 0.7:
return chunk.text # trust re-ranker over compressor
return out or chunk.textการรักษาที่มาของข้อมูล
การบีบอัดต้องรักษาการระบุแหล่งที่มาไว้ครบถ้วน กำกับช่วงข้อความที่เก็บไว้แต่ละช่วงด้วยชิ้นส่วนและเอกสาร ID เพื่อให้ตัวสร้างผลลัพธ์สามารถอ้างอิงได้ หากบีบอัดข้อมูลกำกับออกไป จะสูญเสียความสามารถในการตรวจสอบและตรวจจับการแต่งข้อมูลขึ้นเอง
ส่งต่อรหัสผ่าน pipeline ในรูปฟิลด์แบบมีโครงสร้างเสมอ อย่าส่งเป็นข้อความอิสระที่การบีบอัดอาจตัดทิ้ง
def compress_with_ids(query, chunks):
out = []
for c in chunks:
span = safe_compress(query, c)
out.append({'id': c.id, 'doc': c.meta['doc_id'], 'text': span})
return out # generator cites id; provenance preservedการบีบอัดกับงบประมาณโทเค็น
การบีบอัดทำให้คุณเรียกคืนผู้สมัครได้มากขึ้นเพื่อเพิ่มความครอบคลุม ขณะเดียวกันยังรักษาพรอมต์สุดท้ายให้มีขนาดเล็ก กำหนดงบประมาณโทเค็นสำหรับหน้าต่างบริบท แล้วใช้ pack ช่วงข้อความบีบอัดที่มีคุณค่าสูงสุดเพิ่มเข้าไปทีละช่วงจนกว่าจะถึงงบประมาณ
วิธีนี้แยกปริมาณข้อมูลที่เรียกคืนออกจากปริมาณที่ใช้จ่ายในการสร้างผลลัพธ์ ซึ่งเป็นกลไกสำคัญในการเพิ่มประสิทธิภาพ
def pack(spans, budget_tokens, tok):
spans = sorted(spans, key=lambda s: -s['score'])
used, packed = 0, []
for s in spans:
t = tok(s['text'])
if used + t > budget_tokens:
continue
packed.append(s); used += t
return packedการวัดคุณภาพการบีบอัด
ติดตามตัวเลขสามค่า ได้แก่ อัตราการบีบอัด (ประหยัดโทเค็นได้เท่าใด) ความถูกต้องของ answer (คุณภาพยังคงเดิมหรือไม่) และ ความสอดคล้องกับต้นฉบับ (ตัวบีบอัดหลีกเลี่ยงการเปลี่ยนแปลงข้อเท็จจริงได้หรือไม่) เป้าหมายคืออัตราการบีบอัดสูงสุดที่ไม่ทำให้ความถูกต้องของ answer เปลี่ยนแปลง
ทดสอบระดับความเข้มข้นของการบีบอัดหลายระดับ แล้วเลือกจุดพาเรโตที่ตรงตามเป้าหมายต้นทุนโดยไม่สูญเสียคุณภาพ
def eval_compression(eval_set, levels):
return {
lvl: {
'ratio': mean_ratio(eval_set, lvl),
'acc': answer_accuracy(eval_set, lvl),
'faith': faithfulness(eval_set, lvl),
} for lvl in levels
}pipeline ที่คำนึงถึงการบีบอัด
ตั้งแต่ต้นจนจบ: เรียกคืนข้อมูลให้ครอบคลุม จัดอันดับใหม่ บีบอัดแต่ละชิ้นส่วนที่เหลืออยู่ (แบบสกัดหรืออาศัย LLM) พร้อมข้อมูลที่มา ป้องกันการตัดแต่งมากเกินไป ใช้ pack ให้พอดีกับงบประมาณโทเค็น และสร้างผลลัพธ์พร้อมการอ้างอิง
การบีบอัดคือชั้นที่ทำให้การเรียกคืนข้อมูลแบบครอบคลุมสูงมีต้นทุนที่รับได้ และช่วยให้ตัวสร้างผลลัพธ์มุ่งเน้นเฉพาะสิ่งที่สำคัญ
def pipeline(query):
top = rerank(query, hybrid_retrieve(query, 50))[:12]
spans = compress_with_ids(query, top)
spans = [s for s in spans if s['text']]
packed = pack(spans, budget_tokens=2000, tok=count_tokens)
return generate_with_citations(query, packed)ตรวจสอบอย่างรวดเร็ว
เลือกแนวทางการบีบอัดที่เหมาะสมสำหรับระบบ RAG เชิงข้อเท็จจริงที่มีการอ้างอิง
สรุปทบทวน
ประเด็นสำคัญ:
- การบีบอัดตัดชิ้นส่วนที่เรียกคืนมาให้เหลือเนื้อหาที่เกี่ยวข้องกับคำค้น ช่วยลดต้นทุน เวลาแฝง และข้อมูลที่ชวนเขว
- สำหรับ RAG เชิงข้อเท็จจริงที่มีการอ้างอิง ให้เลือกแบบสกัด (คงข้อความตามต้นฉบับและตรวจสอบที่มาได้) มากกว่าแบบสรุปสร้างใหม่ ส่วนการตัดระดับโทเค็นเหมาะกับบริบทที่ใช้โดยเครื่องเท่านั้น
- การบีบอัดแบบคำนึงถึงคำค้นให้บริบทที่กระชับที่สุดแต่ต้องทำทุกครั้งที่มีคำขอ จึงควรผสานกับบทสรุปที่สร้างไว้ออฟไลน์เพื่อเพิ่มประสิทธิภาพ
- ป้องกันการสูญเสียข้อมูล และรักษาที่มาของชิ้นส่วนและเอกสารไว้สำหรับการอ้างอิง
- ใช้การบีบอัดเพื่อเรียกคืนข้อมูลให้ครอบคลุมขณะรักษาพรอมต์ให้มีขนาดเล็ก ปรับให้ได้อัตราการบีบอัดสูงสุดโดยไม่สูญเสียความถูกต้องของ answer
คำถามที่พบบ่อย
บทเรียน “การบีบอัดบริบท” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การบีบอัดบริบท” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Prompt Engineering ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การบีบอัดบริบท”
ตัดบริบทให้เหลือเฉพาะส่วนสำคัญ คุณปฏิบัติ AI Prompt Engineering ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Prompt Engineering หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Prompt Engineering บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “การบีบอัดบริบท” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Prompt Engineering นี้ได้ไหม
ได้ บทเรียน AI Prompt Engineering ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ก้าวข้าม RAG แบบพื้นฐาน
- การจัดอันดับชิ้นส่วนข้อมูลที่ดึงมาใหม่
- การบีบอัดบริบท
- การเขียนคำสืบค้นใหม่และ HyDE