How `extraction_passes` Improves Recall in LangExtract: Multi-Pass Extraction Explained
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, the extract function forwards the user-supplied extraction_passes value to the annotator at lines 55-61:
# 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 (lines 442-470). This function implements the following logic:
- Loop over passes: The function iterates from
0toextraction_passes - 1(lines 57-60), executing a full single-pass annotation for each iteration. - Collect extractions: Each pass generates its own set of extractions per document.
- Merge results: After all passes complete, the system merges the per-pass extraction lists using
_merge_non_overlapping_extractions.
Implementation in annotation.py
The branching logic between single-pass and multi-pass modes occurs at lines 55-70 in langextract/annotation.py:
# 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 (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.
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 (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:
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_passescontrols 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, 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 (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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →