AiHubMixでJevを呼び出す方法:構造化分類チュートリアル

AIHubMix約 5 分で読めます
AiHubMixでJevを呼び出す方法:構造化分類チュートリアル

結論: jev-1.13 はテキストを生成しません。テキストと名前付きの質問セットを https://aihubmix.com/v1/systemone にPOSTすると、質問名をキーとした型付きの回答(カテゴリ、スコア、または確率)が返ってきます。解析は不要です。以下に動作するリクエスト、レスポンス形式の全体、そして精度を静かに下げてしまう設計上のミスを示します。

Jevの用途

段落ではなく判断が必要な場合に使います。サポートチケットの振り分け、重大度のスコアリング、緊急度の判定、コンテンツのゲーティングなどです。モデルページには端的に「テキスト生成なし、解析不要」と書かれています。

説明、要約、自由形式の出力が必要な場合は、通常のチャットモデルを使ってください。jevはそれらを生成できません。

始める前に

  • [ ] Python 3がインストールされている(標準ライブラリで十分)
  • [ ] AiHubMixのアカウントとAPIキー
  • [ ] キーを AIHUBMIX_API_KEY として環境変数に設定(ソースコードにハードコードしない)

OpenAI SDK、LangChain、requests パッケージのいずれも 不要 です。

ステップ1 — エンドポイントを確認する

POST https://aihubmix.com/v1/systemone
Authorization: Bearer YOUR_KEY
Content-Type: application/json

これはモデル固有のルートであり、/v1/chat/completions ではありません。OpenAI互換のクライアントでは呼び出せません。プレーンなHTTPを使用してください。

ステップ2 — 質問の種類を選ぶ

種類は3つあり、1回のリクエストで自由に組み合わせられます:

種類用途指定する内容
choice単一カテゴリの選択criteria を辞書として指定(ラベル → 定義)
score順序付きスケールでの評価criteria を、最も低いものを先頭にしたリストとして指定
noulはい/いいえの判定 instructions 以外は不要

ステップ3 — リクエストを組み立てる

state は判定対象のテキストです。questions のキーは自分で付ける名前で、レスポンスでも同じ名前が使われます。

payload = {
    "model": "jev-1.13",
    "state": "Hi, I have been trying to connect my Stripe account for 3 days "
             "and it keeps failing. I am losing sales. Please help ASAP.",
    "questions": {
        "department": {
            "type": "choice",
            "instructions": "Which team should handle this",
            "criteria": {
                "billing":   "Payment or subscription issues",
                "technical": "Bugs or integration problems",
                "sales":     "Pricing or account questions",
            },
        },
        "frustration": {
            "type": "score",
            "instructions": "How frustrated the customer appears",
            "criteria": [
                "Calm, just stating facts",
                "Frustrated but civil",
                "Very angry, strong language",
            ],
        },
        "is_urgent": {
            "type": "noul",
            "instructions": "The message conveys urgency or time-sensitivity",
        },
    },
}

ステップ4 — 標準ライブラリで送信する

import json, os, urllib.error, urllib.request

