[控场AI]
· 12 分钟阅读· 6,258 字

OpenAI Agents SDK 对接自定义 API 的三种正确姿势

OpenAI Agents SDK 对接自定义 API 的三种正确姿势

OpenAI Agents SDK 对接第三方网关需关闭追踪并切换到 Chat Completions,三种方案可任选。

文章指出 OpenAI Agents SDK 默认使用 Responses API 通信并回传追踪数据,对接仅实现 /v1/chat/completions 的第三方兼容网关时会产生 404 和追踪报错,容易被误判为模型 ID 错误。修复只需两步:调用 set_tracing_disabled(True) 关闭追踪,再用 set_default_openai_api("chat_completions") 切换 API 形态。作者在 openai-agents 0.23.1 版本上验证了三种方案:显式构造 OpenAIChatCompletionsModel、设置进程级默认客户端、或通过 OpenAIProvider(use_responses=False) 配合 RunConfig 传入。文章还强调 base_url 必须止于 /v1,函数工具在 Chat Completions 上照常工作,若网关剥离 tool_calls 属服务器能力问题。

OpenAI Agents SDK(PyPI 包名 openai-agents)为 Python 开发者提供了一套简洁的工具调用智能体框架。但它的默认配置是面向 OpenAI 官方服务的:使用 Responses API 通信,并将追踪数据回传至 OpenAI。一旦你把目标指向第三方 OpenAI 兼容网关而不修改这些默认值,就会遭遇看似“模型 ID 错误”的 404,或是来自追踪器的神秘网络报错。

本文基于 openai-agents 0.23.1 版本,在一个仅实现 /v1/chat/completions 的本地模拟服务上验证了三种可行方案。示例使用 APIClaw 网关(作者自行搭建,请读者自行权衡),基地址为 https://apiclaw.biz/v1。你完全可以将主机、密钥和模型替换为 vLLM、LiteLLM、Ollama 的 /v1 端点,或任何支持 Chat Completions 的服务器。

OpenAI Agents SDK 自定义 API 配置示意

默认配置里的两个陷阱

陷阱一:API 形态不匹配

set_default_openai_api 默认为 "responses",而多数第三方网关只实现了 /v1/chat/completions,并未提供 /v1/responses。向仅支持 Chat 的网关发起 Responses 请求会直接返回 NotFoundError(404)。

Responses API 是 OpenAI 在 2025 年推出的新一代接口,相比 Chat Completions 更偏向「有状态对话」与「内置工具编排」,请求体与返回结构均不同。第三方网关(vLLM、LiteLLM、Ollama 等)普遍以 OpenAI 兼容层的方式实现 /v1/chat/completions,因为这是生态中事实上的通用协议,而被广泛支持;/v1/responses 出现较晚,多数网关尚未跟进。SDK 的 set_default_openai_api 参数决定它调用哪条路由,因此把它设为 "chat_completions" 本质上是让 SDK 回退到兼容性最好的协议层。

陷阱二:追踪数据无处可去

除非显式调用 set_tracing_disabled(True),SDK 会尝试使用 OpenAI API 密钥导出追踪数据。在自定义网关上,该密钥要么不存在,要么对 OpenAI 的追踪端点无效,结果是聊天功能正常但日志里充满噪音。

在排查模型 ID 之前,先修复这两处:

from agents import set_default_openai_api, set_tracing_disabled

set_tracing_disabled(True)
set_default_openai_api("chat_completions")

Agents SDK 内置的追踪(tracing)机制会把每次运行中的智能体调用、工具调用与交接过程打包成 trace,默认导出到 OpenAI 的追踪端点,用于在官方后台做可视化调试。这一过程独立于对话请求本身,因此即使聊天请求已经指向第三方网关,追踪导出仍会尝试访问 OpenAI 域名并使用你的 OpenAI 密钥鉴权。在自建或第三方网关上,该密钥通常不是合法的 OpenAI 密钥,于是导出失败并在日志中反复报错。set_tracing_disabled(True) 只是关闭这一可选的观测能力,不影响智能体的推理与工具调用行为。

