How to Use Needle 2 for Structured Data Extraction: A Complete Guide

Needle 2 is a 45M-parameter on-device model that converts free-form text into JSON-structured tool calls using a schema-driven extraction pipeline with built-in validation.

Needle 2 from cactus-compute/needle provides on-device structured data extraction through a compact 45 million parameter architecture. This guide demonstrates how to leverage the extract() API to transform unstructured text into validated JSON outputs using either Pydantic models or raw JSON schemas according to the source implementation.

Understanding the Needle 2 Extraction Pipeline

The extraction workflow centers on needle/__init__.py, which orchestrates the conversion of free-form text into structured data through three distinct phases.

The Core Architecture

When you invoke needle.extract(), the library creates a temporary Needle agent that wraps your target schema as a single tool definition. According to the source code in needle/__init__.py (lines 30-55), this agent prepares the schema for ingestion by the native inference engine.

The agent then calls the native inference engine (libneedle.so) via agent._complete() (lines 61-73), which returns a JSON envelope containing a function_calls list. The first call's arguments field contains your extracted data structure.

Engine Selection and Loading

Needle 2 automatically selects the appropriate inference engine based on available resources. The _weight_generation() function reads a four-byte tag from any provided .cact weight file to determine whether to use the Needle 2 or Needle 3 engine (lines 29-38). When no weights are specified, the system loads the default generation 2 engine from a cached Hugging-Face binary (lines 43-73).

Implementing Structured Data Extraction

The practical implementation follows a three-step workflow: schema definition, invocation, and validation.

Defining Your Schema with Pydantic

The most robust approach uses Pydantic models to define expected data structures. The build_schema utilities in needle/agent/tools.py handle the conversion from Pydantic BaseModel classes to JSON schema definitions automatically.

import needle
from pydantic import BaseModel

# Define the expected structure

class Invoice(BaseModel):
    vendor: str
    total: float
    due_date: str  # ISO-8601 date string

# Run extraction on a free-form sentence

text = "Invoice from Acme Corp, $1,200.00, due 2026-09-01"
invoice = needle.extract(text, Invoice)  # strict mode (default)

print(invoice.vendor)   # → Acme Corp

print(invoice.total)    # → 1200.0

print(invoice.due_date) # → 2026-09-01

Running the Extraction

When processing text, the extract() function handles the complete pipeline from text parsing to object instantiation. If you provide a Pydantic model as the schema parameter, the raw dictionary is automatically instantiated as a typed object; otherwise, the function returns the raw dictionary (lines 52-55).


# Using a raw JSON schema instead of Pydantic

schema = {
    "type": "object",
    "properties": {
        "city": {"type": "string"},
        "temp_c": {"type": "number"},
        "sky": {"type": "string"},
    },
    "required": ["city", "temp_c", "sky"],
}
weather = needle.extract("Weather in Paris: 18°C, partly cloudy.", schema)
print(weather)  # {'city': 'Paris', 'temp_c': 18, 'sky': 'partly cloudy'}

Validation and Strict Mode

By default, Needle 2 operates in strict mode (strict=True), which pipes results through _validate_extraction() (lines 15-27). This verification ensures that temporal values such as dates and years are grounded in the original source text and that the engine has not fabricated or negated values. If validation fails, the library raises ExtractionValidationError.

To disable strict validation and receive raw JSON even when validation fails, set strict=False:

invoice_raw = needle.extract(text, Invoice, strict=False)
print(invoice_raw)  # {'vendor': 'Acme Corp', 'total': 1200.0, 'due_date': '2026-09-01'}

Summary

  • Needle 2 uses a 45M-parameter on-device model to generate JSON-structured tool calls from unstructured text via libneedle.so
  • The extract() function in needle/__init__.py orchestrates the complete pipeline from schema wrapping to validation
  • Engine selection occurs automatically through _weight_generation() based on .cact file tags or defaults to the Hugging-Face cached generation 2 engine
  • Strict mode validates temporal grounding and prevents hallucination by default, throwing ExtractionValidationError on validation failures
  • Both Pydantic models and raw JSON schemas are supported as extraction targets, with automatic type instantiation for Pydantic inputs

Frequently Asked Questions

What makes Needle 2 different from other extraction libraries?

Unlike cloud-dependent solutions, Needle 2 operates entirely on-device through a compact 45 million parameter architecture. It produces structured JSON tool calls rather than raw text completions, and includes built-in validation in needle/__init__.py to ensure extracted values are grounded in source material rather than hallucinated.

How does strict validation work in Needle 2?

When strict=True (the default), the library passes extracted results through _validate_extraction() in needle/__init__.py (lines 15-27). This function specifically checks that temporal values like dates and years exist in the original input text, ensuring the model hasn't fabricated information. If validation fails, the library raises an ExtractionValidationError rather than returning invalid data.

Can I use Needle 2 without Pydantic models?

Yes. While Pydantic BaseModel classes provide the best developer experience with automatic type conversion via needle/agent/tools.py, you can pass raw JSON schema dictionaries directly to needle.extract(). The library will return a raw Python dictionary instead of a typed object when using this approach.

What happens when no weight files are provided?

If you don't specify a .cact weight file, Needle 2 automatically loads the default generation 2 engine from a cached Hugging-Face binary. The _weight_generation() function handles this fallback logic in needle/__init__.py (lines 43-73), ensuring the extraction pipeline works immediately after installation without manual model downloads.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →