# How `extraction_passes` Improves Recall in LangExtract: Multi-Pass Extraction Explained

> Learn how LangExtract's extraction_passes improve recall. Discover sequential multi-pass extraction for better entity identification and higher accuracy with Google's LangExtract.

- Repository: [Google/langextract](https://github.com/google/langextract)
- Tags: deep-dive
- Published: 2026-02-16

---

**Setting `extraction_passes` to a value greater than 1 enables sequential multi-pass extraction in LangExtract, allowing the language model multiple opportunities to identify entities missed in previous passes, thereby significantly improving recall.**

LangExtract is an open-source Python library from Google that extracts structured data from unstructured text using large language models. The `extraction_passes` parameter is a critical configuration option that controls how many times the pipeline reprocesses your documents, directly impacting the completeness of extracted entities.

## What Is `extraction_passes` in LangExtract?

The `extraction_passes` parameter controls a **sequential multi-pass extraction mode**. When set to the default value of `1`, LangExtract runs a single-pass extraction. When set to any integer greater than `1`, the pipeline runs the document through the language model multiple times, re-tokenizing the text and issuing fresh prompts for each pass.

In [`langextract/extraction.py`](https://github.com/google/langextract/blob/main/langextract/extraction.py), the `extract` function forwards the user-supplied `extraction_passes` value to the annotator at lines 55-61:

```python

# From langextract/extraction.py

annotated_documents = annotate_documents(
    documents=documents,
    prompt_description=prompt_description,
    examples=examples,
    extraction_passes=extraction_passes,  # Parameter forwarded here

    # ... other parameters

)

```

## How Sequential Multi-Pass Extraction Works

### The Core Mechanism

When `extraction_passes` is greater than 1, LangExtract invokes `_annotate_documents_sequential_passes` in [`langextract/annotation.py`](https://github.com/google/langextract/blob/main/langextract/annotation.py) (lines 442-470). This function implements the following logic:

1. **Loop over passes**: The function iterates from `0` to `extraction_passes - 1` (lines 57-60), executing a full single-pass annotation for each iteration.
2. **Collect extractions**: Each pass generates its own set of extractions per document.
3. **Merge results**: After all passes complete, the system merges the per-pass extraction lists using `_merge_non_overlapping_extractions`.

### Implementation in [`annotation.py`](https://github.com/google/langextract/blob/main/annotation.py)

The branching logic between single-pass and multi-pass modes occurs at lines 55-70 in [`langextract/annotation.py`](https://github.com/google/langextract/blob/main/langextract/annotation.py):

```python

# From langextract/annotation.py

if extraction_passes == 1:
    return _annotate_documents_single_pass(
        documents, prompt_description, examples, ...
    )
else:
    return _annotate_documents_sequential_passes(
        documents, prompt_description, examples, 
        extraction_passes, ...
    )

```

## Why Multiple Passes Improve Recall

### Overcoming Token Window Constraints

Language models have finite context windows. In a single pass, the model may overlook entities located at chunk boundaries or buried in lengthy documents due to prompt length limits. By reprocessing the text in subsequent passes—potentially with different chunking offsets or after earlier extractions have been conceptually "removed" from consideration—the model gets fresh opportunities to spot missed items.

### Context Reinterpretation

Each pass re-tokenizes the text and issues fresh prompts. The language model's attention mechanism may focus on different contextual clues in subsequent iterations. For example, if the first pass identifies "Alice Smith" and "Bob Johnson," the second pass might better recognize that "Carol"—mentioned later as "Alice's assistant"—is also a person entity worth extracting.

## Merging Results Across Passes

The critical component that enables safe multi-pass extraction without duplication is `_merge_non_overlapping_extractions` in [`langextract/annotation.py`](https://github.com/google/langextract/blob/main/langextract/annotation.py) (lines 46-62). This function implements a **first-pass-wins** strategy:

- It compares extraction intervals (character spans) from all passes.
- When intervals overlap, it retains the extraction from the earliest pass (considered the most reliable).
- It appends only non-overlapping extractions from later passes.

The final merged list is emitted as the result at lines 99-105 in [`langextract/annotation.py`](https://github.com/google/langextract/blob/main/langextract/annotation.py).

## Performance and Cost Trade-offs

Each additional pass **reprocesses all tokens**, meaning the number of API calls grows roughly linearly with the `extraction_passes` value. As noted in [`langextract/extraction.py`](https://github.com/google/langextract/blob/main/langextract/extraction.py) (lines 84-90), users should balance the recall boost against:

- **Increased latency**: Each pass requires a full inference cycle.
- **Higher token costs**: Total token consumption multiplies by the number of passes.
- **Diminishing returns**: After 3-4 passes, the marginal gain in recall typically decreases.

## Practical Implementation Example

The following example demonstrates how increasing `extraction_passes` can capture entities missed in a single pass:

```python
from langextract import extract, schema

# Define extraction schema and examples

prompt = "Extract all person names from the text."
examples = [
    schema.Example(
        text="Contact Sarah Connor for details.",
        extractions=[schema.Extraction(label="person", text="Sarah Connor", start=8, end=19)]
    )
]

text = """
Dr. Alice Smith and Bob Johnson attended the meeting. Later, 
the secretary mentioned that Alice's assistant, Carol, was missing.
"""

# Single-pass extraction (default)

result_one = extract(
    text,
    prompt_description=prompt,
    examples=examples,
    extraction_passes=1,
)

print("Single-pass entities:", [e.text for e in result_one[0].extractions])

# Output often misses: ['Alice Smith', 'Bob Johnson']

# Multi-pass extraction with 3 passes

result_multi = extract(
    text,
    prompt_description=prompt,
    examples=examples,
    extraction_passes=3,
)

print("Multi-pass entities:", [e.text for e in result_multi[0].extractions])

# Output often includes: ['Alice Smith', 'Bob Johnson', 'Carol']

```

In this example, the multi-pass configuration frequently captures **"Carol"**—a secondary entity that the single-pass approach often overlooks due to contextual ambiguity or attention distribution.

## Summary

- **`extraction_passes`** controls sequential multi-pass extraction in LangExtract, running the language model multiple times over the same document.
- **Recall improvement** occurs because each pass provides a fresh opportunity to identify entities missed due to token limits, chunk boundaries, or contextual ambiguity.
- **Implementation** resides in [`langextract/annotation.py`](https://github.com/google/langextract/blob/main/langextract/annotation.py), specifically in `_annotate_documents_sequential_passes` (lines 442-470) and `_merge_non_overlapping_extractions` (lines 46-62).
- **First-pass-wins merging** prevents duplication by prioritizing extractions from earlier passes when intervals overlap.
- **Cost scales linearly** with the number of passes, requiring users to balance recall gains against API costs and latency.

## Frequently Asked Questions

### What is the default value of `extraction_passes` in LangExtract?

The default value is `1`, which executes a single-pass extraction. This provides the fastest processing and lowest API cost but may miss entities that require multiple contextual interpretations to identify correctly.

### How does LangExtract handle duplicate entities across multiple passes?

LangExtract uses the `_merge_non_overlapping_extractions` function in [`langextract/annotation.py`](https://github.com/google/langextract/blob/main/langextract/annotation.py) (lines 46-62) to implement a first-pass-wins strategy. When extraction intervals overlap between passes, the system retains the entity from the earliest pass and discards duplicates from later passes, ensuring clean, non-redundant results.

### Does increasing `extraction_passes` always improve recall?

While additional passes generally improve recall by providing more opportunities to identify missed entities, the returns diminish after 3-4 passes. Additionally, because LangExtract reprocesses all tokens in each pass, higher values linearly increase API costs and latency, making it important to test the optimal pass count for your specific document types and extraction schemas.

### Where is the multi-pass logic implemented in the LangExtract source code?

The multi-pass orchestration resides in [`langextract/annotation.py`](https://github.com/google/langextract/blob/main/langextract/annotation.py) within the `_annotate_documents_sequential_passes` function (lines 442-470). This function loops through the requested number of passes, calls the single-pass annotator for each iteration, and then merges results. The branching logic that decides between single-pass and multi-pass modes appears at lines 55-70 in the same file.