意思決定

OpenAI Decisions API

GPT-6 Luna Decisions に、テキスト・画像・JSON についての分類やスコアリングの質問を投げると、コードでそのまま扱える型付きの回答が返ります。ある文がどの程度正しいか、どの値が当てはまるか、スケール上のどこに位置するかを、それぞれ確率付きで取得できます。1回のリクエストで多数の質問を処理でき、通常は1秒未満で完了します。OpenAI 独自の Decisions API と SDK を利用できます。

POST/v1/decisions
モデルID入力、1M トークンあたりOpenAI の価格出力
GPT-6 Luna Decisionsgpt-6-luna-decisions$0.04$0.10無料

GPT-6 Luna Decisions は OpenAI の判断モデルです。入力を読み取り、それについて設定した質問に答えます。テキストは生成しないため、チャットモデルではありません。送信先は /v1/chat/completions ではなく /v1/decisions です。このエンドポイントでは、OpenAI 自身の SDK ドキュメントと同様に gpt-6-luna もモデル ID として使えるので、OpenAI のサンプルコードがそのまま動作します。レスポンスの model は gpt-6-luna-decisions になります。TypeSafe の判断モデル Jev については、意思決定 (Jev) をご覧ください。

質問する

# pip install --upgrade openai
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.zurelay.com/v1",
api_key=os.environ["ZURELAY_API_KEY"],
)
decision = client.decisions.create(
model="gpt-6-luna-decisions",
input="My headphones stopped charging two days after they arrived. I want a refund.",
questions=[
{
"type": "predicate",
"name": "refund",
"instructions": "Is the customer asking for a refund?",
},
{
"type": "choice",
"name": "topic",
"instructions": "What is the ticket about?",
"choices": [
{"value": "billing", "description": "Charges and invoices"},
{"value": "hardware", "description": "A device that is broken or faulty"},
{"value": "shipping", "description": "Delivery and tracking"},
],
},
{
"type": "score",
"name": "sentiment",
"instructions": "How does the customer feel?",
"levels": [
{"label": "very negative"},
{"label": "negative"},
{"label": "neutral"},
],
},
],
)
# One answer per question, in the order asked
for answer in decision.answers:
if answer.type == "refusal":
print(answer.name, "refused")
elif answer.type == "predicate":
print(answer.name, answer.probability)
elif answer.type == "choice":
print(answer.name, answer.choice, answer.confidence)
else:
print(answer.name, answer.score, answer.confidence)
print(decision.usage.input_tokens, "input tokens")

OpenAI の SDK の接続先を https://api.zurelay.com/v1 にし、/v1 は Zurelay 上のほかの OpenAI モデルと同じ設定にして、Zurelay のキーで client.decisions.create を呼び出してください。Node.js では openai 7.30.0 以降が必要です。Python では client.decisions に対応している新しさの openai パッケージが必要です(3.41 なら対応しています)。HTTP クライアントでも同様で、キーを Bearer トークンとして付けて JSON を POST してください。

回答

レスポンス
{
"id": "req_3Fh8sLq0vW2nTc7yRb5kZp1M",
"model": "gpt-6-luna-decisions",
"answers": [
{ "type": "predicate", "name": "refund", "probability": 1 },
{
"type": "choice",
"name": "topic",
"choice": "hardware",
"confidence": 1,
"probabilities": [
{ "value": "billing", "probability": 0 },
{ "value": "hardware", "probability": 1 },
{ "value": "shipping", "probability": 0 }
]
},
{
"type": "score",
"name": "sentiment",
"score": 0.18,
"confidence": 0.85,
"probabilities": [
{ "value": 0, "label": "very negative", "probability": 0.82 },
{ "value": 1, "label": "negative", "probability": 0.18 },
{ "value": 2, "label": "neutral", "probability": 0 }
]
}
],
"usage": {
"input_tokens": 325,
"input_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 0 },
"output_tokens": 0,
"output_tokens_details": { "reasoning_tokens": 0 },
"total_tokens": 325,
"cost": 0.000013
}
}

answers には、質問した順に質問ごとの回答が入り、それぞれに type が、指定した場合は name も含まれます。usage はリクエストの課金対象で、input_tokens の形式です。output_tokens は常に 0 で、cost は米ドルでの費用です。レスポンスの x-request-id ヘッダーを使えばリクエストログからこのリクエストを見つけられ、x-zurelay-input-tokens には課金対象が同じ内容で記載されます。

パラメータ

