Skip to content

Repository files navigation

O4OpenAI - OpenAI / Anthropic Compatible API Gateway

一个可扩展的 API 转换平台,对外同时提供 OpenAI 兼容Anthropic Messages API 兼容的接口,内部调用第三方大模型 API(目前已接入 Agnes AI 和 Moark 模力方舟)。

特性

  • OpenAI Responses API 兼容POST /v1/responses,支持流式和非流式
  • OpenAI API 兼容 — Chat Completions、Images、Videos、Models 接口
  • Anthropic Messages API 兼容 — 支持 POST /v1/messages,兼容 Anthropic SDK
  • 插件化 Provider 架构 — 轻松添加新的第三方平台适配器
  • 流式传输支持 — OpenAI SSE 和 Anthropic SSE 两种格式
  • 客户端 Key 透传 — 支持 Authorization: Bearerx-api-key 两种认证方式
  • 模型映射 — 可以将外部模型名映射到任意 Provider 的模型名
  • 错误透传 — 上游 HTTP 状态码(401/422 等)原样返回给客户端
  • Thinking 模式 — 支持 Agnes 原生的 Thinking 能力(Anthropic 和 OpenAI 两种格式)
  • 工具调用 — 支持完整的 function calling / tool_use 工作流
  • 图生图、首尾帧视频 — 走 Agnes 同一接口,OpenAI 风格封装
  • Multipart 表单支持 — 图片编辑和视频生成支持 multipart/form-data,兼容 OpenAI Python SDK
  • 多图上传 — 图生图支持一次上传最多 16 张图片

支持的 OpenAI 接口

接口 方法 路径 说明
Responses POST /v1/responses OpenAI Responses API,支持流式和非流式
Chat Completions POST /v1/chat/completions 支持流式和非流式
Image Generation POST /v1/images/generations 文生图
Image Edit POST /v1/images/edits 图生图(image + prompt)
Image Variation POST /v1/images/variations 图片变体(Agnes 暂未支持)
Video Generation POST /v1/videos(OpenAI 标准)或 /v1/videos/generations 异步任务:文生视频 / 图生视频 / 首尾帧
Video Status GET /v1/videos/:id 轮询视频任务状态
Video Download GET /v1/videos/:id/content 下载视频文件(302 重定向到视频 URL)
List Models GET /v1/models 列出可用模型
Get Model GET /v1/models/:model 获取模型信息

支持的 Anthropic 接口

接口 方法 路径 说明
Messages POST /v1/messages 兼容 Anthropic Messages API,支持流式和非流式

