# TrafficAPI 调用文档

> **适用版本**: TrafficAPI v0.1.1+  
> **文档日期**: 2026-04-09

---

## 目录

1. [基本信息](#1-基本信息)
2. [认证方式](#2-认证方式)
3. [Claude / Anthropic API](#3-claude--anthropic-api)
4. [Gemini API](#4-gemini-api)
5. [OpenAI 兼容 API](#5-openai-兼容-api)
6. [Antigravity 路由（Claude + Gemini 混合）](#6-antigravity-路由claude--gemini-混合)
7. [公共接口](#7-公共接口)
8. [错误处理](#8-错误处理)

---

## 1. 基本信息

### 1.1 Base URL

```
https://<your-trafficapi-domain>
```

### 1.2 支持的提供商与路由

| 提供商 | 平台标识 | 主要路由前缀 |
|--------|----------|-------------|
| Anthropic (Claude) | `anthropic` | `/v1` |
| Google Gemini | `gemini` | `/v1beta` |
| OpenAI | `openai` | `/v1` (兼容层) |
| Antigravity (混合) | `antigravity` | `/antigravity` |

### 1.3 支持的模型

**Claude 系列**

| 模型名 | 说明 |
|--------|------|
| `claude-opus-4-6` | Opus 最强版 |
| `claude-opus-4-6-thinking` | Opus 扩展思考版 |
| `claude-sonnet-4-6` | Sonnet 均衡版 |
| `claude-sonnet-4-5` | Sonnet 上一代 |
| `claude-sonnet-4-5-thinking` | Sonnet 扩展思考版 |
| `claude-haiku-4-5` | Haiku 轻量版 |

**Gemini 系列**

| 模型名 | 说明 |
|--------|------|
| `gemini-2.5-flash` | Gemini 2.5 快速版 |
| `gemini-2.5-pro` | Gemini 2.5 旗舰版 |
| `gemini-2.5-flash-thinking` | Gemini 2.5 思考版 |
| `gemini-3-flash` | Gemini 3 快速版 |
| `gemini-3-pro-high` | Gemini 3 Pro 高性能 |
| `gemini-3-pro-low` | Gemini 3 Pro 经济版 |
| `gemini-3.1-pro-high` | Gemini 3.1 Pro 高性能 |

---

## 2. 认证方式

所有 AI 调用接口均通过 **API Key** 鉴权，支持以下三种方式（任选其一）：

| 方式 | Header/参数 | 示例 |
|------|------------|------|
| Bearer Token（推荐） | `Authorization` | `Authorization: Bearer sk-xxxxx` |
| x-api-key | `x-api-key` | `x-api-key: sk-xxxxx` |
| Gemini 兼容 | `x-goog-api-key` | `x-goog-api-key: sk-xxxxx` |

> **注意**: API Key 在平台控制台创建，格式通常为 `sk-` 前缀的字符串。

---

## 3. Claude / Anthropic API

完全兼容 Anthropic 官方 API 格式，可直接使用官方 SDK，只需替换 `base_url`。

### 3.0 请求参数说明

#### 通用 Header 参数

| Header | 必填 | 说明 |
|--------|------|------|
| `Authorization` | 是¹ | Bearer 认证，格式：`Bearer sk-xxxxx` |
| `x-api-key` | 是¹ | API Key 直接放入 header，与 `Authorization` 二选一 |
| `Content-Type` | 是 | 固定为 `application/json` |
| `anthropic-version` | 否 | Anthropic API 版本，推荐填写 `2023-06-01` |
| `anthropic-beta` | 否 | 开启 Beta 特性，如 `interleaved-thinking-2025-05-14`（扩展思考）、`prompt-caching-2024-07-31`（提示缓存） |
| `User-Agent` | 否 | 客户端标识，影响粘性会话（Sticky Session）亲和力 |

> ¹ `Authorization`（Bearer）、`x-api-key`、`x-goog-api-key` 三者填一即可。

---

#### `POST /v1/messages` Body 参数

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `model` | string | **是** | — | 模型名称，如 `claude-sonnet-4-6` |
| `messages` | array | **是** | — | 对话消息数组，至少一条 |
| `messages[].role` | string | **是** | — | 消息角色，`user` 或 `assistant` |
| `messages[].content` | string \| array | **是** | — | 消息内容；字符串或内容块数组（支持 `text`、`image`、`tool_use`、`tool_result` 等类型） |
| `max_tokens` | integer | **是** | — | 最大输出 token 数，不同模型上限不同（Opus/Sonnet: 32000，Haiku: 8192） |
| `system` | string \| array | 否 | — | 系统提示；字符串或内容块数组（支持缓存控制 `cache_control`） |
| `stream` | boolean | 否 | `false` | 是否开启 SSE 流式输出 |
| `temperature` | number | 否 | `1.0` | 随机性控制，范围 `0.0~1.0`；越低越确定性 |
| `top_p` | number | 否 | — | Nucleus 采样概率阈值，范围 `0.0~1.0` |
| `top_k` | integer | 否 | — | Top-K 采样，仅保留概率最高的 K 个 token |
| `stop_sequences` | array\<string\> | 否 | — | 遇到这些字符串时停止生成 |
| `tools` | array | 否 | — | 工具定义列表（Function Calling）；每项包含 `name`、`description`、`input_schema` |
| `tool_choice` | object | 否 | — | 工具调用策略：`{"type": "auto"}` / `{"type": "any"}` / `{"type": "tool", "name": "..."}` / `{"type": "none"}` |
| `thinking` | object | 否 | — | 扩展思考配置（需同时传 `anthropic-beta: interleaved-thinking-2025-05-14`） |
| `thinking.type` | string | 否 | — | `enabled`（固定预算）或 `adaptive`（自适应预算） |
| `thinking.budget_tokens` | integer | 否 | — | 思考 token 预算，最小 `1024`，推荐 `32000` |
| `metadata` | object | 否 | — | 请求元数据 |
| `metadata.user_id` | string | 否 | — | 用户标识，用于粘性会话（Sticky Session）路由亲和 |
| `output_config` | object | 否 | — | 输出配置 |
| `output_config.effort` | string | 否 | — | 推理强度：`low` / `medium` / `high` / `max` |
| `context_management` | object | 否 | — | 上下文管理策略（扩展 Beta 功能） |

**`tools` 单项结构**

```json
{
  "name": "tool_name",
  "description": "工具描述",
  "input_schema": {
    "type": "object",
    "properties": {
      "param1": { "type": "string", "description": "参数说明" }
    },
    "required": ["param1"]
  }
}
```

**响应体结构（非流式）**

```json
{
  "id": "msg_xxxxx",
  "type": "message",
  "role": "assistant",
  "model": "claude-sonnet-4-6",
  "content": [
    { "type": "text", "text": "回复内容" }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 25,
    "output_tokens": 80,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0
  }
}
```

| `stop_reason` 取值 | 说明 |
|-------------------|------|
| `end_turn` | 模型正常结束 |
| `max_tokens` | 达到 `max_tokens` 上限 |
| `stop_sequence` | 命中 `stop_sequences` 中的字符串 |
| `tool_use` | 模型请求调用工具 |

**SSE 流式事件序列（`stream: true`）**

```
event: message_start        # 消息开始，包含 usage 初始值
event: content_block_start  # 内容块开始
event: content_block_delta  # 内容增量（text_delta / thinking_delta）
event: content_block_stop   # 内容块结束
event: message_delta        # 消息结束，包含最终 stop_reason 和 usage
event: message_stop         # 流结束标志
```

---

#### `POST /v1/messages/count_tokens` Body 参数

与 `/v1/messages` 相同，但忽略 `stream` 字段，且不实际调用模型，不计费。

---

### 3.1 发送消息 `POST /v1/messages`

#### Curl

```bash
BASE_URL="https://<your-trafficapi-domain>"
API_KEY="sk-xxxxx"

curl -X POST "$BASE_URL/v1/messages" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "你好，介绍一下自己。"
      }
    ]
  }'
```

**流式输出（SSE）**

```bash
curl -X POST "$BASE_URL/v1/messages" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  --no-buffer \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "stream": true,
    "messages": [
      {"role": "user", "content": "写一首七言绝句"}
    ]
  }'
```

**多轮对话**

```bash
curl -X POST "$BASE_URL/v1/messages" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 2048,
    "system": "你是一位专业的代码审查员，回答简洁精准。",
    "messages": [
      {"role": "user", "content": "如何优化 Python 列表推导式？"},
      {"role": "assistant", "content": "列表推导式比等效的 for 循环快约 35%，因为..."},
      {"role": "user", "content": "给我一个具体例子"}
    ]
  }'
```

#### Python（官方 SDK）

```python
import anthropic

client = anthropic.Anthropic(
    api_key="sk-xxxxx",
    base_url="https://<your-trafficapi-domain>",
)

# 普通调用
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "你好，介绍一下自己。"}
    ]
)
print(message.content[0].text)

# 系统提示 + 多轮对话
message = client.messages.create(
    model="claude-opus-4-6",
    max_tokens=2048,
    system="你是一位资深 Go 语言专家。",
    messages=[
        {"role": "user", "content": "解释 goroutine 和 channel 的关系"},
    ]
)
print(message.content[0].text)
```

**流式输出**

```python
import anthropic

client = anthropic.Anthropic(
    api_key="sk-xxxxx",
    base_url="https://<your-trafficapi-domain>",
)

with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "写一首关于春天的诗"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
print()  # 换行
```

**工具调用（Function Calling）**

```python
import anthropic
import json

client = anthropic.Anthropic(
    api_key="sk-xxxxx",
    base_url="https://<your-trafficapi-domain>",
)

tools = [
    {
        "name": "get_weather",
        "description": "获取指定城市的天气信息",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "城市名称，例如：北京、上海"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "温度单位"
                }
            },
            "required": ["city"]
        }
    }
]

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "北京今天天气怎么样？"}]
)

# 处理工具调用结果
for block in response.content:
    if block.type == "tool_use":
        print(f"调用工具: {block.name}")
        print(f"参数: {json.dumps(block.input, ensure_ascii=False, indent=2)}")
```

#### Go（官方 SDK）

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/anthropics/anthropic-sdk-go"
    "github.com/anthropics/anthropic-sdk-go/option"
)

func main() {
    client := anthropic.NewClient(
        option.WithAPIKey("sk-xxxxx"),
        option.WithBaseURL("https://<your-trafficapi-domain>"),
    )

    // 普通调用
    message, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
        Model:     anthropic.F(anthropic.ModelClaudeSonnet4_6),
        MaxTokens: anthropic.F(int64(1024)),
        Messages: anthropic.F([]anthropic.MessageParam{
            anthropic.UserMessageParam([]anthropic.ContentBlockParamUnion{
                anthropic.TextBlockParam{Text: anthropic.F("你好，介绍一下自己。")},
            }),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(message.Content[0].(anthropic.TextBlock).Text)
}
```

**流式输出（Go）**

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/anthropics/anthropic-sdk-go"
    "github.com/anthropics/anthropic-sdk-go/option"
)

func main() {
    client := anthropic.NewClient(
        option.WithAPIKey("sk-xxxxx"),
        option.WithBaseURL("https://<your-trafficapi-domain>"),
    )

    stream := client.Messages.NewStreaming(context.Background(), anthropic.MessageNewParams{
        Model:     anthropic.F(anthropic.ModelClaudeSonnet4_6),
        MaxTokens: anthropic.F(int64(1024)),
        Messages: anthropic.F([]anthropic.MessageParam{
            anthropic.UserMessageParam([]anthropic.ContentBlockParamUnion{
                anthropic.TextBlockParam{Text: anthropic.F("写一首关于春天的诗")},
            }),
        }),
    })

    for stream.Next() {
        event := stream.Current()
        switch delta := event.Delta.(type) {
        case anthropic.ContentBlockDeltaEventDelta:
            if textDelta, ok := delta.AsUnion().(anthropic.TextDelta); ok {
                fmt.Print(textDelta.Text)
            }
        }
    }
    fmt.Println()

    if err := stream.Err(); err != nil {
        log.Fatal(err)
    }
}
```

**纯 HTTP 调用（Go，无 SDK）**

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type MessageRequest struct {
    Model     string    `json:"model"`
    MaxTokens int       `json:"max_tokens"`
    Messages  []Message `json:"messages"`
    Stream    bool      `json:"stream,omitempty"`
}

type Message struct {
    Role    string `json:"role"`
    Content string `json:"content"`
}

func main() {
    const (
        baseURL = "https://<your-trafficapi-domain>"
        apiKey  = "sk-xxxxx"
    )

    reqBody := MessageRequest{
        Model:     "claude-sonnet-4-6",
        MaxTokens: 1024,
        Messages: []Message{
            {Role: "user", Content: "你好，介绍一下自己。"},
        },
    }

    data, _ := json.Marshal(reqBody)
    req, _ := http.NewRequest("POST", baseURL+"/v1/messages", bytes.NewReader(data))
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("anthropic-version", "2023-06-01")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}
```

### 3.2 Token 计数 `POST /v1/messages/count_tokens`

#### Curl

```bash
curl -X POST "$BASE_URL/v1/messages/count_tokens" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-6",
    "messages": [
      {"role": "user", "content": "你好，介绍一下自己。"}
    ]
  }'
```

**响应**

```json
{
  "input_tokens": 18
}
```

#### Python

```python
response = client.messages.count_tokens(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": "你好，介绍一下自己。"}],
)
print(f"Token 数: {response.input_tokens}")
```

#### Go

```go
count, err := client.Messages.CountTokens(context.Background(), anthropic.MessageCountTokensParams{
    Model: anthropic.F(anthropic.ModelClaudeSonnet4_6),
    Messages: anthropic.F([]anthropic.MessageParam{
        anthropic.UserMessageParam([]anthropic.ContentBlockParamUnion{
            anthropic.TextBlockParam{Text: anthropic.F("你好，介绍一下自己。")},
        }),
    }),
})
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Token 数: %d\n", count.InputTokens)
```

### 3.3 列出模型 `GET /v1/models`

#### Curl

```bash
curl "$BASE_URL/v1/models" \
  -H "Authorization: Bearer $API_KEY" \
  -H "anthropic-version: 2023-06-01"
```

---

## 4. Gemini API

完全兼容 Google Gemini 原生 API 格式。

### 4.0 请求参数说明

#### 通用 Header 参数

| Header | 必填 | 说明 |
|--------|------|------|
| `x-goog-api-key` | 是¹ | Gemini 兼容认证方式（推荐） |
| `Authorization` | 是¹ | Bearer 认证，格式：`Bearer sk-xxxxx` |
| `x-api-key` | 是¹ | 与 `Authorization` 等价 |
| `Content-Type` | 是 | 固定为 `application/json` |

> ¹ 三种认证方式选一即可。

---

#### `POST /v1beta/models/{model}:generateContent` 路径参数

| 参数 | 位置 | 必填 | 说明 |
|------|------|------|------|
| `{model}` | URL 路径 | **是** | 模型名，如 `gemini-2.5-flash`、`gemini-2.5-pro` |

---

#### `POST /v1beta/models/{model}:generateContent` Body 参数

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `contents` | array | **是** | 对话消息数组 |
| `contents[].role` | string | **是** | 消息角色：`user` 或 `model` |
| `contents[].parts` | array | **是** | 内容块数组 |
| `contents[].parts[].text` | string | 否 | 文本内容 |
| `contents[].parts[].inlineData` | object | 否 | 内联媒体数据（图片等），含 `mimeType` 和 `data`（base64） |
| `system_instruction` | object | 否 | 系统指令（等同于 system prompt） |
| `system_instruction.parts` | array | 否 | 系统指令内容块，结构同 `contents[].parts` |
| `generationConfig` | object | 否 | 生成配置 |
| `generationConfig.temperature` | number | 否 | 随机性，范围 `0.0~2.0` |
| `generationConfig.maxOutputTokens` | integer | 否 | 最大输出 token 数 |
| `generationConfig.topP` | number | 否 | Nucleus 采样，范围 `0.0~1.0` |
| `generationConfig.topK` | integer | 否 | Top-K 采样 |
| `generationConfig.stopSequences` | array\<string\> | 否 | 遇到这些字符串时停止生成 |
| `generationConfig.candidateCount` | integer | 否 | 返回候选结果数量，默认 `1` |
| `tools` | array | 否 | 工具定义（Function Calling） |
| `tool_config` | object | 否 | 工具调用模式配置 |
| `tool_config.function_calling_config.mode` | string | 否 | `AUTO` / `ANY` / `NONE` |
| `safetySettings` | array | 否 | 安全过滤设置，每项含 `category` 和 `threshold` |

**响应体结构（非流式）**

```json
{
  "candidates": [
    {
      "content": {
        "parts": [{ "text": "回复内容" }],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 25,
    "candidatesTokenCount": 80,
    "totalTokenCount": 105
  }
}
```

| `finishReason` 取值 | 说明 |
|--------------------|------|
| `STOP` | 正常结束 |
| `MAX_TOKENS` | 达到 `maxOutputTokens` 上限 |
| `SAFETY` | 触发安全过滤 |
| `RECITATION` | 内容引用检测 |

> **流式端点**：将路径中的 `generateContent` 替换为 `streamGenerateContent`，响应为 SSE 流，每条数据为完整的 JSON 对象（非增量），客户端需自行拼接文本。

---

### 4.1 生成内容 `POST /v1beta/models/{model}:generateContent`

#### Curl

```bash
BASE_URL="https://<your-trafficapi-domain>"
API_KEY="sk-xxxxx"
MODEL="gemini-2.5-flash"

# x-api-key 方式（推荐用于 Gemini）
curl -X POST "$BASE_URL/v1beta/models/$MODEL:generateContent" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {
        "role": "user",
        "parts": [{"text": "你好，介绍一下自己。"}]
      }
    ]
  }'
```

**含系统指令**

```bash
curl -X POST "$BASE_URL/v1beta/models/$MODEL:generateContent" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "system_instruction": {
      "parts": [{"text": "你是一位精通中文的写作助手，回答简洁优美。"}]
    },
    "contents": [
      {
        "role": "user",
        "parts": [{"text": "写一首关于秋天的五言绝句"}]
      }
    ],
    "generationConfig": {
      "temperature": 0.9,
      "maxOutputTokens": 512
    }
  }'
```

**流式输出**

```bash
curl -X POST "$BASE_URL/v1beta/models/$MODEL:streamGenerateContent" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  --no-buffer \
  -d '{
    "contents": [
      {"role": "user", "parts": [{"text": "解释量子纠缠"}]}
    ]
  }'
```

#### Python（google-generativeai SDK）

```python
import google.generativeai as genai

genai.configure(
    api_key="sk-xxxxx",
    # 通过环境变量或直接设置 transport
    # 需要将请求路由到 TrafficAPI
)

# 推荐：使用 google.generativeai 的 transport 覆盖
import google.ai.generativelanguage as glm
from google.api_core import gapic_v1
from google.auth.credentials import AnonymousCredentials

# 方式一：直接使用 HTTP 请求（最简单）
import httpx

BASE_URL = "https://<your-trafficapi-domain>"
API_KEY = "sk-xxxxx"
MODEL = "gemini-2.5-flash"

response = httpx.post(
    f"{BASE_URL}/v1beta/models/{MODEL}:generateContent",
    headers={"x-goog-api-key": API_KEY},
    json={
        "contents": [
            {"role": "user", "parts": [{"text": "你好，介绍一下自己。"}]}
        ]
    }
)
data = response.json()
print(data["candidates"][0]["content"]["parts"][0]["text"])
```

**流式输出（Python HTTP）**

```python
import httpx
import json

BASE_URL = "https://<your-trafficapi-domain>"
API_KEY = "sk-xxxxx"
MODEL = "gemini-2.5-flash"

with httpx.stream(
    "POST",
    f"{BASE_URL}/v1beta/models/{MODEL}:streamGenerateContent",
    headers={"x-goog-api-key": API_KEY, "Content-Type": "application/json"},
    json={
        "contents": [
            {"role": "user", "parts": [{"text": "解释量子纠缠，500字以内"}]}
        ]
    }
) as stream:
    for line in stream.iter_lines():
        line = line.strip()
        if not line or line == "data: [DONE]":
            continue
        if line.startswith("data: "):
            line = line[6:]
        try:
            chunk = json.loads(line)
            for candidate in chunk.get("candidates", []):
                for part in candidate.get("content", {}).get("parts", []):
                    if "text" in part:
                        print(part["text"], end="", flush=True)
        except json.JSONDecodeError:
            pass
print()
```

#### Go（纯 HTTP）

```go
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
)

type GeminiRequest struct {
    Contents []GeminiContent `json:"contents"`
    GenerationConfig *GeminiGenerationConfig `json:"generationConfig,omitempty"`
}

type GeminiContent struct {
    Role  string       `json:"role"`
    Parts []GeminiPart `json:"parts"`
}

type GeminiPart struct {
    Text string `json:"text"`
}

type GeminiGenerationConfig struct {
    Temperature     float64 `json:"temperature,omitempty"`
    MaxOutputTokens int     `json:"maxOutputTokens,omitempty"`
}

func main() {
    const (
        baseURL = "https://<your-trafficapi-domain>"
        apiKey  = "sk-xxxxx"
        model   = "gemini-2.5-flash"
    )

    reqBody := GeminiRequest{
        Contents: []GeminiContent{
            {
                Role:  "user",
                Parts: []GeminiPart{{Text: "你好，介绍一下自己。"}},
            },
        },
        GenerationConfig: &GeminiGenerationConfig{
            Temperature:     0.7,
            MaxOutputTokens: 1024,
        },
    }

    data, _ := json.Marshal(reqBody)
    url := fmt.Sprintf("%s/v1beta/models/%s:generateContent", baseURL, model)
    req, _ := http.NewRequest("POST", url, bytes.NewReader(data))
    req.Header.Set("x-goog-api-key", apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    var result map[string]any
    json.NewDecoder(resp.Body).Decode(&result)

    candidates := result["candidates"].([]any)
    content := candidates[0].(map[string]any)["content"].(map[string]any)
    parts := content["parts"].([]any)
    text := parts[0].(map[string]any)["text"].(string)
    fmt.Println(text)
}
```

**流式输出（Go）**

```go
package main

import (
    "bufio"
    "bytes"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "strings"
)

func main() {
    const (
        baseURL = "https://<your-trafficapi-domain>"
        apiKey  = "sk-xxxxx"
        model   = "gemini-2.5-flash"
    )

    body := map[string]any{
        "contents": []map[string]any{
            {
                "role":  "user",
                "parts": []map[string]any{{"text": "解释量子纠缠，500字以内"}},
            },
        },
    }
    data, _ := json.Marshal(body)

    url := fmt.Sprintf("%s/v1beta/models/%s:streamGenerateContent", baseURL, model)
    req, _ := http.NewRequest("POST", url, bytes.NewReader(data))
    req.Header.Set("x-goog-api-key", apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    scanner := bufio.NewScanner(resp.Body)
    for scanner.Scan() {
        line := scanner.Text()
        if !strings.HasPrefix(line, "data: ") {
            continue
        }
        raw := strings.TrimPrefix(line, "data: ")
        if raw == "[DONE]" {
            break
        }
        var chunk map[string]any
        if err := json.Unmarshal([]byte(raw), &chunk); err != nil {
            continue
        }
        candidates, _ := chunk["candidates"].([]any)
        for _, c := range candidates {
            cd := c.(map[string]any)
            content := cd["content"].(map[string]any)
            parts := content["parts"].([]any)
            for _, p := range parts {
                if text, ok := p.(map[string]any)["text"].(string); ok {
                    fmt.Print(text)
                }
            }
        }
    }
    fmt.Println()
}
```

### 4.2 列出模型 `GET /v1beta/models`

#### Curl

```bash
curl "$BASE_URL/v1beta/models" \
  -H "x-goog-api-key: $API_KEY"
```

---

## 5. OpenAI 兼容 API

完全兼容 OpenAI Chat Completions 格式，可直接使用 OpenAI 官方 SDK，只需替换 `base_url`。

后端会自动将请求路由到相应平台（Claude/OpenAI），并将响应转换回 OpenAI 格式。

### 5.0 请求参数说明

#### 通用 Header 参数

| Header | 必填 | 说明 |
|--------|------|------|
| `Authorization` | 是 | Bearer 认证，格式：`Bearer sk-xxxxx` |
| `Content-Type` | 是 | 固定为 `application/json` |
| `User-Agent` | 否 | 客户端标识，影响粘性会话亲和力 |

---

#### `POST /v1/chat/completions` Body 参数

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `model` | string | **是** | — | 模型名，如 `claude-sonnet-4-6`、`gpt-oss-120b-medium` |
| `messages` | array | **是** | — | 对话消息数组 |
| `messages[].role` | string | **是** | — | 消息角色：`system` / `user` / `assistant` / `tool` |
| `messages[].content` | string \| array | **是** | — | 消息内容；支持多模态内容块（`type: text` / `type: image_url`） |
| `messages[].name` | string | 否 | — | 发送者名称（`tool` 角色时为工具名） |
| `messages[].tool_call_id` | string | 否 | — | 工具调用 ID（`tool` 角色回复时使用） |
| `max_tokens` | integer | 否 | 模型默认 | 最大输出 token 数 |
| `stream` | boolean | 否 | `false` | 是否开启 SSE 流式输出 |
| `temperature` | number | 否 | `1.0` | 随机性，范围 `0.0~2.0` |
| `top_p` | number | 否 | `1.0` | Nucleus 采样概率阈值 |
| `frequency_penalty` | number | 否 | `0.0` | 频率惩罚，范围 `-2.0~2.0`，减少重复词 |
| `presence_penalty` | number | 否 | `0.0` | 存在惩罚，范围 `-2.0~2.0`，鼓励新话题 |
| `stop` | string \| array | 否 | — | 遇到这些字符串时停止生成，最多 4 项 |
| `n` | integer | 否 | `1` | 生成候选回复数量 |
| `tools` | array | 否 | — | 工具定义列表（Function Calling） |
| `tools[].type` | string | 否 | — | 固定为 `"function"` |
| `tools[].function.name` | string | 否 | — | 工具名称 |
| `tools[].function.description` | string | 否 | — | 工具描述 |
| `tools[].function.parameters` | object | 否 | — | 工具参数 JSON Schema |
| `tool_choice` | string \| object | 否 | `"auto"` | 工具调用策略：`"none"` / `"auto"` / `"required"` / `{"type": "function", "function": {"name": "..."}}` |
| `response_format` | object | 否 | — | 响应格式，如 `{"type": "json_object"}` 强制 JSON 输出 |
| `seed` | integer | 否 | — | 随机种子（尽力保证确定性输出） |
| `user` | string | 否 | — | 终端用户标识，用于监控滥用行为 |
| `stream_options` | object | 否 | — | 流式选项，如 `{"include_usage": true}` 在流末追加用量统计 |

**响应体结构（非流式）**

```json
{
  "id": "chatcmpl-xxxxx",
  "object": "chat.completion",
  "created": 1700000000,
  "model": "claude-sonnet-4-6",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "回复内容"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 25,
    "completion_tokens": 80,
    "total_tokens": 105
  }
}
```

| `finish_reason` 取值 | 说明 |
|---------------------|------|
| `stop` | 模型正常结束 |
| `length` | 达到 `max_tokens` 上限 |
| `tool_calls` | 模型请求调用工具 |
| `content_filter` | 内容过滤触发 |

**SSE 流式数据块格式（`stream: true`）**

```
data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"你好"},"finish_reason":null}]}

data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE]
```

---

### 5.1 Chat Completions `POST /v1/chat/completions`

#### Curl

```bash
BASE_URL="https://<your-trafficapi-domain>"
API_KEY="sk-xxxxx"

curl -X POST "$BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "messages": [
      {"role": "system", "content": "你是一位资深软件工程师。"},
      {"role": "user", "content": "解释 CAP 定理"}
    ],
    "max_tokens": 1024,
    "temperature": 0.7
  }'
```

**流式输出（SSE）**

```bash
curl -X POST "$BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  --no-buffer \
  -d '{
    "model": "claude-sonnet-4-6",
    "messages": [
      {"role": "user", "content": "写一段 Python 快速排序代码"}
    ],
    "stream": true
  }'
```

**函数调用**

```bash
curl -X POST "$BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "messages": [
      {"role": "user", "content": "北京现在几点了？"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_current_time",
          "description": "获取指定时区的当前时间",
          "parameters": {
            "type": "object",
            "properties": {
              "timezone": {
                "type": "string",
                "description": "时区，如 Asia/Shanghai"
              }
            },
            "required": ["timezone"]
          }
        }
      }
    ],
    "tool_choice": "auto"
  }'
```

#### Python（OpenAI SDK）

```python
from openai import OpenAI

client = OpenAI(
    api_key="sk-xxxxx",
    base_url="https://<your-trafficapi-domain>/v1",
)

# 普通调用
response = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[
        {"role": "system", "content": "你是一位资深软件工程师。"},
        {"role": "user", "content": "解释 CAP 定理"},
    ],
    max_tokens=1024,
    temperature=0.7,
)
print(response.choices[0].message.content)

# 流式输出
stream = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": "写一段 Python 快速排序代码"}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta
    if delta.content:
        print(delta.content, end="", flush=True)
print()
```

**函数调用（Python OpenAI SDK）**

```python
from openai import OpenAI
import json

client = OpenAI(
    api_key="sk-xxxxx",
    base_url="https://<your-trafficapi-domain>/v1",
)

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"},
                },
                "required": ["city"],
            },
        },
    }
]

response = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": "上海天气怎么样？"}],
    tools=tools,
    tool_choice="auto",
)

message = response.choices[0].message
if message.tool_calls:
    for call in message.tool_calls:
        print(f"工具: {call.function.name}")
        print(f"参数: {json.loads(call.function.arguments)}")
```

#### Go（OpenAI SDK）

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/openai/openai-go"
    "github.com/openai/openai-go/option"
)

func main() {
    client := openai.NewClient(
        option.WithAPIKey("sk-xxxxx"),
        option.WithBaseURL("https://<your-trafficapi-domain>/v1"),
    )

    // 普通调用
    completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
        Model: openai.F("claude-sonnet-4-6"),
        Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
            openai.SystemMessage("你是一位资深软件工程师。"),
            openai.UserMessage("解释 CAP 定理"),
        }),
        MaxTokens:   openai.F(int64(1024)),
        Temperature: openai.F(0.7),
    })
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(completion.Choices[0].Message.Content)
}
```

**流式输出（Go）**

```go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/openai/openai-go"
    "github.com/openai/openai-go/option"
)

func main() {
    client := openai.NewClient(
        option.WithAPIKey("sk-xxxxx"),
        option.WithBaseURL("https://<your-trafficapi-domain>/v1"),
    )

    stream := client.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
        Model: openai.F("claude-sonnet-4-6"),
        Messages: openai.F([]openai.ChatCompletionMessageParamUnion{
            openai.UserMessage("写一段 Go 实现的二叉树遍历"),
        }),
    })

    for stream.Next() {
        chunk := stream.Current()
        if len(chunk.Choices) > 0 {
            fmt.Print(chunk.Choices[0].Delta.Content)
        }
    }
    fmt.Println()

    if err := stream.Err(); err != nil {
        log.Fatal(err)
    }
}
```

**纯 HTTP 调用（Go，无 SDK）**

```go
package main

import (
    "bufio"
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "log"
    "net/http"
    "strings"
)

func main() {
    const (
        baseURL = "https://<your-trafficapi-domain>"
        apiKey  = "sk-xxxxx"
    )

    body := map[string]any{
        "model": "claude-sonnet-4-6",
        "messages": []map[string]string{
            {"role": "user", "content": "解释 CAP 定理"},
        },
        "max_tokens": 1024,
        "stream":     true,
    }
    data, _ := json.Marshal(body)

    req, _ := http.NewRequest("POST", baseURL+"/v1/chat/completions", bytes.NewReader(data))
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    scanner := bufio.NewScanner(resp.Body)
    for scanner.Scan() {
        line := scanner.Text()
        if !strings.HasPrefix(line, "data: ") {
            continue
        }
        raw := strings.TrimPrefix(line, "data: ")
        if raw == "[DONE]" {
            break
        }
        var chunk map[string]any
        if err := json.Unmarshal([]byte(raw), &chunk); err != nil {
            continue
        }
        choices := chunk["choices"].([]any)
        delta := choices[0].(map[string]any)["delta"].(map[string]any)
        if content, ok := delta["content"].(string); ok {
            fmt.Print(content)
        }
    }
    fmt.Println()

    // 非流式调用
    body2 := map[string]any{
        "model": "claude-sonnet-4-6",
        "messages": []map[string]string{
            {"role": "user", "content": "你好"},
        },
    }
    data2, _ := json.Marshal(body2)
    req2, _ := http.NewRequest("POST", baseURL+"/v1/chat/completions", bytes.NewReader(data2))
    req2.Header.Set("Authorization", "Bearer "+apiKey)
    req2.Header.Set("Content-Type", "application/json")

    resp2, err := http.DefaultClient.Do(req2)
    if err != nil {
        log.Fatal(err)
    }
    defer resp2.Body.Close()
    body3, _ := io.ReadAll(resp2.Body)
    var result map[string]any
    json.Unmarshal(body3, &result)
    choices := result["choices"].([]any)
    message := choices[0].(map[string]any)["message"].(map[string]any)
    fmt.Println(message["content"])
}
```

### 5.2 Responses API `POST /v1/responses`

Responses API 兼容 OpenAI Responses 格式（含 WebSocket 流式支持）。

```bash
curl -X POST "$BASE_URL/v1/responses" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "input": "你好，介绍一下自己。",
    "stream": false
  }'
```

---

## 6. Antigravity 路由（Claude + Gemini 混合）

Antigravity 平台同时支持 Claude 和 Gemini 模型，通过 `/antigravity` 前缀路由。

### 6.1 Claude via Antigravity

```bash
curl -X POST "$BASE_URL/antigravity/v1/messages" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{
    "model": "claude-sonnet-4-6",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "你好"}
    ]
  }'
```

### 6.2 Gemini via Antigravity

```bash
MODEL="gemini-2.5-flash"
curl -X POST "$BASE_URL/antigravity/v1beta/models/$MODEL:generateContent" \
  -H "x-goog-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contents": [
      {"role": "user", "parts": [{"text": "你好"}]}
    ]
  }'
```

### 6.3 Antigravity 支持的模型（含别名映射）

| 请求模型名 | 实际路由模型 |
|-----------|-------------|
| `claude-opus-4-6` | `claude-opus-4-6-thinking` |
| `claude-sonnet-4-6` | `claude-sonnet-4-6` |
| `claude-haiku-4-5` | `claude-sonnet-4-6`（升级） |
| `gemini-2.5-flash` | `gemini-2.5-flash` |
| `gemini-2.5-pro` | `gemini-2.5-pro` |
| `gemini-3-flash-preview` | `gemini-3-flash` |
| `gemini-3-pro-preview` | `gemini-3-pro-high` |
| `gemini-3.1-pro-preview` | `gemini-3.1-pro-high` |

---

## 7. 公共接口

### 7.1 健康检查 `GET /health`

```bash
curl "$BASE_URL/health"
```

**响应**

```json
{"status": "ok"}
```

### 7.2 获取使用量 `GET /v1/usage`

```bash
curl "$BASE_URL/v1/usage" \
  -H "Authorization: Bearer $API_KEY"
```

---

## 8. 错误处理

### 8.1 错误格式

不同平台返回不同格式的错误，网关会根据调用端点自动适配：

**Anthropic 格式**（`/v1/messages`）

```json
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "invalid x-api-key"
  }
}
```

**OpenAI 格式**（`/v1/chat/completions`）

```json
{
  "error": {
    "type": "authentication_error",
    "message": "invalid api key"
  }
}
```

**Gemini 格式**（`/v1beta/...`）

```json
{
  "error": {
    "code": 401,
    "message": "API key not valid.",
    "status": "UNAUTHENTICATED"
  }
}
```

### 8.2 常见 HTTP 状态码

| 状态码 | 含义 | 处理建议 |
|--------|------|----------|
| `200` | 成功 | - |
| `400` | 请求格式错误 | 检查请求体参数 |
| `401` | 认证失败 | 检查 API Key 是否正确 |
| `403` | 权限不足 / IP 被限制 | 联系管理员 |
| `429` | 请求过于频繁 / 并发超限 | 降低请求频率，等待后重试 |
| `500` | 服务器内部错误 | 联系管理员 |
| `529` | 上游服务过载 | 稍后重试 |

