0Pricing
AI Prompt Engineering · درس

نمط تلخيص Map-Reduce

لخّصوا كل جزء بشكل مستقل، ثم ركّبوا الملخصات معًا

نمط تلخيص Map-Reduce درس مجاني في AI Prompt Engineering على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Prompt Engineering، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Prompt Engineering 4 دروس في المجموع.

نمط Map-Reduce

عندما يتجاوز مستند ما نافذة سياق LLM، لا يمكنكم تمريره بأكمله دفعة واحدة. يحل نمط map-reduce هذه المشكلة:

  • Map: تلخيص كل مقطع بشكل مستقل
  • Reduce: دمج ملخصات جميع المقاطع في ملخص نهائي واحد

يشبه هذا النمط MapReduce التقليدي في الأنظمة الموزعة — إذ يطبّق منطق التقسيم والحل نفسه على المهام اللغوية.

الخطوة الأولى: مرحلة Map

في مرحلة map، يُرسل كل مقطع إلى LLM مع مطالبة للتلخيص. يُرجع النموذج ملخصاً قصيراً لذلك المقطع فقط. ثم تُجمع هذه الملخصات في قائمة.

ينبغي أن يكون كل ملخص أقصر بكثير من المقطع الأصلي — عادةً ما يتراوح طوله بين 10 و20% من الطول الأصلي. وهذا الضغط هو ما يجعل خطوة reduce ممكنة.

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]

الخطوة الثانية: مرحلة Reduce

في مرحلة reduce، تُلصق جميع ملخصات المقاطع معاً وتُرسل إلى LLM مع مطالبة للتركيب. وينتج النموذج ملخصاً نهائياً واحداً متماسكاً.

إذا كانت ملخصات المقاطع لا تزال طويلة جداً بحيث لا تتسع لها نافذة سياق واحدة، فطبّقوا reduce بشكل تكراري — لخّصوا مجموعات الملخصات أولاً، ثم ادمجوا تلك الملخصات.

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

تجميع الأجزاء: Raw API

فيما يلي خط أنابيب map-reduce الكامل باستخدام استدعاءات OpenAI API مباشرة — دون الحاجة إلى إطار عمل. ويمنحكم ذلك تحكماً كاملاً في المطالبات والمعلمات في كل مرحلة.

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)

MapReduceDocumentsChain في LangChain

يوفّر LangChain سلسلة MapReduceDocumentsChain جاهزة تتولى تقسيم النص إلى مقاطع، واستدعاءات map المتوازية، وخطوة reduce. وهي مريحة، لكنها أقل مرونة من استدعاءات API المباشرة.

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'])

تنفيذ مرحلة Map بالتوازي

ملخص كل مقطع مستقل عن غيره، لذا يمكن تنفيذ مرحلة map بالتوازي. وباستخدام ThreadPoolExecutor في Python، تُرسل جميع استدعاءات API الخاصة بالمقاطع بشكل متزامن، مما يقلل وقت التنفيذ الفعلي بشكل كبير.

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

Reduce التكراري

عندما يكون المستند طويلاً جداً، قد تتجاوز ملخصات المقاطع نفسها نافذة السياق. طبّقوا reduce بشكل تكراري: جمّعوا الملخصات في دفعات، وطبّقوا reduce على كل دفعة، ثم طبّقوه على ملخصات الدفعات.

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-reduce الساذج فقدان التفاصيل المهمة أثناء الضغط. وتشمل طرق الحد من ذلك ما يلي:

  • اطلبوا من خطوة map الحفاظ على الأسماء والأرقام والتواريخ
  • اطلبوا من خطوة reduce التحقق من وجود تناقضات بين الأقسام
  • استخدموا حجماً أكبر للمقطع حتى يكون سياق map أكثر ثراءً
  • أجروا مرحلة تحقق: اطلبوا من النموذج التحقق مما إذا كانت الكيانات الأساسية من المستند الأصلي تظهر في الملخص النهائي
MAP_PROMPT = '''Summarize the following section in 5 sentences.
Preserve all key names, numbers, dates, and conclusions.

Section:
{chunk}'''

