# Pydantic AI
URL: /integrations/pydantic-ai

---
title: Pydantic AI
sidebarTitle: Pydantic AI
description: Build provider-agnostic, typed Python browser agents with dependency injection.
llm: true
---

[Pydantic AI](https://ai.pydantic.dev/) is the Pydantic team's agent framework. It's provider-agnostic and reuses the Pydantic models you'd already validate API I/O with for tool arguments and final outputs, so adding an agent to a typed Python codebase doesn't introduce a parallel schema layer. The Steel integration passes a Playwright `Page` through `RunContext.deps`, so every tool in an agent run sees the same cloud browser without module globals.

### Requirements

*   **Steel API Key**: Active Steel subscription
*   **Model provider key**: OpenAI, Anthropic, Google, or any other Pydantic AI-supported provider
*   **Python**: 3.10+

### Connect Steel to Pydantic AI

Define a `BrowserDeps` dataclass holding the Steel-backed Playwright `Page`, register tools that read `ctx.deps.page`, and pass `deps=` to `agent.run`:

```python Python -wc
from dataclasses import dataclass
from playwright.async_api import Page, async_playwright
from pydantic_ai import Agent, RunContext
from steel import Steel

@dataclass
class BrowserDeps:
    page: Page

async def navigate(ctx: RunContext[BrowserDeps], url: str) -> dict:
    """Navigate to a URL and wait for the page to load."""
    await ctx.deps.page.goto(url, wait_until="domcontentloaded")
    return {"url": ctx.deps.page.url, "title": await ctx.deps.page.title()}

agent = Agent(
    "openai:gpt-5-mini",
    deps_type=BrowserDeps,
    tools=[navigate],
)

steel = Steel(steel_api_key=STEEL_API_KEY)
session = steel.sessions.create()
playwright = await async_playwright().start()
browser = await playwright.chromium.connect_over_cdp(
    f"{session.websocket_url}&apiKey={STEEL_API_KEY}"
)
page = browser.contexts[0].pages[0]

result = await agent.run("Open example.com and report the title.", deps=BrowserDeps(page=page))
```

Full runnable starter: [Steel + Pydantic AI recipe →](/cookbook/pydantic-ai)

### FAQ

### Do I need to change my existing Pydantic AI code to use Steel?

No — Steel enters through dependency injection. You connect Playwright to a Steel session over CDP and pass the resulting `Page` in via `deps=BrowserDeps(page=page)`; your agent, tools, and output models stay the same.

### How do I connect Pydantic AI to a Steel browser session?

Create a session with `steel.sessions.create()`, connect via `chromium.connect_over_cdp(f"{session.websocket_url}&apiKey={STEEL_API_KEY}")`, take `browser.contexts[0].pages[0]`, and pass it as `deps=BrowserDeps(page=page)` to `agent.run()`.

### Does Pydantic AI work with Steel's proxies, stealth mode, and CAPTCHA solving?

Yes — set them on `sessions.create()` (e.g. `use_proxy`, `solve_captcha`, `stealth_config`). The agent only sees a Playwright `Page` through `ctx.deps`, so session options never leak into tool code.


### Resources

*   [Pydantic AI documentation](https://ai.pydantic.dev/) – Agents, tools, output validators, retries, and Logfire integration
*   [Steel Sessions API reference](/api-reference) – Programmatic session control for Steel browsers
*   [Steel Discord](https://discord.gg/steel-dev) – Get help and share what you build