支持的 Anthropic 特性:

  • system 系统提示(string 或 blocks 数组)
  • max_tokenstemperaturetop_ptop_k
  • stop_sequences 停止序列
  • tools / tool_choice 工具调用
  • thinking 思考模式({"type":"enabled","budget_tokens":2048}
  • stream 流式 SSE(message_start / content_block_delta / message_stop 等完整事件类型)
  • 图片输入(base64 / URL)
  • x-api-keyAuthorization: Bearer 双认证方式

已接入的 Provider

Agnes AI (agnes)

  • Base URL: https://apihub.agnes-ai.com/v1
  • 模型:
    • agnes-1.5-flash — 文本生成
    • agnes-2.0-flash — 文本生成
    • agnes-image-2.0-flash — 文生图
    • agnes-image-2.1-flash — 文生图 / 图生图
    • agnes-video-v2.0 — 文生视频 / 图生视频 / 首尾帧
  • 文档: https://agnes-ai.com/doc

Moark 模力方舟 (moark)

  • Base URL: https://api.moark.com/v1
  • 协议: 高度兼容 OpenAI 官方接口(Chat / Images / Models),同时提供 Anthropic Messages 兼容、OpenAI Responses 兼容(由网关在 handler 层转译到 Chat)。
  • 认证: Authorization: Bearer <你的访问令牌>,调用 /v1/tokens/packages/balance 可查询资源包余额。
  • 文档: https://moark.com/docs/openapi/v1

代表模型(完整列表以 /v1/models 返回为准):

  • Chat / 文本
    • DeepSeek-V3_1-TerminusDeepSeek-V3DeepSeek-R1
    • Qwen2.5-72B-InstructQwen3-235B-A22B-Instruct-2507
    • GLM-4.6GLM-4.7GLM-4.7-Flash
    • ERNIE-4.5-TurboKimi-K2.5Kimi-K2-Thinking
  • 文生图
    • FLUX.1-devQwen-ImageKolorsLongCat-Image
  • 图生图(multipart/form-data)
    • LongCat-Image-EditQwen-Image-EditFLUX.1-Kontext-dev
  • 视频(异步任务)
    • 文生视频:POST /async/videos/generations(model + prompt)
    • 图生视频:POST /async/videos/image-to-video(model + prompt + image_url)
    • 轮询状态:GET /task/{task_id}
    • 模型:Wan2.1-T2V-14BWan2.7HunyuanVideo-1.5CogVideoX-5b
    • ViduQ2-TurboViduQ2-ProViduQ3-TurboViduQ3-ProHappyHorse-1.0

实现要点:

  • Chat / 文本:Moark 接受标准 OpenAI 请求体(含 toolsresponse_format、多模态 image_url 等),网关直接透传。额外参数(如 top_kguided_jsonguided_choice)通过 Extra map 合并到请求体。
  • 图生图/v1/images/edits):Moark 要求 multipart/form-dataimage 字段是 URL 时按文本字段提交;是 base64 / Data URI 时解码后作为文件字段提交。
  • 视频:根据输入类型自动路由到不同端点:
    • 无图片输入 → POST /async/videos/generations(文生视频,body: model + prompt
    • 有图片输入 → POST /async/videos/image-to-video(图生视频,body: model + prompt + image_url
    • 客户端轮询 GET /v1/videos/{id} 时网关转发到 GET /v1/task/{task_id},根据 output.url 拼回 OpenAI 视频响应。
  • 模型发现:支持 GET /v1/models 动态获取上游模型列表,失败时回退到硬编码列表。
  • Anthropic MessagesOpenAI Responses:无需在 provider 层处理,网关统一在 handler 层转译到 Chat 完成后透传。

Provider 能力矩阵

能力 Agnes Moark
Chat ✅(OpenAI 透传)
Image Generation ✅(OpenAI 透传)
Image Edit (图生图) ✅(调用 /images/generationsimage 数组) ✅(/images/edits multipart)
Image Variation ❌(Agnes 无此端点) ❌(Moark 无此端点)
Video Generation ✅(异步任务) ✅(异步任务)
Mask Inpainting ⚠️ Agnes 不支持 mask,已忽略 ⚠️ 部分模型支持 mask

快速开始

安装依赖

go mod tidy

配置

config.yaml 示例:

server:
  port: 1241
  host: "0.0.0.0"
  mode: "debug"

gateway:
  # 外网可访问的 URL,用于 base64 图片转临时 URL
  public_url: "http://your-public-url"
  temp_image_ttl: 10
  temp_image_cleanup_interval: 5

providers:
  agnes:
    base_url: "https://apihub.agnes-ai.com/v1"
    enabled: true
    models:
      - external_model: "agnes-1.5-flash"
        provider_model: "agnes-1.5-flash"
      - external_model: "agnes-2.0-flash"
        provider_model: "agnes-2.0-flash"
      - external_model: "agnes-image-2.0-flash"
        provider_model: "agnes-image-2.0-flash"
      - external_model: "agnes-image-2.1-flash"
        provider_model: "agnes-image-2.1-flash"
      - external_model: "agnes-video-v2.0"
        provider_model: "agnes-video-v2.0"

重要:客户端的 API Key 通过 Authorization: Bearer <key> 头透传给 Provider, 不要config.yaml 中配置 Provider 的 API Key。

启动

go run cmd/server/main.go

或编译后运行:

# macOS
go build -o o4openai ./cmd/server/

# 交叉编译 Linux
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o dist/o4openai-linux-amd64 ./cmd/server/
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o dist/o4openai-linux-arm64 ./cmd/server/

测试用例

1. Chat Completions(非流式)

curl http://localhost:1241/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-1.5-flash",
    "messages": [{"role": "user", "content": "Hello!"}],
    "stream": false
  }'

2. Chat Completions(流式 SSE)

curl -N http://localhost:1241/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-1.5-flash",
    "messages": [{"role": "user", "content": "数到3"}],
    "stream": true
  }'

3. 文生图

curl http://localhost:1241/v1/images/generations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-image-2.1-flash",
    "prompt": "A cute cat",
    "n": 1,
    "size": "1024x1024"
  }'

4. 图生图

# image 可以是 HTTP(S) URL、Data URI (data:image/png;base64,...) 或纯 base64
curl http://localhost:1241/v1/images/edits \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-image-2.1-flash",
    "image": "https://example.com/photo.png",
    "prompt": "Change the sky to a starry night, keep the rest",
    "n": 1,
    "size": "1024x1024"
  }'

5. 文生视频(异步)

RESP=$(curl -s http://localhost:1241/v1/videos \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-video-v2.0",
    "input": [{"type": "text", "text": "A butterfly in a sunny garden"}]
  }')

TASK_ID=$(echo "$RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
echo "Task ID: $TASK_ID"

6. 图生视频

curl http://localhost:1241/v1/videos \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-video-v2.0",
    "input": [
      {"type": "text", "text": "the flower gently sways in the breeze"},
      {"type": "image", "image": "https://example.com/flower.png"}
    ]
  }'

