1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

この記事でやること

OpenAI や Anthropic の API 向けに書いたコードが手元にあるとき、それを別の基盤に載せ替えるのはどれくらい大変なのか。

さくらのAI Engine は OpenAI/Anthropic 互換をうたっています。ただ「互換」と書かれていても、実際にどこまで動くかは触ってみないと分かりません。tool use は? streaming は? JSON出力は?

そこでこの記事では、検証のルールを1つ決めて確かめました。

base_url と APIキーだけを差し替える。アプリ側のコードは触らない。

この縛りで、実務でよく使う機能を一つずつ叩いています。

あわせて、さくらのAI Engine の課金がトークン量ではなくリクエスト回数である点についても整理しました。ここはトークン課金の常識と設計の勘所が変わるので、無償枠を使い切る前に知っておきたいです。

本記事は「さくらのAI Engine 3,000リクエスト使い切りチャレンジ」への参加記事です。

結論

差し替えだけでどこまで動いたか

機能 形式 結果 観測
通常応答 OpenAI finish_reason: stop
streaming OpenAI SSE を終端まで正常に受信
tool use(function calling) OpenAI tool_calls 返却 → 結果返しの往復が成立
JSON出力(json_object) OpenAI マークダウンで包まれない生JSON
メッセージ Anthropic stop_reason: end_turn、thinking と text が分離

全部そのまま動きました。 しかも1つのアカウントトークンで、OpenAI 形式(/v1/chat/completions)と Anthropic 形式(/v1/messages)の両方を、それぞれの作法のまま叩けます。

課金設計で押さえておくこと

内容
課金単位 トークン量ではなくリクエスト回数
無償枠 chat completions は月3,000リクエスト
超過時 自動課金されず、レートリミットで止まる

回数課金なので、1リクエストにまとめる方が有利です。トークン課金だとコンテキストを削りたくなりますが、ここでは逆になります。

詰まったのは互換性ではなく手元の環境

2箇所で止まりましたが、どちらもさくら側ではなく自分の環境の問題で、回避はいずれも一行でした。詳細は後述します。

準備:トークン発行まで

さくらのクラウド会員でログインし、AI Engine のコントロールパネル から進みます。

  1. 利用規約に同意 → 基盤モデル無償プランを選択
  2. 左メニュー アカウントトークンアカウントトークンを作成
  3. 発行された <UUID>:<シークレット> 形式の文字列を保管(再表示されません

先に共有しておきたい点が1つあります。

トークンの形式が独特です。 UUID:シークレット のペア全体で1つのAPIキーになります。OpenAI の sk-... とは形が違うので、Authorization: Bearer <UUID:シークレット> に丸ごと入れます。

無償プランの枠は公式マニュアル記載で以下のとおりです。

種別 無償枠(月)
チャット補完(chat completions) 3,000 リクエスト
ベクトル埋め込み(embeddings) 10,000 リクエスト
音声の文字起こし(audio transcriptions) 50 リクエスト
音声合成(audio speech) 50 リクエスト

疎通確認は公式の curl そのままで通ります。モデルはすべて gpt-oss-120b を使いました。

curl 'https://api.ai.sakura.ad.jp/v1/chat/completions' \
  -H 'Authorization: Bearer <UUID:シークレット>' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "gpt-oss-120b",
    "messages": [{"role":"user","content":"ping"}],
    "max_tokens": 500,
    "stream": false
  }'

使うエンドポイントは2つです。

  • OpenAI 互換:https://api.ai.sakura.ad.jp/v1/chat/completions
  • Anthropic 互換:https://api.ai.sakura.ad.jp/v1/messages

差し替えだけでどこまで載るか

ここからが本題です。冒頭のルールどおり、アプリ側のコードには一切手を入れていません。

tool use(function calling)

gpt-oss 系で function calling が通るかは事前に読めませんでしたが、結果は OpenAI 仕様どおりでした。

1回目のリクエストで tools を渡すと、本文ではなく tool_calls が返り、finish_reasontool_calls になります。

実行結果
[m3-1] status=200 finish=tool_calls content=NONE

その tool_calls に対してツールの実行結果(role: "tool")を返して2回目を叩くと、最終応答が返ります。

実行結果
[m3-2] status=200 finish=stop content=yes

5回試して毎回同じパターンでした。「初回でツール呼び出し → 結果を返して最終応答」という OpenAI エージェントの基本フローがそのまま動きます。

JSON出力(response_format)

