Pydantic AIPydantic AI 2.51 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
29 small wins to finish your pathNext lesson →

Real models: providers, keys and model names

A real model is named as a provider and a model id, like openai:gpt-4.1, and the provider's client reads its API key from an environment variable.

Last updated: 28 Sep, 2026 · Pydantic AI 2.51

The stand-in from FunctionModel: write a stand-in model needed no key. To send a ticket to a hosted model you name it as a single string and set the matching key. This is the one line that changes when you leave the stand-in.

Naming a provider and reading its key

With no OPENAI_API_KEY set, creating the agent fails at once, and the message says what to set:

Example
from pydantic_ai import Agent

agent = Agent("openai:gpt-4.1", instructions="You answer support tickets.")

With the key exported, the same line works and run_sync sends the ticket to the provider:

bash
export OPENAI_API_KEY="sk-..."
Model nameInstallKey
openai:gpt-4.1pydantic-ai-slim[openai]OPENAI_API_KEY
anthropic:claude-sonnet-4-6pydantic-ai-slim[anthropic]ANTHROPIC_API_KEY
google:gemini-2.5-flashpydantic-ai-slim[google]GOOGLE_API_KEY
groq:openai/gpt-oss-120bpydantic-ai-slim[groq]GROQ_API_KEY
Project files used on this pageThis lesson builds on a project from earlier lessons. The code below imports this file. Click a file to see its code, or follow the link to the lesson that wrote it. To run the code yourself, keep it in the same folder.
View the code here
shop_model.py
import re

from pydantic_ai import ModelResponse, TextPart, ToolCallPart
from pydantic_ai.models.function import AgentInfo, FunctionModel


def sort_ticket(text):
    text = text.lower()
    if "charged" in text or "refund" in text:
        return "billing", 4
    if "parcel" in text or "arrived" in text:
        return "shipping", 3
    return "other", 1


def shop_reply(messages, info: AgentInfo) -> ModelResponse:
    prompts = [p.content for m in messages for p in m.parts if p.part_kind == "user-prompt"]
    ticket = prompts[-1]
    last = messages[-1].parts[-1]
    order = re.search(r"A-\d{4}", ticket)

    # 1. The ticket names an order and the agent has a tool: ask for it.
    if order and info.function_tools and last.part_kind == "user-prompt":
        tool = info.function_tools[0].name
        return ModelResponse(parts=[ToolCallPart(tool, {"order_id": order.group()})])

    # 2. A tool answered: write the reply from what it said.
    if last.part_kind == "tool-return" and info.allow_text_output:
        return ModelResponse(parts=[TextPart(f"Order {order.group()}: {last.content}.")])

    # 3. The agent wants a typed answer: fill in its output tool.
    category, priority = sort_ticket(ticket)
    if info.output_tools:
        args = {"category": category, "priority": priority}
        return ModelResponse(parts=[ToolCallPart(info.output_tools[0].name, args)])

    # 4. Otherwise, plain text.
    return ModelResponse(parts=[TextPart(f"Sorted as {category}.")])


shop_model = FunctionModel(shop_reply, model_name="shop")

Choosing the model when you run

An agent does not need a model when it is created. Passing model= on a run picks one for that run and overrides the agent's own model. Here the stand-in fills in:

Example
agent = Agent(instructions="You answer support tickets.")
print(agent.run_sync("My parcel never arrived", model=shop_model).output)

With no model on the agent and none on the run, the run fails:

Example
agent = Agent(instructions="You answer support tickets.")
agent.run_sync("My parcel never arrived")

Creating an agent before the key exists

Example
agent = Agent("openai:gpt-4.1", defer_model_check=True)
print(agent.run_sync("I was charged twice", model=shop_model).output)

defer_model_check=True waits until the first run that uses the named model before building it. Your module can then be imported on a machine without keys, such as a test runner, as long as those runs use another model. The testing and capstone parts rely on this.

Reaching many providers through the Gateway

The Pydantic AI Gateway sits between your agent and the providers. One Gateway key reaches several providers, and the model string gains a gateway/ prefix. The rest of the agent stays the same:

python
from pydantic_ai import Agent

agent = Agent("gateway/openai:gpt-4.1", instructions="You answer support tickets.")
bash
export PYDANTIC_AI_GATEWAY_API_KEY="pylf_v..."
ProviderModel string
OpenAIgateway/openai:gpt-4.1
Anthropicgateway/anthropic:claude-sonnet-4-6
Groqgateway/groq:openai/gpt-oss-120b
AWS Bedrockgateway/bedrock:us.amazon.nova-micro-v1:0

What the Gateway adds is around the calls: spending limits per project or key, failing over between providers that serve the same model, and every request logged in Pydantic Logfire. Turn it on from Logfire and create a key there.

Running a model on your own machine

Ollama runs open models locally and speaks the OpenAI API, so Pydantic AI connects with the OpenAI model class and an Ollama provider:

Example
from pydantic_ai import Agent
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.ollama import OllamaProvider

model = OpenAIChatModel("qwen2.5:3b", provider=OllamaProvider(base_url="http://localhost:11434/v1"))
agent = Agent(model, instructions="You answer support tickets.")

Small local models are weaker at calling tools and filling typed output than hosted ones, so expect more retries, covered in Validation retries: when the model gets it wrong, if you try the course with one.

Watch out. Model ids and provider defaults change often. Pin the id you tested, and read KnownModelName in pydantic_ai.models for the names your installed version accepts, rather than trusting an id from an older article.
Try it yourself
  • Set OPENAI_API_KEY=not-a-real-key and create the agent again. What happens on run_sync?
  • Pass model="test" to run_sync on the agent with no model.
  • Look up KnownModelName in pydantic_ai.models to see every model name the library knows.

Little by little, you're building something great.