รูปแบบการสรุปแบบ Map-Reduce
สรุปแต่ละส่วนแยกกัน แล้วสังเคราะห์เป็นบทสรุป
รูปแบบการสรุปแบบ Map-Reduce เป็นบทเรียน AI Prompt Engineering ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Prompt Engineering และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
รูปแบบแมป-รีดิวซ์
เมื่อเอกสารยาวเกินหน้าต่างบริบทของ LLM คุณจะส่งเอกสารทั้งหมดไปพร้อมกันไม่ได้ รูปแบบแมป-รีดิวซ์ช่วยแก้ปัญหานี้:
- แมป: สรุปชิ้นข้อความแต่ละชิ้นแยกจากกัน
- รีดิวซ์: สังเคราะห์บทสรุปของชิ้นข้อความทั้งหมดให้เป็นบทสรุปสุดท้ายหนึ่งฉบับ
รูปแบบนี้เหมือนกับ MapReduce แบบดั้งเดิมจากระบบแบบกระจาย — ใช้ตรรกะการแบ่งแล้วพิชิตแบบเดียวกันกับงานด้านภาษา
ขั้นตอนที่ 1: ขั้นตอนแมป
ในขั้นตอนแมป ชิ้นข้อความแต่ละชิ้นจะถูกส่งไปยัง LLM พร้อมพรอมต์สำหรับการสรุป โมเดลจะส่งคืนบทสรุปสั้น ๆ ของชิ้นข้อความนั้นเท่านั้น จากนั้นจึงรวบรวมบทสรุปเหล่านี้ไว้ในรายการ
บทสรุปแต่ละฉบับควรสั้นกว่าชิ้นข้อความต้นฉบับมาก โดยทั่วไปมีความยาวประมาณ 10–20% ของความยาวต้นฉบับ การบีบอัดนี้ทำให้ขั้นตอนรีดิวซ์สามารถดำเนินการได้
import openai
client = openai.OpenAI(api_key='sk-...')
def summarize_chunk(chunk, model='gpt-4o'):
resp = client.chat.completions.create(
model=model,
messages=[
{'role': 'system', 'content': 'Summarize the following text concisely in 3-5 sentences.'},
{'role': 'user', 'content': chunk}
]
)
return resp.choices[0].message.content
def map_phase(chunks):
return [summarize_chunk(c) for c in chunks]ขั้นตอนที่ 2: ขั้นตอนรีดิวซ์
ในขั้นตอนรีดิวซ์ บทสรุปของชิ้นข้อความทั้งหมดจะถูกนำมาต่อกันและส่งไปยัง LLM พร้อมพรอมต์สำหรับการสังเคราะห์ โมเดลจะสร้างบทสรุปสุดท้ายฉบับเดียวที่มีความต่อเนื่อง
หากบทสรุปของชิ้นข้อความยังยาวเกินกว่าจะใส่ในหน้าต่างบริบทเดียวได้ ให้ใช้การรีดิวซ์แบบเรียกซ้ำ — สรุปกลุ่มบทสรุปก่อน แล้วจึงสังเคราะห์บทสรุปเหล่านั้น
def reduce_phase(chunk_summaries, model='gpt-4o'):
combined = '\n\n'.join(
f'Section {i+1}:\n{s}'
for i, s in enumerate(chunk_summaries)
)
resp = client.chat.completions.create(
model=model,
messages=[
{'role': 'system', 'content': 'You are given summaries of consecutive sections of a document. Write a single coherent summary of the entire document.'},
{'role': 'user', 'content': combined}
]
)
return resp.choices[0].message.contentการรวมทุกอย่างเข้าด้วยกัน: เอพีไอโดยตรง
นี่คือไปป์ไลน์แมป-รีดิวซ์ฉบับสมบูรณ์โดยใช้การเรียกใช้เอพีไอของ OpenAI โดยตรง — ไม่ต้องใช้เฟรมเวิร์ก วิธีนี้ช่วยให้คุณควบคุมพรอมต์และพารามิเตอร์ในแต่ละขั้นตอนได้อย่างเต็มที่
def map_reduce_summarize(document, chunk_size=1000):
chunks = fixed_chunk(document, max_tokens=chunk_size)
print(f'Chunks: {len(chunks)}')
chunk_summaries = map_phase(chunks)
print(f'Map phase complete. Summaries: {len(chunk_summaries)}')
final_summary = reduce_phase(chunk_summaries)
return final_summary
with open('long_report.txt') as f:
doc = f.read()
result = map_reduce_summarize(doc)
print(result)LangChain MapReduceDocumentsChain
LangChain มี MapReduceDocumentsChain สำเร็จรูปที่จัดการการแบ่งข้อความ การเรียกใช้ขั้นตอนแมปแบบขนาน และขั้นตอนรีดิวซ์ให้ คุณจะใช้งานได้สะดวก แต่มีความยืดหยุ่นน้อยกว่าการเรียกใช้เอพีไอโดยตรง
from langchain_openai import ChatOpenAI
from langchain.chains.summarize import load_summarize_chain
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.docstore.document import Document
llm = ChatOpenAI(model='gpt-4o', openai_api_key='sk-...')
splitter = RecursiveCharacterTextSplitter(chunk_size=3000, chunk_overlap=200)
with open('long_report.txt') as f:
text = f.read()
docs = splitter.create_documents([text])
chain = load_summarize_chain(llm, chain_type='map_reduce')
result = chain.invoke(docs)
print(result['output_text'])การทำขั้นตอนแมปแบบขนาน
บทสรุปของชิ้นข้อความแต่ละชิ้นไม่ขึ้นต่อกัน ดังนั้นจึงสามารถทำขั้นตอนแมปแบบขนานได้ การใช้ ThreadPoolExecutor ของไพธอนจะทำให้การเรียกใช้เอพีไอสำหรับชิ้นข้อความทั้งหมดถูกส่งไปพร้อมกัน ซึ่งช่วยลดเวลาที่ใช้จริงลงอย่างมาก
from concurrent.futures import ThreadPoolExecutor, as_completed
def map_phase_parallel(chunks, max_workers=10):
summaries = [None] * len(chunks)
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {
executor.submit(summarize_chunk, chunk): i
for i, chunk in enumerate(chunks)
}
for future in as_completed(futures):
idx = futures[future]
summaries[idx] = future.result()
return summariesรีดิวซ์แบบเรียกซ้ำ
เมื่อเอกสารยาวมาก บทสรุปของชิ้นข้อความเองก็อาจยาวเกินหน้าต่างบริบทได้ ให้ใช้การรีดิวซ์แบบเรียกซ้ำ: จัดกลุ่มบทสรุปเป็นชุด ๆ รีดิวซ์แต่ละชุด แล้วจึงรีดิวซ์บทสรุปของแต่ละชุดอีกครั้ง
def recursive_reduce(summaries, batch_size=10):
while len(summaries) > 1:
batches = [
summaries[i:i + batch_size]
for i in range(0, len(summaries), batch_size)
]
summaries = [reduce_phase(batch) for batch in batches]
print(f'Reduced to {len(summaries)} summaries')
return summaries[0]การรักษารายละเอียดสำคัญ
ความล้มเหลวที่พบได้บ่อยของการแมป-รีดิวซ์แบบไม่ระมัดระวังคือ รายละเอียดสำคัญสูญหายระหว่างการบีบอัด วิธีลดปัญหามีดังนี้:
- กำหนดในพรอมต์ของขั้นตอนแมปให้รักษาชื่อ ตัวเลข และวันที่ไว้
- ขอให้ขั้นตอนรีดิวซ์ตรวจสอบความขัดแย้งระหว่างส่วนต่าง ๆ
- ใช้ขนาดชิ้นข้อความที่ใหญ่ขึ้น เพื่อให้บริบทของขั้นตอนแมปมีข้อมูลมากขึ้น
- ดำเนินการตรวจสอบยืนยัน: ถามโมเดลว่าองค์ประกอบสำคัญจากเอกสารต้นฉบับปรากฏอยู่ในบทสรุปสุดท้ายหรือไม่
MAP_PROMPT = '''Summarize the following section in 5 sentences.
Preserve all key names, numbers, dates, and conclusions.
Section:
{chunk}'''เชน refine: รูปแบบทางเลือก
เชน refine เป็นอีกทางเลือกหนึ่งนอกเหนือจากแมป-รีดิวซ์ โดยจะประมวลผลชิ้นข้อความตามลำดับ: บทสรุปของชิ้นข้อความ N จะถูกส่งไปพร้อมกับชิ้นข้อความ N+1 และโมเดลจะปรับปรุงบทสรุปสะสม วิธีนี้ให้ผลลัพธ์ที่ต่อเนื่องมากกว่า แต่ไม่สามารถทำงานแบบขนานได้และช้ากว่า
ใช้ refine เมื่อความต่อเนื่องของเนื้อเรื่องมีความสำคัญ (เช่น สัญญาทางกฎหมาย) ใช้แมป-รีดิวซ์เมื่อความเร็วมีความสำคัญ (เช่น ชุดบทความข่าว)
def refine_summarize(chunks):
current_summary = summarize_chunk(chunks[0])
for chunk in chunks[1:]:
prompt = (
f'Existing summary:\n{current_summary}\n\n'
f'New section:\n{chunk}\n\n'
'Update the summary to incorporate the new section.'
)
resp = client.chat.completions.create(
model='gpt-4o',
messages=[{'role': 'user', 'content': prompt}]
)
current_summary = resp.choices[0].message.content
return current_summaryการจัดการต้นทุนและโทเค็น
แมป-รีดิวซ์ต้องเรียกใช้เอพีไอหลายครั้ง สำหรับเอกสาร 100 ชิ้นข้อความ โดยใช้ gpt-4o ที่ราคา $5 ต่อโทเค็นอินพุต 1M:
- แมป: 100 ชิ้นข้อความ × 1000 โทเค็น = 100k โทเค็นอินพุต ≈ $0.50
- รีดิวซ์: ประมาณ 10k โทเค็น (บทสรุป) ≈ $0.05
- รวม: ประมาณ $0.55 ต่อเอกสาร
หากต้องการลดต้นทุน ให้ใช้ gpt-4o-mini สำหรับขั้นตอนแมป ($0.15 ต่อ 1M) และใช้ gpt-4o เฉพาะสำหรับขั้นตอนรีดิวซ์ แนวทางแบบผสมนี้ลดต้นทุนได้ 70% โดยคุณภาพลดลงเพียงเล็กน้อย
def map_phase_cheap(chunks):
# Use mini model for map — cheaper, sufficient for chunk summaries
return [
summarize_chunk(c, model='gpt-4o-mini')
for c in chunks
]
def reduce_phase_quality(summaries):
# Use full model for final synthesis
return reduce_phase(summaries, model='gpt-4o')ควรใช้แมป-รีดิวซ์เมื่อใด
การสรุปแบบแมป-รีดิวซ์เหมาะที่สุดสำหรับ:
- เอกสารที่ยาวเกินหน้าต่างบริบทของโมเดล
- การสรุปเอกสารจำนวนมากเป็นชุด ๆ (สามารถทำงานแบบขนานในระดับเอกสารได้เช่นกัน)
- สถานการณ์ที่คุณต้องการควบคุมพรอมต์ในแต่ละขั้นตอน
วิธีนี้เหมาะน้อยกว่าสำหรับการดึงข้อเท็จจริงเฉพาะรายการ (ให้ใช้การดึงข้อมูลแทน) หรือเมื่อเอกสารสั้นพอที่จะใส่ในบริบทได้ (ให้สรุปโดยตรง)
ตรวจสอบความรู้
ในรูปแบบการสรุปแบบแมป-รีดิวซ์ จะเกิดอะไรขึ้นในขั้นตอนรีดิวซ์?
สรุป: การสรุปแบบแมป-รีดิวซ์
รูปแบบแมป-รีดิวซ์ช่วยจัดการเอกสารที่ยาวเกินกว่าจะเรียกใช้ LLM เพียงครั้งเดียว:
- แมป: สรุปชิ้นข้อความแต่ละชิ้นแยกจากกัน — สามารถทำงานแบบขนานได้
- รีดิวซ์: สังเคราะห์บทสรุปของชิ้นข้อความให้เป็นบทสรุปสุดท้ายหนึ่งฉบับ
- รีดิวซ์แบบเรียกซ้ำ: ใช้เมื่อบทสรุปเองยาวเกินไป
- เคล็ดลับด้านต้นทุน: ใช้โมเดลราคาถูกสำหรับขั้นตอนแมป และโมเดลคุณภาพสูงสำหรับขั้นตอนรีดิวซ์
MapReduceDocumentsChain ของ LangChain มีการนำไปใช้งานสำเร็จรูปให้ บทเรียนถัดไปจะครอบคลุมการสรุปแบบลำดับชั้นสำหรับหนังสือและบทความวิจัย
คำถามที่พบบ่อย
บทเรียน “รูปแบบการสรุปแบบ Map-Reduce” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “รูปแบบการสรุปแบบ Map-Reduce” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Prompt Engineering ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Prompt Engineering มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “รูปแบบการสรุปแบบ Map-Reduce”
สรุปแต่ละส่วนแยกกัน แล้วสังเคราะห์เป็นบทสรุป คุณปฏิบัติ AI Prompt Engineering ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Prompt Engineering หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Prompt Engineering บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “รูปแบบการสรุปแบบ Map-Reduce” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน AI Prompt Engineering นี้ได้ไหม
ได้ บทเรียน AI Prompt Engineering ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- กลยุทธ์การแบ่งข้อความยาวเป็นส่วน
- รูปแบบการสรุปแบบ Map-Reduce
- การสรุปแบบลำดับชั้น
- การรักษาบริบทระหว่างส่วนต่าง ๆ