すべての記事に戻る

開発者ガイド

Jev TypeSafe:TypeScriptに型付きAI判断を組み込む

Jev TypeSafeの実践ガイド。型付き質問を定義し、API応答を実行時に検証して、TypeScriptアプリで不確実な判断を安全に振り分けます。

執筆者:Jev AI2026年9月24日読了時間:8分
Jev TypeSafe:TypeScriptに型付きAI判断を組み込む

jev typesafeで検索すると、関連はあるものの異なる二つの概念に行き着くことがあります。Jevの型付きAI判断と、TypeScriptの型システムです。このガイドでは、コンパイル時の型を信頼できる実行時データと混同せずに、両者を連携する方法を解説します。Jevは状態に関する構造化された質問に回答しますが、その応答を検証し、アプリが何を実行できるかを決めるのはTypeScriptサービスです。

Jevのサイトでは、ソフトウェアチーム向けの独立した判断ツールとして紹介されています。JevはTypeSafeと提携・運営関係になく、TypeSafeからの推奨も受けていません。まずはJev AIのホームページオンラインPlaygroundをご覧ください。

サーバー境界を通るAPIリクエストと検証済みの判断データを示すスケッチ

TypeScriptアプリで「Jevを型安全に使う」とは

TypeScriptは実行前にコードを検査します。しかし、リモートサービスのHTTP応答が宣言した型に一致することまでは証明できません。response.json()の値は、構造を確認するまでunknownとして扱います。

重要な境界は二つあります。

  1. リクエストの構築: TypeScriptで状態や質問の定義を一貫させます。
  2. 応答の解析: 実行時検査で、ネットワークデータに必要なフィールドがあることを確認します。

モデルの回答は判断のシグナルであり、操作の実行許可ではありません。実行を制御するのは、アプリ独自の業務ルール、決定的な検査、承認フローです。

数学スケッチ:TypeScriptのコンパイル時検査と応答の実行時検証を対比

Jevの三つの質問タイプから始める

Jevのドキュメントでは、三つの型付き質問が説明されています。固定の振り分け先にはChoice、順序のある評価にはScore、明確なYes/No判断にはNoulを使います。一つの状態に対して、複数の質問を同じリクエストで行えます。

タイプ 適した用途 確認する結果
Choice チーム、キュー、カテゴリの選択 選択肢、各確率、confidence
Score 順序尺度による重大度、品質、緊急度 加重スコア、段階ごとの確率、confidence
Noul 明確な命題が真かどうか 「はい」である確率(0〜1)

判定基準は具体的に記述します。チケットを請求、技術、営業に分けるなら、Jevに分類を作らせず、各選択肢に当てはまる条件を示しましょう。

数学ノート風の三分割図:Choiceの分岐、Scoreの段階尺度、Noulの確率弧

型付きリクエストを作り、応答を検証する

以下は、サーバー側のTypeScriptサービスから、ドキュメントにあるSystem Oneエンドポイントを呼び出す例です。リクエストの形を型で表し、APIキーをサーバー内に置き、unknownとして受け取ったJSONの構造を確認してからアプリに返します。

type Question =
  | { type: "choice"; instructions: string; criteria: Record<string, string> }
  | { type: "score"; instructions: string; criteria: string[] }
  | { type: "noul"; instructions: string };

type EvaluationRequest = {
  model: "jev-latest";
  state: string | Record<string, unknown> | string[];
  questions: Record<string, Question>;
};

function asRecord(value: unknown): Record<string, unknown> | null {
  return typeof value === "object" && value !== null && !Array.isArray(value)
    ? (value as Record<string, unknown>)
    : null;
}

function isProbabilityMap(value: unknown): value is Record<string, number> {
  const map = asRecord(value);
  return !!map && Object.values(map).every(
    (item) => typeof item === "number" && Number.isFinite(item) && item >= 0 && item <= 1
  );
}

