10
2

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 の Decisions API を触ってみた

10
Last updated at Posted at 2026-10-08

はじめに

少し前に、TypeSafe AIのjevが話題になりました。文章を生成せず、決められた型の答えと確信度だけを返すモデルで、LLMより桁違いに速くて安いとうたわれています。

同じ発想のAPIとして、OpenAIが2026年10月6日、Decisions APIを全開発者向けの公開ベータで提供開始しました。分類やスコアリングのような「決められた選択肢から選ぶ」処理に絞ったAPIです。

対応モデルはgpt-6-lunaのみ、料金は入力100万トークンあたり0.10ドルです。正式提供は「今後数週間」とされています。※2026年10月時点

これまで同じことをするなら、Responses APIのStructured Outputsでenumを指定するのが定番でした。そこで今回は、レシートの明細を家計簿のカテゴリに分ける題材で、Decisions APIとResponses APIを同じgpt-6-lunaで比べてみました。

Decisions APIとは

Decisions APIは、入力に対して「型の決まった答え」だけを返すAPIです。文章は生成しません。

質問の型は次の3つです。

type 答えの形 使いどころ
predicate はい/いいえの確率(0〜1) 条件に当てはまるかの判定(スパム判定、要対応かどうか、ポリシー違反の検出)
choice 選択肢のどれか1つ+各選択肢の確率 カテゴリ分類、問い合わせの振り分け
score 段階評価の値+各段階の確率 程度の評価(緊急度、感情の強さ、品質や関連度の採点)

答えには、選択肢ごとの確率とconfidence(確信度)が付いてきます。

料金は入力トークン分だけです。文章を生成しないので、出力トークンはそもそも発生しません。

画像も入力できます。jevはまだ画像に対応していないので、ここはDecisions APIの強みですね。ただし、画像はbase64のdata URLに限られ、URLやfile_idは使えません。

公式ドキュメントには「Responses APIより約10倍速い」と書かれています。

呼び出し方とレスポンス

準備

Decisions APIを使うには、openaiのSDKを新しいバージョンに上げる必要があります。JavaScript版は7.30.0以上です。

npm install openai@latest

カテゴリの定義

選択肢はDecisions APIとResponses APIの両方で使い回します。

src/categories.ts
export const CATEGORIES = [
  { value: "食費", description: "スーパーやコンビニで買った食材・飲み物・お菓子(持ち帰って食べるもの)" },
  { value: "外食", description: "飲食店での食事、カフェ、テイクアウト、フードデリバリー" },
  { value: "日用品", description: "洗剤・ティッシュ・ゴミ袋・電池などの消耗品" },
  { value: "交通", description: "電車・バス・タクシー・新幹線・駐車場・交通系ICのチャージ" },
  { value: "娯楽", description: "映画・本・ゲーム・カラオケなどの趣味や遊び" },
  { value: "医療・美容", description: "病院・薬・ドラッグストアの医薬品・美容院" },
  { value: "その他", description: "上のどれにも当てはまらないもの、中身がわからないもの" },
] as const;

export const INSTRUCTIONS = "レシートの明細1行(店名・品目・金額)を、家計簿のカテゴリに分類してください。";

呼び出し

呼び出しは、client.decisions.createにinputとquestionsを渡すだけです。

src/decisions.ts
import OpenAI from "openai";
import { CATEGORIES, INSTRUCTIONS } from "./categories.ts";

const client = new OpenAI();

export async function classifyWithDecisions(text: string) {
  const decision = await client.decisions.create({
    model: "gpt-6-luna",
    input: text,
    questions: [
      {
        type: "choice",
        name: "category",
        instructions: INSTRUCTIONS,
        choices: CATEGORIES.map(({ value, description }) => ({ value, description })),
      },
    ],
  });

  const [answer] = decision.answers;
  if (answer.type === "refusal") return { category: null, confidence: null, usage: decision.usage };
  if (answer.type !== "choice") throw new Error(`unexpected answer type: ${answer.type}`);

  return {
    category: String(answer.choice),
    confidence: answer.confidence,
    probabilities: answer.probabilities,
    usage: decision.usage,
  };
}

answersはquestionsと同じ順番で返ってきます。モデルが答えを断った場合はtype: "refusal"が返るので、その分岐も入れておきます。

レスポンス

「めぐりズム完熟ゆず1枚 ¥165」を渡したときの実際のレスポンスです。

{
  "model": "gpt-6-luna",
  "answers": [
    {
      "type": "choice",
      "name": "category",
      "choice": "医療・美容",
      "probabilities": [
        { "value": "食費", "probability": 0.01 },
        { "value": "外食", "probability": 0 },
        { "value": "日用品", "probability": 0.3 },
        { "value": "交通", "probability": 0 },
        { "value": "娯楽", "probability": 0.01 },
        { "value": "医療・美容", "probability": 0.49 },
        { "value": "その他", "probability": 0.19 }
      ],
      "confidence": 0.41
    }
  ],
  "usage": {
    "input_tokens": 336,
    "input_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 0 },
    "output_tokens": 0,
    "output_tokens_details": { "reasoning_tokens": 0 },
    "total_tokens": 336
  }
}

めぐりズムは蒸気で温めるアイマスクなので、「医療・美容」と「日用品」のどちらとも言えます。レスポンスを見ると、医療・美容0.49、日用品0.30と確率が割れていて、confidenceも0.41と低めです。モデルが迷っていることが数字でわかります。

