编写 API 代理:统一 Anthropic Messages、OpenAI Response、DeepSeek 格式

发布于 2026-07-26 04:38

编写 API 代理:统一 Anthropic Messages、OpenAI Response、DeepSeek 格式

1. 统一中间格式设计

设计一个内部标准格式,能够表达三种 API 的公共能力:

字段 类型 说明
model string 模型名称
messages array 消息数组(user/assistant)
system string (opt) 系统提示,独立字段便于转换
max_tokens int 最大输出 token
temperature float 随机性控制
top_p float 核采样概率
top_k int (opt) Anthropic 专有
stop list[str] 停止词
stream bool 是否流式
tools list 工具定义

2. 核心差异映射

内部格式 Anthropic Messages OpenAI Response (Codex) DeepSeek Chat
max_tokens max_tokens max_output_tokens max_tokens
stop stop_sequences stop stop
system 顶层参数 instructions messages[0].role=system
top_k 支持 不支持 不支持
thinking 支持 不支持 不支持

3. 架构图

+-------------------------------------------------------------+
|                     Client Request                          |
|                POST /v1/unified/chat                       |
+---------------------------+---------------------------------+
                            |
                            v
+-------------------------------------------------------------+
|                   Unified API Layer                         |
|  +-------------+  +-------------+  +-------------+         |
|  |    Router   |  |  Validator  |  |  Translater |         |
+---------------------------+---------------------------------+
                            |
                            v
+-------------------------------------------------------------+
|                    Provider Adapters                        |
|  +----------+  +----------+  +----------+                  |
|  |Anthropic  |  |OpenAI Resp |  |DeepSeek   |              |
|  |          |  |(Codex)    |  |          |                  |
+---------------------------+---------------------------------+
                            |
                            v
+-------------------------------------------------------------+
|                   Provider APIs                             |
|  https://api.anthropic.com/v1/messages                     |
|  https://api.openai.com/v1/responses                       |
|  https://api.deepseek.com/v1/chat/completions              |
+-------------------------------------------------------------+

4. 路由配置 Schema

providers:
  - name: anthropic
    base_url: https://api.anthropic.com
    endpoint: /v1/messages
    models: [claude-*, claude-*]
    headers:
      x-api-key: ${ANTHROPIC_API_KEY}
      
  - name: openai_response
    base_url: https://api.openai.com/v1
    endpoint: /responses
    models: [o1-*, o3-*, computer-use-preview]
    headers:
      Authorization: Bearer ${OPENAI_API_KEY}
      
  - name: deepseek
    base_url: https://api.deepseek.com/v1
    endpoint: /chat/completions
    models: [deepseek-chat, deepseek-coder]
    headers:
      Authorization: Bearer ${DEEPSEEK_API_KEY}

5. 请求格式转换

def to_anthropic(req: UnifiedRequest) -> dict:
    body = {
        "model": req.model,
        "max_tokens": req.max_tokens,
        "messages": req.messages,
        "temperature": req.temperature,
        "top_p": req.top_p,
    }
    if req.system:
        body["system"] = req.system
    if req.stop:
        body["stop_sequences"] = req.stop
    if req.thinking:
        body["thinking"] = req.thinking
    return body

def to_openai_response(req: UnifiedRequest) -> dict:
    return {
        "model": req.model,
        "input": req.messages,
        "max_output_tokens": req.max_tokens,
        "temperature": req.temperature,
        "instructions": req.system,
        "stop": req.stop,
        "stream": req.stream,
        "tools": req.tools
    }

def to_deepseek(req: UnifiedRequest) -> dict:
    msgs = req.messages.copy()
    if req.system:
        msgs.insert(0, {"role": "system", "content": req.system})
    return {
        "model": req.model,
        "messages": msgs,
        "max_tokens": req.max_tokens,
        "temperature": req.temperature,
        "top_p": req.top_p,
        "stop": req.stop,
        "stream": req.stream
    }

6. 响应格式统一

def normalize_response(provider: str, resp: dict) -> dict:
    if provider == "anthropic":
        return {
            "id": resp.get("id"),
            "role": "assistant",
            "content": extract_text_content(resp.get("content", [])),
            "finish_reason": map_stop_reason(resp.get("stop_reason")),
            "usage": {
                "input_tokens": resp["usage"]["input_tokens"],
                "output_tokens": resp["usage"]["output_tokens"]
            }
        }
    else:
        choice = resp.get("choices", [{}])[0] if provider == "openai_chat" else resp.get("output", [{}])[0]
        return {
            "role": "assistant",
            "content": choice.get("text", "") or choice.get("content", ""),
            "finish_reason": choice.get("finish_reason") or choice.get("type"),
            "usage": {
                "input_tokens": resp["usage"]["prompt_tokens"] or resp["usage"]["input_tokens"],
                "output_tokens": resp["usage"]["completion_tokens"] or resp["usage"]["output_tokens"]
            }
        }

7. 模型路由逻辑

