OpenAI Decisions APIを使用するには、`https://api.openai.com/v1/decisions`にPOSTリクエストを送信します。リクエストには、`"model": "gpt-6-luna"`、`input`(テキスト、画像、またはその両方)、および各質問が`predicate`、`choice`、または`score`である`questions`配列を含めます。解析するテキストではなく、確率付きの型付き回答が返され、100万入力トークンあたり0.10ドルを支払い、出力、キャッシュ読み取り、キャッシュ書き込みの料金はかかりません。このエンドポイントは、2026年10月6日現在、パブリックベータ版です。
このガイドでは、キーの取得、curl、Python、JavaScriptでの最初の呼び出し、各回答タイプの読み取り、1つのサポートチケットに対する3つの質問、画像入力、しきい値、およびApidogでのテストセットアップについて説明します。このエンドポイントをいつ選択するかについては、「OpenAI Decisions APIとは何か」から始めてください。
Decisions APIリクエストの概要
| フィールド | 取るもの |
|---|---|
model |
gpt-6-luna(ベータ版で利用可能な唯一のモデル) |
input |
文字列、または`content`が文字列、あるいは`input_text`と`input_image`型のパーツである`user`メッセージの配列 |
questions[].type |
predicate、choice、またはscore |
questions[].instructions |
必須。平易な言葉で書かれた質問 |
questions[].name |
オプション。回答でそのまま返される(省略された場合は`null`) |
questions[].choices |
choiceのみ。2〜255個の一意な{value, description}オブジェクト、valueは文字列またはブール値 |
questions[].levels |
scoreのみ。順序付けられた{label, description}オブジェクト、低いものが最初、インデックスは0から |
safety_identifier |
オプションの不透明なエンドユーザーID、最大128文字 |
出典: Decisions APIリファレンス。このエンドポイントにはtemperature、stream、tools、text.formatはありません。
キーを取得して最初の呼び出しを行う
OpenAIダッシュボードでキーを作成し(OpenAI APIキーガイドでその方法を説明しています)、それをOPENAI_API_KEYとしてエクスポートし、決してコードに貼り付けないでください。次に、1つのはい/いいえの質問をします。
curl https://api.openai.com/v1/decisions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-luna",
"input": "The box arrived crushed and the screen is cracked.",
"questions": [
{"type": "predicate", "name": "damaged",
"instructions": "Does the customer report a damaged item?"}
]
}'
レスポンスには、model、answers、usageの3つのトップレベルフィールドがあります。これはOpenAIのリファレンスからの形式であり、エンドポイントが出力に対して課金しないため、output_tokensは0です。
{
"model": "gpt-6-luna",
"answers": [
{"type": "predicate", "name": "damaged", "probability": 0.95}
],
"usage": {
"input_tokens": 42,
"input_tokens_details": {"cached_tokens": 0, "cache_write_tokens": 0},
"output_tokens": 0,
"output_tokens_details": {"reasoning_tokens": 0},
"total_tokens": 42
}
}
Python(SDK 3.26.0以降)での同じ呼び出し:
from openai import OpenAI
client = OpenAI() # reads OPENAI_API_KEY from the environment
decision = client.decisions.create(
model="gpt-6-luna",
input="The box arrived crushed and the screen is cracked.",
questions=[
{"type": "predicate", "name": "damaged",
"instructions": "Does the customer report a damaged item?"}
],
)
print(decision.answers[0].probability)
そしてJavaScript(SDK 7.30.0以降)では:
import OpenAI from "openai";
const client = new OpenAI();
const decision = await client.decisions.create({
model: "gpt-6-luna",
input: "The box arrived crushed and the screen is cracked.",
questions: [
{ type: "predicate", name: "damaged",
instructions: "Does the customer report a damaged item?" },
],
});
console.log(decision.answers[0].probability);
回答をタイプ別に読み取る
回答は、要求した順序で返され、それぞれに`type`が付いています。任意の質問が`refusal`として返される可能性があるため、タイプによって処理を切り替えます。
predicateは、条件が真である確率を0から1で示す`probability`を返します。choiceは、`choice`(勝利した`value`)、`{value, probability}`オブジェクトの配列としての`probabilities`、および`confidence`を返します。scoreは、`score`、`{value, label, probability}`オブジェクトの配列としての`probabilities`(ここで`value`は0ベースのレベルインデックス)、および`confidence`を返します。スコアはレベルインデックスの確率加重平均であるため、レベル間に位置することもあります。例えば1.1は「レベル1とレベル2の間で、1に近い」ことを意味します。refusalは、`type`と`name`のみを返します。モデルはその質問を拒否しました。同じリクエスト内の他の質問は引き続き回答を受け取ることができます。
for a in decision.answers:
if a.type == "refusal":
send_to_review(a.name)
elif a.type == "predicate":
flag = a.probability > 0.9
elif a.type == "choice":
route = a.choice if a.confidence > 0.8 else "review"
elif a.type == "score":
priority = round(a.score)
OpenAIのガイドでは、次のように区別しています。部門のような順序のないカテゴリには`choice`を使用し、重要度のような順序付けられたレベルには`score`を使用します。
1つのサポートチケットに対する3つの質問
独立した質問は1つのリクエストと1つの`input`を共有し、各質問は異なるタイプを使用できます。以下は、単一のチケットに対する述語、選択肢、スコアの例です。
{
"model": "gpt-6-luna",
"input": "I was charged twice for my order.",
"questions": [
{"type": "predicate", "name": "refund_requested",
"instructions": "Is the customer asking for money back?"},
{"type": "choice", "name": "department",
"instructions": "Which team should handle this ticket?",
"choices": [
{"value": "billing", "description": "Charges, refunds, invoices"},
{"value": "technical", "description": "Bugs and errors in the product"},
{"value": "shipping", "description": "Delivery and tracking"},
{"value": "other", "description": "Anything else"}
]},
{"type": "score", "name": "urgency",
"instructions": "How urgent is this ticket?",
"levels": [
{"label": "low", "description": "No time pressure"},
{"label": "medium", "description": "Needs a reply this week"},
{"label": "high", "description": "Customer is blocked or losing money"}
]}
]
}
`answers`配列は同じ順序で返されます。以下の`choice`値は、この正確な入力に対するOpenAIのガイド値です。述語とスコアの値は例示的なものです。
"answers": [
{"type": "predicate", "name": "refund_requested", "probability": 0.88},
{"type": "choice", "name": "department", "choice": "billing",
"probabilities": [
{"value": "billing", "probability": 0.95},
{"value": "technical", "probability": 0.02},
{"value": "shipping", "probability": 0.01},
{"value": "other", "probability": 0.02}
],
"confidence": 0.93},
{"type": "score", "name": "urgency", "score": 1.6,
"probabilities": [
{"value": 0, "label": "low", "probability": 0.05},
{"value": 1, "label": "medium", "probability": 0.30},
{"value": 2, "label": "high", "probability": 0.65}
],
"confidence": 0.65}
]
ガイドからの2つのルール:カテゴリがすべての入力をカバーしない場合は`other`のようなフォールバックを含めること、そして隣接するスコアレベルが異なる意味を持つように観察可能な基準に基づいて質問を作成することです。2番目の決定が最初の回答に依存する場合は、別のリクエストを送信してください。
画像入力
`user`メッセージ内にコンテンツパートとして画像を渡します。ガイドでは、インラインのBase64データURLを記載しています。
{
"model": "gpt-6-luna",
"input": [{
"role": "user",
"content": [
{"type": "input_text", "text": "Photo attached to a return request."},
{"type": "input_image", "image_url": "data:image/jpeg;base64,/9j/4AAQ..."}
]
}],
"questions": [
{"type": "predicate", "name": "visible_damage",
"instructions": "Is the product visibly damaged?"}
]
}
APIリファレンスには、公開アクセス可能なHTTP(S) URL、1つのリクエスト内のすべてのメッセージで最大128枚の画像、およびオプションの`detail`フィールド(`low`、`high`、`auto`、`original`)も記載されているため、ホストされたURLを信頼する前に自分のアカウントでテストしてください。`file_id`入力はどちらのページでもサポートされていません。
ラベル付きの例からしきい値を選択する
OpenAIは、このエンドポイントの精度やキャリブレーションの数値を公開していません。そのガイダンスは、偽陽性対偽陰性のコストに基づいて、ルーティング、フィルタリング、またはレビューのしきい値を設定するために、自身のアプリケーションからのラベル付きの例を使用することです。実際には、これは人間が選択した部門を持つ実際のチケットの小さなCSVを同じリクエストで実行し、`confidence`がクリーンなルートと人手が必要なルートをどこで分離するかを確認できることを意味します。次のセクションでは、そのループを構築します。
ApidogでDecisions APIをテストする
保存されたリクエストにより、しきい値の調整と回帰チェックを繰り返し実行できます。Apidogでのセットアップは次のとおりです。
- キーを環境変数として保存する。環境を作成し、`OPENAI_API_KEY`をシークレット変数として追加し(Apidogの環境とシークレット変数でセットアップを説明しています)、`Authorization`ヘッダーを`Bearer {{OPENAI_API_KEY}}`に設定します。キーが共有リクエストボディに保存されることはありません。
- 質問タイプごとに1つのリクエストを保存する。`Content-Type: application/json`を指定して`https://api.openai.com/v1/decisions`へのPOSTリクエストを作成し、上記のチケット例から`choice`の質問を単独で貼り付けて保存します。述語およびスコアバージョンについても複製します。
- JSONPathアサーションを追加する。選択リクエストの場合:ステータスが200、`$.answers[0].type`が`choice`、`$.answers[0].choice`が`billing`、`$.answers[0].confidence`が0.8より大きい、`$.usage.output_tokens`が0であることをアサートします。損傷述語の場合、`$.answers[?(@.name=='damaged')].probability`が0.9より大きいことをアサートします。指示の文言の変更、またはモデルの動作の変更があった場合、チケットの誤ルーティングではなくテストが失敗するようになります。
- ラベル付けされたチケットに対して実行する。保存されたリクエストからテストシナリオを構築し、`ticket_text`と`expected_department`の2つの列を持つ小さなCSVを添付します。`{{ticket_text}}`を`input`にマッピングし、`$.answers[0].choice`が`{{expected_department}}`と等しいことをアサートします。実行レポートには各行の`confidence`が表示され、これはOpenAIがしきい値を設定するために使用するデータとして示しているものです。すべての誤ルーティングが発生する点より下を、コードでの「自動ルーティング」のしきい値とします。
- フロントエンドの`answers`配列をモックする。ルーターまたはUIを、同じエンドポイントのモックに向けます。そのモックは、しきい値の上下の`confidence`を持つ`choice`回答と、`refusal`を返します。これにより、入力トークンを消費する前にレビューキューのパスが構築されます。Apidogでの条件付きモックレスポンスは、リクエストコンテンツに基づいてモックを切り替える方法を説明しています。
- CIでシナリオを実行する。アクセストークンをエクスポートし、パイプラインにステップを追加します。
apidog run --access-token "$APIDOG_ACCESS_TOKEN" \
-t "$SCENARIO_ID" -e "$ENV_ID" -r cli,junit
アサーションが失敗するとビルドも失敗するため、`confidence`のわずかな低下もサポートキューではなくデプロイ前に検出されます。より広範なパターンについては、「LLMアプリケーションのテスト」を参照してください。
エラーとエッジケースの処理
- 429 レート制限。Decisions固有の制限は公開されていません。ご自身の制限については「Settings > Organization > Limits」を確認してください。指数関数的にバックオフし、`Retry-After`ヘッダーが存在する場合はそれに従ってください。レート制限超過ガイドには、リトライラッパーが記載されています。
- 拒否された回答。`type: "refusal"`は例外ではなくルーティング結果として扱います。そのチケットを人間に送り、同じリクエストからの他の回答は保持します。
- 依存する決定。すべての質問は、共有された入力に対して独立して評価されます。以前の回答に依存するものは、独自の別のリクエストが必要です。
FAQ
Decisions APIの料金はいくらですか? `gpt-6-luna`の場合、100万入力トークンあたり0.10ドルで、出力、キャッシュ読み取り、キャッシュ書き込みの料金はかかりません。3つの質問を含む500トークンのチケットは500 / 1,000,000 x $0.10 = $0.00005なので、そのようなチケットが100万枚あれば50ドルかかります。272Kトークンを超える長文入力は2倍、地域処理は10%追加されます。
Decisions APIは無料ですか? いいえ。Decisions APIに無料枠はありません。無料でGPT-6 Lunaを試したい場合は、GPT-6 Lunaの無料利用方法に関する記事に既存のものが記載されています。
どれくらいの速さですか? OpenAIはResponses APIよりも約10倍速いと述べていますが、絶対的なレイテンシー数値は公表していません。OpenAIフォーラムのある開発者は、画像決定が約0.8秒で行われたと報告しています。
Decisions APIはどのモデルで動作しますか? 現在は`gpt-6-luna`のみです。これはLuna上のエンドポイントであり、独立したモデルではありません。モデル自体については「GPT-6 Lunaとは何か」を参照してください。
代わりに構造化出力を使用すべきなのはいつですか? 抽出されたフィールドや書面による説明など、独自のJSONスキーマでオブジェクトが必要な場合、またはモデルが引数付きのツールを要求すべき関数呼び出しの場合です。Decisions API vs Responses APIの記事では、同じチケットを両方の方法で処理した例が示されています。
Jevと比較してどうですか? どちらも確率付きの型付き回答を返し、入力のみで課金されます。Jevはテキスト専用で100万あたり0.042ドルです。Decisions API vs Jevの比較には詳細な表が掲載されています。
次のステップ
このガイドの3つの質問を含むチケットリクエストを送信し、次に独自のラベル付きチケット20件に対して実行し、`confidence`が正しいルートと間違ったルートをどこで分離するかを確認してください。その後、リクエスト、CSVシナリオ、アサーションをまとめて保持するためにApidogをダウンロードし、今日選択したしきい値がデプロイごとに再チェックされるようにします。
