How to Use `needle.extract()` for One-Shot Structured Extraction in Python
needle.extract() is a convenience function that performs single-call structured data extraction from text using a Pydantic model or dictionary schema, without requiring a full agent-tool loop.
The needle library provides a lightweight way to extract structured information from unstructured text using local LLMs. The extract() function in needle/__init__.py offers the fastest path from raw text to typed data—ideal for one-shot extraction tasks where you need exactly one structured result.
What needle.extract() Does Under the Hood
The function orchestrates four steps to hide boilerplate from you:
- Creates a transient
Needleagent with your schema as the sole tool - Executes a completion against the compiled engine
- Extracts the first function call from the LLM response
- Returns a typed result (Pydantic instance or dictionary)
According to the cactus-compute/needle source code, the implementation spans lines 49-79 of needle/__init__.py:
def extract(text, schema, *, system=None, weights=None, max_new_tokens=256):
# lines 49-53: Build single-tool agent
agent = Needle(tools=[schema], system=system, weights=weights or _active_weights)
# lines 73-74: Run completion
response = agent.complete(text, max_new_tokens)
# lines 74-78: Parse first function call
calls = response.get("function_calls") or []
if not calls:
return None
arguments = calls[0].get("arguments") or {}
# lines 78-79: Return typed or raw result
return schema(**arguments) if _is_pydantic_model(schema) else arguments
This design means you never manually instantiate Needle, register tools, or parse function_calls yourself.
Method 1: Extract with a Pydantic Model (Type-Safe)
For production code, pass a Pydantic BaseModel as your schema. needle.extract() validates and instantiates the model automatically.
from pydantic import BaseModel
import needle
class Order(BaseModel):
product: str
quantity: int
price: float
text = "I would like to buy 3 notebooks for $7.50 each."
order = needle.extract(text, Order)
print(order)
# → Order(product='notebooks', quantity=3, price=7.5)
The function detects Pydantic models via _is_pydantic_model(schema) and calls schema(**arguments) to construct your typed object.
Method 2: Extract with a Dictionary Schema (Quick & Ad-Hoc)
For prototyping or dynamic schemas, use a plain dictionary with type hints as strings.
import needle
schema = {
"name": "str",
"age": "int",
"city": "str"
}
bio = "Alice is 29 years old and lives in Berlin."
result = needle.extract(bio, schema)
print(result)
# → {'name': 'Alice', 'age': 29, 'city': 'Berlin'}
Dictionary schemas skip Pydantic validation and return raw dictionaries, making them ideal for exploratory extraction.
Method 3: Customize System Prompt and Token Budget
Control extraction behavior with optional keyword arguments:
| Parameter | Purpose | Default |
|---|---|---|
system |
Custom system prompt for the LLM | None |
weights |
Specific model weights to load | _active_weights (global) |
max_new_tokens |
Hard limit on completion length | 256 |
import needle
custom_system = "You are an expert data parser. Extract the fields exactly as requested."
text = "Invoice #12345: total $250, due 2024-09-15."
invoice = needle.extract(
text,
{"invoice_id": "str", "total": "float", "due_date": "str"},
system=custom_system,
max_new_tokens=128
)
print(invoice)
# → {'invoice_id': '12345', 'total': 250.0, 'due_date': '2024-09-15'}
The system prompt shapes how the LLM interprets your extraction task—use it to enforce format constraints or domain expertise.
Weight Handling and Performance Notes
When you omit weights, needle.extract() reuses the globally active weights (_active_weights). This matters for performance: the underlying compiled engine cannot unload weights, so consecutive calls with different schemas re-initialize the engine but keep the model resident in memory.
From needle/model/architecture.py, this weight management ensures you don't pay full load costs on repeated extractions.
For single extractions with a fresh model, pass explicit weights to trigger a new load.
Summary
needle.extract()wraps agent creation, tool binding, and call parsing into one function- Accepts Pydantic models (typed results) or dictionaries (raw results) as schemas
- Returns
Nonewhen the LLM produces nofunction_calls - Reuses global weights by default; customize via the
weightsparameter - Implemented in
needle/__init__.pylines 49-79, with completion logic inneedle/model/run.py
Frequently Asked Questions
What happens if the LLM doesn't return any function calls?
needle.extract() returns None. The source checks response.get("function_calls") or [] and exits early when the list is empty (lines 74-76 of needle/__init__.py). This occurs when the model fails to generate a structured extraction for your input.
Can I use needle.extract() with multiple extraction schemas at once?
No. The function is designed for one-shot extraction with a single schema. Internally it constructs a Needle agent with tools=[schema]—only one tool. For multi-schema extraction, instantiate Needle directly and register multiple tools.
How does needle.extract() handle type conversion?
Type conversion depends on your schema format. With Pydantic models, Pydantic's own validation coerces values (e.g., "7.50" → 7.5). With dictionary schemas, the underlying LLM engine performs extraction and the raw arguments are returned—types match what the engine produces, typically JSON-compatible primitives.
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 →