0Pricing
AI Prompt Engineering · Lesson

Map-Reduce Summarization Pattern

Summarize each chunk independently then synthesize the summaries.

Map-Reduce Summarization Pattern is a free AI Prompt Engineering lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the AI Prompt Engineering learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

The Map-Reduce Pattern

When a document exceeds the LLM context window, you cannot pass it all at once. The map-reduce pattern solves this:

  • Map: summarize each chunk independently
  • Reduce: synthesize all chunk summaries into one final summary

This mirrors the classic MapReduce from distributed systems — the same divide-and-conquer logic applied to language tasks.

Step 1: The Map Phase

In the map phase, each chunk is sent to the LLM with a summarization prompt. The model returns a short summary of that chunk only. These summaries are collected into a list.

Each summary should be much shorter than the original chunk — typically 10–20% of the original length. This compression is what makes the reduce step feasible.

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]

Step 2: The Reduce Phase

In the reduce phase, all chunk summaries are concatenated and sent to the LLM with a synthesis prompt. The model produces a single coherent final summary.

If the chunk summaries are still too long to fit in one context window, apply reduce recursively — summarize groups of summaries first, then synthesize those.

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

Putting It Together: Raw API

Here is the complete map-reduce pipeline using raw OpenAI API calls — no framework required. This gives you full control over prompts and parameters at each phase.

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 provides a ready-made MapReduceDocumentsChain that handles chunking, parallel map calls, and the reduce step. It is convenient but less flexible than raw API calls.

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

Parallelizing the Map Phase

Each chunk summary is independent, so the map phase can be parallelized. Using Python's ThreadPoolExecutor, all chunk API calls are sent concurrently, dramatically reducing wall-clock time.

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

Recursive Reduce

When a document is very long, the chunk summaries themselves may exceed the context window. Apply reduce recursively: group summaries into batches, reduce each batch, then reduce the batch 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]

Preserving Key Details

A common failure of naive map-reduce: important details are lost during compression. Mitigations:

  • Prompt the map step to preserve names, numbers, dates
  • Ask the reduce step to check for contradictions between sections
  • Use a higher chunk size so the map context is richer
  • Run a verification pass: ask the model if key entities from the original appear in the final summary
MAP_PROMPT = '''Summarize the following section in 5 sentences.
Preserve all key names, numbers, dates, and conclusions.

Section:
{chunk}'''

Refine Chain: An Alternative Pattern

The refine chain is an alternative to map-reduce. It processes chunks sequentially: the summary of chunk N is passed alongside chunk N+1, and the model updates the running summary. This produces more coherent output but cannot be parallelized and is slower.

Use refine when narrative coherence matters (e.g., legal contracts). Use map-reduce when speed matters (e.g., news article batches).

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

Cost and Token Management

Map-reduce makes many API calls. For a 100-chunk document with gpt-4o at $5/1M input tokens:

  • Map: 100 chunks × 1000 tokens = 100k input tokens ≈ $0.50
  • Reduce: ~10k tokens (summaries) ≈ $0.05
  • Total: ~$0.55 per document

To reduce cost: use gpt-4o-mini for the map phase ($0.15/1M) and gpt-4o only for reduce. This hybrid approach cuts costs by 70% with minimal quality loss.

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

When to Use Map-Reduce

Map-reduce summarization is best for:

  • Documents longer than the model context window
  • Batch summarization of many documents (parallelize at document level too)
  • Situations where you need control over prompt at each step

It is less suited for: extracting a specific fact (use retrieval instead), or when the document is short enough to fit in context (just summarize directly).

Knowledge Check

In the map-reduce summarization pattern, what happens during the reduce phase?

Recap: Map-Reduce Summarization

The map-reduce pattern handles documents too long for a single LLM call:

  • Map: summarize each chunk independently — can be parallelized
  • Reduce: synthesize chunk summaries into one final summary
  • Recursive reduce: apply when summaries themselves are too long
  • Cost tip: use a cheap model for map, quality model for reduce

LangChain's MapReduceDocumentsChain provides a ready-made implementation. Next lesson covers hierarchical summarization for books and research papers.

Frequently asked questions

Is the “Map-Reduce Summarization Pattern” lesson free?

Yes — the full text of “Map-Reduce Summarization Pattern” is free to read here on the web, and the AI Prompt Engineering course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the AI Prompt Engineering course, upgrade to CoddyKit PRO.

What will I learn in “Map-Reduce Summarization Pattern”?

Summarize each chunk independently then synthesize the summaries. You practise AI Prompt Engineering with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start AI Prompt Engineering?

No prior experience is required. AI Prompt Engineering on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Map-Reduce Summarization Pattern” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this AI Prompt Engineering lesson?

Yes. Every AI Prompt Engineering lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Chunking Strategies for Long Texts
  2. Map-Reduce Summarization Pattern
  3. Hierarchical Summarization
  4. Maintaining Context Across Chunks
← Back to AI Prompt Engineering