response_format: {"type":"json_object"} を付けて叩いた実レスポンスです。

実行結果
{
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "{\n  \"name\": \"太郎\",\n  \"age\": 30\n}",
        "reasoning": "The user says ... output a JSON object with name and age ..."
      },
      "finish_reason": "stop"
    }
  ]
}

見どころが2つあります。

content が生JSONで返ります。 マークダウンのコードブロックで包まれないので、そのまま json.loads() できます。「JSONで返して」と指示したときの整形処理が要りません。

reasoning が content に混ざりません。 別フィールド reasoning に分離されているので、OpenAI SDK の message.content をそのままパースするコードが壊れません。

1つのトークンで Anthropic 形式も叩ける

個人的に一番効いたのがここです。同じアカウントトークン・同じモデル名のまま、Anthropic の Messages API 形式(/v1/messages)を叩いてみました。

curl -s 'https://api.ai.sakura.ad.jp/v1/messages' \
  -H "Authorization: Bearer $SAKURA_AI_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'anthropic-version: 2023-06-01' \
  -d '{
    "model":"gpt-oss-120b",
    "max_tokens":1000,
    "messages":[{"role":"user","content":"ping"}]
  }'
実行結果
{
  "type": "message",
  "role": "assistant",
  "content": [
    {
      "type": "thinking",
      "thinking": "The user just says \"ping\". ... Respond with \"pong\".",
      "signature": "db88f0f2530d465db463c320ad1d9c72"
    },
    { "type": "text", "text": "pong" }
  ],
  "model": "gpt-oss-120b",
  "stop_reason": "end_turn",
  "usage": { "input_tokens": 68, "output_tokens": 37 }
}

Anthropic Messages API の構造そのままです。

つまり OpenAI 形式で書いたコードも、Anthropic 形式で書いたコードも、どちらもエンドポイントを差し替えるだけで載ります。 片方の資産しか無くても移行できますし、両方が混在するプロジェクトでも1つのトークンで足ります。

per-request 課金をどう設計に落とすか

さくらのAI Engine の課金は、トークン量ではなくリクエスト回数で数えます。ここはトークン課金と設計の勘所が変わるので、実務目線で整理しておきます。

1回にどれだけ詰めても1リクエスト

「短いリクエストを何度も投げる」より「1リクエストにまとめる」方が回数効率が良くなります。

トークン課金だとコンテキストを削りたくなりますが、回数課金ではまとめる方が有利です。分類やタグ付けのような小タスクをループで叩いているなら、複数件を1プロンプトにバッチングするだけで消費回数が大きく減ります。

往復が増える機能は回数も増える

tool use は「初回のツール呼び出し」と「結果を返す2回目」で最低2リクエスト、マルチターンはターン数ぶんリクエストが積み上がります。

エージェント的に何度も往復する設計は、それだけ無償枠3,000回を早く消費します。回数を意識するなら、往復数そのものを減らす設計(不要なツールコールを削る、1ターンで済ませる)が良さそう。

利用量カウンタはリアルタイムではない

コントロールパネルの「利用量」で消費リクエスト数を確認できますが、叩いた直後は反映されず、集計にラグがあります(反映途中に部分的な数値が見える瞬間もありました)。

枠の消費をモニタリングしたい場合、コンソールの数字を即時の残量表示として当てにしない方がよさそうです。正確な管理が要るなら、アプリ側で自分のリクエスト数をカウントしておくのが確実です。

まとめ

  • OpenAI/Anthropic 向けに書いたコードは、base_url と APIキーの差し替えだけで載る。通常応答・streaming・tool use・JSON出力・Anthropic Messages 形式まで、手元では全部動いた
  • 1つのアカウントトークンで両形式が叩けるので、資産が混在していても移行できる
  • 課金はリクエスト回数。1回にまとめる方が有利で、往復の多いエージェント設計は枠の消費が早い
  • 無償枠を超えても自動課金されずレートリミットで止まるので、コスト面で事故りにくい
  • 詰まりどころは互換性ではなく手元の環境(TLS、max_tokens)。どちらも回避は一行

「まず動かしてみる」までの距離が短いサービスでした。手元にコード資産がある人ほど、載せ替えの手軽さを実感できると思います。

検証環境

  • モデル:gpt-oss-120b
  • 各機能パターンを複数回ずつ実行し、レスポンスの再現性を確認
  • OpenAI 互換 /v1/chat/completions、Anthropic 互換 /v1/messages の両方を同一トークンで検証
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?