客户端集成

把任意 OpenAI SDK 指向 Cordy Gateway——鉴权、流式、工具调用、嵌入、路由请求头与产品化扩展。

Cordy Gateway 使用 OpenAI API。任何能指定自定义 base_url 的客户端或 SDK,除了 URL 与密钥外无需改动代码即可工作。本页端到端展示常见集成模式。

连接

在你的客户端上设置两项:

  • Base URL: https://<host>:8002/v1(仅本地无 TLS 试用时使用 http://)。
  • API key: 一个以 wnx_ 为前缀的密钥,作为 bearer 令牌发送。

鉴权接受两种请求头之一:

Authorization: Bearer wnx_<key>

X-API-Key: wnx_<key>

标准 OpenAI SDK 会自动使用 Authorization: Bearer 形式。API 密钥必须放在请求头中——URL 查询串中的密钥不被接受。

Python

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["CORDY_API_KEY"],   # wnx_...
    base_url=os.environ["CORDY_BASE_URL"],  # https://<host>:8002/v1
)

JavaScript / TypeScript

import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.CORDY_API_KEY,   // wnx_...
  baseURL: process.env.CORDY_BASE_URL, // https://<host>:8002/v1
});

全文中,model 都是在 Admin 中配置的公开模型 slug,而非厂商模型名。

对话补全

非流式

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "system", "content": "你是一个简洁的助手。"},
        {"role": "user", "content": "用一行话介绍 Cordy Gateway。"},
    ],
    temperature=0.7,
    max_tokens=256,
)
print(resp.choices[0].message.content)
const resp = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [
    { role: "system", content: "你是一个简洁的助手。" },
    { role: "user", content: "用一行话介绍 Cordy Gateway。" },
  ],
  temperature: 0.7,
  max_tokens: 256,
});
console.log(resp.choices[0].message.content);

每个对话请求都必须至少包含一条 user 消息;仅有 system 或仅有 assistant 的历史会以 400 被拒绝。

流式(SSE)

设置 stream=True 以在生成过程中接收服务端事件(server-sent events)。流以 [DONE] 哨兵结束。

stream = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "流式输出一首关于路由的短诗。"}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
print()
const stream = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "流式输出一首关于路由的短诗。" }],
  stream: true,
});
for await (const chunk of stream) {
  const delta = chunk.choices[0]?.delta?.content;
  if (delta) process.stdout.write(delta);
}

若上游流在没有 finish reason 的情况下关闭,网关会在 [DONE] 之前发出一个带内的 stream_interrupted 错误事件,使客户端能区分正常结束与截断。路由请求头(X-Channel-IdX-ProviderX-Failover-Count)在流式响应与非流式响应上均存在。

用 curl 查看原始 SSE:

curl -N "$CORDY_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $CORDY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini","stream":true,"messages":[{"role":"user","content":"hi"}]}'

工具 / 函数调用

工具调用使用标准的 OpenAI toolstool_choice 字段。若传入 tool_choice,则也必须传入非空的 tools 列表。

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取某城市的当前天气。",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
            },
        },
    }
]

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "巴黎现在天气怎么样?"}],
    tools=tools,
    tool_choice="auto",
)

msg = resp.choices[0].message
if msg.tool_calls:
    call = msg.tool_calls[0]
    print(call.function.name, call.function.arguments)
const tools = [
  {
    type: "function",
    function: {
      name: "get_weather",
      description: "获取某城市的当前天气。",
      parameters: {
        type: "object",
        properties: { city: { type: "string" } },
        required: ["city"],
      },
    },
  },
];

const resp = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "巴黎现在天气怎么样?" }],
  tools,
  tool_choice: "auto",
});

const msg = resp.choices[0].message;
if (msg.tool_calls) {
  const call = msg.tool_calls[0];
  console.log(call.function.name, call.function.arguments);
}

你可以把 assistant 消息回写进 messages(规范的多轮模式),把你的工具结果作为 role: "tool" 消息追加,再次调用以让模型使用该结果。

嵌入

emb = client.embeddings.create(
    model="text-embedding-3-small",
    input=["第一段文档", "第二段文档"],
)
print(len(emb.data), "个向量")
print(len(emb.data[0].embedding), "维")
const emb = await client.embeddings.create({
  model: "text-embedding-3-small",
  input: ["第一段文档", "第二段文档"],
});
console.log(emb.data.length, "个向量");