modelstring必須
gpt-6-luna-decisions、またはこのエンドポイントではgpt-6-luna。
input文字列または配列必須
判定の対象:空でないテキスト、またはユーザーメッセージの配列 { "role": "user", "content": ... }("type": "message" は省略可)。メッセージの content はテキストまたはパーツの配列で、詳細は以下のとおりです。
questionsarray必須
1〜64個の質問を指定でき、記載した順に回答されます。
safety_identifierstring
任意:リクエストの対象となるエンドユーザーを識別する不透明な ID です(自社のユーザー ID のハッシュなど)。
prompt_cache_keystring
受け付けますが無視されます(prompt_cache_options も同様です)。キャッシュは自動で行われ、入力トークンの料金はすべて同じです。
各質問
typestring必須
predicate、choice、または score。
instructionsstring必須
質問をテキストで入力してください。画像は、ここではなく入力(input)に含めます。
namestring
任意項目です。リクエスト内で一意にしてください。質問の回答に含まれて返されるため、名前で回答を読み取れます。
choicesarray
choice(必須)の場合:2〜255個の値を指定します。各値は{ "value": ..., "description": ... }。値はテキストまたはtrue/falseで、それぞれ一意である必要があります。説明は省略可能です。
levelsarray
score(必須)の場合:2〜10段階のレベルを低い順に指定します。各レベルは { "label": ..., "description": ... }、説明は任意です。
メッセージのコンテンツの構成要素
input_text{ text }
テキスト。
input_image{ image_url, detail }
PNG、JPEG、WebP、GIF形式の画像。base64のデータURL、またはZurelayがダウンロードする公開httpsリンクを指定できます。detailは省略可能です。指定できる値はlow、high、auto、originalです。
input_json{ data }
レコードやアプリの状態などのオブジェクトまたは配列です。モデルはこれをコンパクトな JSON テキストとして読み取り、そのテキストとしてカウントされます。

質問の種類

種別質問内容Answer
predicate入力に関する記述が真である可能性の高さprobability、0〜1の範囲
choice2〜255個の値のうち、どれが適しているかchoice、confidence、そしてすべての値のprobabilities
score2〜10段階の順序つきレベルの中での位置score、confidence、そしてあらゆるレベルのprobabilities

1回のリクエストで3つすべてを組み合わせられます。入力はまとめて1回だけ読み込まれるため、複数の質問を1つのリクエストで送るほうが、質問ごとに別々のリクエストを送るよりもコストを抑えられます。

プレディケート

入力に関する文、またははい/いいえで答えられる質問です。回答のprobabilityは、その内容が真である可能性の高さを表します。「はい」なら1に近く、「いいえ」なら0に近く、入力から明確に判断できない場合はその中間の値になります。

質問してから回答する
{ "type": "predicate", "name": "refund", "instructions": "Is the customer asking for a refund?" }
{ "type": "predicate", "name": "refund", "probability": 1 }

選択

指定した値の中から1つを選び、それぞれの確率を返します。説明を付けると値の意味を伝えられるため、値がコードだけの場合に役立ちます。値には true や false も使えます。文字列の "true" と真偽値の true は、別の値として扱われます。

Question
{
"type": "choice",
"name": "language",
"instructions": "Which language is the message written in?",
"choices": [
{ "value": "en", "description": "English" },
{ "value": "es", "description": "Spanish" },
{ "value": "other", "description": "Any other language" }
]
}

スコア

入力をあなたが定義したレベルに、低いほうから順に割り当てます。score は期待レベルで、各レベルのインデックス(0から数えます)を、その確率で重み付けした値です。そのため、2つのレベルの間の値になることがあります。上の例のレスポンスでは、0.18 は大部分が最初のレベルで、2番目のレベルがわずかに混ざっています。probabilities の各エントリーには、レベルのインデックスを示す value と、その label が含まれます。

Question
{
"type": "score",
"name": "relevance",
"instructions": "How well does the passage answer the search query?",
"levels": [
{ "label": "irrelevant" },
{ "label": "related", "description": "On the topic, but doesn't answer it" },
{ "label": "answers it" }
]
}

画像

入力に画像を含めるには、ユーザーメッセージのパートとしてテキストと並べて指定します。base64 のデータ URL、または公開されている https リンクを指定できます。リンクの場合は Zurelay が画像をダウンロードして転送します。対応形式は PNG、JPEG、WebP、GIF です。大きな画像はリンクで送信してください。

import base64, os
from openai import OpenAI
client = OpenAI(base_url="https://api.zurelay.com/v1", api_key=os.environ["ZURELAY_API_KEY"])
with open("return-photo.jpg", "rb") as file:
photo = "data:image/jpeg;base64," + base64.b64encode(file.read()).decode()
decision = client.decisions.create(
model="gpt-6-luna-decisions",
input=[
{
"role": "user",
"content": [
{"type": "input_text", "text": "Photo sent with a return request for a blender."},
{"type": "input_image", "image_url": photo, "detail": "low"},
],
}
],
questions=[
{
"type": "predicate",
"name": "damaged",
"instructions": "Does the photo show visible damage to the product?",
},
{
"type": "choice",
"name": "product",
"instructions": "What product is in the photo?",
"choices": [
{"value": "blender"},
{"value": "kettle"},
{"value": "other", "description": "Anything else, or no product"},
],
},
],
)
print(decision.answers)

