快速开始
部署受支持的 Docker Compose 技术栈,接入供应商与模型,签发 API 密钥,并发出第一个请求。
本指南带你从零到一,向自部署的 Cordy Gateway 发出一个可用的请求。它采用受支持的部署路径——Docker Compose——并以一个真实的对话补全收尾,分别通过 curl、OpenAI Python SDK 与 OpenAI JavaScript SDK 完成。
预计约 15–20 分钟。你将:
- 检查前置条件。
- 在
.env文件中配置密钥。 - 用 Docker Compose 启动生产技术栈。
- 创建管理员用户。
- 在 Admin 中注册供应商、通道与模型。
- 签发一个
wnx_API 密钥。 - 发出第一个请求。
- 验证健康状态。
1. 前置条件
- Docker Engine 24+ 与 Docker Compose v2 插件(
docker compose,而非旧版docker-compose)。 - 主机上已有 Cordy Gateway 发行物(仓库或交付包),以便
docker-compose.prod.yml以及deploy/与docker/目录齐备。 - 主机为完整技术栈(Postgres、Redis、PgBouncer、Admin、Gateway、worker、nginx)预留至少 4 GB 空闲内存。
- 真实生产部署需要:域名与 TLS 证书。内置 nginx 终止的是明文 HTTP;请在
docker/nginx/中加入443server block 与证书,或用你自己的反向代理置于技术栈之前。本地试用可跳过 TLS(见第 2 步的说明)。
确认 Docker 就绪:
docker --version
docker compose version
2. 配置密钥
复制模板并填全占位符:
cp deploy/env.template .env
生成你必须设置的三个密钥:
# Django 密钥
python -c "import secrets; print(secrets.token_urlsafe(50))"
# 通道凭据加密密钥(Fernet)
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# 一个强数据库口令——任意长随机串
python -c "import secrets; print(secrets.token_urlsafe(24))"
至少在 .env 中设置以下必填变量:
| 变量 | 用途 | 说明 |
|---|---|---|
DB_NAME | Postgres 数据库名 | 例如 cordy |
DB_USER | Postgres 用户 | |
DB_PASSWORD | Postgres 口令 | 使用生成的值 |
DJANGO_SECRET_KEY | Django 加密密钥 | 使用生成的值 |
DJANGO_ALLOWED_HOSTS | Admin 服务的主机名 | 逗号分隔;本地试用加 localhost,127.0.0.1 |
DJANGO_ADMIN_URL | Admin URL 路径前缀 | 必须以 / 结尾;取一个不显而易见的值,例如 ops-7f3a/ |
CHANNEL_ENCRYPTION_KEYS | 上游凭据的 Fernet 密钥 | Admin 与 Gateway 服务必须一致 |
本地试用说明:内置 nginx 提供明文 HTTP。仅在无 TLS 的本地测试时,才在
.env中设置DJANGO_SECURE_SSL_REDIRECT=False,使 Admin 不强制跳转 HTTPS。任何真实部署都应保持其默认值True。
CHANNEL_ENCRYPTION_KEYS 在生产中为必填:Gateway 与 Admin 缺少它都会拒绝启动,且两者必须使用相同的值,否则通道凭据无法解密。请将 .env 排除在版本控制之外,并把密钥存放在你的密钥管理系统中。
每个变量详见配置参考。
3. 启动技术栈
docker compose -f docker-compose.prod.yml --env-file .env up -d --build
它会启动完整的生产拓扑:
| 服务 | 角色 | 端口 |
|---|---|---|
nginx | 负载均衡 / TLS 终止点 | 发布 GATEWAY_HTTP_PORT(默认 8002) |
gateway | 数据平面(Starlette + Granian,兼容 OpenAI 的 API) | 内部 8002,由 nginx 前置 |
admin | 控制平面(Django Admin) | 发布 ADMIN_HTTP_PORT(默认 8001) |
postgres | 带 pg_cron 的 PostgreSQL 18 | 仅内部 |
pgbouncer | 网关热路径的事务连接池 | 仅内部 |
redis | Redis 8——速率限制、配额、缓存、缓冲 | 仅内部 |
worker | 后台 worker(用量结算、审计上传) | 仅内部 |
Admin 容器会自动执行数据库迁移并收集静态文件,然后再启动。Postgres、PgBouncer 与 Redis 仅在内部网络,不对主机发布。
观察启动并确认服务健康:
docker compose -f docker-compose.prod.yml ps
docker compose -f docker-compose.prod.yml logs -f admin
4. 创建管理员用户
创建一个 Django 超级用户以登录 Admin:
docker compose -f docker-compose.prod.yml exec admin \
uv run python manage.py createsuperuser
按提示输入邮箱与口令。随后在此登录:
http://<host>:8001/<DJANGO_ADMIN_URL>
例如,若 DJANGO_ADMIN_URL=ops-7f3a/,登录 URL 即为 http://<host>:8001/ops-7f3a/。
5. 注册供应商、通道与模型
Cordy Gateway 通过一条记录链来解析客户端请求的 model。你在 Admin 的 Gateway Configuration 下一次性创建它们。服务一个模型所需的最小接线:
- Provider(供应商)——上游厂商集成(例如 OpenAI)。设置
name、provider_type(例如OPENAI)与状态ACTIVE。 - Public model(公开模型)——客户端在
model字段中请求的公开标识(例如 sluggpt-4o-mini)。这是客户端唯一能看到的模型名。 - Provider model(供应商模型)——将 Provider 与 Public model 关联到具体上游模型名(例如
gpt-4o-mini),并带input_price/output_price与能力标志(supports_chat、supports_embeddings、supports_streaming)。 - Channel(通道)——该 Provider 上的一个路由目标。设置其上游凭据(API 密钥——以 Fernet 加密存储)、可选
base_url、weight、priority与可选region。 - Channel provider model(通道-供应商模型绑定)——将 Channel 与 Provider model 绑定,使该模型可经由该通道提供服务。该供应商模型必须属于该通道所属的供应商。
一旦至少有一个活跃通道能服务你的公开模型,该模型即变为可路由。完整演练见供应商,链路在请求时如何解析见核心概念。
6. 签发 API 密钥
在 Admin 中创建(或选定)一个用户,然后为该用户创建 API key。创建时,网关会生成一个以 wnx_ 为前缀的密钥,并仅一次显示完整明文——请立即复制;数据库只保存其 SHA-256 哈希。
创建密钥时,设置:
- Scopes(作用域)——该密钥可调用的接口族(
chat、completions、embeddings、models、balance、admin)。只授予所需项;空作用域列表表示"允许所有该拥有者本可访问的接口"(遗留默认)。新密钥应遵循最小权限。 - Quota(配额)——月度令牌额度。
- Rate limit(速率限制)——每分钟请求数。
导出密钥以供下一步使用:
export CORDY_API_KEY="wnx_...你的密钥..."
export CORDY_BASE_URL="http://<host>:8002/v1" # 生产环境使用 https://...
7. 发出第一个请求
curl
curl -sS "$CORDY_BASE_URL/chat/completions" \
-H "Authorization: Bearer $CORDY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "用一句话向 Cordy Gateway 打个招呼。"}
]
}'
请把 gpt-4o-mini 替换为你创建的公开模型 slug。成功的响应是一个标准的 OpenAI 对话补全对象。
Python(OpenAI SDK)
pip install openai
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["CORDY_API_KEY"],
base_url=os.environ["CORDY_BASE_URL"], # http://<host>:8002/v1
)
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "用一句话向 Cordy Gateway 打个招呼。"}
],
)
print(resp.choices[0].message.content)
JavaScript / TypeScript(OpenAI SDK)
npm install openai
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.CORDY_API_KEY,
baseURL: process.env.CORDY_BASE_URL, // http://<host>:8002/v1
});
const resp = await client.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "user", content: "用一句话向 Cordy Gateway 打个招呼。" },
],
});
console.log(resp.choices[0].message.content);
8. 验证健康状态
健康接口为公开访问(无需 API 密钥):
# 存活——进程是否在运行?
curl -sS http://<host>:8002/health
# 就绪——此刻是否真能服务对话/嵌入?
curl -sS http://<host>:8002/health/ready
# 各供应商健康明细
curl -sS http://<host>:8002/health/providers
进程一旦运行,/health 即返回 200。在至少有一个通道可服务流量之前,/health/ready 与 /health/detailed 会返回 503——这在你完成第 5 步接线之前属于预期;一旦有模型可路由即转为 200。
故障排查
- 部署后每个请求都返回
401。 网关数据平面直接从DB_NAME/DB_USER/DB_PASSWORD构建数据库 DSN(它不解析DATABASE_URL)。若这些在gateway服务上缺失或有误,它便无法连上数据库,所有请求鉴权失败。确认网关的DB_*值与 admin 一致。 401 invalid_api_key。 密钥有误或从未激活。在 Admin 中重新签发密钥,并原样复制那一次性明文,包括wnx_前缀。404 model_not_found或/v1/models列表为空。 模型链不完整或未激活。确认 Public model、Provider model、Channel 与 Channel-provider-model 记录均存在且为ACTIVE,且通道有有效的上游凭据。/health/ready一直是503。 尚无通道可服务流量。完成供应商/通道/模型接线,再查看/health/providers的各供应商状态以及admin与gateway日志。- 本地无 TLS 试用时 Admin 登录跳转到 HTTPS。 在
.env中设置DJANGO_SECURE_SSL_REDIRECT=False并重建admin服务。真实部署切勿如此。 CHANNEL_ENCRYPTION_KEYS启动报错。 该变量未设置,或 Admin 与 Gateway 值不同。为两个服务设置相同的 Fernet 密钥。- 供应商调用返回上游鉴权错误。 通道存储的凭据有误。在 Admin 中编辑该通道并重新填入上游 API 密钥。