n4nAI

How to use the OpenAI Python SDK with n4n.ai

Step-by-step guide to configuring the OpenAI Python SDK base_url with n4n.ai to call 240+ models, handle fallback, and meter token usage through one OpenAI-compatible endpoint.

n4n Team3 min read620 words

Audio narration

Coming soon — every post will get a voice note here.

Pointing the openai python sdk base_url n4n.ai at the gateway takes three lines of code and unlocks 240+ models behind one OpenAI-compatible interface. You keep your existing completion calls, tool usage, and streaming logic; you just change where the client sends requests.

Step 1: Install the OpenAI Python SDK

The official openai package is the only dependency. Use version 1.0 or later—the legacy 0.x line uses a different client shape and will fight you.

pip install "openai>=1.40"

If you’re in a notebook or async framework, the same package ships AsyncOpenAI. No extra plugins required for what we’re doing.

Step 2: Configure the client with the n4n.ai endpoint

Create a single client instance and point it at the gateway. The openai python sdk base_url n4n.ai setting is just the base_url argument; the API key is the gateway key, not the upstream provider’s key.

from openai import OpenAI

client = OpenAI(
    base_url="https://api.n4n.ai/v1",
    api_key="sk-n4n-xxxxxxxxxxxxxxxx",
    timeout=30.0,
)

Keep the client as a module-level singleton. The SDK manages a connection pool internally; recreating it per request wastes sockets and adds latency. If you need to switch models at runtime, pass the model string per call—don’t build a new client.

Using environment variables

You can avoid hardcoding by exporting OPENAI_API_KEY and OPENAI_BASE_URL. The SDK picks them up automatically:

export OPENAI_API_KEY="sk-n4n-xxxxxxxxxxxxxxxx"
export OPENAI_BASE_URL="https://api.n4n.ai/v1"

Then client = OpenAI() with no args works. This is the cleanest path for twelve-factor deployments.

Step 3: Send your first chat completion

A minimal call looks identical to calling OpenAI directly. The difference is the model field accepts any of the 240+ identifiers the gateway routes to.

resp = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",
    messages=[
        {"role": "system", "content": "You are a terse senior engineer."},
        {"role": "user", "content": "What is head-of-line blocking?"},
    ],
    temperature=0.2,
)
print(resp.choices[0].message.content)

Choosing a model

Model IDs follow the provider/family convention. Examples that work today:

  • openai/gpt-4o
  • openai/gpt-4o-mini
  • anthropic/claude-3.5-sonnet
  • meta-llama/llama-3.1-70b-instruct
  • google/gemini-1.5-pro

If you pass an unknown ID, the gateway returns a 404 with a clear message. List available models programmatically:

models = client.models.list()
for m in models.data[:5]:
    print(m.id)

Step 4: Stream responses

For interactive apps, stream. The SDK yields chunks; you iterate and print deltas. This avoids waiting for the full generation and makes your UI feel responsive.

stream = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[{"role": "user", "content": "Write a haiku about TCP."}],
    stream=True,
    temperature=0.8,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)

Streaming also gives you early insight into malformed outputs. If the first chunk is garbage, you can abort the connection instead of paying for a full completion.

Async streaming

If you’re on FastAPI or any asyncio stack, use AsyncOpenAI and async for:

from openai import AsyncOpenAI

aclient = AsyncOpenAI(base_url="https://api.n4n.ai/v1", api_key="sk-n4n-xxx")

async def main():
    stream = await aclient.chat.completions.create(
        model="anthropic/claude-3.5-sonnet",
        messages=[{"role":"user","content":"Stream a list of HTTP codes."}],
        stream=True,
    )
    async for chunk in stream:
        if chunk.choices[0].delta.content:
            print(chunk.choices[0].delta.content, end="")

Step 5: Pass provider routing and cache hints

n4n.ai honors client routing directives and forwards provider cache-control hints, so you can pin a provider or request caching without leaving the SDK. The OpenAI SDK doesn’t model these fields natively, but extra_body passes them straight through.

resp = client.chat.completions.create(
    model="anthropic/claude-3.5-sonnet",
    messages=[{"role": "user", "content": "Summarize RFC 7231 section 4."}],
    extra_body={
        "route": {"prefer": ["anthropic"]},
        "cache_control": {"type": "ephemeral", "ttl": 300},
    },
)

This tells the gateway to prefer Anthropic’s deployment and to treat the prompt as cacheable for five minutes. If Anthropic is degraded, the gateway still falls back per its policy, but your preference is respected when possible.

Why this matters

Provider-specific features like prompt caching normally require vendor SDKs. By forwarding hints through extra_body, you keep one code path and still get provider optimizations.

Step 6: Handle errors and fallback

The gateway provides automatic fallback when a provider is rate-limited or degraded, so most transient errors never reach your code. Still, write defensive code. Network blips, invalid model IDs, and exhausted quotas surface as APIError subclasses.

from openai import APIError, RateLimitError

try:
    resp = client.chat.completions.create(
        model="openai/gpt-4o",
        messages=[{"role": "user", "content": "Test"}],
    )
except RateLimitError as e:
    # Gateway already tried fallbacks; upstream fully saturated
    print("Rate limited:", e.response.json().get("error", {}).get("message"))
except APIError as e:
    print("API error", e.status_code, e.message)

For critical paths, implement a simple retry with exponential backoff on RateLimitError and APIConnectionError. Don’t retry on 4xx validation errors—they won’t fix themselves.

Step 7: Verify success

Verification is two-fold: confirm the request reached the gateway and confirm token metering.

First, list models to prove the base URL resolves:

assert any(m.id == "openai/gpt-4o" for m in client.models.list().data)

Second, inspect usage on a real call:

resp = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[{"role": "user", "content": "Ping"}],
)
print(resp.usage.prompt_tokens, resp.usage.completion_tokens, resp.usage.total_tokens)

If those numbers are non-zero and the call returns in a reasonable time, your openai python sdk base_url n4n.ai integration is working. The gateway’s per-token usage metering matches what you see in resp.usage, so you can reconcile against your billing dashboard later.

Quick smoke test script

Put it together in a ten-line script:

from openai import OpenAI

client = OpenAI(base_url="https://api.n4n.ai/v1", api_key="sk-n4n-xxx")
models = client.models.list()
print("Model count:", len(models.data))
r = client.chat.completions.create(
    model="openai/gpt-4o-mini",
    messages=[{"role":"user","content":"Say hello in JSON."}],
)
print(r.choices[0].message.content)
print("Tokens:", r.usage.total_tokens)

Run it. If you see a JSON greeting and a token count, you’re done.

Tagspythonopenai-sdkn4n-aiintegration

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All python + openai-compatible sdk integration posts →