跳轉到

Batch API

Batch API 讓你能夠非同步地向 AI Agent 發送多個訊息。這非常適合高效處理大量請求,而無需維持持久連線。

概述

Batch API 讓你能夠:

  • 在單一 API 呼叫中提交多個請求
  • 在背景非同步處理請求
  • 追蹤批次進度並取得結果
  • 在批次完成時接收 Webhook 通知
  • 取消進行中的批次

建立批次

提交一批請求進行非同步處理。

端點: POST /api/v1/batches

請求內容

欄位 類型 必填 說明
agent_id UUID 所有請求的預設 Agent ID(必須有已發布版本)
requests array 要處理的請求列表(1-1000 項)
webhook object 通知的 Webhook 設定

請求項目結構

requests 陣列中的每個項目:

欄位 類型 必填 說明
custom_id string 你的關聯鍵(最多 256 字元,在批次中必須唯一)
message string 要發送的訊息
agent_id UUID 覆蓋此特定請求的 Agent
external_user_id string 外部用戶識別碼
name string 建立的聊天名稱(最多 256 字元)
attached_file_uuids array 檔案附件的 UUID 列表
history_id integer 現有的聊天歷史 ID,用於繼續對話

Webhook 設定

欄位 類型 必填 說明
url string Webhook URL(必須是 HTTPS)
events array 要通知的事件:completedfailedcancelled(預設:["completed", "failed"]
secret string 用於簽署 Webhook 負載的密鑰(最多 255 字元)

範例

curl -X POST "https://api.codeer.ai/api/v1/batches" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "550e8400-e29b-41d4-a716-446655440000",
    "requests": [
      {
        "custom_id": "req-001",
        "message": "你們的營業時間是什麼?",
        "external_user_id": "user_123"
      },
      {
        "custom_id": "req-002",
        "message": "如何退貨?",
        "external_user_id": "user_456"
      }
    ],
    "webhook": {
      "url": "https://your-server.com/webhooks/codeer",
      "events": ["completed", "failed"],
      "secret": "your-webhook-secret"
    }
  }'

回應

狀態碼: 202 Accepted

{
  "data": {
    "id": "batch-uuid-here",
    "status": "in_progress",
    "agent_id": "550e8400-e29b-41d4-a716-446655440000",
    "total_requests": 2,
    "completed_requests": 0,
    "failed_requests": 0,
    "created_at": "2024-01-15T10:30:00Z",
    "completed_at": null,
    "cancelled_at": null
  },
  "message": null,
  "error_code": 0
}

Agent 必須已發布

預設的 agent_id 和任何個別請求的 agent_id 覆蓋都必須參照已發布的 Agent。使用未發布 Agent 的請求將被拒絕。


列出批次

取得批次列表,支援分頁和狀態篩選。

端點: GET /api/v1/batches

查詢參數

參數 類型 預設值 說明
limit integer 50 每頁結果數(最多 1000)
offset integer 0 要跳過的結果數
status string - 依狀態篩選:in_progresscompletedfailedcancellingcancelled

範例

curl -X GET "https://api.codeer.ai/api/v1/batches?limit=10&status=completed" \
  -H "x-api-key: YOUR_API_KEY"

回應

{
  "data": [
    {
      "id": "batch-uuid-here",
      "status": "completed",
      "agent_id": "550e8400-e29b-41d4-a716-446655440000",
      "total_requests": 100,
      "completed_requests": 98,
      "failed_requests": 2,
      "created_at": "2024-01-15T10:30:00Z",
      "completed_at": "2024-01-15T10:45:00Z",
      "cancelled_at": null
    }
  ],
  "pagination": {
    "limit": 10,
    "offset": 0,
    "total_records": 50,
    "total_pages": 5,
    "current_page": 1,
    "next_page": "https://api.codeer.ai/api/v1/batches?offset=10&limit=10",
    "prev_page": null
  },
  "message": null,
  "error_code": 0
}

取得批次

取得特定批次的目前狀態。