def select_provider(model: str) -> tuple[str, str]:
    """返回 (provider_type, api_style)"""
    if model.startswith("claude"):
        return ("anthropic", "messages")
    elif model.startswith("o") or "computer" in model:
        return ("openai", "response")
    elif model.startswith("gpt"):
        return ("openai", "chat")
    elif "deepseek" in model:
        return ("deepseek", "chat")
    raise ValueError(f"Unknown model: {model}")

# 用法
provider_type, api_style = select_provider("o1-preview")
# provider_type = "openai", api_style = "response"

8. 完整代码实现

from typing import Optional
import httpx
import os

class UnifiedRequest:
    def __init__(self, model: str, messages: list, max_tokens: int = 4096,
                 temperature: float = 1.0, top_p: float = 1.0,
                 system: str = None, stop: list = None,
                 stream: bool = False, tools: list = None, thinking: dict = None):
        self.model = model
        self.messages = messages
        self.max_tokens = max_tokens
        self.temperature = temperature
        self.top_p = top_p
        self.system = system
        self.stop = stop or []
        self.stream = stream
        self.tools = tools or []
        self.thinking = thinking

class UnifiedProxy:
    def __init__(self):
        self.providers = {
            "anthropic": {"base_url": "https://api.anthropic.com"},
            "openai": {"base_url": "https://api.openai.com/v1"},
            "deepseek": {"base_url": "https://api.deepseek.com/v1"}
        }
        self.client = httpx.AsyncClient(timeout=300)

    def _select_provider(self, model: str) -> tuple:
        if model.startswith("claude"):
            return ("anthropic", "messages")
        elif model.startswith("o") or "computer" in model:
            return ("openai", "response")
        elif model.startswith("gpt"):
            return ("openai", "chat")
        elif "deepseek" in model:
            return ("deepseek", "chat")
        raise ValueError(f"Unknown model: {model}")

    def _to_anthropic(self, req: UnifiedRequest) -> dict:
        body = {
            "model": req.model,
            "max_tokens": req.max_tokens,
            "messages": req.messages,
            "temperature": req.temperature,
            "top_p": req.top_p,
        }
        if req.system:
            body["system"] = req.system
        if req.stop:
            body["stop_sequences"] = req.stop
        if req.thinking:
            body["thinking"] = req.thinking
        return body

    def _to_openai_response(self, req: UnifiedRequest) -> dict:
        return {
            "model": req.model,
            "input": req.messages,
            "max_output_tokens": req.max_tokens,
            "temperature": req.temperature,
            "instructions": req.system,
            "stop": req.stop,
            "stream": req.stream,
            "tools": req.tools
        }

    def _to_openai_chat(self, req: UnifiedRequest) -> dict:
        msgs = req.messages.copy()
        if req.system:
            msgs.insert(0, {"role": "system", "content": req.system})
        return {
            "model": req.model,
            "messages": msgs,
            "max_tokens": req.max_tokens,
            "temperature": req.temperature,
            "top_p": req.top_p,
            "stop": req.stop,
            "stream": req.stream
        }

    def _to_deepseek(self, req: UnifiedRequest) -> dict:
        msgs = req.messages.copy()
        if req.system:
            msgs.insert(0, {"role": "system", "content": req.system})
        return {
            "model": req.model,
            "messages": msgs,
            "max_tokens": req.max_tokens,
            "temperature": req.temperature,
            "top_p": req.top_p,
            "stop": req.stop,
            "stream": req.stream
        }

    async def chat(self, request: UnifiedRequest) -> dict:
        provider, api_style = self._select_provider(request.model)
        config = self.providers["anthropic"] if provider == "anthropic" else self.providers[provider]
        adapter = getattr(self, f"_to_{provider}")
        payload = adapter(request)
        url = f"{config['base_url']}{config['endpoint']}"
        headers = {"Authorization": f"Bearer {os.getenv(provider.upper() + '_API_KEY')}"}
        if provider == "anthropic":
            headers["x-api-key"] = os.getenv("ANTHROPIC_API_KEY")
            headers["anthropic-version"] = "2023-06-01"
        resp = await self.client.post(url, json=payload, headers=headers)
        raw = resp.json()
        return self._normalize_response(provider, raw)

9. 使用示例

proxy = UnifiedProxy()

request = UnifiedRequest(
    model="claude-3-opus-20240229",
    system="You are helpful",
    messages=[{"role": "user", "content": "Explain quantum computing"}],
    max_tokens=1000
)

response = await proxy.chat(request)
print(response["content"])

10. 流式支持

SSE 响应标准化需要处理 content_block_deltamessage_stop(Anthropic)和 choices[].delta(OpenAI/DeepSeek)两种格式,统一输出 {type: "content"|"done", delta: string}


来源:官方 SDK 与 API 文档


如果你觉得本文有用,请点赞,收藏,转发

你有什么问题,请留言,我来帮你解答。


← 返回博客列表