Can Pydantic Models Be Used Directly as Extraction Schemas in Needle?

Yes, Needle treats Pydantic models as first-class extraction schemas, automatically converting them to OpenAI-compatible JSON schemas for LLM tool extraction.

The cactus-compute/needle library eliminates manual schema writing by detecting pydantic.BaseModel subclasses and generating proper extraction schemas at runtime. This native integration means you can define structured data requirements using Pydantic's familiar syntax, then pass models directly as function type hints for automatic schema generation.

How Needle Detects Pydantic Models

Needle's schema building pipeline includes explicit Pydantic detection in needle/agent/tools.py. The _is_pydantic_model function (lines 45-48) identifies when a parameter annotation inherits from pydantic.BaseModel:


# From needle/agent/tools.py (lines 45-48)

def _is_pydantic_model(annotation) -> bool:
    """Check if an annotation is a Pydantic model."""
    return isinstance(annotation, type) and issubclass(annotation, pydantic.BaseModel)

Once detected, the model conversion flows through pydantic_schema (lines 51-61), which extracts field definitions, types, defaults, and descriptions into standard JSON Schema format.

Complete Working Example

Here's how to use a Pydantic model directly as an extraction schema in a Needle tool:


# example.py

import pydantic
from needle import tool

# Step 1: Define your data model

class Weather(pydantic.BaseModel):
    """Current weather conditions."""
    location: str              # Required field

    temperature_c: float      # Required numeric field

    description: str = "clear"  # Optional with default

# Step 2: Use the model as a direct type hint

@tool
def get_weather(info: Weather) -> str:
    """Retrieve a weather report based on the provided info."""
    return f"The weather in {info.location} is {info.temperature_c}°C and {info.description}."

# Step 3: Needle generates the extraction schema automatically

The resulting schema from build_schema(get_weather) produces:

{
    "name": "get_weather",
    "description": "Retrieve a weather report based on the provided info.",
    "parameters": {
        "type": "object",
        "properties": {
            "info": {
                "type": "object",
                "properties": {
                    "location": {"type": "string"},
                    "temperature_c": {"type": "number"},
                    "description": {"type": "string", "default": "clear"}
                },
                "required": ["location", "temperature_c"]
            }
        },
        "required": ["info"]
    }
}

Schema Generation Pipeline

The conversion happens in three stages inside needle/agent/tools.py:

  1. build_schema (lines 11-42) — Entry point that processes function signatures and docstrings
  2. _json_type (lines 68-70) — Dispatches to pydantic_schema when _is_pydantic_model returns True
  3. pydantic_schema (lines 51-61) — Converts Pydantic fields to JSON Schema properties, handling:
    • Type mappings (str→string, float→number, etc.)
    • Required vs. optional fields
    • Default values
    • Field descriptions from docstrings

Nested Models and Complex Structures

Pydantic models with nested structures work automatically. Needle recursively processes compound types:

from typing import List
from needle import tool
import pydantic

class Address(pydantic.BaseModel):
    street: str
    city: str

class Person(pydantic.BaseModel):
    name: str
    addresses: List[Address]  # Nested model in a list

@tool
def register_person(data: Person) -> str:
    """Register a person with their addresses."""
    return f"Registered {data.name} with {len(data.addresses)} addresses"

The generated schema includes the full nested Address definition under data.properties.addresses.items.

Validation and Testing

The Needle repository includes comprehensive tests confirming Pydantic schema functionality:

Summary

  • Direct type hint usage — Annotate function parameters with pydantic.BaseModel subclasses
  • Automatic detection — Needle's _is_pydantic_model identifies Pydantic classes at runtime
  • Full schema generationpydantic_schema converts models to OpenAI-compatible JSON Schema
  • Nested support — Complex models with nested structures and collections work without additional configuration

Frequently Asked Questions

Does Needle support Pydantic v2 models?

Yes, Needle's pydantic_schema function (lines 51-61 in needle/agent/tools.py) uses Pydantic's core schema generation APIs that work with both Pydantic v1 and v2. The validation logic in tests/test_tools.py confirms compatibility across versions.

What happens if a Pydantic model has validation rules?

Needle extracts the type structure and field metadata, but does not embed Pydantic validation rules (like Field(gt=0)) into the JSON Schema sent to the LLM. The returned data is validated when Pydantic instantiates the model, so invalid values raise pydantic.ValidationError at runtime.

Can I use standard Python types instead of Pydantic?

Yes. Needle's _json_type handles both standard types (str, int, float, bool, list, dict) and Pydantic models. Standard types map directly to JSON Schema primitives, while Pydantic models trigger the full conversion pipeline for structured data extraction.

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 →