High-volume summarization is one of the most common first production workloads for Claude, and the reference design is stable: split documents into model-sized pieces, summarize each piece ("map"), then summarize the summaries ("reduce"). The interesting decisions are where you split, how you keep costs down, and how you make the output machine-readable. Everything below uses documented Claude capabilities; the glue — queues, retries, storage — is standard engineering practice you own.
Step 1: Decide whether you need to chunk at all
Current Claude models carry large context windows — 1M tokens on most current models, 200K on Haiku 4.5 — so many "long" documents fit in a single request. PDFs are supported directly as document blocks (up to 600 pages per request on a 1M-context model), with each page costing roughly 1,500–3,000 text tokens plus image tokens, since pages are processed both as extracted text and as images. If a document fits, skip map-reduce: one well-structured request produces a more coherent summary than stitched fragments.
When you do send long inputs, follow Anthropic's long-context guidance: put the document content at the top of the prompt and your instructions at the end (placing queries at the end can improve response quality by up to 30%), and wrap multiple documents in <document> tags with <source> subtags so the model can keep them apart.
Step 2: Map-reduce for what doesn't fit
For documents beyond the window — or when you want per-section summaries anyway — chunk on natural boundaries (sections, chapters, filings) rather than fixed byte counts, so no fact is cut in half. Each map call takes one chunk plus a fixed instruction template; the reduce call takes all map outputs plus a template asking for a consolidated summary. Keep the instruction templates identical across calls: a stable prompt prefix is what makes prompt caching work, since caching is a strict prefix match and cache reads bill at 0.1x the base input price. See RAG chunking strategies for the chunking trade-offs in depth.
Step 3: Run the volume through batch processing
Map calls are independent, which makes them ideal batch work. On the first-party Claude API and Claude Platform on AWS, Anthropic's Message Batches API accepts up to 100,000 requests or 256 MB per batch, charges 50% of standard prices, and usually finishes in under an hour (requests unfinished at 24 hours expire unbilled; results stay downloadable for 29 days). Each request carries a custom_id you choose — use your document/chunk ID so results rejoin your pipeline deterministically. Because batches can take longer than five minutes, use the 1-hour prompt-cache TTL on shared context instead of the default 5-minute one.
Step 4: Make the output a schema, not prose
Downstream systems want fields, not paragraphs. Structured outputs (output_config with a JSON schema, objects set additionalProperties: false) guarantee the response parses, so your reduce step and your database never see free-form text where a field should be. Structured outputs are generally available on the Claude API, Claude Platform on AWS, Bedrock, and Vertex AI, and in beta on Foundry.
from anthropic import AnthropicVertex
client = AnthropicVertex(project_id="my-project", region="global")
schema = {"type": "object", "additionalProperties": False,
"properties": {"summary": {"type": "string"},
"topics": {"type": "array", "items": {"type": "string"}}},
"required": ["summary", "topics"]}
msg = client.messages.create(
model="claude-sonnet-5", max_tokens=1024,
output_config={"format": {"type": "json_schema", "schema": schema}},
messages=[{"role": "user", "content": f"<document>{chunk}</document>\nSummarize."}])
Model choice and operational guardrails
A common split: Haiku 4.5 ($1/$5 per million tokens) for map calls, where each chunk is self-contained, and Sonnet 5 or Opus 4.8 for the reduce call, where synthesis quality matters most. Combined with batch pricing, the map phase often ends up costing pennies per document. Operationally: treat 429 and 5xx errors as retryable with backoff (the official SDKs already retry them), check for stop_reason: "max_tokens" on truncated summaries and re-run with a higher limit, and validate every structured output against your schema before it enters storage — a refusal returns HTTP 200 with stop_reason: "refusal" and may not match the schema.
Where to go next
Compare the per-platform gaps in the feature gaps article, or continue to the extraction-to-database pattern for pipelines that pull fields rather than summaries. The feature matrix shows batch availability at a glance.