7. 首尾帧生视频

curl http://localhost:1241/v1/videos \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-video-v2.0",
    "input": [
      {"type": "text", "text": "smooth cinematic transition between keyframes"},
      {"type": "image", "image": "https://example.com/frame1.png"},
      {"type": "image", "image": "https://example.com/frame2.png"}
    ]
  }'

8. 轮询视频状态

curl http://localhost:1241/v1/videos/$TASK_ID \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY"

状态流转:queuedin_progresscompleted / failed / expired

completed 时返回:

{
  "id": "task_xxx",
  "status": "completed",
  "output": [{
    "type": "url",
    "url": "https://storage.googleapis.com/.../video.mp4",
    "duration": 5.0,
    "mime_type": "video/mp4"
  }]
}

9. 下载视频内容

# 视频未完成时返回 video_not_ready 错误;完成后 302 重定向到实际视频 URL
curl -L http://localhost:1241/v1/videos/$TASK_ID/content \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -o video.mp4

10. 列出模型

curl http://localhost:1241/v1/models

Anthropic 兼容接口测试

11. Anthropic Messages(非流式)

curl http://localhost:1241/v1/messages \
  -H "x-api-key: YOUR_AGNES_API_KEY" \
  -H "content-type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "agnes-2.0-flash",
    "max_tokens": 256,
    "messages": [{"role": "user", "content": "你好"}]
  }'

响应:

{
  "id": "msg_chatcmpl-xxx",
  "type": "message",
  "role": "assistant",
  "content": [{"type": "text", "text": "你好!"}],
  "model": "agnes-2.0-flash",
  "stop_reason": "end_turn",
  "usage": {"input_tokens": 10, "output_tokens": 3}
}

12. Anthropic Messages(流式 SSE)

curl -N http://localhost:1241/v1/messages \
  -H "x-api-key: YOUR_AGNES_API_KEY" \
  -H "content-type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "agnes-2.0-flash",
    "max_tokens": 128,
    "stream": true,
    "messages": [{"role": "user", "content": "说你好"}]
  }'

13. Anthropic Messages(带 system prompt)

curl http://localhost:1241/v1/messages \
  -H "x-api-key: YOUR_AGNES_API_KEY" \
  -H "content-type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "agnes-2.0-flash",
    "max_tokens": 64,
    "system": "你只能用英文回答",
    "messages": [{"role": "user", "content": "说你好"}]
  }'

14. Anthropic Messages(带 Thinking 模式)

curl http://localhost:1241/v1/messages \
  -H "x-api-key: YOUR_AGNES_API_KEY" \
  -H "content-type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "agnes-2.0-flash",
    "max_tokens": 2048,
    "thinking": {"type": "enabled", "budget_tokens": 1024},
    "messages": [{"role": "user", "content": "写一段 Python 排序代码"}]
  }'

15. 使用 Anthropic Python SDK

import anthropic

client = anthropic.Anthropic(
    base_url="http://localhost:1241",
    api_key="YOUR_AGNES_API_KEY"
)

# 非流式
message = client.messages.create(
    model="agnes-2.0-flash",
    max_tokens=256,
    messages=[{"role": "user", "content": "Hello!"}]
)
print(message.content[0].text)

# 流式
with client.messages.stream(
    model="agnes-2.0-flash",
    max_tokens=256,
    messages=[{"role": "user", "content": "Hello!"}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

8. Responses API(非流式)

curl http://localhost:1241/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-1.5-flash",
    "input": "Hello!",
    "stream": false
  }'

9. Responses API(流式 SSE)

curl -N http://localhost:1241/v1/responses \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_AGNES_API_KEY" \
  -d '{
    "model": "agnes-1.5-flash",
    "input": "Count to 3",
    "stream": true
  }'

错误响应

OpenAI 接口错误

场景 HTTP 状态码
客户端未传 Authorization 401
客户端传了错误的 API Key 401(透传 Agnes 的 401)
请求参数错误(缺字段、格式错) 400
Agnes 上游 4xx 错误(如 422) 透传 4xx
网关内部错误 500

错误响应体遵循 OpenAI 格式:

{
  "error": {
    "message": "Chat completion failed: no API key provided: client must send Authorization: Bearer <key>",
    "type": "invalid_request_error",
    "code": "provider_error"
  }
}

Anthropic 接口错误

Anthropic 接口(/v1/messages)返回 Anthropic 格式的错误:

{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Missing or invalid API key. Please provide x-api-key header."
  }
}
HTTP 状态码 Anthropic 错误类型
400 invalid_request_error
401 authentication_error
403 permission_error
404 not_found_error
429 rate_limit_error
500 api_error
503 overloaded_error

架构

┌──────────────────────────────────────────────────────────────┐
│                        Client                                │
│       (OpenAI SDK / Anthropic SDK / curl / 任何客户端)       │
└──────────┬───────────────────────────────┬───────────────────┘
           │ OpenAI API                    │ Anthropic Messages API
           │ (Authorization: Bearer)       │ (x-api-key / Authorization)
           ▼                               ▼
┌──────────────────────────────────────────────────────────────┐
│                    O4OpenAI Gateway                           │
│                                                              │
│  ┌───────────────┐  ┌──────────────┐  ┌──────────────────┐  │
│  │ OpenAI Handler│  │   Anthropic  │  │    Middleware     │  │
│  │ (chat/image/  │  │   Handler    │  │ (CORS/Log/Auth)  │  │
│  │  video/models)│  │ (/v1/messages)│  │                  │  │
│  └───────┬───────┘  └──────┬───────┘  └──────────────────┘  │
│          │                 │                                  │
│          │   格式转换层    │                                  │
│          │ ◄──────────────┘ (Anthropic → OpenAI → Agnes)    │
│          ▼                                                    │
│  ┌───────────────┐                                           │
│  │   Registry    │  (Provider 注册表/路由)                    │
│  └───────┬───────┘                                           │
│          │                                                    │
│  ┌───────┴──────────────────────────────────────────┐        │
│  │         Provider Interface (接口层)               │        │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────────┐     │        │
│  │  │  Agnes   │ │  Moark   │ │   Future     │     │        │
│  │  │ Provider │ │ Provider │ │  Providers   │     │        │
│  │  └────┬─────┘ └────┬─────┘ └──────────────┘     │        │
│  └───────┼────────────┼────────────────────────────┘        │
│          │ (error/status passthrough)                        │
│          ▼                                                   │
│    Agnes AI API / Moark API                                  │
│    https://apihub.agnes-ai.com/v1                            │
│    https://api.moark.com/v1                                  │
└──────────────────────────────────────────────────────────────┘

添加新的 Provider

  1. internal/provider/ 下创建新目录(如 anthropic/
  2. 实现 model.Provider 接口
  3. config.yaml 中添加 Provider 配置
  4. cmd/server/main.go 中注册 Provider
// model.Provider 接口
type Provider interface {
    Name() string
    SupportedModels() []ModelInfo
    ChatCompletion(ctx, req) (*Response, error)
    ChatCompletionStream(ctx, req) (io.ReadCloser, error)
    ImageGeneration(ctx, req) (*Response, error)
    ImageEdit(ctx, req) (*Response, error)
    ImageVariation(ctx, req) (*Response, error)
    VideoGeneration(ctx, req) (*Response, error)
    VideoRetrieve(ctx, videoID) (*Response, error)
    SupportsChat() bool
    SupportsImageGeneration() bool
    SupportsImageEdit() bool
    SupportsImageVariation() bool
    SupportsVideoGeneration() bool
}

Agnes AI 接口适配差异

差异点 处理方式
图生图端点 Agnes 用 /images/generations + image 数组,而非 OpenAI 的 /images/edits
视频端点 Agnes 用 POST /videos + 异步轮询 GET /videos/{task_id}
视频 URL 字段 Agnes 用 remixed_from_video_id(名字反直觉),我们把它映射到 output[].url
视频状态枚举 Agnes: queued/in_progress/processing/running/completed/failed/expired → 归一化为 OpenAI 标准: queued/in_progress/completed/failed/expired
response_format 位置 图生图的 response_format 必须放在 extra_body
图片输入 image 数组支持公网 URL、Data URI、纯 base64
num_frames 约束 必须是 8n+1,≤ 441;网关自动四舍五入
多图视频 多张图放在 extra_body.image 数组里;含"keyframe"/"transition"时自动设 mode=keyframes
流式输出 Agnes 兼容 OpenAI SSE 格式,直接透传并重写模型名
HTTP 状态码 全部透传上游状态码(401/422 等)
Thinking 模式 Anthropic thinking 字段和 OpenAI chat_template_kwargs 均透传给 Agnes
工具调用 Anthropic tools/tool_choice 转换为 OpenAI 格式后透传给 Agnes
top_k 参数 Anthropic top_k 通过 Extra map 透传给 Agnes

环境变量

变量 说明
O4OPENAI_SERVER_PORT 服务端口(覆盖 config)
O4OPENAI_GATEWAY_PUBLIC_URL 网关外网 URL
O4OPENAI_PROVIDERS_AGNES_APIKEY Agnes 兜底 Key(可选,客户端 Key 优先)

License

MIT

About

一个可扩展的 API 转换平台,对外同时提供 OpenAI 兼容和 Anthropic Messages API 兼容的接口,内部调用第三方大模型 API(目前已接入 Agnes AI)。

Resources

Stars

12 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages