How to Use `needle.extract()` for Typed Pydantic Results: A Complete Guide
needle.extract() is a one-shot helper that performs structured extraction from unstructured text and returns a strongly-typed Pydantic model or plain dictionary.
The needle library provides this convenience function to eliminate boilerplate when you need to parse free-form text into typed data structures. Instead of manually configuring agents and tools, you define a schema and receive parsed results in a single call.
The extract() Function Signature
The public API is defined in [needle/__init__.py](https://github.com/cactus-compute/needle/blob/main/needle/__init__.py) at line 79:
def extract(
text: str,
schema,
system: str | None = None,
max_new_tokens: int = 256,
weights: str | None = None
):
text– The unstructured input to parse.schema– A PydanticBaseModelsubclass or dictionary defining the expected structure.system– Optional system prompt to customize LLM behavior.max_new_tokens– Generation limit (default 256).weights– Optional path to custom model weights.
How extract() Works Under the Hood
The implementation follows a clear five-step workflow as seen in the source code:
- Agent initialization – A temporary
Needleagent is created withtools=[schema]as the sole tool (line 86). - Engine setup – The shared engine is re-initialized with this tool configuration, loading custom weights if provided or falling back to globally active weights (line 85).
- LLM inference – Input text is sent through the private
_completemethod (line 87), located in [needle/model/run.py](https://github.com/cactus-compute/needle/blob/main/needle/model/run.py). - Function-call parsing – The response is inspected for
function_callsentries (lines 88-90). If absent, the function returnsNone. - Typed return – Arguments from the first function call are unpacked. If
schemais a Pydantic model (_is_pydantic_model(schema)returnsTrue), the function returnsschema(**arguments); otherwise it returns the raw dictionary (lines 91-92).
This design makes extract() safe for repeated calls without manual agent lifecycle management.
Extracting into Pydantic Models
The primary use case for needle.extract() is obtaining type-safe results. Define your schema with Pydantic and receive a validated model instance:
from pydantic import BaseModel
from needle import extract
class WeatherReport(BaseModel):
location: str
temperature_c: float
condition: str
text = "The weather in Berlin is 22.5°C and sunny."
result = extract(text, WeatherReport)
print(result) # → WeatherReport(location='Berlin', temperature_c=22.5, condition='sunny')
print(result.dict()) # → {'location': 'Berlin', 'temperature_c': 22.5, 'condition': 'sunny'}
The returned object is a full Pydantic instance—you get IDE autocomplete, validation, and serialization methods like .dict(), .json(), and .model_dump().
Extracting into Plain Dictionaries
For quick prototyping or dynamic schemas, pass a dictionary instead of a Pydantic class:
from needle import extract
schema = {
"name": "str",
"age": "int",
"email": "str"
}
text = "John Doe is 30 years old, email john@example.com."
result = extract(text, schema)
print(result) # → {'name': 'John Doe', 'age': 30, 'email': 'john@example.com'}
Note that dictionary schemas return raw Python dictionaries without Pydantic validation—they're convenient but lack type safety.
Customizing System Prompts and Weights
Fine-tune extraction behavior with the optional parameters:
from needle import extract
custom_prompt = "You are a helpful assistant that extracts contact info."
result = extract(
"Contact: Alice, 28, alice@domain.com",
schema={"name": "str", "age": "int", "email": "str"},
system=custom_prompt,
weights="my-special-weights"
)
print(result)
The system prompt guides the LLM's extraction strategy, while weights loads a specific model checkpoint. If omitted, weights defaults to whatever is globally active in the needle runtime.
Engine Re-initialization and Thread Safety
A key implementation detail in needle/__init__.py is that extract() re-initializes the shared engine on each call. According to the cactus-compute/needle source code, this ensures:
- Isolation – Each extraction uses a fresh tool configuration without polluting global state.
- Reusability – No manual cleanup between calls with different schemas.
- Weight flexibility – Per-call weight overrides without permanent model swapping.
For production throughput, consider reusing a persistent Needle agent if latency is critical—extract() trades marginal overhead for convenience.
Summary
needle.extract()provides one-shot structured extraction with minimal setup.- Returns Pydantic models for
BaseModelschemas, dictionaries for plain dict schemas. - Internally creates a temporary
Needleagent with the schema as the sole tool. - Located in
needle/__init__.pywith low-level calls throughneedle/model/run.pyandneedle/model/architecture.py. - Supports customization via
systemprompts andweightsoverrides.
Frequently Asked Questions
What happens if the LLM doesn't return a valid function call?
extract() returns None. Lines 88-90 in needle/__init__.py explicitly check for function_calls in the response and short-circuit to None when absent.
Can I use extract() with nested Pydantic models?
Yes. The _is_pydantic_model() check recursively validates nested structures, and the unpacking logic at lines 91-92 passes all extracted arguments to your model's constructor, including nested BaseModel fields.
Is there a performance penalty for calling extract() repeatedly?
Marginal. Each call re-initializes the engine (line 86), which adds setup overhead. For high-throughput applications, instantiate a persistent Needle agent directly instead of using this helper.
How does extract() handle type coercion?
Pydantic handles coercion automatically when schema(**arguments) is called. The raw LLM outputs (typically JSON-like structures) are passed as keyword arguments, and Pydantic's validation layer converts strings to numbers, parses dates, or enforces constraints according to your field definitions.
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 →