方案 A:OpenAIChatCompletionsModel(最明确)

将配置了自定义 base_url 的 AsyncOpenAI 客户端传入 OpenAIChatCompletionsModel,智能体就完全不会触碰 Responses 路径。

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",  # 注意包含 /v1
    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())

如果不希望在调用处引入 asyncio,Runner.run_sync(...) 的效果完全相同。

方案 B:设置进程级默认客户端

当进程中所有智能体都应使用同一网关时,一次性设置全局默认值更为简洁。

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",  # 现在直接传字符串即可
)

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

顺序很重要:若默认 API 仍为 "responses",同一个客户端仍会向 /v1/responses 发请求,仅支持 Chat 的网关依旧返回 404。

方案 C:OpenAIProvider + use_responses=False

当你需要通过 RunConfig(model_provider=...) 传入提供者对象而非修改全局配置时,OpenAIProvider 是标准做法。

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 会让 get_model 返回 OpenAIChatCompletionsModel。你也可以直接把 base_url= 和 api_key= 传给 OpenAIProvider,省去预先构建客户端。

RunConfig 是 Runner.run / run_sync 的每次运行级配置对象,可用来覆盖模型提供者、模型设置、输入过滤等,而无需改动进程级全局状态。OpenAIProvider 则封装了「如何根据模型名构造出模型对象」的逻辑:当 use_responses=True(默认)时,get_model 返回走 Responses 路由的模型包装器;设为 False 则返回 OpenAIChatCompletionsModel。这种方式的优势在于配置随调用传递,同一进程中不同智能体可以使用不同提供者,适合多网关共存或测试环境与生产环境混用的场景。

base_url 的 /v1 路径规则

OpenAI Python 客户端会在你提供的 base_url 后追加 /chat/completions。路径拼错的后果很直接:

base_url实际请求路径在 OpenAI 布局网关上的典型结果
https://apiclaw.biz/v1/v1/chat/completions成功
https://apiclaw.biz/chat/completions404
https://apiclaw.biz/v1/chat/completions/v1/chat/completions/chat/completions404

永远只写到 /v1,不要把完整的聊天端点粘贴进 base_url。

保持 Responses 时会看到什么

在笔者仅支持 Chat 的模拟服务上,保留默认 "responses" 会抛出:

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

这并非模型 ID 有误,而是 SDK 调用了不同路由。切换到 Chat Completions(上述任一方案)后,用同样的模型字符串重试即可。

函数工具在 Chat Completions 上照常工作

函数工具经过同一模型包装器,因此功能不受影响。最小示例如下:

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)

如果网关从聊天响应中剥离了 tool_calls,智能体会陷入循环或直接给出无工具调用的回答——这属于服务器能力问题,而非 Agents SDK 的 base_url 缺陷。在深入调试 runner 之前,先用带 "tools" 字段的原始 /v1/chat/completions 请求验证一次。

实用检查清单

  1. pip install openai-agents(本文测试版本 0.23.1)。
  2. 除非你确实要向 OpenAI 发送追踪数据,否则调用 set_tracing_disabled(True)。
  3. 强制使用 Chat Completions:OpenAIChatCompletionsModel、set_default_openai_api("chat_completions") 或 OpenAIProvider(..., use_responses=False) 三选一。
  4. base_url 以 /v1 结尾,而非 /v1/chat/completions。
  5. 模型 ID 取自网关模型列表的完整字符串,不用简短别名。
  6. 在封装进 Agent 之前,先确认裸的 client.chat.completions.create(...) 能正常调用。

这六项一旦到位,Agents SDK 就不再与网关较劲,你可以专心打磨指令、工具和智能体交接逻辑了。

#OpenAI Agents SDK#自定义 API#Chat Completions#Responses API#base_url 配置#追踪禁用#OpenAIProvider#工具调用
分享:

相关推荐