> ## Documentation Index
> Fetch the complete documentation index at: https://developers.meshapi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Pydantic AI

> Run Pydantic AI agents on Mesh via OpenAIProvider — typed tools, structured output, and the auto-router with one base URL.

Pydantic AI reaches Mesh through its OpenAI model class and `OpenAIProvider`, which takes a `base_url`. Typed tools, validated structured output, and dependency injection all work unchanged.

## Install

```bash theme={null}
pip install "pydantic-ai-slim[openai]"
```

The full `pydantic-ai` package works too; `pydantic-ai-slim[openai]` pulls only the OpenAI-compatible provider, which is all Mesh needs.

## Connect

```python theme={null}
import os

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.openai import OpenAIProvider

model = OpenAIChatModel(
    "auto",                                    # or any Mesh catalog id
    provider=OpenAIProvider(
        base_url="https://api.meshapi.ai/v1",
        api_key=os.environ["MESH_API_KEY"],    # rsk_...
    ),
)

agent = Agent(model, system_prompt="Be concise.")
```

> [!NOTE]
>
> The class was named `OpenAIModel` in earlier releases and `OpenAIChatModel` in current ones. If an import fails, try the other name:
>
> ```python theme={null}
> try:
>     from pydantic_ai.models.openai import OpenAIChatModel as Model
> except ImportError:
>     from pydantic_ai.models.openai import OpenAIModel as Model
> ```

## Tool calling

Decorate a function and Pydantic AI derives the schema from its type hints:

```python theme={null}
@agent.tool_plain
def get_shipment_status(order_id: str) -> dict:
    """Look up the shipment status of an order."""
    book = {"A-1042": {"state": "in transit", "eta_days": 2}}
    if order_id in book:
        return {"status": "success", "order_id": order_id, **book[order_id]}
    return {"status": "error", "error_message": f"No order {order_id}."}


result = await agent.run("What's the shipment status of order A-1042?")
print(result.output)
```

`result.all_messages()` carries the full exchange, including the tool-call and tool-return parts, if you need to inspect what the model did.

## Structured output

An `output_type` makes Mesh's response validate into your model:

```python theme={null}
from pydantic import BaseModel


class Shipment(BaseModel):
    order_id: str
    state: str
    eta_days: int


agent = Agent(model, output_type=Shipment)
```

## Caveats

Everything in [Caveats that apply to every framework](https://developers.meshapi.ai/agent/frameworks.md#caveats-that-apply-to-every-framework) applies here.

Pydantic AI prints a one-time observability banner on startup. Set `PYDANTIC_AI_NO_BANNER=1` to silence it; it is unrelated to Mesh.

## Related

* [Agent frameworks](https://developers.meshapi.ai/agent/frameworks.md) — the shared pattern and compatibility matrix
* [Auto-routing](https://developers.meshapi.ai/docs/capabilities/auto-routing.md) — how `auto` picks a model
* [Structured outputs](https://developers.meshapi.ai/docs/capabilities/tool-calling.md) — the tool and schema format Mesh accepts


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.