Newsletter, guides

LangChain map reduce vs stuff vs refine chain types

LangChain map reduce, stuff and refine summarization compared for 2026. When each chain type wins, with current langchain-classic and LangGraph code.

, 8 min read, updated

You wired up a LangChain summarization chain in five minutes and it worked on the test PDF. Then a real customer document hit the model’s context limit and the API returned an error. You switched to chain_type="map_reduce" because a forum answer said so. Now it works, but the summaries feel disjointed and cost more than they should.

A LangChain chain type is a document-combining strategy that summarizes long text by splitting it into chunks and merging the model outputs in a set pattern. stuff, map_reduce and refine are the three summarization chain types, and each trades cost, speed and coherence differently. This guide shows when each one wins, and the current LangChain 1.x and LangGraph code for map reduce.

Key takeaways

  • stuff puts every chunk into one prompt and makes one LLM call. It is the cheapest and most coherent option whenever the text fits the context window.
  • map_reduce summarizes each chunk in parallel, then combines the summaries in a final call. It scales past the context window but can lose ideas that span chunks.
  • refine walks the chunks in order and updates a running summary. It keeps narrative order but runs sequentially, so latency grows with every chunk.
  • In LangChain 1.x, load_summarize_chain lives in langchain-classic. For new map reduce code, use LangGraph’s Send API.
  • map_rerank is a question-answering chain type in the deprecated load_qa_chain, not a summarization strategy.

What are LangChain chain types?

Chain types are strategies for feeding documents to an LLM when they may not fit in one call. Each one decides how many calls to make, in what order, and how to combine the results.

Three summarization strategies side by side: stuff sends all chunks in one call, map reduce summarizes chunks in parallel then combines them, refine updates one running summary chunk by chunk

They differ on three axes: the number of LLM calls, how much cross-chunk context survives, and how predictable the cost is. In LangChain 1.x the classic chains still work through the langchain-classic package:

# filename: summarize_classic.py
# description: The classic summarize chain in LangChain 1.x.
from langchain.chat_models import init_chat_model
from langchain_classic.chains.summarize import load_summarize_chain

llm = init_chat_model("anthropic:claude-haiku-5-5")

# chain_type is "stuff" (default), "map_reduce" or "refine".
chain = load_summarize_chain(llm, chain_type="map_reduce")
result = chain.invoke({"input_documents": docs})  # docs: list[Document]
print(result["output_text"])

When should you use the stuff chain?

Use stuff when the whole document fits in the model’s context window with room left for the summary. That is the whole test.

The stuff chain joins every chunk into one prompt and makes one call. The model sees everything at once, so coherence is as high as it gets. There is no per-chunk overhead, so cost is lowest. The only failure is a document longer than the context window.

Context windows are now large. Every current Claude model accepts 1M tokens as of October 2026. Do not guess from page counts. Count the tokens of your real inputs with your provider’s token counting endpoint, and compare that to the model’s limit.

Do not reach for another chain type until stuff fails on real inputs. Even inside the limit, put the document at the top of the prompt and the instructions after it, which Anthropic’s prompting guide recommends for long inputs.

How does LangChain map reduce summarization work?

Map reduce summarizes each chunk on its own (the map step), then combines the chunk summaries in one final call (the reduce step). It wins when the input is larger than the context window, or when you have many independent documents.

For new code, build map reduce in LangGraph, whose docs name map reduce as the main use of the Send API. Send fans out one map call per chunk at run time, and a list reducer collects the results.

LangGraph map reduce graph where START fans out one Send per chunk to parallel map nodes, their summaries merge into shared state, and a reduce node writes the final summary
# filename: summarize_map_reduce.py
# description: Map reduce summarization in LangGraph with the Send API.
import operator
from typing import Annotated, TypedDict

from langchain.chat_models import init_chat_model
from langgraph.graph import END, START, StateGraph
from langgraph.types import Send

map_llm = init_chat_model("anthropic:claude-haiku-5-5")
reduce_llm = init_chat_model("anthropic:claude-sonnet-5-5")


class State(TypedDict):
    chunks: list[str]
    summaries: Annotated[list[str], operator.add]  # each map call appends
    final_summary: str


class ChunkState(TypedDict):
    chunk: str


async def map_chunk(state: ChunkState) -> dict:
    reply = await map_llm.ainvoke(
        f"Summarize this passage in 3 sentences:\n\n{state['chunk']}"
    )
    return {"summaries": [reply.text]}


def fan_out(state: State) -> list[Send]:
    return [Send("map_chunk", {"chunk": c}) for c in state["chunks"]]


async def reduce_summaries(state: State) -> dict:
    joined = "\n\n".join(f"- {s}" for s in state["summaries"])
    reply = await reduce_llm.ainvoke(
        "Combine these chunk summaries into one coherent summary "
        f"of the whole document:\n\n{joined}"
    )
    return {"final_summary": reply.text}


graph = StateGraph(State)
graph.add_node("map_chunk", map_chunk)
graph.add_node("reduce_summaries", reduce_summaries)
graph.add_conditional_edges(START, fan_out, ["map_chunk"])
graph.add_edge("map_chunk", "reduce_summaries")
graph.add_edge("reduce_summaries", END)
app = graph.compile()

# result = await app.ainvoke({"chunks": chunks})
# print(result["final_summary"])

