The configuration
base_url and api_key go on OpenAIProvider, not on the model. This is
the structural difference from every other page in this section, and it is the
library’s own recommended shape for an OpenAI-compatible endpoint. The
environment fallbacks are OPENAI_BASE_URL and OPENAI_API_KEY, read by the
provider. The /v1 belongs in the value: the provider passes your base URL
straight to the OpenAI SDK underneath, which appends the endpoint path and adds
no /v1 of its own.
There is also an escape hatch, if you already build an OpenAI client elsewhere in
your application and would rather configure it in one place:
OpenAIProvider(openai_client=my_async_client). It is mutually exclusive with
base_url and api_key, and the provider asserts that rather than quietly
preferring one.
Use OpenAIChatModel, and name it
Do not reach this API through the bareopenai: model string. Pydantic AI
has two OpenAI model classes, and the short string form resolves to the one that
calls OpenAI’s Responses API:
Chat completions is the surface this site documents, which is why the example
above instantiates
OpenAIChatModel directly rather than passing a model string
to Agent. The library’s own documentation agrees for OpenAI-compatible
endpoints in general: its section on them says OpenAIChatModel is what backs
every OpenAI-compatible provider, and every third-party example on that page uses
it.
What else is specific to this framework
The model name is a plain string, so nothing is validated locally. The type is a union ofstr with a literal list of OpenAI’s own model names, and the bare
str in that union means the literals are editor autocompletion rather than a
gate. OpenAIChatModel("openai/gpt-4o-mini") is accepted as written and the id is
checked where it should be, by us, at request time. This is the opposite of
LlamaIndex’s behaviour and it is the friendlier one.
There is no default model. An Agent is constructed with one, so nothing here
can send a bare id you did not write.
Structured output and tool calling need no other endpoint. Both run through
the same chat completions call, so the feature set that makes this library worth
using does not widen the API surface it needs. See
tool calling and
structured outputs for what travels.
Nothing calls the catalog or embeddings. No default agent run reaches
GET /v1/models or an embeddings endpoint.
Where the request id is
On the exception, in a generic header dictionary rather than a named property.ModelHTTPError is raised for a 4xx or 5xx from the provider and carries
status_code, body and headers, with header keys lowercased:
headers is None when the provider supplied none, so the guard above is not
decoration. Our error envelope arrives in body, so read type and code out
of it rather than matching on the message text. Every shipped code is in
errors.
UnexpectedModelBehavior is a different thing and is not an HTTP failure: it is
raised when a reply is not the shape the library expected. A refusal from us
arrives as ModelHTTPError.
What we did not verify
Checked, and where. Thatbase_url and api_key belong to
OpenAIProvider and that OPENAI_BASE_URL and OPENAI_API_KEY are their
fallbacks; that openai_client is an alternative to both and is asserted
mutually exclusive; that OpenAIChatModel calls chat completions and
OpenAIResponsesModel calls the Responses API, and that the bare openai:
prefix resolves to the latter while openai-chat: resolves to the former; that
the model name type is a union including bare str; that ModelHTTPError
carries status_code, body and lowercased headers, with headers optional;
that structured output and tool calling use the same chat completions call; that
no default flow calls the catalog or embeddings. Read from the
pydantic/pydantic-ai repository on its main branch, in
pydantic_ai_slim/pydantic_ai/models/openai.py, providers/openai.py,
models/__init__.py and exceptions.py, plus that repository’s own
docs/models/openai.md, which is the source of the published page.
Not checked. That a call configured this way succeeds against our hostname.
Nothing on this page has been executed, because the base URL this site prints is
not yet a host that answers.
Not checked either. Which library version renamed the model class. An earlier
name for OpenAIChatModel is referred to by other projects’ own migrations, and
we did not find a changelog entry pinning the rename to a release, so this page
uses the current name and tells you nothing about older ones.
And not checked. What POST /v1/responses does against this API. The advice
to pin OpenAIChatModel is because chat completions is the documented surface,
not because we have observed what the other path returns.