سلسلة Refine: نمط بديل

تُعد سلسلة refine بديلاً عن map-reduce. فهي تعالج المقاطع بالتتابع: يُمرَّر ملخص المقطع N إلى جانب المقطع N+1، ثم يحدّث النموذج الملخص المتراكم. وينتج عن ذلك مخرجات أكثر تماسكاً، لكن لا يمكن تنفيذها بالتوازي، كما أنها أبطأ.

استخدموا refine عندما يكون تماسك السرد مهماً (مثل العقود القانونية). واستخدموا map-reduce عندما تكون السرعة مهمة (مثل دفعات المقالات الإخبارية).

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

إدارة التكلفة والرموز

ينفّذ map-reduce العديد من استدعاءات API. بالنسبة إلى مستند يتكون من 100 مقطع باستخدام gpt-4o بسعر $5/1M من رموز الإدخال:

  • Map: ‏100 مقطع × 1000 رمز = ‏100k من رموز الإدخال ≈ $0.50
  • Reduce: نحو 10k من الرموز (الملخصات) ≈ $0.05
  • الإجمالي: نحو $0.55 لكل مستند

لتقليل التكلفة: استخدموا gpt-4o-mini في مرحلة map (بسعر $0.15/1M)، واستخدموا gpt-4o فقط في مرحلة reduce. ويخفض هذا الأسلوب الهجين التكاليف بنسبة 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')

متى يُستخدم Map-Reduce

يُعد تلخيص map-reduce مناسباً للآتي:

  • المستندات الأطول من نافذة سياق النموذج
  • تلخيص عدد كبير من المستندات دفعة واحدة (مع إمكانية التنفيذ بالتوازي على مستوى المستندات أيضاً)
  • الحالات التي تحتاجون فيها إلى التحكم في المطالبة في كل خطوة

وهو أقل ملاءمة لاستخراج حقيقة محددة (استخدموا الاسترجاع بدلاً منه)، أو عندما يكون المستند قصيراً بما يكفي ليتسع له السياق (لخّصوه مباشرةً).

اختبار المعرفة

في نمط تلخيص map-reduce، ماذا يحدث أثناء مرحلة reduce؟

مراجعة: تلخيص Map-Reduce

يعالج نمط map-reduce المستندات الأطول من أن يتسع لها استدعاء واحد لـ LLM:

  • Map: تلخيص كل مقطع بشكل مستقل — ويمكن تنفيذه بالتوازي
  • Reduce: دمج ملخصات المقاطع في ملخص نهائي واحد
  • Reduce التكراري: يُستخدم عندما تكون الملخصات نفسها طويلة جداً
  • نصيحة لتقليل التكلفة: استخدموا نموذجاً منخفض التكلفة في map ونموذجاً عالي الجودة في reduce

يوفّر MapReduceDocumentsChain في LangChain تطبيقاً جاهزاً. ويتناول الدرس التالي التلخيص الهرمي للكتب والأوراق البحثية.

الأسئلة الشائعة

هل درس «نمط تلخيص Map-Reduce» مجاني؟

نعم — نص درس «نمط تلخيص Map-Reduce» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Prompt Engineering، انتقل إلى CoddyKit PRO. تتضمن دورة AI Prompt Engineering 4 دروس في المجموع.

ماذا ستتعلم في «نمط تلخيص Map-Reduce»؟

لخّصوا كل جزء بشكل مستقل، ثم ركّبوا الملخصات معًا تتمرن على AI Prompt Engineering مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ AI Prompt Engineering؟

لا تُشترط خبرة سابقة. AI Prompt Engineering على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «نمط تلخيص Map-Reduce»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس AI Prompt Engineering هذا؟

نعم. كل درس في AI Prompt Engineering يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. استراتيجيات تقسيم النصوص الطويلة
  2. نمط تلخيص Map-Reduce
  3. التلخيص الهرمي
  4. الحفاظ على السياق عبر الأجزاء
← العودة إلى AI Prompt Engineering