All map calls run in parallel, so wall-clock time stays low on large inputs. The cost is N map calls plus one reduce call, and the map step dominates. That is why the map step uses a small, fast model and the reduce step a stronger one. The weakness is boundary loss: each chunk is summarized alone, so an idea that spans two chunks can disappear. If the joined summaries are still too long, reduce them in batches and repeat.

LangGraph also gives you streaming of each step and checkpointing, so a failed map call can resume instead of restarting. See LangGraph persistence and thread models for how checkpointers work.

When does refine beat map reduce?

Use refine when chunk order carries the meaning and you cannot lose context across chunks. It summarizes chunk 1, then asks the model to update that summary with chunk 2, then chunk 3, and so on.

# filename: summarize_refine.py
# description: Refine summarization. Sequential, one call per chunk.
from langchain.chat_models import init_chat_model

llm = init_chat_model("anthropic:claude-sonnet-5-5")


async def refine_summary(chunks: list[str]) -> str:
    running = ""
    for chunk in chunks:
        reply = await llm.ainvoke(
            f"Existing summary so far:\n{running}\n\n"
            f"Refine it using this new passage:\n{chunk}"
        )
        running = reply.text
    return running

Two properties follow. It is sequential, because chunk N depends on the summary after chunk N-1, so latency grows linearly with length. And the running summary keeps narrative order in a way map reduce cannot. For a story, an investigation or a step-by-step argument, refine gives the more faithful result.

The price is time and tokens. Each call re-reads the running summary, so total input tokens grow faster than with map reduce. Refine suits batch jobs where coherence matters more than speed.

How do you pick the right chain type?

Ask two questions in order. Does the text fit the context window, and does chunk order matter?

Decision flow that picks stuff when the text fits the context window, map reduce when it does not and chunk order does not matter, and refine when order matters
  1. If the text fits the context window with room to spare, use stuff.
  2. If it does not fit and chunks are independent, use map reduce. It is parallel and fast.
  3. If it does not fit and order matters, use refine, and accept the latency.

map_rerank does not belong in this list. It scores answers to a question chunk by chunk and keeps the best one, so it is a QA strategy, not a summarizer.

What chain type should you use for RAG summarization?

For RAG, use stuff with the retrieved chunks, often after a quote extraction step. RAG summarization means retrieving the top k chunks for a query and writing one answer from them, which is a different job from summarizing one long document.

Retrieve the top chunks, ask the model to pull out the exact quotes that answer the query, then write the answer from those quotes in one call. Anthropic’s prompting guide recommends quoting relevant parts first for long document tasks. You get the coherence of stuff, fewer tokens in the final call, and none of map reduce’s boundary loss.

If the retrieved chunks are too large even for stuff, the retriever is usually returning too many. Tune k first, as in tuning retriever top-k on your own data. To check that each sentence of the answer is supported by the chunks, add a fact-checking pass for RAG answers.

What to do next

  1. Search your code for chain_type=, load_summarize_chain and load_qa_chain. Note which chain type each call uses.
  2. Move those imports to langchain_classic, or plan to replace them with LangGraph.
  3. Count the tokens of the real inputs each call receives. Switch to stuff wherever they fit with room to spare.
  4. For inputs that overflow, choose map reduce if chunks are independent and refine if order matters.
  5. For RAG answers, replace per-chunk summarization with quote extraction plus one stuff call.
  6. Track cost and latency per chain in your tracing stack, as in Langfuse and Grafana monitoring.

Frequently asked questions

What is the difference between stuff, map_reduce and refine in LangChain?

stuff sends every chunk in one LLM call. map_reduce summarizes each chunk in parallel and then combines the summaries. refine walks the chunks in order and updates a running summary each step. Stuff is cheapest and most coherent but limited by the context window. Map reduce is fast but can lose cross-chunk ideas. Refine keeps order at the cost of latency.

Is load_summarize_chain deprecated in LangChain 1.0?

It still works, but it moved. In LangChain 1.x, load_summarize_chain lives in the langchain-classic package, imported from langchain_classic.chains.summarize. It accepts stuff, map_reduce and refine. For new map reduce code, LangGraph’s Send API is the current pattern. The related load_qa_chain is formally deprecated and points to create_agent with a retrieval tool.

How do you do map reduce summarization in LangGraph?

Define a state with a list of chunks and a summaries list that uses operator.add as its reducer. A conditional edge from START returns one Send per chunk to a map node, which returns its summary. The summaries merge into shared state, and an edge to a reduce node combines them into the final summary. LangGraph runs the map nodes in parallel.

When should I use map_reduce instead of stuff?

Use map reduce when the input is larger than the model’s context window, or when you have many independent documents to summarize at once. The map calls run in parallel, so latency stays low even for large inputs. The trade-off is that ideas spanning chunk boundaries can be lost. If the text fits the context window, stuff is cheaper and more coherent.

What does map_rerank do in LangChain?

map_rerank is a question-answering chain type in load_qa_chain, not a summarizer. It asks the question against each chunk separately, has the model score its own answer, and returns the highest scoring one. It suits questions whose answer sits in a single chunk. load_qa_chain is deprecated, and LangChain recommends an agent with a retrieval tool for new RAG code.

Sources

Subscribe to Top 1% Engineers

One issue at a time on building AI systems that hold up in production: architecture, the open source that matters, and what to do on Monday. Every number cited.

We email you each new issue. You can leave at any time. Privacy

More guides

See the newsletter and every guide