def ask(payload):
    req = urllib.request.Request(
        "https://aihubmix.com/v1/systemone",
        data=json.dumps(payload).encode(),
        headers={"Authorization": "Bearer " + os.environ["AIHUBMIX_API_KEY"],
                 "Content-Type": "application/json"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(req, timeout=60) as r:
            return json.loads(r.read())
    except urllib.error.HTTPError as e:
        raise SystemExit(f"HTTP {e.code}: {e.read().decode(errors='replace')[:500]}")

リクエストの構築は関数の中に収めてください。モジュールのトップレベルで構築・送信すると、ファイルをインポートするだけで呼び出しが実行され、トークンを消費してしまいます。

ステップ5 — 回答を読む

各回答は、その type に対応するキーに値を格納するため、1つのアクセサで3種類すべてを扱えます:

data = ask(payload)
for name, ans in data["answers"].items():
    kind = ans["type"]
    print(name, kind, ans[kind], ans.get("confidence"))
print("usage:", data.get("usage"))

検証済みの出力:

department   choice  billing   0.51
frustration  score   1         1
is_urgent    noul    1         None
usage: {'input_tokens': 424, 'output_tokens': 73}

ステップ6 — レスポンス全体の構造を理解する

出力ループでは有用なフィールドが隠れてしまいます。score 回答の生のJSONは次のとおりです:

{
  "type": "score",
  "score": 1,
  "legend": {"0": "Calm, just stating facts", "1": "Frustrated but civil", "2": "Very angry, strong language"},
  "probabilities": {"0": 0, "1": 1, "2": 0},
  "confidence": 1
}
  • legend はインデックスを元の表現に対応づけます。整数自体が意味を持つので、コード内にルックアップテーブルは不要です。
  • probabilities は確率分布全体を返すため、僅差の判定を検出するのに役立ちます。
  • noul には confidence フィールドがありません。 その確率が判断の指標になります。

トップレベルには、usage、id、provider(TypeSafe)、および解決されたバックエンドのバージョン typesafe/jev-1.13-20260917 も返されます。

精度を下げる設計上のミス

上記のリクエストでは、department が billing を信頼度 0.51 で返しました。同一のリクエストを繰り返すと、同じラベルが 0.38 で返されました。回答は安定していたものの、示された確信度は安定していませんでした。

原因はモデルではなくcriteriaにあります。billing は「支払いまたはサブスクリプションの問題」、technical は「バグまたは連携の問題」です。Stripeの連携が失敗し続ける場合、実際には両方に該当します。モデルはスキーマに書き込まれた曖昧さを報告していたにすぎません。

本番運用前の2つのルール:

  1. choice のcriteriaは互いに排他的になるよう書いてください。人間が2つのラベルで迷うなら、モデルも迷います。
  2. 信頼度のしきい値を設定し、しきい値未満の結果は決定として受け入れず、人間のキューに回してください。不確実性を認めるモデルは、それを隠すモデルより価値があります。

公開前チェックリスト

  • [ ] キーは環境変数、またはVCSが無視する 600 モードのファイルから読み込む
  • [ ] choice のcriteriaに重複がないか確認済み
  • [ ] 信頼度のしきい値を定義し、その下の場合のフォールバック経路を用意済み
  • [ ] noul の回答は別途処理する(confidence を持たないため)
  • [ ] 使わない質問は削除済み(3つの質問は入力424トークン、2つは355トークン)
  • [ ] 2xx以外のレスポンスは生のボディとともにログ記録

FAQ

OpenAI SDKは使えますか? いいえ。/v1/systemone はOpenAI互換のルートではありません。

jevは文や要約を返せますか? いいえ。定義した型付きの質問にのみ答えます。

1リクエストあたりいくつの質問を送れますか? 検証したテストでは2つと3つを使用しました。質問ごとに入力と出力のトークンが加算されるため、実際に使う項目だけを含めてください。

バージョンのエイリアスはありますか? モデルページには jev-1.13 とともに jev-latest エイリアスが掲載されています。再現性が重要な場合は、明示的なバージョンを固定してください。

料金はいくらですか? モデルページには、入力トークンが $0.0462 / M、出力トークンが $0 / M と掲載されています。これはベンダーの数値です。予算を組む前に最新の料金を確認してください。

コンテキストウィンドウはどのくらいですか? モデルページの記載に不一致があります。ヘッダーでは64K、プロバイダーの表では32Kとなっています。どちらかに頼る前に、自分の最も長い入力で検証してください。

このガイドの範囲

上記のすべては、単一の入力に対する3回のライブ呼び出しで検証しました。レイテンシ、バッチ処理、スループット、また例と異なる入力での動作は扱っていません。信頼度のずれは再現された観察であり、測定された誤り率ではありません。しきい値を設定する前に、自分のデータで再現を確認してください。

AiHubMixで始める

jev-1.13 はAiHubMixで利用でき、モデルページには本チュートリアルで参照したすべての情報が掲載されています:/v1/systemone エンドポイント、criteria の形式を含む3種類の質問、レスポンスの全フィールド、そして公表されている料金(入力トークン $0.0462 / M、出力トークン $0 / M)。jev-latest エイリアスは最新リリースに解決されるため、バージョンが上がっても常に最新の状態が保たれます。

こちらから始めてください: https://aihubmix.com/model/jev-latest

次のステップ:

  1. AiHubMixのアカウントを作成し、APIキーを発行する
  2. ステップ3のリクエストと、ステップ4の ask() 関数をコピーする
  3. state を、自分のキューの実際のレコードに置き換える
  4. そのレコードを現在どのように分類しているかと結果を比較する

このガイドが役に立ったら、構造化出力モデルと分類パイプラインに関する今後の記事もぜひ購読してください。

ひとつのゲートウェイで複数のAIプロバイダーへ。 本番運用のために設計。

AIHubMix公式サイトへ