n4nAI

Configure ChatOpenAI for the n4n.ai unified API endpoint

Practical walkthrough to configure ChatOpenAI for the n4n.ai endpoint: set base URL, API key, model routing, and verify a live LangChain call.

n4n Team5 min read1,000 words

Audio narration

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

To configure ChatOpenAI for the n4n.ai unified API endpoint, you point LangChain’s client at the gateway’s OpenAI-compatible base URL and supply a gateway API key. This swaps the default OpenAI host for a single endpoint that fronts 240+ models and handles provider degradation transparently. The steps below take you from a clean Python environment to a verified streaming chat call with usage metering.

Step 1: Install the current LangChain OpenAI package

The legacy langchain umbrella package still ships a ChatOpenAI, but it is frozen and receives only security fixes. Use langchain-openai (the maintained split package) to avoid silently pinned dependencies and to get SDK v1+ support.

pip install langchain-openai python-dotenv

If you are on a notebook, restart the kernel after install. Dependency resolution for the openai SDK is strict; pin openai>=1.30 if you hit BaseUrl conflicts with older transitive packages. Do not mix langchain and langchain-openai imports in the same module—the symbol collision produces confusing TypeErrors on model_kwargs.

Step 2: Store credentials outside source

ChatOpenAI reads OPENAI_API_KEY by default. Overriding that global is possible but messy in multi-tenant code or when you run tests against both OpenAI and the gateway. Load a dedicated variable from .env and pass it explicitly to the constructor.

# .env
N4N_API_KEY="sk-gateway-xxxxxxxxxxxxxxxx"
# config.py
from dotenv import load_dotenv
import os

load_dotenv()
GATEWAY_KEY = os.getenv("N4N_API_KEY")
assert GATEWAY_KEY, "Set N4N_API_KEY in .env"

Never hardcode the key. The gateway meters per-token usage against this credential, so treat it like a production secret and rotate it through your secrets manager, not via commit.

Step 3: Initialize ChatOpenAI with the gateway base URL

When you configure ChatOpenAI for the n4n.ai endpoint, pass base_url explicitly and use a model slug that includes the upstream provider. The gateway routes provider/model strings to the correct backend and translates request shapes.

from langchain_openai import ChatOpenAI
from config import GATEWAY_KEY

chat = ChatOpenAI(
    model="openai/gpt-4o",
    base_url="https://api.n4n.ai/v1",
    api_key=GATEWAY_KEY,
    temperature=0.2,
    max_tokens=1024,
    timeout=30,
    max_retries=2,
)

Practical notes from shipping this:

  • Trailing slashes on base_url break the OpenAI SDK’s path joining. Omit them.
  • model is not validated client-side. A typo returns a 404 from the gateway, not a local error.
  • max_retries is the SDK retry, not the gateway’s provider fallback. The gateway already shifts traffic when a provider is rate-limited or degraded; client retries only handle local network blips.
  • Set timeout aggressively. A 30s ceiling forces your calling code to fail fast and lets you apply your own circuit breaker.

Step 4: Send a blocking completion

Run a minimal invocation to confirm the wiring. Use a cheap model if you are iterating heavily.

resp = chat.invoke("What is the cheapest AWS region for infrequently accessed objects?")
print(resp.content)

Expected output is a string answer. If you see AuthenticationError, your key is wrong or unset. If you see NotFoundError, the model slug is unsupported—list available models via the gateway’s /v1/models endpoint with the same key. Do not assume model names mirror OpenAI’s native naming; the provider/ prefix is mandatory for non-OpenAI backends.

Step 5: Pass routing directives and cache hints

The gateway honors client routing directives and forwards provider cache-control hints. In LangChain, arbitrary headers go through default_headers. Use them to force a routing preference or enable prompt caching where the upstream supports it.

chat_cached = ChatOpenAI(
    model="anthropic/claude-3-5-sonnet",
    base_url="https://api.n4n.ai/v1",
    api_key=GATEWAY_KEY,
    default_headers={
        "Cache-Control": "max-age=300",
    },
    model_kwargs={"system": "You are a terse infra assistant."},
)

