[KongchangAI]
· 2 min read· 1,471 words

Three Correct Ways to Connect OpenAI Agents SDK to a Custom API

Three Correct Ways to Connect OpenAI Agents SDK to a Custom API

The OpenAI Agents SDK needs tracing disabled and Chat Completions enabled to connect to third-party gateways; three approaches available.

The OpenAI Agents SDK defaults to the Responses API and OpenAI tracing, causing 404s and tracing errors when connecting to third-party gateways that implement only /v1/chat/completions. Fix it in two steps: set_tracing_disabled(True) and set_default_openai_api("chat_completions"). The author validated three approaches on openai-agents 0.23.1: explicit OpenAIChatCompletionsModel, a process-level default client, or OpenAIProvider(use_responses=False) via RunConfig. Also ensure base_url ends at /v1, and note that function tools work normally on Chat Completions.

Title

Three Correct Ways to Connect OpenAI Agents SDK to a Custom API

Meta Description

The OpenAI Agents SDK defaults to the Responses API and OpenAI tracing, which leads to 404s when connecting to third-party compatible gateways. This article covers three configuration approaches (OpenAIChatCompletionsModel, a process-level default client, and OpenAIProvider), plus base_url path rules, tool-calling verification, and a checklist to help developers quickly adapt to custom APIs.

The OpenAI Agents SDK (PyPI package name openai-agents) gives Python developers a clean framework for tool-calling agents. But its defaults are oriented toward OpenAI's official services: it communicates via the Responses API and sends tracing data back to OpenAI. The moment you point it at a third-party OpenAI-compatible gateway without changing these defaults, you'll hit 404s that look like "wrong model ID" errors, or mysterious network errors from the tracer.

This article is based on openai-agents version 0.23.1 and validates three viable approaches against a local mock service that implements only /v1/chat/completions. The examples use the APIClaw gateway (built by the author; evaluate it at your own discretion), with a base URL of https://apiclaw.biz/v1. You can freely substitute the host, key, and model with the /v1 endpoints of vLLM, LiteLLM, Ollama, or any server that supports Chat Completions.

OpenAI Agents SDK custom API configuration diagram

Two Traps in the Default Configuration

Trap One: API Shape Mismatch

set_default_openai_api defaults to "responses", but most third-party gateways implement only /v1/chat/completions and do not provide /v1/responses. Sending a Responses request to a Chat-only gateway returns a NotFoundError (404) directly.

Responses API is OpenAI's next-generation interface introduced in 2025. Compared with Chat Completions, it leans more toward "stateful conversations" and "built-in tool orchestration," and both its request body and response structure differ. Third-party gateways (vLLM, LiteLLM, Ollama, etc.) generally implement /v1/chat/completions as a compatibility layer because it is the de facto universal protocol in the ecosystem and is widely supported; /v1/responses appeared later, and most gateways have not caught up yet. The SDK's set_default_openai_api parameter determines which route it calls, so setting it to "chat_completions" essentially makes the SDK fall back to the most compatible protocol layer.

Trap Two: Nowhere for Tracing Data to Go

Unless you explicitly call set_tracing_disabled(True), the SDK will try to export tracing data using your OpenAI API key. On a custom gateway, that key either doesn't exist or is invalid for OpenAI's tracing endpoint, so chat works fine but the logs are full of noise.

Before troubleshooting model IDs, fix these two things first:

from agents import set_default_openai_api, set_tracing_disabled

set_tracing_disabled(True)
set_default_openai_api("chat_completions")

The tracing mechanism built into the Agents SDK packages each run's agent calls, tool calls, and handoffs into a trace, which by default is exported to OpenAI's tracing endpoint for visual debugging in the official dashboard. This process is independent of the conversation requests themselves, so even if chat requests already point to a third-party gateway, tracing export still attempts to access the OpenAI domain and authenticate with your OpenAI key. On a self-hosted or third-party gateway, that key is usually not a valid OpenAI key, so the export fails and repeatedly reports errors in the logs. set_tracing_disabled(True) simply disables this optional observability feature and does not affect the agent's reasoning or tool-calling behavior.

Approach A: OpenAIChatCompletionsModel (Most Explicit)

Pass an AsyncOpenAI client configured with a custom base_url into OpenAIChatCompletionsModel, and the agent will never touch the Responses path.

import asyncio
from openai import AsyncOpenAI
from agents import Agent, Runner, OpenAIChatCompletionsModel, set_tracing_disabled

set_tracing_disabled(True)

client = AsyncOpenAI(
    base_url="https://apiclaw.biz/v1",  # note the /v1 included
    api_key="YOUR_API_KEY",
)

model = OpenAIChatCompletionsModel(
    model="YOUR_MODEL_ID",
    openai_client=client,
)

agent = Agent(
    name="assistant",
    instructions="Reply in one short paragraph.",
    model=model,
)

async def main():
    result = await Runner.run(agent, "What is a base URL in an OpenAI client?")
    print(result.final_output)

asyncio.run(main())

If you don't want to introduce asyncio at the call site, Runner.run_sync(...) works identically.

Approach B: Setting a Process-Level Default Client

When all agents in the process should use the same gateway, setting the global default once is cleaner.

from openai import AsyncOpenAI
from agents import (
    Agent,
    Runner,
    set_default_openai_client,
    set_default_openai_api,
    set_tracing_disabled,
)

set_tracing_disabled(True)
set_default_openai_client(
    AsyncOpenAI(base_url="https://apiclaw.biz/v1", api_key="YOUR_API_KEY")
)
set_default_openai_api("chat_completions")