端點: GET /api/v1/batches/{batch_id}

路徑參數

參數 類型 說明
batch_id UUID 批次 ID

範例

curl -X GET "https://api.codeer.ai/api/v1/batches/batch-uuid-here" \
  -H "x-api-key: YOUR_API_KEY"

回應

{
  "data": {
    "id": "batch-uuid-here",
    "status": "in_progress",
    "agent_id": "550e8400-e29b-41d4-a716-446655440000",
    "total_requests": 100,
    "completed_requests": 45,
    "failed_requests": 2,
    "created_at": "2024-01-15T10:30:00Z",
    "completed_at": null,
    "cancelled_at": null
  },
  "message": null,
  "error_code": 0
}

批次狀態值

狀態 說明
in_progress 批次正在處理中
completed 所有請求已處理完成
failed 批次處理失敗
cancelling 正在取消中
cancelled 批次已取消

取得批次結果

取得批次中個別請求的結果。

端點: GET /api/v1/batches/{batch_id}/results

路徑參數

參數 類型 說明
batch_id UUID 批次 ID

查詢參數

參數 類型 預設值 說明
limit integer 50 每頁結果數(最多 1000)
offset integer 0 要跳過的結果數
status string - 依狀態篩選:pendingprocessingsuccessfailed

範例

curl -X GET "https://api.codeer.ai/api/v1/batches/batch-uuid-here/results?status=success" \
  -H "x-api-key: YOUR_API_KEY"

回應

{
  "data": [
    {
      "custom_id": "req-001",
      "status": "success",
      "response_content": "我們的營業時間是週一至週五,上午 9 點到下午 6 點。",
      "response_usage": {
        "tool_calls": [
          {
            "model": "gemini-2.5-flash",
            "call_type": "tool_call",
            "total_tokens": 195,
            "prompt_tokens": 150,
            "completion_tokens": 45
          }
        ],
        "total_calls": 1,
        "total_tokens": 195,
        "main_response": null,
        "total_prompt_tokens": 150,
        "total_completion_tokens": 45
      },
      "error_code": null,
      "error_message": null,
      "history_id": 12345,
      "conversation_id": 6789,
      "processed_at": "2024-01-15T10:31:00Z"
    },
    {
      "custom_id": "req-002",
      "status": "failed",
      "response_content": null,
      "response_usage": null,
      "error_code": 500,
      "error_message": "處理過程中發生內部伺服器錯誤",
      "history_id": null,
      "conversation_id": null,
      "processed_at": "2024-01-15T10:31:05Z"
    }
  ],
  "pagination": { ... },
  "message": null,
  "error_code": 0
}

請求狀態值

狀態 說明
pending 請求已排隊等待處理
processing 請求正在處理中
success 請求已成功完成
failed 請求失敗

結果中的錯誤代碼

結果中的錯誤代碼遵循 HTTP 語義:

錯誤代碼 說明
400 驗證錯誤(請求資料無效)
408 批次處理逾時,請求在完成前已中止
499 批次已被取消
500 處理過程中發生內部伺服器錯誤

取消批次

取消進行中的批次。待處理的請求將被取消,而已在處理中的請求將會完成。

端點: POST /api/v1/batches/{batch_id}/cancel

路徑參數

參數 類型 說明
batch_id UUID 批次 ID

範例

curl -X POST "https://api.codeer.ai/api/v1/batches/batch-uuid-here/cancel" \
  -H "x-api-key: YOUR_API_KEY"

回應

狀態碼: 202 Accepted

{
  "data": {
    "id": "batch-uuid-here",
    "status": "cancelling",
    "agent_id": "550e8400-e29b-41d4-a716-446655440000",
    "total_requests": 100,
    "completed_requests": 45,
    "failed_requests": 2,
    "created_at": "2024-01-15T10:30:00Z",
    "completed_at": null,
    "cancelled_at": null
  },
  "message": null,
  "error_code": 0
}