model_kwargs is passed through to the OpenAI-shaped request body. Not every upstream accepts the same fields; the gateway translates where the target provider diverges. Test new kwargs against a single call before baking them into a chain. If a header is ignored, the gateway logs it but does not error—verify behavior with a repeated prompt to confirm cache hits via reduced latency or usage metadata.

Step 6: Stream tokens and use async

Production chat UIs need streaming. ChatOpenAI exposes .stream() and .astream() synchronously and asynchronously.

for chunk in chat.stream("Explain RAID 0 vs RAID 1 in two bullets"):
    if chunk.content:
        print(chunk.content, end="", flush=True)
import asyncio

async def main():
    async for chunk in chat.astream("Same RAID question, async"):
        if chunk.content:
            print(chunk.content, end="", flush=True)

asyncio.run(main())

Streaming bypasses max_tokens only if the gateway’s downstream allows it; set a sane cap to avoid runaway bills. The gateway’s per-token metering still applies to streamed output, so your usage dashboard will reflect every emitted token.

Step 7: Wire into a LangChain chain

The configured client drops into any LangChain expression language pipeline without modification.

from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_messages([
    ("system", "Answer as a senior SRE."),
    ("user", "{question}")
])

chain = prompt | chat
print(chain.invoke({"question": "How do I debug a 503 from a load balancer?"}))

Because the client is just an OpenAI-compatible wrapper, swapping to a different model is a one-line change: model="google/gemini-1.5-pro". No other code moves. This is the real payoff—your application logic stays pinned to the OpenAI contract while the gateway abstracts provider diversity.

Step 8: Capture usage metadata

Every response from the gateway includes token counts in the OpenAI-compatible usage field. LangChain exposes this on the AIMessage.response_metadata.

msg = chat.invoke("Count to three.")
print(msg.response_metadata.get("usage"))

Pipe that into your metrics system. Because the gateway meters per-token usage, you can attribute cost to specific model slugs without building your own accounting layer. Set alerts on sudden spikes in completion_tokens for a given route, and use the system_fingerprint if present to detect backend shifts during fallback events.

Verify success end to end

A green run satisfies three checks:

  1. The Python process prints a non-empty content from Step 4.
  2. Streaming loops in Step 6 emit incremental strings without raising.
  3. The chain in Step 7 returns a coherent answer referencing the system role.

If you want an independent sanity check outside LangChain, hit the endpoint with curl using the same key and base URL stored in a shell variable. This isolates gateway issues from LangChain packaging.

BASE_URL="https://api.n4n.ai/v1"
curl "$BASE_URL/chat/completions" \
  -H "Authorization: Bearer $N4N_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-4o","messages":[{"role":"user","content":"ping"}]}'

A valid JSON choices array confirms the credential, route, and model slug. If curl works but LangChain fails, the problem is in your ChatOpenAI parameter mapping, not the network.

Troubleshooting

401 Unauthorized — Key missing or scrambled. Print GATEWAY_KEY[:4] to confirm load from env.

404 Not Found — Model slug unknown. The gateway fronts 240+ models but expects provider/model. Guess less, check /v1/models.

TimeoutError — Default SDK timeout is 600s; we set 30s. Raise it for large contexts, but pair with a watchdog in calling code.

SSL errors in corporate proxies — Set HTTPS_PROXY env or pass a custom httpx.Client to ChatOpenAI via the client arg.

Inconsistent latency — Expected when the gateway fails over to a secondary provider. Your code should treat the endpoint as a single resilient service, not a specific model instance.

Why this setup holds up in production

Keeping the base_url and api_key in one factory function pays for itself in the first incident. Teams that scatter these parameters across modules lose the ability to switch gateways or rotate keys cleanly. A single make_chat(model, **overrides) helper that returns a configured ChatOpenAI instance gives you one place to inject headers, set timeouts, and enforce model-slug allowlists. The OpenAI-compatible shape means you can later point the same client at a local mock or a different gateway with a one-line config change—no downstream edits required.

Tagslangchainchatopenain4n-aiconfiguration

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 langchain getting started with n4n.ai posts →