チャットは、会話からテキストを生成します。Sakuranbo AI には、チャットのエンドポイントが 2 つあります。どちらも同じモデルを実行し、同じ方法で課金します。違いは、リクエストとレスポンスの形式だけです。
POST /v1/chat/completionsは、OpenAI Chat Completions API と互換性があります。POST /v1/messagesは、Anthropic Messages API と互換性があります。
どちらのエンドポイントも、Authorization: Bearer で送る API キーが必要です。認証を参照してください。POST /v1/messages は、Anthropic SDK がキーを入れる x-api-key ヘッダでも、キーを受け取ります。
このページの例では、sakuranbo/cherrytext-1.0-flash を使います。テキストモデルを探すには、GET /v1/models を task=chat で呼び出します。モデル APIを参照してください。テキストモデルでないモデルを指定すると、404 と model_not_found を返します。
公式 SDK を使う
Section titled “公式 SDK を使う”OpenAI と Anthropic の公式 SDK を使えます。SDK の接続先を Sakuranbo AI にして、Sakuranbo AI の API キーを渡します。OpenAI SDK には、/v1 を含むベース URL を指定します。Anthropic SDK は /v1/messages を自分で付け足すため、ベース URL に /v1 は含めません。
TypeScript の OpenAI SDK:
import OpenAI from "openai";
const apiKey = process.env.SAKURANBO_API_KEY;if (!apiKey) throw new Error("Set the SAKURANBO_API_KEY environment variable.");
const client = new OpenAI({ baseURL: "https://api.sakuranbo.ai/v1", apiKey,});
const completion = await client.chat.completions.create({ model: "sakuranbo/cherrytext-1.0-flash", messages: [ { role: "system", content: "You are a concise assistant." }, { role: "user", content: "Summarize the benefits of prepaid API credits in two lines." } ], max_tokens: 2048});
console.log(completion.choices[0]?.message.content);Python の OpenAI SDK:
import os
from openai import OpenAI
client = OpenAI( base_url="https://api.sakuranbo.ai/v1", api_key=os.environ["SAKURANBO_API_KEY"],)
completion = client.chat.completions.create( model="sakuranbo/cherrytext-1.0-flash", messages=[ { "role": "system", "content": "You are a concise assistant.", }, { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines.", }, ], max_tokens=2048,)
print(completion.choices[0].message.content)TypeScript の Anthropic SDK:
import Anthropic from "@anthropic-ai/sdk";
const apiKey = process.env.SAKURANBO_API_KEY;if (!apiKey) throw new Error("Set the SAKURANBO_API_KEY environment variable.");
// Pass the key as authToken too, so the SDK does not send ANTHROPIC_AUTH_TOKEN from the environment.const client = new Anthropic({ baseURL: "https://api.sakuranbo.ai", apiKey, authToken: apiKey,});
const message = await client.messages.create({ model: "sakuranbo/cherrytext-1.0-flash", max_tokens: 2048, system: "You are a concise assistant.", messages: [ { role: "user", content: "Summarize the benefits of prepaid API credits in two lines." } ]});
console.log(message.content);Python の Anthropic SDK:
import os
import anthropic
api_key = os.environ["SAKURANBO_API_KEY"]
# Pass the key as auth_token too, so the SDK does not send ANTHROPIC_AUTH_TOKEN from the environment.client = anthropic.Anthropic( base_url="https://api.sakuranbo.ai", api_key=api_key, auth_token=api_key,)
message = client.messages.create( model="sakuranbo/cherrytext-1.0-flash", max_tokens=2048, system="You are a concise assistant.", messages=[ { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines.", }, ],)
print(message.content)API はサーバーから呼び出してください。API キーを、ブラウザで動くコードに置かないでください。
OpenAI 形式
Section titled “OpenAI 形式”POST /v1/chat/completions は、messages
のリストを受け取り、モデルの次のメッセージを返します。
curl -X POST "https://api.sakuranbo.ai/v1/chat/completions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $SAKURANBO_API_KEY" \ -d '{ "model": "sakuranbo/cherrytext-1.0-flash", "messages": [ { "role": "system", "content": "You are a concise assistant." }, { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines." } ], "max_tokens": 2048}'const response = await fetch("https://api.sakuranbo.ai/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.SAKURANBO_API_KEY}`, }, body: JSON.stringify({ "model": "sakuranbo/cherrytext-1.0-flash", "messages": [ { "role": "system", "content": "You are a concise assistant." }, { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines." } ], "max_tokens": 2048 }),});const data = await response.json();console.log(data);import os
import requests
response = requests.post( "https://api.sakuranbo.ai/v1/chat/completions", headers={ "Authorization": f"Bearer {os.environ['SAKURANBO_API_KEY']}", }, json={ "model": "sakuranbo/cherrytext-1.0-flash", "messages": [ { "role": "system", "content": "You are a concise assistant.", }, { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines.", }, ], "max_tokens": 2048, },)print(response.json())生成されたメッセージは choices[0].message に入り、usage にはトークン数と料金が入ります。使用量と料金を参照してください。
リクエストフィールド
Section titled “リクエストフィールド”| 名前 | 型 | 必須 | 既定値 | 制約 |
|---|---|---|---|---|
model | string | はい | ||
messages | object[] | はい | 1 件以上 | |
max_tokens | integer | いいえ | ||
max_completion_tokens | integer | いいえ | ||
temperature | number | いいえ | 0〜2 | |
top_p | number | いいえ | 0〜1 | |
stop | string | string[] | いいえ | string[]: 最大 4 件 | |
seed | integer | いいえ | 1 以上 | |
user | string | いいえ | 最大 512 文字 | |
tools | object[] | いいえ | 最大 128 件 | |
tool_choice | string | object | いいえ | string: 次のいずれか: none, auto, required | |
response_format | object | いいえ | ||
n | number | いいえ | 次のいずれか: 1 | |
stream | boolean | いいえ | ||
stream_options | object | null | いいえ |
パラメータの範囲と既定値は、モデルごとに決まります。次の表は、例のモデルのものです。
| 名前 | 型 | 必須 | 既定値 | 制約 | 説明 |
|---|---|---|---|---|---|
messages | object[] | はい | OpenAI Chat Completions 形式の会話メッセージ。 | ||
max_tokens | integer | いいえ | 4096 | 1〜131,072 | 推論に使うトークンを含む、生成するトークン数の上限。小さすぎると、回答を書く前に応答が打ち切られることがあります。残高の仮押さえはこの値で計算します。 |
temperature | number | いいえ | 1 | 0〜2 | サンプリング温度。 |
stream | boolean | いいえ | false | トークンを Server-Sent Events で逐次返します。 |
範囲外の max_tokens を指定すると、400 と invalid_request を返します。error.details.minimum と error.details.maximum に、許容範囲が入ります。リクエストに max_tokens と max_completion_tokens の両方があるときは、max_completion_tokens を使います。
関数ツール(tools と tool_choice)と response_format に対応しています。ツール呼び出しは、choices[0].message.tool_calls に入って返ります。
メッセージに入れられるのはテキストだけです。画像など、ほかの種類のコンテンツパートを入れると 400 を返し、error.param がそのパートを指します。フィールドの表にないパラメータも 400 を返し、error.param にパラメータの名前が入ります。
assistant メッセージにテキストも tool_calls の項目もないとき、または content の配列が空のときは、400 を返します。推論の途中で出力が切れたときなど、テキストもツール呼び出しもないレスポンスが返ることがあるため、そのレスポンスは履歴に追加せず、max_tokens を増やして送り直してください。
Anthropic 形式
Section titled “Anthropic 形式”POST /v1/messages は、Anthropic Messages API の形式で会話を受け取ります。
curl -X POST "https://api.sakuranbo.ai/v1/messages" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $SAKURANBO_API_KEY" \ -d '{ "model": "sakuranbo/cherrytext-1.0-flash", "max_tokens": 2048, "system": "You are a concise assistant.", "messages": [ { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines." } ]}'const response = await fetch("https://api.sakuranbo.ai/v1/messages", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.SAKURANBO_API_KEY}`, }, body: JSON.stringify({ "model": "sakuranbo/cherrytext-1.0-flash", "max_tokens": 2048, "system": "You are a concise assistant.", "messages": [ { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines." } ] }),});const data = await response.json();console.log(data);import os
import requests
response = requests.post( "https://api.sakuranbo.ai/v1/messages", headers={ "Authorization": f"Bearer {os.environ['SAKURANBO_API_KEY']}", }, json={ "model": "sakuranbo/cherrytext-1.0-flash", "max_tokens": 2048, "system": "You are a concise assistant.", "messages": [ { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines.", }, ], },)print(response.json())リクエストフィールド
Section titled “リクエストフィールド”| 名前 | 型 | 必須 | 既定値 | 制約 |
|---|---|---|---|---|
model | string | はい | ||
messages | object[] | はい | 1 件以上 | |
system | string | object[] | いいえ | ||
max_tokens | integer | はい | ||
temperature | number | いいえ | 0〜1 | |
top_p | number | いいえ | 0〜1 | |
stop_sequences | string[] | いいえ | 最大 4 件 | |
stream | boolean | いいえ | ||
tools | object[] | いいえ | 最大 128 件 | |
tool_choice | object | いいえ |
OpenAI 形式との違いは次のとおりです。
max_tokensは必須です。systemはトップレベルのフィールドです。ロールがsystemのメッセージを入れると、400を返します。temperatureの許容範囲は Anthropic API に従うため、POST /v1/chat/completionsの範囲とは異なります。anthropic-versionヘッダは不要です。SDK が送ってきても、サーバーは無視します。- メッセージに入れられるのは、テキストとツールのブロックだけです。
imageブロックを入れると400を返します。top_kやthinkingなど、フィールドの表にないパラメータも400を返します。 assistantメッセージには、空でない文字列のcontent、またはtextかtool_useのブロックを含むcontentの配列が必要です。推論の途中で出力が切れたときなど、contentが空の配列で返ったレスポンスを履歴に追加すると400を返すため、max_tokensを増やして送り直してください。- エラーの本文はすべて Anthropic 形式です。
typeはerrorで、詳細はerrorに入り、request_idはトップレベルのフィールドです。401、404、405も同じです。
ストリーミング
Section titled “ストリーミング”stream を true にすると、レスポンスをサーバー送信イベントで受け取れます。最初のトークンは、モデルが生成するとすぐに届きます。
curl -N -X POST "https://api.sakuranbo.ai/v1/chat/completions" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $SAKURANBO_API_KEY" \ -d '{ "model": "sakuranbo/cherrytext-1.0-flash", "messages": [ { "role": "system", "content": "You are a concise assistant." }, { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines." } ], "max_tokens": 2048, "stream": true, "stream_options": { "include_usage": true }}'const response = await fetch("https://api.sakuranbo.ai/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${process.env.SAKURANBO_API_KEY}`, }, body: JSON.stringify({ "model": "sakuranbo/cherrytext-1.0-flash", "messages": [ { "role": "system", "content": "You are a concise assistant." }, { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines." } ], "max_tokens": 2048, "stream": true, "stream_options": { "include_usage": true } }),});const reader = response.body!.getReader();const decoder = new TextDecoder();while (true) { const { done, value } = await reader.read(); if (done) break; process.stdout.write(decoder.decode(value, { stream: true }));}import os
import requests
response = requests.post( "https://api.sakuranbo.ai/v1/chat/completions", headers={ "Authorization": f"Bearer {os.environ['SAKURANBO_API_KEY']}", }, json={ "model": "sakuranbo/cherrytext-1.0-flash", "messages": [ { "role": "system", "content": "You are a concise assistant.", }, { "role": "user", "content": "Summarize the benefits of prepaid API credits in two lines.", }, ], "max_tokens": 2048, "stream": True, "stream_options": { "include_usage": True, }, }, stream=True,)for line in response.iter_lines(decode_unicode=True): if line: print(line)OpenAI 形式では、各イベントは chat.completion.chunk オブジェクトを持つ data: 行で、新しいテキストは choices[].delta に入ります。ストリームは data: [DONE] で終わります。料金を含む usage オブジェクトは、choices が空配列の最後のチャンクで届きます。届くのは、stream_options.include_usage を true にしたときだけです。
Anthropic 形式では、各イベントは event: 行と data: 行を持ちます。イベントは次の順で届きます。
message_start- コンテンツブロックごとに、
content_block_start、1 つ以上のcontent_block_delta、content_block_stop message_delta。stop_reasonと、料金を含むusageが入りますmessage_stop
Anthropic SDK は、自分が知っているフィールドだけから最終的なメッセージを組み立てるため、そこに usage.cost は入りません。料金を読み取るには、message_delta イベントの usage を読んでください。
認証エラーや検証エラーなど、ストリームが始まる前の失敗は、通常の JSON のエラーを、その HTTP ステータスで返します。ストリームが始まったあとの失敗では、ステータスを変えられず、200 のままです。OpenAI 形式では、error オブジェクトを持つ data: 行を送り、続けて data: [DONE] を送ります。Anthropic 形式では、event: error イベントを送り、message_stop は送りません。
使用量と料金
Section titled “使用量と料金”ストリーミングでないレスポンスは、料金を 2 か所で、トークン数を usage で伝えます。
usage.costは、micro USD の金額をamount_micro_usdに、10 進文字列の金額をamount_usdに持ちます。X-Usage-Cost-Usdヘッダに、同じ USD の文字列が入ります。usageにトークン数が入ります。OpenAI 形式ではprompt_tokens、completion_tokens、total_tokens、prompt_tokens_details.cached_tokensです。Anthropic 形式ではinput_tokens、output_tokens、cache_read_input_tokensです。input_tokensに、キャッシュされたトークンは含まれません。
ストリーミングのレスポンスには、X-Usage-Cost-Usd ヘッダがありません。代わりに、最後の usage オブジェクトから料金を読み取ってください。
リクエストを実行する前に、Sakuranbo AI は残高から一定の金額を確保します。金額は、入力の大きさと max_tokens から見積もります。リクエストが終わると、実際のトークン数から請求額を計算し、確保した金額の残りを残高に戻します。出力を何も生成する前にモデル側で失敗したリクエストは、課金されません。
- 確保する金額に
max_tokensを使うため、実際の料金なら残高に収まるリクエストでも、402で拒否されることがあります。max_tokensは、必要な長さに設定してください。 - モデルが出力を生成し始めたあとにストリームが途切れたときは、ストリームがエラーで終わっても、そのリクエストは課金されます。出力には推論の出力を含み、利用者に届いたかどうかを問わず課金されます。Anthropic 形式は推論の出力を返さないため、テキストを何も受け取っていなくても課金されることがあります。最終的なトークン数が届かなかったときは、請求額を見積もります。入力は、確保に使った上限で数え、出力は、推論の出力とツールの呼び出しを含め、すでに生成された出力の大きさで数えるため、請求額が実際の使用量より高くなることがあります。確保した金額を超えることはありません。
- ストリームが終わる前に接続を閉じても、リクエストは最後まで実行され、生成された出力のすべてが課金されます。
- チャットのリクエストでは、
Idempotency-Keyを使いません。再試行したリクエストは新しいリクエストで、もう一度課金されます。
価格は、モデルカタログのモデルのページと料金のページで確認できます。実行する前に POST /v1/estimate で計算することもできます。見積 APIを参照してください。残高の読み取り方は、残高とキーの利用上限を参照してください。
| コード | HTTP ステータス | 種別 | 説明 |
|---|---|---|---|
invalid_request | 400 | invalid_request_error | リクエストの形式が不正か、値が範囲外です。有効な値が分かる場合は details.allowed に入ります。 |
unauthorized | 401 | authentication_error | API キーが指定されていない、形式が不正、存在しない、失効済み、または期限切れです。レスポンスからは、どれに当たるかは分かりません。 |
balance_insufficient | 402 | insufficient_balance | 利用可能な残高が、このリクエストのために確保する金額に足りません。error.details.limit_source は balance です。 |
key_limit_exceeded | 402 | insufficient_balance | このリクエストを受理すると、API キーの利用上限を超えます。error.details.limit_source は key で、error.details.resets_at にカウンターが数え直される時刻が入ります。 |
account_suspended | 403 | permission_error | アカウントが停止されているため、画像・動画・チャットのリクエストを受け付けません。サポートにお問い合わせください。残高、入金、API キー、ジョブは引き続き利用できます。 |
model_not_found | 404 | not_found_error | 指定したモデル ID がカタログにありません。チャットのエンドポイントは、テキストモデルでないモデルに対しても、このコードを返します。 |
payload_too_large | 413 | invalid_request_error | リクエスト本文が、許容サイズを超えています。error.details.max_bytes に上限が入ります。 |
rate_limited | 429 | rate_limit_error | モデルの提供元がリクエストを制限しています。POST /v1/reports は、同じアドレスから通報が多く送られたときにも、このコードを返します。Retry-After ヘッダの時間が過ぎてから再試行してください。 |
upstream_error | 502 | upstream_error | 上流の提供元がエラーを返しました。 |
upstream_unavailable | 503 | overloaded_error | 上流の提供元が一時的に容量不足です。時間をおいて再試行してください。 |
POST /v1/messages は、同じコードと HTTP ステータスを、Anthropic
のエラー形式で返します。error.type は Anthropic API
に従うため、表の「種別」の列と異なることがあります。balance_insufficient と key_limit_exceeded
は billing_error、payload_too_large は request_too_large、content_policy_violation は
invalid_request_error、upstream_error は api_error です。分岐には error.type ではなく
error.code を使ってください。
429 または 503 のレスポンスでは、Retry-After ヘッダの秒数だけ待ってから再試行してください。402 のレスポンスには error.details.limit_source が入り、値は balance か key です。残高とキーの利用上限を参照してください。すべてのコードは、エラーを参照してください。
価格はすべて USD 表示です。表示価格には当社のマージンを含みます。