# How to Integrate Pydantic Models for Structured Extraction with Needle

> Learn to integrate Pydantic models with Needle for structured data extraction. Needle automatically converts type hints to JSON Schema for LLMs, enabling type-safe extraction.

- Repository: [Cactus Compute, Inc./needle](https://github.com/cactus-compute/needle)
- Tags: how-to-guide
- Published: 2026-09-04

---

**Needle automatically converts Pydantic BaseModel type hints into JSON Schema definitions that LLMs use to return structured data, enabling type-safe extraction without manual schema engineering.**

When you integrate Pydantic models for structured extraction with Needle, you eliminate the need to manually write JSON schemas for LLM function calling. The framework introspects your Python type annotations at runtime, generates compliant schemas, and handles deserialization automatically. This gives you both the flexibility of natural language interfaces and the safety of Pydantic validation.

## Detecting Pydantic Models via `_is_pydantic_model`

Needle identifies Pydantic models through the `_is_pydantic_model` utility in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py). This function inspects a class's Method Resolution Order (MRO) to verify inheritance from `pydantic.BaseModel`.

According to the source code, the detection mechanism walks the class hierarchy and checks the module name to confirm the object is a genuine Pydantic model rather than a similar-looking class. This check triggers the schema conversion pipeline whenever Needle encounters a type hint that inherits from BaseModel.

## Converting Models to JSON Schema with `pydantic_schema`

Once Needle detects a Pydantic model, it invokes the `pydantic_schema` function (located at [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py)) to extract the schema. This utility calls `model.model_json_schema()` for Pydantic v2 compatibility, falling back to the legacy `model.schema()` method for older versions.

The function then reshapes the raw Pydantic schema into Needle's tool format, extracting the `name`, `parameters`, and optional description fields. This transformation ensures the output conforms to the JSON Schema specification required by LLM providers while preserving all validation constraints defined in your Pydantic model.

## Integrating Schemas into Tool Definitions

The `build_schema` function coordinates the final integration. While walking a function's type hints via `_json_type`, Needle delegates Pydantic model processing to `pydantic_schema`. The resulting schema becomes part of the tool's `parameters` object.

When you decorate a function with `@tool`, Needle stores the complete generated schema on the function as the `_needle_tool` attribute. At runtime, this metadata is exposed to the LLM as a standard tool definition:

```json
{
  "name": "my_tool",
  "description": "...",
  "parameters": {
    "type": "object",
    "properties": {
      "payload": { "type": "object", "properties": { ... } }
    },
    "required": ["payload"]
  }
}

```

## Complete Implementation Example

This example demonstrates the full pipeline from model definition to structured extraction:

```python
from pydantic import BaseModel, Field
from needle import tool, Needle

# 1️⃣ Define the extraction schema

class WeatherQuery(BaseModel):
    """Ask for the weather in a specific city."""
    city: str = Field(..., description="Name of the city")
    units: str = Field("metric", description="Metric or imperial")

# 2️⃣ Register the tool with Needle

@tool
def get_weather(request: WeatherQuery) -> str:
    """Fetch weather info."""
    return f"Weather for {request.city} ({request.units}) is 23°C"

# 3️⃣ Execute through Needle's inference loop

needle = Needle()
response = needle.run("What's the weather in Berlin?")
print(response)  # → "Weather for Berlin (metric) is 23°C"

```

Under the hood, `build_schema` detects the `WeatherQuery` annotation and calls `pydantic_schema` to generate the JSON schema. When the LLM returns a JSON object matching that schema, Needle deserializes it into a `WeatherQuery` instance before passing it to your function.

## Key Source Files

The Pydantic integration spans three critical locations in the repository:

- **[`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py)** – Contains `_is_pydantic_model`, `pydantic_schema`, and `build_schema`, which form the complete conversion pipeline.
- **[`needle/__init__.py`](https://github.com/cactus-compute/needle/blob/main/needle/__init__.py)** – Re-exports `tool` and `Field` so users can import them directly via `from needle import tool, Field`.
- **[`tests/test_tools.py`](https://github.com/cactus-compute/needle/blob/main/tests/test_tools.py)** – Houses the test suite including `test_pydantic_model_schema`, which validates the schema generation logic against reference Pydantic models.

## Summary

- **Automatic Detection**: Needle's `_is_pydantic_model` function in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) identifies Pydantic BaseModel subclasses by inspecting the class MRO.
- **Schema Generation**: The `pydantic_schema` utility extracts JSON schemas using Pydantic's native `model_json_schema()` or `schema()` methods.
- **Runtime Binding**: Tool schemas are stored in the `_needle_tool` function attribute, making them available to the LLM at inference time.
- **Type Safety**: Incoming LLM responses are automatically parsed into Pydantic model instances before your function executes, providing validation and IDE support.

## Frequently Asked Questions

### How does Needle determine if a type hint is a Pydantic model?

Needle uses the `_is_pydantic_model` function located in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py). This utility walks the class's Method Resolution Order (MRO) and checks if any parent class originates from the `pydantic` module, confirming legitimate BaseModel inheritance.

### Which Pydantic schema generation methods does Needle support?

The `pydantic_schema` function in [`needle/agent/tools.py`](https://github.com/cactus-compute/needle/blob/main/needle/agent/tools.py) attempts to call `model.model_json_schema()` first for Pydantic v2 compatibility, then falls back to `model.schema()` for legacy v1 installations. This dual support ensures broad version compatibility.

### Where does Needle store the generated tool schema?

When you apply the `@tool` decorator, Needle attaches the complete JSON schema to your function as the `_needle_tool` attribute. This metadata dictionary includes the tool name, description, and parameters derived from your Pydantic models.

### Can I use Pydantic Field descriptions in my extraction schemas?

Yes. When `pydantic_schema` processes your model, it preserves Field-level metadata including descriptions and constraints. These become part of the JSON Schema's `description` fields and validation rules, helping the LLM understand the expected data format.