input 接受单个字符串或字符串数组。空输入会以 400 被拒绝。

仅支持文本

网关目前仅支持文本。对话消息的 content 可以是普通字符串,或一个 {"type": "text", "text": "..."} 分片数组(会被拼接)。任何非文本分片——image_urlaudio 等多模态类型——都会以清晰的 400 错误被拒绝。请勿发送图像或音频。

产品化扩展

在 OpenAI 标准接口之外,网关还暴露只读的产品化接口,你的客户端可用同一密钥调用(它们需要 balance 作用域)。

余额与配额

curl -sS "$CORDY_BASE_URL/balance" -H "Authorization: Bearer $CORDY_API_KEY"

返回该密钥的令牌配额(quota_limitquota_usedquota_remaining)以及所属用户的预付 credit_balance_usd

订阅

curl -sS "$CORDY_BASE_URL/subscriptions" -H "Authorization: Bearer $CORDY_API_KEY"

返回用户的等级、套餐、订阅状态与功能摘要。

套餐目录

curl -sS "$CORDY_BASE_URL/packages" -H "Authorization: Bearer $CORDY_API_KEY"

返回平台套餐的只读目录(等级、配额上限、定价)。

用量分析

curl -sS "$CORDY_BASE_URL/account/analytics?period_days=30" \
  -H "Authorization: Bearer $CORDY_API_KEY"

返回已鉴权用户自身在一个滚动窗口内聚合的用量、时延与成本。period_days 接受 1365(默认 30);越界值会被夹取。注意:此接口仅在 /v1 前缀下可用。

请求头

你可以按请求影响路由与可靠性:

请求头取值作用
X-Routing-Strategyweightedcheapestfastestregion_aware覆盖本请求的路由策略。
X-Region区域代码,例如 us-eastregion_aware 路由设置调用方区域。
Idempotency-Key任意唯一字符串为 POST 提供重放保护:TTL 内的重复请求返回已存响应,而不再次调用上游。也接受 X-Idempotency-Key

示例——最便宜路由 + 幂等键:

curl -sS "$CORDY_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $CORDY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Routing-Strategy: cheapest" \
  -H "Idempotency-Key: order-4711-attempt-1" \
  -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}]}'

用 OpenAI SDK 传自定义请求头:

resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "hi"}],
    extra_headers={"X-Routing-Strategy": "fastest"},
)
const resp = await client.chat.completions.create(
  { model: "gpt-4o-mini", messages: [{ role: "user", content: "hi" }] },
  { headers: { "X-Routing-Strategy": "fastest" } },
);

响应头

成功响应包含可供你记录或呈现的可观测性请求头:

请求头含义
X-Channel-Id服务本请求的通道。
X-Provider所用的上游供应商。
X-Failover-Count成功前尝试了多少个通道。
X-Routing-Overhead-Ms路由所耗时间,不含上游调用。
X-Idempotency-Status重放了已存响应时为 hit;未适用幂等时为 skipped

错误处理

错误使用 OpenAI 风格的信封:{"error": {"type", "message", "code", ...}}。你的客户端应显式处理的有:

  • 402 insufficient_credits——账户预付信用耗尽。应停止并充值,而非重试;重试会同样失败。
  • 429code: quota_exceeded(月度令牌配额)或速率限制码——退避后稍后重试,或提高上限。
  • 401——密钥缺失、无效、已吊销、未激活或已过期。不要用同一密钥重试。
  • 403 scope_denied——密钥缺少该接口的作用域。签发一个具备正确作用域的密钥。
  • 503 auth_service_unavailable——瞬时的鉴权基础设施问题。遵循 Retry-After 并重试。

完整错误表见 API 参考

关于 Cordy 客户端应用的说明

Cordy 自家的终端用户客户端应用是独立产品。它们可选择性地将某个 Cordy Gateway 部署指定为后端,但并非必需——如上所示,任何兼容 OpenAI 的客户端都可直接对网关工作。

后续步骤

  • API 参考——完整的接口、作用域与错误表。
  • 供应商——服务端如何配置模型与路由。