Summarizing Long Documents: Map-Reduce or a 1M Context Window
Map-reduce is for documents that do not fit the context window or need parallelism, not for saving money. Both approaches with code and cost math.
6 min · · development · автоматизация
Summarizing long documents is a common task: an annual report, a bundle of contracts, an email export, a thick research PDF. There are two approaches: split the text into parts and summarize each separately (map-reduce), or send the whole document to a model with a large context window. Below is when to pick which, working code, and a cost estimate at Zukko prices.
The key point about choosing
A common myth is that "map-reduce is cheaper". On the same model it is not: with map-reduce the model still reads the entire document (each chunk once), and on top of that come per-chunk instructions, intermediate summaries on the output side, and reading those summaries again at the reduce step. You end up with more tokens, not fewer.
Map-reduce is chosen for other reasons:
- The document does not fit the model's context.
glm-5.3andglm-5.3-flashhave a 128K-token context; a 300K-token document will not fit in one request. - Parallelism. Chunks can be processed concurrently, so total time depends on chunk size rather than document size.
- Per-section summaries. If you need a chapter-by-chapter report or references to specific parts, intermediate summaries are useful on their own.
Sending the whole document wins when it fits the chosen model's context: the model sees connections between sections (an appendix referring to a contract clause, a conclusion relying on a table at the start), and the code is simpler. claude-sonnet-5, claude-opus-5-5, gpt-5.6-sol and gpt-5.6-luna have a 1M-token context.
How many tokens are in a document
Roughly: a hundred pages of business prose is tens of thousands of tokens, and Russian text usually takes more tokens than the same amount of English. For an exact count on Claude models there is a token counting endpoint; see the count_tokens docs. For other models, use usage from the response to your first request.
Code: both approaches and automatic selection
You need pip install openai and a fetch_... key in OPENAI_API_KEY.
import os
from concurrent.futures import ThreadPoolExecutor
from openai import OpenAI
client = OpenAI(
base_url="https://api.zukko.pro/v1",
api_key=os.environ["OPENAI_API_KEY"],
)
CONTEXT = {
"glm-5.3-flash": 128_000, "glm-5.3": 128_000,
"gpt-5.6-luna": 1_000_000, "gpt-5.6-sol": 1_000_000,
"claude-sonnet-5": 1_000_000, "claude-opus-5-5": 1_000_000,What matters here:
summarizesends the document whole if it fits the model's context with headroom, and switches to map-reduce only when it does not.- Chunks are split by paragraph; a paragraph longer than the limit stays one large chunk, so for such texts add sentence-level splitting.
- The map step runs in 5 parallel threads. Zukko does not rate-limit requests on its side, but a key can have daily and monthly dollar limits: once reached, you get a 429 with code
key_daily_limit_reachedorkey_monthly_limit_reached. - If there are so many parts that their summaries do not fit the context, reduce in several levels: first in groups of 10–20, then the final pass.
More about the client is in the Python SDK guide.
Cost comparison
Every model on Zukko charges the same for input and output, so the formula is simple: (input + output) × price / 1,000,000. Assumptions: an instruction is about 50 tokens, a chunk summary about 400, the final summary about 1,500.
A 50K-token document, same model
Map-reduce with 4,000-token chunks gives 13 chunks. Input: 50,000 (document) + 13 × 50 (instructions) + about 5,250 (reading intermediate summaries at the reduce step) ≈ 56,000. Output: 13 × 400 + 1,500 = 6,700. Total ≈ 62,700 tokens.
Whole document: input ≈ 50,050, output 1,500. Total ≈ 51,550 tokens.
| Model | Map-reduce | Whole document |
|---|---|---|
glm-5.3-flash ($0.04) | 62,700 × 0.04 / 1,000,000 ≈ $0.0025 | 51,550 × 0.04 / 1,000,000 ≈ $0.0021 |
claude-sonnet-5 ($0.3) | 62,700 × 0.3 / 1,000,000 ≈ $0.019 | 51,550 × 0.3 / 1,000,000 ≈ $0.015 |
On the same model, map-reduce costs about 11K extra tokens: that is the price of splitting.
A 400K-token document
It does not fit glm-5.3-flash (128K), so the options are map-reduce on a cheap model or the whole document in a 1M-context model.
- Map-reduce on
glm-5.3-flash: 100 chunks. Input ≈ 400,000 + 100 × 50 + 40,050 ≈ 445,000, output ≈ 100 × 400 + 1,500 = 41,500. Total 486,500 × 0.04 / 1,000,000 ≈ $0.019. - Whole document in
gpt-5.6-luna: (400,000 + 1,500) × 0.1 / 1,000,000 ≈ $0.040. - Whole document in
claude-sonnet-5: 401,500 × 0.3 / 1,000,000 ≈ $0.12. - Map-reduce on
claude-sonnet-5: 486,500 × 0.3 / 1,000,000 ≈ $0.15.
The price difference here comes from the model's price, not from the method. Which result works for you is something to test on two or three of your own documents: compare which facts, numbers and decisions made it into each summary. The current model list is at GET https://api.zukko.pro/v1/models or on the "Models" page in the dashboard.
A caveat about repeated questions and caching
If you ask many questions about one large document, every request resends the whole document as input. Vendors charge roughly 10% of the input price for reading such a repeated prefix from cache, while Zukko bills cached tokens at the regular input price. Ten questions about a 400K-token document on gpt-5.6-luna cost 10 × 400,000 × 0.1 / 1,000,000 = $0.40. It is cheaper to produce one detailed summary and ask questions against it.
How to choose: a quick cheat sheet
| Situation | Approach |
|---|---|
| The document fits the chosen model's context | Whole document |
| The document is larger than the model's context | Map-reduce or a 1M-context model |
| You need a summary per section | Map-reduce |
| Links between distant parts of the text matter | Whole document |
| Many documents, speed matters | Map-reduce with parallel requests |
To run the code, create a key in the dashboard; setup steps are in the quick start.
FAQ
Does map-reduce lose information?
It can: a connection that crosses a chunk boundary is invisible to the model at the map step. Overlapping chunks (the last paragraph of the previous chunk at the start of the next) and asking for unresolved references in intermediate summaries both help. For contracts and documents with cross-references, sending the whole document is more reliable.
How do I handle PDF and DOCX files?
Extract the text first, then pass it to summarize:
import pdfplumber
from docx import Document
with pdfplumber.open("report.pdf") as pdf:
pdf_text = "\n\n".join(page.extract_text() or "" for page in pdf.pages)
docx_text = "\n\n".join(p.text for p in Document("contract.docx").paragraphs)Scans without a text layer need OCR; extract_text will return empty strings.
How do I get the summary in a specific language?
Add a line like "Answer in Russian" to the prompt. Check the quality in your language and domain on several documents before running it on the whole archive.
How do I control summary length?
Set the length in the prompt: "no more than 300 words" or "5 bullet points". max_tokens is a hard cut-off of the answer, not a length control: if the limit is too low, the summary stops mid-sentence.
zukko
Pay 25×
less
for Claude Code & ChatGPT
One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.
Related articles
- Translating subtitles with a neural network: SRT without broken timecodesThe main risk when translating SRT with a neural network is a broken file structure. A scheme where timecodes never reach the model, and a Python script with validation.
- Editing texts with a neural network: proofreading, style and cuttingDifferent kinds of editing need different prompts. Wording for proofreading, style and cutting, how to get edits with explanations and how not to lose the author's voice.
- A neural network for writing scripts: Bash, PowerShell and PythonA model writes scripts for routine fast, but running them blindly is risky. How to state the task, demand a safe dry-run mode and check the result before launch.
- Dify in Docker: installation, first-run setup and connecting modelsInstall Dify with Docker Compose, create the admin account and connect Claude, GPT and DeepSeek models on one key. Plus what to do when containers will not start.