取消行為

  • 只有狀態為 in_progress 的批次可以被取消
  • 已在 processing 狀態的請求將正常完成
  • 待處理的請求將被標記為失敗,錯誤代碼為 499
  • 批次狀態將從 cancelling 轉變為 cancelled,當所有進行中的請求完成時

Webhooks

設定後,Webhook 將以 HTTP POST 請求發送到你指定的 URL。

Webhook 負載

{
  "event": "batch.completed",
  "timestamp": "2024-01-15T10:45:00Z",
  "data": {
    "id": "batch-uuid-here",
    "status": "completed",
    "total_requests": 100,
    "completed_requests": 98,
    "failed_requests": 2
  }
}

Webhook 簽名

如果你在 Webhook 設定中提供了 secret,負載將使用 HMAC-SHA256 簽名。 請讀取 X-Codeer-SignatureX-Codeer-Timestamp 標頭,並用 {timestamp}.{raw_payload} 驗證簽名:

import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    signed_payload = f"{timestamp}.".encode("utf-8") + payload
    expected = hmac.new(
        secret.encode("utf-8"),
        signed_payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)

Webhook 事件

事件 說明
batch.completed 批次中的所有請求已處理完成
batch.failed 批次處理失敗
batch.cancelled 批次已被取消

程式碼範例

Python

import requests
import time

API_KEY = "your-api-key"
BASE_URL = "https://api.codeer.ai/api/v1"

headers = {
    "x-api-key": API_KEY,
    "Content-Type": "application/json"
}

# 建立批次
batch_response = requests.post(
    f"{BASE_URL}/batches",
    headers=headers,
    json={
        "agent_id": "your-agent-id",
        "requests": [
            {"custom_id": f"req-{i}", "message": f"問題 {i}"}
            for i in range(10)
        ]
    }
)
batch = batch_response.json()["data"]
batch_id = batch["id"]
print(f"已建立批次:{batch_id}")

# 輪詢完成狀態
while True:
    status_response = requests.get(
        f"{BASE_URL}/batches/{batch_id}",
        headers=headers
    )
    status = status_response.json()["data"]["status"]
    print(f"批次狀態:{status}")

    if status in ["completed", "failed", "cancelled"]:
        break
    time.sleep(5)

# 取得結果
results_response = requests.get(
    f"{BASE_URL}/batches/{batch_id}/results",
    headers=headers
)
results = results_response.json()["data"]
for result in results:
    print(f"{result['custom_id']}: {result['status']}")
    if result["response_content"]:
        print(f"  回應:{result['response_content'][:100]}...")

JavaScript

const API_KEY = 'your-api-key';
const BASE_URL = 'https://api.codeer.ai/api/v1';

const headers = {
  'x-api-key': API_KEY,
  'Content-Type': 'application/json'
};

// 建立批次
const batchResponse = await fetch(`${BASE_URL}/batches`, {
  method: 'POST',
  headers,
  body: JSON.stringify({
    agent_id: 'your-agent-id',
    requests: Array.from({ length: 10 }, (_, i) => ({
      custom_id: `req-${i}`,
      message: `問題 ${i}`
    }))
  })
});
const { data: batch } = await batchResponse.json();
console.log(`已建立批次:${batch.id}`);

// 輪詢完成狀態
const pollBatch = async (batchId) => {
  while (true) {
    const statusResponse = await fetch(`${BASE_URL}/batches/${batchId}`, { headers });
    const { data } = await statusResponse.json();
    console.log(`批次狀態:${data.status}`);

    if (['completed', 'failed', 'cancelled'].includes(data.status)) {
      return data;
    }
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
};

await pollBatch(batch.id);

// 取得結果
const resultsResponse = await fetch(`${BASE_URL}/batches/${batch.id}/results`, { headers });
const { data: results } = await resultsResponse.json();
results.forEach(result => {
  console.log(`${result.custom_id}: ${result.status}`);
  if (result.response_content) {
    console.log(`  回應:${result.response_content.slice(0, 100)}...`);
  }
});