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

# Pydantic AI integration guide

> [!NOTE]
>
> **What you'll build:** A Pydantic AI agent running on a SambaCloud-hosted model, with structured-output, tool-calling, and streaming examples.

## Overview

[Pydantic AI](https://pydantic.dev/docs/ai/) is a type-safe agent framework for Python, built by the Pydantic team. It ships a built-in SambaNova provider, so you get:

> **Built-in SambaNova provider**
>
> Pass `"sambanova:<model>"` to an `Agent` and it reads your key from `SAMBANOVA_API_KEY`. Nothing extra to install or configure.

> **Type-safe agents**
>
> Define an agent's expected output as a Pydantic model and get a validated Python object back, not raw text to parse yourself.

> **Tool calling**
>
> Register plain Python functions as tools with `@agent.tool`. Pydantic AI generates the schema from the function signature.

> **Model-agnostic**
>
> Swap models by changing the model string. The rest of your agent code stays the same.

## Prerequisites

* A [SambaCloud account](https://cloud.sambanova.ai/?utm_source=pydantic-ai\&utm_medium=external\&utm_campaign=cloud_signup) and API key from the [SambaCloud portal](https://cloud.sambanova.ai/apis?utm_source=pydantic-ai\&utm_medium=external\&utm_campaign=cloud_signup)
* Python 3.11 or later. On older versions, `pip` silently installs an outdated `pydantic-ai`; see [Troubleshooting](#troubleshooting).
* Familiarity with Python virtual environments and Pydantic models

## Setup

**1. Create and activate a virtual environment**

```bash macOS / Linux theme={}
python3 -m venv .venv
source .venv/bin/activate
```

```powershell Windows theme={}
python -m venv .venv
.venv\Scripts\Activate.ps1
```

**2. Install Pydantic AI**

```bash theme={}
pip install pydantic-ai
```

> [!TIP]
>
> This installs `pydantic`, `openai`, and Pydantic AI's own dependencies together. For a smaller install with only what SambaCloud needs, use `pip install "pydantic-ai-slim[openai]"`.

**3. Export your SambaCloud API key**

```bash macOS / Linux theme={}
export SAMBANOVA_API_KEY="your-sambacloud-api-key"
```

```powershell Windows theme={}
$env:SAMBANOVA_API_KEY="your-sambacloud-api-key"
```

Pydantic AI's SambaNova provider reads this variable automatically.

> [!WARNING]
>
> Never commit your API key to source control. Use a `.env` file loaded with `python-dotenv`, or your shell's secret manager.

**4. Run your first agent**

```python quickstart.py theme={}
from pydantic_ai import Agent

agent = Agent("sambanova:MiniMax-M3")
result = agent.run_sync("What can you do?")
print(result.output)
```

```bash theme={}
python quickstart.py
```

The `sambanova:` prefix selects Pydantic AI's [SambaNova provider](https://pydantic.dev/docs/ai/models/compatible-apis/#sambanova), which sends requests to `https://api.sambanova.ai/v1`. Everything after the prefix is the SambaCloud model ID.

> [!TIP]
>
> Pydantic AI prints a startup banner to standard error before the output. It's informational, not an error. Set `PYDANTIC_AI_NO_BANNER=1` to turn it off.

## Example: structured output

Give the agent a Pydantic model as its `output_type`. The agent returns a validated instance of that model, not a string you have to parse.

```python structured_example.py theme={}
from pydantic import BaseModel
from pydantic_ai import Agent


class CityInfo(BaseModel):
    city: str
    country: str
    population_estimate: int


agent = Agent("sambanova:MiniMax-M3", output_type=CityInfo)
result = agent.run_sync("Tell me about Paris, France.")
print(result.output)
```

Run it:

```bash theme={}
python structured_example.py
```

```text Output theme={}
city='Paris' country='France' population_estimate=2161000
```

> [!NOTE]
>
> Swap `MiniMax-M3` for any model on the [SambaCloud supported models](https://docs.sambanova.ai/docs/en/models/sambacloud-models.md) page. With the default settings, structured output is delivered through a forced tool call, so the model must support function calling. See [Function calling and JSON mode](https://docs.sambanova.ai/docs/en/features/function-calling.md) for the current list.

> **What Pydantic AI actually sends to SambaCloud**
>
> Pydantic AI turns `output_type=CityInfo` into a single function tool named `final_result`, with your model's JSON schema as its parameters, and forces the model to call it with `tool_choice: "required"`. This is the request it sends to `https://api.sambanova.ai/v1/chat/completions`:
>
> ```json Request body theme={}
> {
>   "model": "MiniMax-M3",
>   "stream": false,
>   "messages": [{"role": "user", "content": "Tell me about Paris, France."}],
>   "tool_choice": "required",
>   "tools": [
>     {
>       "type": "function",
>       "function": {
>         "name": "final_result",
>         "description": "The final response which ends this conversation",
>         "parameters": {
>           "type": "object",
>           "properties": {
>             "city": {"type": "string"},
>             "country": {"type": "string"},
>             "population_estimate": {"type": "integer"}
>           },
>           "required": ["city", "country", "population_estimate"],
>           "additionalProperties": false
>         },
>         "strict": true
>       }
>     }
>   ]
> }
> ```
>
> ```json Response (choices[0].message) theme={}
> {
>   "role": "assistant",
>   "content": null,
>   "tool_calls": [
>     {
>       "id": "call_50823124eee04fb1a4",
>       "type": "function",
>       "function": {
>         "name": "final_result",
>         "arguments": "{\"city\": \"Paris\", \"country\": \"France\", \"population_estimate\": 2161000}"
>       }
>     }
>   ]
> }
> ```
>
> Pydantic AI parses the tool call's `arguments` into your Pydantic model and validates it, which is what turns the JSON above into the `CityInfo(...)` object `result.output` returns.

## Example: tool calling

Register a Python function as a tool with `@agent.tool`. Pydantic AI generates the tool schema from the function's type hints and docstring, sends it to the model, and runs the function when the model calls it.

```python tool_example.py theme={}
from pydantic_ai import Agent, RunContext

agent = Agent(
    "sambanova:MiniMax-M3",
    instructions="Use the get_weather tool to answer weather questions.",
)


@agent.tool
def get_weather(ctx: RunContext[None], city: str) -> str:
    """Get the current weather for a city."""
    return f"It is sunny and 22C in {city}."


result = agent.run_sync("What's the weather like in Tokyo right now?")
print(result.output)
```

Run it:

```bash theme={}
python tool_example.py
```

```text Output theme={}
The weather in Tokyo right now is **sunny** with a temperature of **22°C** (about 72°F). Sounds like a lovely day to be outside! ☀️
```

> [!NOTE]
>
> `MiniMax-M3` is a reasoning model and emits a `ThinkingPart` before each response, but this does not interfere with tool calling: it still returns a proper tool call on the first attempt rather than answering in prose. Not every reasoning model behaves this way, so re-check if you switch models.

> **The full message trace (result.all\_messages())**
>
> Inspecting `result.all_messages()` shows the full round trip: a `ThinkingPart` and a `ToolCallPart`, the `ToolReturnPart` with your function's result, then a second `ThinkingPart` before the final answer. Use it to check that the model called `get_weather` rather than answering from its own guess.
>
> ```text theme={}
> ModelRequest [
>     UserPromptPart(content="What's the weather like in Tokyo right now?"),
> ]
> ModelResponse [
>     ThinkingPart(content='The user is asking about the current weather in Tokyo. I should use the get_weather tool to fetch this information.'),
>     ToolCallPart(tool_name='get_weather', args='{"city": "Tokyo"}'),
> ]
> ModelRequest [
>     ToolReturnPart(tool_name='get_weather', content='It is sunny and 22C in Tokyo.'),
> ]
> ModelResponse [
>     ThinkingPart(content='The tool returned the weather information for Tokyo. Let me provide a clear response to the user.'),
>     TextPart(content='The weather in Tokyo right now is **sunny** with a temperature of **22°C** (about 72°F). Sounds like a lovely day to be outside! ☀️'),
> ]
> ```

## Example: streaming

Use `run_stream` to print the response as it's generated instead of waiting for the full answer.

```python stream_example.py theme={}
import asyncio

from pydantic_ai import Agent

agent = Agent("sambanova:MiniMax-M3")


async def main() -> None:
    async with agent.run_stream("What are your capabilities?") as result:
        async for chunk in result.stream_text(delta=True):
            print(chunk, end="", flush=True)
    print()


asyncio.run(main())
```

Run it:

```bash theme={}
python stream_example.py
```

`stream_text(delta=True)` yields only the new text in each chunk. Streaming also works with an `output_type`: iterate `result.stream_output()` to get partially validated objects as they arrive.

## Configure the provider explicitly

The `sambanova:` model string is shorthand. To pass the key yourself, or to change the base URL, build the model with `SambaNovaProvider`:

```python theme={}
import os

from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.sambanova import SambaNovaProvider

model = OpenAIChatModel(
    "MiniMax-M3",
    provider=SambaNovaProvider(api_key=os.environ["SAMBANOVA_API_KEY"]),
)
agent = Agent(model)
```

| Parameter | Description |
| :- | :- |
| `api_key` | Your SambaCloud API key. Defaults to the `SAMBANOVA_API_KEY` environment variable. |
| `base_url` | SambaCloud API base URL. Defaults to the `SAMBANOVA_BASE_URL` environment variable, then to `https://api.sambanova.ai/v1`. |

> **Using the generic OpenAIProvider instead**
>
> SambaCloud is OpenAI-compatible, so Pydantic AI's generic `OpenAIProvider` also works with the same examples:
>
> ```python theme={}
> import os
>
> from pydantic_ai import Agent
> from pydantic_ai.models.openai import OpenAIChatModel
> from pydantic_ai.providers.openai import OpenAIProvider
>
> model = OpenAIChatModel(
>     "MiniMax-M3",
>     provider=OpenAIProvider(
>         base_url="https://api.sambanova.ai/v1",
>         api_key=os.environ["SAMBANOVA_API_KEY"],
>     ),
> )
> agent = Agent(model)
> ```

## Example use cases

The examples above each show one feature. The example below builds on structured output and tool calling in a complete, runnable app.

* [Trip-briefing agent](https://github.com/sambanova/integrations/tree/main/pydantic_ai_integration): a terminal travel assistant that chains two tools to look up a city and its live forecast, returns a validated `TripBrief` object, and keeps the conversation so follow-up questions know which city you meant. It also shows features this page doesn't cover: dependency injection, tool retries, and typed tool results.

## Additional resources

> **[Pydantic AI repository](https://github.com/pydantic/pydantic-ai)**
>
> Source code, examples, and release notes for Pydantic AI.

> **[Pydantic AI documentation](https://pydantic.dev/docs/ai/)**
>
> Official guides covering agents, tools, dependency injection, and multi-agent workflows.

> **[SambaNova provider in Pydantic AI](https://pydantic.dev/docs/ai/models/compatible-apis/#sambanova)**
>
> Pydantic AI's own reference for the `sambanova:` model prefix and `SambaNovaProvider`.

> **[Supported models](https://docs.sambanova.ai/docs/en/models/sambacloud-models.md)**
>
> Current list of models available on SambaCloud.

> **[Function calling and JSON mode](https://docs.sambanova.ai/docs/en/features/function-calling.md)**
>
> Which SambaCloud models support tool calling and structured output.

## Troubleshooting

> **ModuleNotFoundError: No module named 'pydantic\_ai'**
>
> Install with `pip install pydantic-ai`, then confirm your virtual environment is active: `which python3` (`Get-Command python` on Windows) should point inside `.venv`.

> **UserError: Set the `SAMBANOVA_API_KEY` environment variable**
>
> The SambaNova provider found no key. Export it before running, with `export SAMBANOVA_API_KEY="your-key"`, and verify with `echo $SAMBANOVA_API_KEY`. On Windows PowerShell, use `$env:SAMBANOVA_API_KEY="your-key"` and verify with `echo $env:SAMBANOVA_API_KEY`. An `export` applies only to the shell it ran in, so a new terminal needs it again.

> **UserError: Native structured output is not supported by this model**
>
> You wrapped `output_type` in `NativeOutput(...)`, and Pydantic AI's SambaNova provider doesn't list SambaCloud models as supporting JSON schema output, so it stops before sending the request. Pass the Pydantic model directly (`output_type=CityInfo`). The default mode uses a forced tool call, which is what the [structured output example](#example-structured-output) runs.

> **Agent never calls the registered tool**
>
> Confirm the model you passed supports function calling. See [Function calling and JSON mode](https://docs.sambanova.ai/docs/en/features/function-calling.md) for the current list. A model without function-calling support answers in prose instead of emitting a tool call, and Pydantic AI has no fallback for that case.

> **An older pydantic-ai version was installed**
>
> The current release requires Python 3.11 or later. On an unsupported version `pip` installs the newest release that still supports it rather than reporting an error, so the install looks successful. Check with `pip show pydantic-ai`, and recreate the virtual environment on Python 3.11 or later if the version is older than you expect.