### 8.3 Python 错误处理示例

```python
import anthropic

client = anthropic.Anthropic(
    api_key="sk-xxxxx",
    base_url="https://<your-trafficapi-domain>",
)

try:
    message = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{"role": "user", "content": "你好"}],
    )
    print(message.content[0].text)
except anthropic.AuthenticationError as e:
    print(f"认证失败: {e}")
except anthropic.RateLimitError as e:
    print(f"速率限制: {e}")
except anthropic.APIStatusError as e:
    print(f"API 错误 {e.status_code}: {e.message}")
```

### 8.4 Go 错误处理示例

```go
message, err := client.Messages.New(ctx, params)
if err != nil {
    var apiErr *anthropic.Error
    if errors.As(err, &apiErr) {
        switch apiErr.StatusCode {
        case 401:
            log.Println("认证失败，请检查 API Key")
        case 429:
            log.Println("请求频率过高，请稍后重试")
        default:
            log.Printf("API 错误 %d: %s", apiErr.StatusCode, apiErr.Message)
        }
    } else {
        log.Printf("网络错误: %v", err)
    }
    return
}
```

---

## 附录：快速参考

### A. SDK 安装

```bash
# Python - Anthropic 官方 SDK
pip install anthropic

# Python - OpenAI 官方 SDK
pip install openai

# Python - HTTP 客户端
pip install httpx

# Go - Anthropic SDK
go get github.com/anthropics/anthropic-sdk-go

# Go - OpenAI SDK
go get github.com/openai/openai-go
```

