Using Pydantic BaseModel as Tools in Needle 2: First-Class Integration

Needle 2 treats Pydantic BaseModel classes as first-class tools, automatically converting model definitions into OpenAI-compatible JSON schemas without requiring wrapper functions or the @tool decorator.

The cactus-compute/needle agent framework eliminates boilerplate when integrating structured data models with LLM tool-calling capabilities. By passing a Pydantic model class directly to the Needle constructor, the engine introspects the model's fields, types, and docstrings to generate compliant tool schemas on the fly.

How Needle 2 Registers Pydantic BaseModel as Tools

When you include a Pydantic model in the tools list, Needle's internal resolution pipeline handles the conversion through three distinct phases defined in the source code.

Model Detection via _is_pydantic_model

In needle/agent/tools.py (lines 49-53), the _is_pydantic_model helper inspects candidate classes to determine if they inherit from Pydantic's BaseModel. This check enables Needle to distinguish between standard Python callables and data models that require schema extraction rather than function registration.

Schema Generation with pydantic_schema

Once detected, the pydantic_schema function (lines 55-66 of needle/agent/tools.py) generates the JSON Schema representation. This process maps Pydantic field types to OpenAI-compatible parameter types, ensuring the LLM receives properly structured function definitions with accurate type constraints.

Tool Registration and Instance Construction

The _resolve method in needle/__init__.py (lines 100-110) registers the generated schema under the model's class name. When the LLM invokes the tool, the extract function (lines 81-93 of needle/__init__.py) constructs an instance of the model by passing the LLM-supplied arguments directly to the Pydantic constructor.

Practical Implementation Examples

You can integrate Pydantic models into your agent workflows using three distinct patterns supported by the Needle 2 architecture.

Basic Model Definition

Define your data structure with field types and docstrings. According to the source implementation, the docstring becomes the tool's description, while field annotations define the parameter schema:


# models.py

import pydantic

class Weather(pydantic.BaseModel):
    """Query for weather information."""
    city: str
    units: str = "metric"

Agent-Based Tool Usage

Pass the model class directly to the Needle constructor. The framework automatically detects the Pydantic base class and registers the generated schema:


# usage.py

from needle import Needle
from models import Weather

agent = Needle(tools=[Weather])
response = agent.run("What's the weather in Paris?")
print(response["results"])  # → [{'city': 'Paris', 'units': 'metric'}]

One-Shot Extraction

For single-turn extraction without maintaining a persistent agent, use the extract function, which internally triggers the same schema generation and instantiation pipeline:

from needle import extract
from models import Weather

result = extract("Give me the forecast for Tokyo", Weather)
print(result)  # → Weather(city='Tokyo', units='metric')

Combining with Function Tools

Pydantic models coexist seamlessly with decorated functions in the same agent, as the _resolve method handles heterogeneous tool types:

from needle import Needle, tool

@tool
def greet(name: str) -> str:
    """Say hello."""
    return f"Hello, {name}!"

agent = Needle(tools=[Weather, greet])

# The LLM can invoke either Weather (schema-based) or greet (function-based)

Understanding Tool Schema Generation

Needle's integration leverages Pydantic's introspection capabilities to create precise tool specifications when using BaseModel as tools.

Field Mapping: Each model field becomes a parameter in the generated JSON schema. Type annotations translate directly to OpenAI parameter types (e.g., strstring, intinteger).

Optional vs Required: Fields with default values are marked as optional parameters in the schema. Fields without defaults are flagged as required arguments that the LLM must provide, as implemented in the pydantic_schema logic.

Documentation Inheritance: The model's docstring populates the tool's description field, while individual field descriptions (via Field(..., description=...)) annotate specific parameters in the resulting schema.

Summary

  • Native Support: Needle 2 accepts Pydantic BaseModel classes directly in the tools parameter without decorators or wrapper functions.
  • Automatic Schema Generation: The engine detects models using _is_pydantic_model and generates OpenAI-compatible JSON schemas via pydantic_schema in needle/agent/tools.py (lines 49-66).
  • Instantiation Pipeline: The extract function in needle/__init__.py (lines 81-93) handles model instantiation when the LLM calls the tool.
  • Flexible Integration: Pydantic tools work alongside standard @tool decorated functions in mixed agent configurations.

Frequently Asked Questions

Can I use nested Pydantic models as tools in Needle 2?

Yes. Needle's pydantic_schema function recursively processes nested model definitions, converting complex object hierarchies into properly structured JSON schemas. The LLM receives the complete parameter structure, and extract instantiates the full nested model tree when processing the tool call.

How does Needle handle validation when using BaseModel as tools?

When the LLM returns parameters, extract passes them directly to the Pydantic constructor, triggering Pydantic's native validation. If the arguments fail validation (wrong types, missing required fields), Pydantic raises a standard ValidationError that propagates to your application code for handling.

What's the difference between using the @tool decorator and passing a BaseModel directly?

The @tool decorator wraps functions for LLM invocation, requiring you to manually parse arguments and return structured data. Passing a BaseModel class directly leverages Needle's automatic schema extraction and instantiation pipeline, eliminating the need for wrapper functions while maintaining type safety through Pydantic's validation layer.

Can I mix Pydantic models and regular functions in the same Needle agent?

Absolutely. The _resolve method in needle/__init__.py (lines 100-110) processes heterogeneous tool lists, routing Pydantic models through the schema generation pipeline while handling decorated functions through the standard function registry. Both tool types become available to the LLM in the same conversation context.

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 →