agent = Agent(
    name="assistant",
    instructions="Be concise.",
    model="YOUR_MODEL_ID",  # now just pass the string directly
)

result = Runner.run_sync(agent, "List three reasons to pin a base URL.")
print(result.final_output)

Order matters: if the default API is still "responses", the same client will still send requests to /v1/responses, and a Chat-only gateway will still return 404.

Approach C: OpenAIProvider + use_responses=False

When you need to pass a provider object through RunConfig(model_provider=...) rather than modifying global configuration, OpenAIProvider is the standard approach.

from openai import AsyncOpenAI
from agents import Agent, Runner, OpenAIProvider, RunConfig, set_tracing_disabled

set_tracing_disabled(True)

client = AsyncOpenAI(base_url="https://apiclaw.biz/v1", api_key="YOUR_API_KEY")
provider = OpenAIProvider(openai_client=client, use_responses=False)

agent = Agent(
    name="assistant",
    instructions="Be concise.",
    model="YOUR_MODEL_ID",
)

result = Runner.run_sync(
    agent,
    "Explain chat completions vs responses in one sentence.",
    run_config=RunConfig(model_provider=provider),
)
print(result.final_output)

use_responses=False makes get_model return OpenAIChatCompletionsModel. You can also pass base_url= and api_key= directly to OpenAIProvider, saving you from pre-building the client.

RunConfig is the per-run configuration object for Runner.run / run_sync. It can override the model provider, model settings, input filters, and so on without changing process-level global state. OpenAIProvider encapsulates the logic of "how to construct a model object from a model name": when use_responses=True (the default), get_model returns a model wrapper that goes through the Responses route; setting it to False returns OpenAIChatCompletionsModel. The advantage of this approach is that the configuration travels with the call, so different agents in the same process can use different providers — ideal for scenarios with multiple gateways coexisting or where test and production environments are mixed.

/v1 Path Rules for base_url

The OpenAI Python client appends /chat/completions to the base_url you provide. Getting the path wrong has immediate consequences:

base_urlActual request pathTypical result on an OpenAI-layout gateway
https://apiclaw.biz/v1/v1/chat/completionsSuccess
https://apiclaw.biz/chat/completions404
https://apiclaw.biz/v1/chat/completions/v1/chat/completions/chat/completions404

Always stop at /v1; never paste the full chat endpoint into base_url.

What You'll See If You Keep Responses

On the author's Chat-only mock service, keeping the default "responses" throws:

openai.NotFoundError: Error code: 404 -
{'error': {'message': 'Responses API not available on this gateway',
           'type': 'invalid_request_error'}}

This is not a wrong model ID — the SDK is calling a different route. After switching to Chat Completions (any of the approaches above), retry with the same model string.

Function Tools Work as Usual on Chat Completions

Function tools go through the same model wrapper, so functionality is unaffected. Here's a minimal example:

from agents import Agent, Runner, OpenAIChatCompletionsModel, function_tool, set_tracing_disabled
from openai import AsyncOpenAI

set_tracing_disabled(True)
client = AsyncOpenAI(base_url="https://apiclaw.biz/v1", api_key="YOUR_API_KEY")

@function_tool
def add(a: int, b: int) -> int:
    """Add two integers."""
    return a + b

agent = Agent(
    name="math",
    instructions="Use the add tool for arithmetic.",
    model=OpenAIChatCompletionsModel(model="YOUR_MODEL_ID", openai_client=client),
    tools=[add],
)

print(Runner.run_sync(agent, "What is 7 + 5?").final_output)

If the gateway strips tool_calls from the chat response, the agent will get stuck in a loop or give an answer without tool calls — that's a server capability issue, not an Agents SDK base_url defect. Before diving deep into debugging the runner, verify with a raw /v1/chat/completions request that includes a "tools" field.

Practical Checklist

  1. pip install openai-agents (version 0.23.1 was tested in this article).
  2. Unless you genuinely want to send tracing data to OpenAI, call set_tracing_disabled(True).
  3. Force Chat Completions: pick one of OpenAIChatCompletionsModel, set_default_openai_api("chat_completions"), or OpenAIProvider(..., use_responses=False).
  4. base_url ends with /v1, not /v1/chat/completions.
  5. The model ID is the full string from the gateway's model list, not a short alias.
  6. Before wrapping it in an Agent, confirm that a bare client.chat.completions.create(...) call works.

Once these six items are in place, the Agents SDK stops fighting the gateway, and you can focus on refining your instructions, tools, and agent handoff logic.

One-line Summary

The OpenAI Agents SDK requires disabling tracing and switching to Chat Completions when connecting to third-party gateways, with three approaches to choose from.

Paragraph Summary

The article points out that the OpenAI Agents SDK defaults to communicating via the Responses API and sending tracing data back to OpenAI. When connecting to third-party compatible gateways that implement only /v1/chat/completions, this produces 404s and tracing errors that are easily mistaken for wrong model IDs. The fix takes just two steps: call set_tracing_disabled(True) to disable tracing, then use set_default_openai_api("chat_completions") to switch the API shape. The author validated three approaches on version 0.23.1 of openai-agents: explicitly constructing an OpenAIChatCompletionsModel, setting a process-level default client, or passing OpenAIProvider(use_responses=False) via RunConfig. The article also emphasizes that base_url must end at /v1, that function tools work as usual on Chat Completions, and that a gateway stripping tool_calls is a server capability issue.

#OpenAI Agents SDK#custom API#Chat Completions#base_url#third-party gateway
Share:

Related articles