output_tokensは0で、Decisions APIは文章を生成しないので出力トークンが発生せず、料金は入力の336トークン分だけです。

Structured Outputsとの違い

同じ分類をResponses APIのStructured Outputsで書くと、次のようになります。

src/responses.ts
import OpenAI from "openai";
import { CATEGORIES, INSTRUCTIONS } from "./categories.ts";

const client = new OpenAI();

const categoryList = CATEGORIES.map(({ value, description }) => `- ${value}: ${description}`).join("\n");

export async function classifyWithResponses(text: string, effort?: "none") {
  const response = await client.responses.create({
    model: "gpt-6-luna",
    ...(effort && { reasoning: { effort } }),
    instructions: `${INSTRUCTIONS}\n\nカテゴリ:\n${categoryList}`,
    input: text,
    text: {
      format: {
        type: "json_schema",
        name: "receipt_category",
        strict: true,
        schema: {
          type: "object",
          properties: {
            category: { type: "string", enum: CATEGORIES.map(({ value }) => value) },
          },
          required: ["category"],
          additionalProperties: false,
        },
      },
    },
  });

  const { category } = JSON.parse(response.output_text) as { category: string };
  return { category, usage: response.usage };
}

同じ明細を渡したときの結果はこうなりました。

{"category":"日用品"}
usage: input_tokens 159 / output_tokens 69(うち reasoning_tokens 53)

並べてみると、違いは次のとおりです。

Decisions API Responses API(Structured Outputs)
書くもの 質問の型と選択肢 JSON Schemaとプロンプト
返ってくるもの 答え+全選択肢の確率+confidence JSONの文字列(答えだけ)
迷っているかどうか 確率とconfidenceでわかる わからない
パース 不要(型つきのオブジェクト) JSON.parseが必要
出力トークン 発生しない 生成した分だけ発生。推論トークンも含む
自由な文章や抽出 できない できる

Responses APIは、答えが「日用品」の一言だけで返ってきます。迷ったうえでの日用品なのか、自信を持って日用品なのかは、レスポンスからはわかりません。Decisions APIなら「confidenceが0.6未満なら人に確認してもらう」のような分岐をそのまま書けます。

逆に、品目名や金額を抜き出したい、理由を文章で説明させたいといった用途には、Decisions APIは使えません。公式ドキュメントでも、自分で決めたJSON Schemaでデータを生成したいときはStructured Outputsを使うように案内されています。

実測

条件

レシートの明細48件を、次の3パターンで1件ずつ分類しました。

  • Decisions API(gpt-6-luna)
  • Responses API(gpt-6-luna、reasoning.effortはデフォルトのmedium)
  • Responses API(gpt-6-luna、reasoning.effort: "none")

料金はusageのトークン数から計算しています(Responses APIは入力$0.10、出力$0.50 / 1M tokens)。

結果

正解数 中央値 p95 1000件あたりの料金
Decisions API 48/48 195ms 280ms $0.033
Responses API 47/48 1,600ms 3,081ms $0.053
Responses API(effort: none) 47/48 1,555ms 2,783ms $0.041

同じモデルで精度も同等のまま、Decisions APIは中央値で約8倍速く、料金は6割ほどでした。

Responses APIの推論をオフにすると、出力トークンは1,809から679に減りました。それでも中央値は45msしか縮んでいません。遅さの原因は推論より、文字を1つずつ生成する仕組みのほうにありそうです。

1回あたりの入力トークンはDecisions APIのほうが多い(336対159)ものの、出力トークンが発生しない分トータルでは安くなります。選択肢の説明が長いと、この差は縮むかもしれません。

Decisions APIが迷った品目

confidence 明細 確率
0.41 ファミリーマート めぐりズム完熟ゆず1枚 ¥165 医療・美容0.49 / 日用品0.30 / その他0.19
0.70 マツモトキヨシ カロリーメイト 4本 ¥238 食費0.74 / 医療・美容0.23
0.85 カラオケ ○○ 飲食 投げ飲み放題アルコール ¥1,210 娯楽0.87 / 外食0.09

人が分類しても迷う明細ほど確率が割れています。confidenceが低いものだけユーザーに確認してもらう、といった使い方ができそうです。

まとめ

Decisions APIは、決められた選択肢から選ぶ処理に特化したAPIです。答えと一緒に確率とconfidenceが返ってきます。

一方で、文章の生成や値の抜き出しはできないので、Structured Outputsの代わりにはなりません。分類・振り分け・スコアリングならDecisions API、データを作るならStructured Outputsという使い分けになります。

分類やスコアリングのためだけにStructured Outputsを使っている人には、Decisions APIはかなりおすすめです!特に、レスポンスの遅さやコストが気になっている人や、「モデルがどれくらい自信を持って答えているのか」を知りたい人には合うと思います!
ゲームなどにも使えるかもしれませんね。

最後まで読んでいただき、ありがとうございました!
もし記事が参考になりましたら、いいねや共有をしていただけると嬉しいです🎉


株式会社サードスコープではAIを活用したシステムやサービスを開発しています。開発と導入支援の経験をもとに、現場での使い方まで踏まえてご提案します。

弊社では人材教育から実務支援まで幅広い業務に対応したAI中心設計による次世代のビジネスプラットフォームを提供しています。

参考

10
2
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
10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?