### B. 环境变量配置（推荐）

```bash
# .env 或 shell 配置
export TRAFFICAPI_BASE_URL="https://<your-trafficapi-domain>"
export TRAFFICAPI_API_KEY="sk-xxxxx"
```

```python
import os
import anthropic

client = anthropic.Anthropic(
    api_key=os.environ["TRAFFICAPI_API_KEY"],
    base_url=os.environ["TRAFFICAPI_BASE_URL"],
)
```

### C. 各 API 路由速查

| 操作 | 方法 | 路径 |
|------|------|------|
| Claude 发送消息 | `POST` | `/v1/messages` |
| Claude 计算 Token | `POST` | `/v1/messages/count_tokens` |
| Claude 模型列表 | `GET` | `/v1/models` |
| Gemini 生成内容 | `POST` | `/v1beta/models/{model}:generateContent` |
| Gemini 流式生成 | `POST` | `/v1beta/models/{model}:streamGenerateContent` |
| Gemini 模型列表 | `GET` | `/v1beta/models` |
| OpenAI Chat | `POST` | `/v1/chat/completions` |
| OpenAI Responses | `POST` | `/v1/responses` |
| Antigravity Claude | `POST` | `/antigravity/v1/messages` |
| Antigravity Gemini | `POST` | `/antigravity/v1beta/models/{model}:generateContent` |
| 健康检查 | `GET` | `/health` |
| 使用量查询 | `GET` | `/v1/usage` |