async function classifyTicket(ticket: string) {
  const apiKey = process.env.JEV_API_KEY;
  if (!apiKey) throw new Error("JEV_API_KEY is not configured");
  const request = {
    model: "jev-latest",
    state: { message: ticket },
    questions: {
      department: {
        type: "choice",
        instructions: "Which team should handle this ticket?",
        criteria: {
          billing: "Payments, invoices, refunds, or payouts",
          technical: "Bugs, outages, or integration failures",
          sales: "Pricing, upgrades, or new accounts"
        }
      }
    }
  } satisfies EvaluationRequest;

  const response = await fetch("/ja/v1/systemone", {
    method: "POST",
    headers: {
      Authorization: "Bearer " + apiKey,
      "Content-Type": "application/json"
    },
    body: JSON.stringify(request)
  });

  if (!response.ok) throw new Error("Jev request failed: " + response.status);

  const payload: unknown = await response.json();
  const root = asRecord(payload);
  const answers = asRecord(root?.answers);
  const answer = asRecord(answers?.department);

  if (
    answer?.type !== "choice" ||
    typeof answer.choice !== "string" ||
    typeof answer.confidence !== "number" ||
    !Number.isFinite(answer.confidence) ||
    answer.confidence < 0 ||
    answer.confidence > 1 ||
    !isProbabilityMap(answer.probabilities)
  ) {
    throw new Error("Unexpected Jev response shape");
  }

  return {
    team: answer.choice,
    confidence: answer.confidence,
    probabilities: answer.probabilities
  };
}

const result = await classifyTicket("Three deploys failed and production is returning 500s.");
if (result.confidence >= 0.8) {
  // Apply your allowlist and business rules before routing.
} else {
  // Send uncertain cases to a human-review queue.
}

この検証は、このワークフローが使うフィールドを確認します。後続処理が別のフィールドを使うなら、その項目も検証してください。応答全体を宣言済みの型へキャストしただけで、リモートサービスがその型を満たすと考えてはいけません。

状態から並列質問を経て、アプリ側の振り分けまたは人による確認へ進むフロー図

confidenceは保証ではなくシグナルとして使う

JevのChoiceとScore応答には各選択肢の確率とconfidenceが含まれ、Noulは「はい」の確率を返します。これらは比較や振り分けに役立ちますが、confidenceは測定済みの正確さと同じではなく、安全性の保証でもありません。

自動化する前に、実際の用途を代表するラベル付きサンプルを用意します。重要な誤りを測定し、その結果に基づいてしきい値を設定し、未満の場合の処理を決めます。影響の大きい操作では、モデルのシグナルが強くても、決定的なポリシー検査と人の承認を残してください。

数学スケッチ:幅の異なる確率曲線と人手確認のしきい値

Jev TypeSafeを本番導入する際の確認事項

  • 判断に必要なテキストや構造化フィールドだけを送り、無関係な個人情報は除きます。
  • JEV_API_KEYはサーバー側のシークレットストアに保存します。ブラウザーコードや公開リポジトリには置きません。
  • 実操作へ接続する前に、Jev Playgroundで通常例、曖昧な例、敵対的な例を試します。
  • リクエストIDと検証結果を記録し、認証情報や不要な機密状態はログに残しません。
  • 一時的なHTTP 429・529には、上限付きの指数バックオフを使用します。
  • スキーマ不一致はエラーとして扱い、黙って既定の操作を選ばないようにします。
  • 入力の傾向や業務コストが変わったら、しきい値を見直します。

現在のリクエストと応答のフィールドはJev APIドキュメントを確認してください。本番利用量を見積もる際はプランと使用量も参照できます。

Jev TypeSafeはTypeScriptと同じですか?

違います。Jevは選択、スコア、Yes確率などの型付き判断結果を返します。TypeScriptはアプリのコードを静的に検査します。堅牢な連携には両方が必要です。リクエストと内部結果に型を付け、信頼できないネットワークデータは実行時に検証します。

TypeScriptの型でAPI応答を検証できますか?

できません。型注釈はJavaScriptの実行前に消えます。応答をunknownとして解析し、振り分け、保存、表示の前に、アプリが依存するフィールドを検査してください。

判断後にJevが操作を実行しますか?

実行はアプリ側で管理します。Jevには範囲の定まった質問を評価させ、アプリ独自の権限、許可リスト、決定的ルール、承認手順で続行を判断します。

まとめ

実用的なjev typesafe連携では、モデルの構造化判断と、それを使うアプリのロジックとの境界を明確にします。質問を絞り、応答を実行時に検証し、実例で評価し、不確実または影響の大きいケースは確認フローへ送ります。

© 2026 Jev AI Journalホームに戻る