画像は、サイズとdetailに応じてトークンが加算されます。1200 × 630 の画像は、highまたはautoで約750トークン、lowでは約150トークンです。細かい文字ではなく画像全体について尋ねる場合は、lowを使います。画像を渡せるのは入力のみで、質問の指示にはテキストを使います。

JSON入力

構造化データは、テキストや画像と並べて input_json パートにそのまま入れられます。モデルはコンパクトな JSON テキストとして読み取り、そのテキストとして課金されます。

JSON での入力
"input": [
{
"role": "user",
"content": [
{ "type": "input_text", "text": "A sign-up from our app:" },
{
"type": "input_json",
"data": { "name": "Free Gift Card Giveaway", "email": "win-now@example.net", "bio": "Click my link" }
}
]
}
]

拒否

どの質問も、回答ではなく拒否として返される場合があります。その場合でも、リクエスト内の他の質問には通常どおり回答が返されます。各回答のフィールドを読む前に、まず type を確認してください。テストでは、入力 “Refund requested 38 hours ago.” に対して述語 “Page on-call?” を指定したところ、拒否として返されました。

拒否された質問
{ "type": "refusal", "name": "page_on_call" }

拒否は通常のレスポンスとして返され、そのusageにはリクエストの課金対象が示されます。質問をより明確にしてもう一度送信するか、担当者に引き継いでください。

制限

  • 1リクエストあたり最大 1.05M トークンです(入力とすべての質問の合計)。テストでは、918K トークンの入力でも問題なく動作しました。
  • 質問は1〜64件です。choiceには2〜255個の一意の値、scoreには2〜10段階のレベルを指定できます。
  • ユーザーメッセージのみ受け付けます。system、developer、assistant のメッセージと、関数呼び出しやツール呼び出しの項目は拒否されます。コンテキストはユーザーメッセージか、質問の instructions に入れてください。
  • ストリーミングは使えません。stream は拒否され、回答は一括で返されます。
  • 形式が不正なリクエストや、API が受け付けないフィールドを含むリクエストは、モデルに届く前に、そのフィールド名(questions[2].choices など)を示す 400 で拒否されます。料金はかかりません。
  • 一部のモデルに限定したキーでは、リストに gpt-6-luna-decisions を含める必要があります。リクエストで gpt-6-luna と指定した場合も同様です。詳しくはキーの制限とルールをご覧ください。

速度

当社のテストでは、回答は通常 0.3〜1 秒で返り、画像付きの場合は約 1 秒です。900K トークンの入力では約 10 秒かかりました。

意思決定の料金

GPT-6 Luna Decisions の料金は、入力 1M トークンあたり $0.04 です。回答は無料です。 トークンは、入力(1 回だけ数えます)に、質問ごとにモデル自身の約 110〜160 トークンを加えた数です。短いテキストに対する短い predicate 1 つで合計約 160 トークン、2 つで約 320 トークン、2,600 トークンの入力に 4 つの質問で約 3,200 トークンになります。画像は上記のとおり、そのトークン数が加算されます。 そのため、短いテキストに対する 1 問のチェックは約 $0.0000064、100 万件で約 $6.40 になります。

各レスポンスの usage ヘッダーと x-zurelay-input-tokens ヘッダーに課金の基準が示されます。すべてのリクエストはリクエストログで確認でき、失敗したリクエストには料金がかかりません。

エラー

ステータスコード発生条件
400invalid_requestリクエストの形式が不正か、API が受け付けない内容が含まれています。メッセージに内容と場所が示されます。
400invalid_input画像リンクをダウンロードできなかったか、PNG、JPEG、WebP、GIF 形式の画像ではありません。
400context_length_exceeded入力と質問の合計が 1.05M トークンを超えています。入力を短くして送信してください。
503model_unavailable または service_unavailableモデルが一時的に利用できません。retry-after ヘッダーに示された秒数が経過してから再試行してください。

キー、クレジット、予算、レート制限に関するエラーは、ほかのエンドポイントと同じです。詳しくはエラーをご覧ください。OpenAI の SDK は、再試行する価値のあるエラーを自動で再試行します。

まず試してみる

ダッシュボードのプレイグラウンドで GPT-6 Luna Decisions を選び、コンテンツを貼り付けるか画像を添付して、横に質問を設定します。「コードを取得」ボタンを押すと、同じリクエストを OpenAI の SDK(Python または Node.js)または cURL のコードで出力できます。

ご質問や不足している情報はありますか? サポートチームにお問い合わせください。通常1分以内にメールで回答します。