การเขียนคำสืบค้นใหม่และ HyDE
ปรับปรุงความครอบคลุมของการดึงข้อมูล
การเขียนคำสืบค้นใหม่และ HyDE เป็นบทเรียน AI Prompt Engineering ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Prompt Engineering และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
คำค้นคือจุดอ่อนที่สุด
คุณภาพการเรียกคืนถูกจำกัดด้วยคำค้น คำค้นดิบของผู้ใช้มักสั้น คลุมเครือ เต็มไปด้วยคำสรรพนาม หรือใช้ถ้อยคำต่างจากในเอกสาร การแปลงคำค้นจะปรับรูปคำค้นก่อนการเรียกคืน เพื่อเพิ่มทั้งความครอบคลุมและความแม่นยำ
นี่เป็นหนึ่งในการปรับปรุงที่มีต้นทุนต่ำแต่ให้ผลคุ้มค่าสูงที่สุดเมื่อเทียบกับ RAG แบบพื้นฐาน เพียงแก้คำค้น ทุกขั้นตอนถัดไปก็ได้รับประโยชน์
def transform_query(raw, history):
# Resolve references, expand, decompose, or hypothesize
# BEFORE embedding and retrieving.
return rewrite(raw, history)การเขียนคำค้นใหม่
การแปลงที่ง่ายที่สุดคือ ให้ LLM เขียนคำค้นของผู้ใช้ใหม่ให้อยู่ในรูปที่ชัดเจน ครบถ้วนในตัวเอง และเหมาะกับการเรียกคืน วิธีนี้แก้คำสะกดผิด ขยายคำย่อ และลบส่วนเกินจากบทสนทนา
เรื่องนี้สำคัญเป็นพิเศษในแชตหลายรอบ ซึ่งข้อความล่าสุดไม่สามารถเข้าใจได้หากไม่มีบริบท (แล้วอันที่สองล่ะ?)
def rewrite_query(raw):
prompt = (
'Rewrite the user question into a clear, standalone search '
'query optimized for document retrieval. Keep key entities.\n'
'Question: ' + raw
)
return llm(prompt, temperature=0).strip()การย่อบทสนทนา
ใน RAG แบบแชต ให้ย่อบทสนทนาและรอบสนทนาใหม่รวมกันเป็นคำถามแบบเอกเทศคำถามเดียว หากไม่ทำเช่นนี้ คำสรรพนามและข้อความที่ละไว้จะทำให้เวกเตอร์ฝังไม่มีความหมาย และการเรียกคืนจะล้มเหลว
ส่งต่อรอบสนทนาก่อนหน้า เพื่อให้ตัวเขียนคำค้นใหม่สามารถแปลงคำว่า สิ่งนั้น อันนั้น หรืออันก่อนหน้า ให้เป็นเอนทิตีที่ระบุชัดเจนและตัวเรียกคืนจับคู่ได้
def condense(history, follow_up):
prompt = (
'Given the conversation, rewrite the follow-up as a standalone '
'question with all references resolved.\nConversation:\n' +
render(history) + '\nFollow-up: ' + follow_up
)
return llm(prompt, temperature=0).strip()การขยายคำค้น
การขยายจะสร้างคำพ้องความหมาย คำที่เกี่ยวข้อง หรือถ้อยคำทางเลือก เพื่อขยายความครอบคลุมทั้งด้านคำศัพท์และความหมาย วิธีนี้ช่วยแก้ปัญหาคำศัพท์ไม่ตรงกัน เช่น เอกสารใช้คำว่า “ทำให้เป็นโมฆะ” แต่ผู้ใช้ใช้คำว่า “เพิกถอน”
ขยายคำค้นเพื่อการเรียกคืน แล้วเรียกคืนด้วยผลรวมของรายการ อย่าแสดงรูปแบบที่ขยายแล้วให้ผู้ใช้เห็น ระวังการขยายมากเกินไป เพราะอาจดึงผลลัพธ์นอกหัวข้อเข้ามา
def expand(query, n=3):
prompt = (
'List ' + str(n) + ' alternative phrasings of this query using '
'synonyms and domain terms, one per line.\n' + query
)
variants = parse_lines(llm(prompt, temperature=0.5))
return [query] + variantsการเรียกคืนด้วยหลายคำค้น
สร้างการเรียบเรียงใหม่ที่หลากหลายหลายรูปแบบ เรียกคืนข้อมูลสำหรับแต่ละรูปแบบ แล้ว fuse รายการผลลัพธ์เข้าด้วยกัน (การผสานอันดับย้อนกลับ) ถ้อยคำที่ต่างกันจะเปิดเผยชิ้นส่วนที่เกี่ยวข้องต่างกัน การผสานจึงรวมจุดแข็งของแต่ละรูปแบบและทำให้ความครอบคลุมมีเสถียรภาพ
วิธีนี้แลกการเรียกคืนที่เพิ่มขึ้นกับความทนทานต่อการใช้ถ้อยคำที่ไม่ดีเพียงรูปแบบใดรูปแบบหนึ่ง
def multi_query(raw, n=4):
queries = expand(raw, n)
rankings = [dense_retrieve(q, 30) for q in queries]
fused = rrf(*rankings)
return dedup(fused)การแยกคำถาม
คำถามที่ซับซ้อนและต้องใช้เหตุผลหลายขั้นจำเป็นต้องแยกเป็นส่วนย่อย โดยเรียกคืนข้อมูลสำหรับแต่ละคำถามย่อยแยกกัน แล้วจึงนำมาประกอบกัน การถามว่า CEO ของบริษัทที่เข้าซื้อ X มีอายุมากกว่า... ไม่สามารถตอบได้ด้วยการเรียกคืนเพียงครั้งเดียว
แยกคำถาม เรียกคืนข้อมูลสำหรับแต่ละคำถามย่อย และให้ตัวสร้างผลลัพธ์รวมหลักฐานที่รวบรวมมา
def decompose_and_retrieve(question):
subs = parse_lines(llm(
'Break this into independent sub-questions, one per line.\n' +
question, temperature=0))
evidence = {s: rerank(s, dense_retrieve(s, 30))[:3] for s in subs}
return evidence # generator synthesizes the final answerHyDE: แนวคิดหลัก
HyDE (เวกเตอร์ฝังเอกสารสมมติ, Gao และคณะ, 2022) พลิกวิธีคิดของปัญหานี้ แทนที่จะสร้างเวกเตอร์ฝังจากคำค้นสั้น ๆ ระบบจะให้ LLM สร้างเอกสารคำตอบสมมติ จากนั้นสร้างเวกเตอร์ฝังจากเอกสารนั้นและใช้เอกสารนั้นในการเรียกคืน
เอกสารสมมติมีระดับภาษาเดียวกับเอกสารจริง ดังนั้นเวกเตอร์ฝังของมันจึงอยู่ใกล้คำตอบจริงมากกว่า ช่วยแก้ความไม่ตรงกันระหว่างคำค้นกับเอกสาร
def hyde(query):
hypo = llm(
'Write a short passage that would answer this question, as if '
'from a reference document.\nQuestion: ' + query,
temperature=0.3)
return dense_retrieve_by_vector(embed(hypo), k=30) # embed the answerเหตุใด HyDE จึงเพิ่มความครอบคลุม
คำถามกับคำตอบมักใช้ถ้อยคำต่างกัน แต่คำถามกับคำตอบปลอมที่ดูเป็นไปได้จะใช้ถ้อยคำคล้ายกับคำตอบจริง HyDE ใช้ประโยชน์จากความรู้เดิมเชิงสร้างสรรค์ของ LLM เพื่อเชื่อมช่องว่างนี้ แม้เอกสารสมมติจะมีข้อผิดพลาดด้านข้อเท็จจริงก็ตาม
ความถูกต้องของเอกสารสมมติไม่สำคัญมากนัก ขอเพียงมีคำศัพท์และโครงสร้างที่เหมาะสมเพื่อให้ไปอยู่ใกล้เอกสารจริงในปริภูมิเวกเตอร์ฝังก็เพียงพอ
# Robustness: average several hypothetical docs to reduce variance
def hyde_avg(query, n=3):
vecs = [embed(llm(HYDE_PROMPT + query, temperature=0.5))
for _ in range(n)]
centroid = sum(vecs) / n
return dense_retrieve_by_vector(centroid, 30)ข้อแลกเปลี่ยนและรูปแบบความล้มเหลวของ HyDE
HyDE เพิ่มการสร้างผลลัพธ์ด้วย LLM ก่อนการเรียกคืน ทำให้เวลาแฝงและต้นทุนสูงขึ้น และอาจแต่งข้อมูลขึ้นเองเป็นเอกสารสมมติที่ออกนอกหัวข้อ ส่งผลเสียต่อความครอบคลุมสำหรับคำค้นเฉพาะทางหรือคำค้นนอกขอบเขตข้อมูลที่โมเดลไม่รู้จัก
ลดผลกระทบด้วยการผสานการเรียกคืนจากเวกเตอร์ HyDE กับการเรียกคืนจากคำค้นดิบผ่านการผสานผลลัพธ์ เพื่อไม่ให้เอกสารสมมติที่ไม่ดีเพียงฉบับเดียวทำลายความครอบคลุมทั้งหมด
def hyde_hybrid(query):
a = dense_retrieve_by_vector(embed(hyde_doc(query)), 30)
b = dense_retrieve(query, 30) # raw-query fallback
return dedup(rrf(a, b)) # robust to bad hypotheticalsการเลือกและผสานเทคนิค
การแปลงเหล่านี้ส่งเสริมกัน ใช้การย่อสำหรับแชต ใช้การขยาย/หลายคำค้นเพื่อแก้ช่องว่างด้านคำศัพท์ ใช้การแยกเป็นส่วนย่อยสำหรับคำถามหลายขั้น และใช้HyDEเมื่อระดับภาษาของคำถามกับเอกสารไม่ตรงกัน ระบบใช้งานจริงจำนวนมากจะต่อขั้นตอนโดยย่อก่อน จากนั้นใช้ HyDE แล้ว fuse เข้ากับคำค้นดิบ และจัดอันดับใหม่
การแปลงแต่ละขั้นที่เพิ่มเข้ามาต้องใช้การเรียก LLM เพิ่มหนึ่งครั้ง จึงควรเลือกใช้ตามประเภทคำค้น แทนที่จะทำทุกขั้นตอนเสมอ
def route_transform(query, history, qtype):
q = condense(history, query) if history else query
if qtype == 'multi_hop': return decompose_and_retrieve(q)
if qtype == 'mismatch': return hyde_hybrid(q)
if qtype == 'vocab_gap': return multi_query(q)
return dense_retrieve(q, 30)การประเมินการแปลง
ประเมินการแปลงแต่ละรายการจากการเพิ่มขึ้นของ อัตราการเรียกคืน@k ในการค้นคืน และความแม่นยำของคำตอบเมื่อเทียบกับคำค้นดิบ โดยใช้ชุดข้อมูลที่ไม่มีการรั่วไหล ติดตามเวลาแฝงที่เพิ่มขึ้นและค่าใช้จ่ายของ LLM เพื่อเก็บไว้เฉพาะการแปลงที่ให้ผลคุ้มค่า
โปรดระวัง: การแปลงที่ช่วยเพิ่มการเรียกคืนแต่เพิ่มสิ่งรบกวน อาจลดความแม่นยำของคำตอบได้ เว้นแต่จะใช้ร่วมกับการจัดอันดับใหม่และการบีบอัด
def eval_transform(name, fn, eval_set):
return {
'recall@10': recall_at_k(eval_set, retriever=fn, k=10),
'answer_acc': answer_accuracy(eval_set, retriever=fn),
'extra_latency_ms': transform_latency(fn),
}ตรวจสอบอย่างรวดเร็ว
พิจารณาเหตุผลว่าเหตุใด HyDE จึงทำงานได้ แม้สมมติฐานจะไม่สมบูรณ์
ทบทวน
ประเด็นสำคัญที่ได้เรียนรู้:
- การค้นคืนถูกจำกัดด้วยคำค้น การแปลงคำค้นเป็นการยกระดับ RAG ที่มีต้นทุนต่ำแต่ให้ผลมาก
- การเขียนใหม่/การย่อคำค้นทำให้คำค้นจากการสนทนาใช้ได้โดยลำพัง การขยายและคำค้นหลายชุดช่วยแก้ช่องว่างด้านคำศัพท์
- การแยกย่อยจัดการคำถามหลายขั้นด้วยการค้นคืนแยกตามคำถามย่อย
- HyDE ฝังคำตอบสมมติเพื่อเชื่อมความไม่ตรงกันของระดับภาษาระหว่างคำถามกับเอกสาร โดยไม่จำเป็นต้องให้สมมติฐานนั้นถูกต้อง
- รวมการแปลงตามประเภทคำค้น ผสานกับคำค้นดิบเพื่อความทนทาน และประเมินการเรียกคืน ความแม่นยำของคำตอบ เวลาแฝง และค่าใช้จ่าย
คำถามที่พบบ่อย
บทเรียน “การเขียนคำสืบค้นใหม่และ HyDE” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การเขียนคำสืบค้นใหม่และ HyDE” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Prompt Engineering ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเขียนคำสืบค้นใหม่และ HyDE”
ปรับปรุงความครอบคลุมของการดึงข้อมูล คุณปฏิบัติ AI Prompt Engineering ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Prompt Engineering หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Prompt Engineering บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “การเขียนคำสืบค้นใหม่และ HyDE” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Prompt Engineering นี้ได้ไหม
ได้ บทเรียน AI Prompt Engineering ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ก้าวข้าม RAG แบบพื้นฐาน
- การจัดอันดับชิ้นส่วนข้อมูลที่ดึงมาใหม่
- การบีบอัดบริบท
- การเขียนคำสืบค้นใหม่และ HyDE