openai package takes its base URL as a constructor argument, so pointing it
here is configuration rather than adaptation, and the rest of your code does not
change.
The configuration
base_url and api_key are the whole change. Both also read from the
environment if you would rather not pass them: the SDK reads OPENAI_BASE_URL
and OPENAI_API_KEY when the arguments are absent, which is how you point an
application you cannot edit at this API.
The /v1 belongs in the value. The SDK’s own default is the full path
https://api.openai.com/v1, and it builds a request by appending
/chat/completions to whatever you configure. It does not add /v1 for you. A
base URL without it produces a 404 rather than an error that explains itself.
What is specific to this SDK
There is no default model, so there is nothing to un-pin.model is a
required argument on chat.completions.create, which means this SDK cannot send
a bare id you did not write. It is the only library in this section where the
pinned-id rule of the
integrations overview costs you nothing beyond
prefixing the ids you already had.
Nothing happens at construction. OpenAI(...) makes no network call and
validates nothing against the server, so a wrong base URL surfaces on your first
request rather than at startup. The SDK never asks GET /v1/models on its own
either. It reaches an endpoint only when your code calls the method for it.
A resource we do not serve raises rather than hangs. Calling
client.embeddings.create(...) against this base URL reaches a path this API
does not serve for you, and the SDK turns the 404 into openai.NotFoundError.
That is worth knowing because it is the one shape of failure that looks like a
configuration mistake and is not: the base URL is right and the endpoint is
absent. See OpenAI compatibility. A 404 is
not in the SDK’s retry set, so it fails on the first attempt rather than after a
backoff.
The streamed usage line is skipped for you. A streamed reply carries one SSE
comment line before data: [DONE]. This SDK’s stream decoder discards a line
beginning with a colon, so it never reaches your loop:
Where the request id is
Every response carries the same id on two headers:
x-uniblock-request-id,
which is ours, and x-request-id, which is the one the official OpenAI SDKs
surface on their error objects. Every error envelope repeats it as
request_id. Quote it when you ask us about a request. Without it we are
guessing at which of your requests you mean.x-request-id, which is the header the SDK already reads:
type and code, never on the message text. The fields are the
contract and the sentences are prose. APIStatusError also has the subclasses
you already catch, so an unpinned model id arrives as BadRequestError and a
refusal for credit arrives with status 402. Every shipped code is in
errors.
What we did not verify
Checked, and where. Thatbase_url is the constructor argument and that its
type is a string or an httpx.URL; that OPENAI_BASE_URL and OPENAI_API_KEY
are the environment variables; that the constructor makes no network call; that
request_id is read from the x-request-id response header; that the stream
decoder discards comment lines. All of it was read from the openai-python
repository on its main branch, in src/openai/_client.py,
src/openai/_exceptions.py and src/openai/_streaming.py, plus that
repository’s own README.
Not checked. That a call configured this way succeeds against our hostname.
Nothing on this page has been executed. The base URL this site prints is not yet
a host that answers, so there was nothing to run it against, and we would rather
say that than let a page’s silence imply a test that did not happen.
Not checked either. Which SDK version each of these facts first held in. They
were read from the current main branch and this page pins no version. If you are
on an old release and base_url behaves differently, the library’s own changelog
is the authority and this page is not.