0Pricing
AI Prompt Engineering · บทเรียน

รูปแบบการสรุปแบบ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. กลยุทธ์การแบ่งข้อความยาวเป็นส่วน
  2. รูปแบบการสรุปแบบ Map-Reduce
  3. การสรุปแบบลำดับชั้น
  4. การรักษาบริบทระหว่างส่วนต่าง ๆ
← กลับไปที่ AI Prompt Engineering