Jev で問い合わせを振り分ける:4 つの担当、情報不足、人による確認

請求・技術・営業・その他を Choice で判定し、情報不足を Noul で検出し、人が確認すべき場合をコードで決める、小さく検証しやすい振り分けの作り方。

このガイドの範囲:リクエスト形式とアプリケーションコードは、2026-09-25 に確認した TypeSafe 公式ドキュメントに基づいています。問い合わせ文、ラベル、しきい値は業務ルールを説明するための合成例です。モデルの出力、精度、速度、費用の比較は掲載していません。利用前に、自社のラベル付きデータで測定してください。

1. ルーターに任せる範囲を決める

ここで作るルーターが行うのは、担当キューの選択と情報不足の検出だけです。返信文の作成、返金、アカウント変更は行いません。そうした操作は通常の権限管理の後ろに置いてください。Jev は型付きの答えを返します。Choice は選ばれた選択肢、各選択肢の確率、confidence を返し、Noul は答えが「はい」である確率を 0 から 1 の数値で返します。この構造があるので、次の判断をコードで確実に行えます。

2. 4 つの担当の境界を書き出す

以下は説明用の業務ルールの例です。自社の運用に合わせて書き換えてください。

担当扱う内容他へ回す条件
billing既存の請求、請求書、返金、支払い方法、更新時の決済失敗購入前に料金を尋ねている(sales へ)
technical不具合、障害、エラーメッセージ、ログインの問題、連携エラー実際には発生済みの請求に関する問題(billing へ)
sales料金の質問、プラン比較、新規購入、見積もりすでに契約中で、特定の請求について尋ねている(billing へ)
other提携、取材、採用への応募、一般的なご意見自動では閉じず、必ず人が読む

この境界を選択肢の説明文に書き込みます。TypeSafe の Jev 1.13 の既知の制約ページによると、Jev は指示を文字どおりに読みます。誤った答えを見て「本当はこういう意味だった」と説明したくなったら、その一文が criteria に足りなかった部分です。other は必ず本物の選択肢として残してください。どれにも当てはまらない問い合わせを、いちばん近い担当に無理やり入れずに済みます。

3. 実験室のリクエストから始める

実験室の support-routing の例 を開くと、次のリクエストが読み込まれます。本文を書き換えて JSON や cURL をコピーできます。API キーが必要なのは実際に送信するときだけです。

{
  "model": "jev-1.13.0",
  "state": {
    "message": "今月、同じサブスクリプションの料金が二重に請求されました。"
  },
  "questions": {
    "decision": {
      "type": "choice",
      "instructions": "この問い合わせはどのチームが担当すべきですか? 該当するチームがない場合は other を選んでください。",
      "criteria": {
        "billing": "支払い、請求、請求書、返金",
        "technical": "不具合、障害、連携エラー",
        "sales": "料金や新規購入の相談",
        "other": "これらのチームの担当外の問い合わせ"
      }
    }
  }
}

cURL では、キーを環境変数から読み、本文を引用符付きのヒアドキュメントで渡します。

curl --fail-with-body --max-time 20 https://api.typesafe.ai/v1/systemone \
  -H "Authorization: Bearer $TYPESAFE_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JEV_ATLAS_REQUEST'
{
  "model": "jev-1.13.0",
  "state": {
    "message": "今月、同じサブスクリプションの料金が二重に請求されました。"
  },
  "questions": {
    "decision": {
      "type": "choice",
      "instructions": "この問い合わせはどのチームが担当すべきですか? 該当するチームがない場合は other を選んでください。",
      "criteria": {
        "billing": "支払い、請求、請求書、返金",
        "technical": "不具合、障害、連携エラー",
        "sales": "料金や新規購入の相談",
        "other": "これらのチームの担当外の問い合わせ"
      }
    }
  }
}
JEV_ATLAS_REQUEST

本番では、担当の判定と情報不足の判定を 1 回のリクエストにまとめます。2 つの質問は同じ state に対してそれぞれ独立に評価され、一方の答えがもう一方の前提になることはありません。組み合わせはコードで行います。teamneeds_details は自分で付ける ID で、答えも同じ ID で返ります。

{
  "model": "jev-1.13.0",
  "state": {
    "subject": "今月の請求が二重になっています",
    "message": "今月、同じサブスクリプションの料金が二重に請求されました。請求書番号の末尾は 4471 と 4472 です。",
    "channel": "email"
  },
  "questions": {
    "team": {
      "type": "choice",
      "instructions": "このサポート依頼はどのチームが担当すべきですか? 顧客の主な依頼内容で判断してください。どの専門チームにも当てはまらない場合は other を選んでください。",
      "criteria": {
        "billing": "既存アカウントの請求、請求書、返金、支払い方法、支払いの失敗",
        "technical": "不具合、障害、エラーメッセージ、ログインの問題、連携エラー",
        "sales": "購入前の料金に関する質問、プランの比較、新規購入や見積もり",
        "other": "これら 3 チームの担当外。提携、取材、一般的なご意見など"
      }
    },
    "needs_details": {
      "type": "noul",
      "instructions": "サポート担当者が作業を始めるために必要な情報(どのアカウント、注文、製品、エラーか)がこの依頼に欠けていますか?",
      "criteria": {
        "true": "作業開始に必要な情報が少なくとも一つ欠けている",
        "false": "作業を始められる程度に対象が特定されている"
      }
    }
  }
}

4. 情報不足をはっきり扱う

needs-clarification の例 は、依頼に必要な情報が欠けているかを Noul で尋ねます。

{
  "model": "jev-1.13.0",
  "state": {
    "request": "それを別の宛先に送ってください。",
    "known_context": "文書も受取先のアドレスも指定されていません。"
  },
  "questions": {
    "decision": {
      "type": "noul",
      "instructions": "送るものと送信先の両方を特定するために、この依頼には追加の情報が必要ですか?",
      "criteria": {
        "true": "必要な情報が少なくとも一つ欠けている",
        "false": "送るものと送信先の両方が明示されている"
      }
    }
  }
}

Noul は、答えが「はい」である確率の推定値を 0 から 1 で返し、confidence は付きません。値が高いときは担当を推測させず、足りない点を顧客に具体的に尋ねます。確実に判定できることはコードで確認してください。たとえばフォームで注文番号やアカウントのメールアドレスが必須なら、モデルを呼ぶ前にその項目をコードで検査します。

5. しきい値と人による確認はコードで決める

// Node 18+ or any runtime with fetch. Example thresholds: calibrate them on your
// own labeled tickets; they are starting points, not measured values.
const ENDPOINT = 'https://api.typesafe.ai/v1/systemone';
const ROUTE_AT_CONFIDENCE = 0.8;
const ASK_AT_MISSING = 0.7;
const TEAMS = new Set(['billing', 'technical', 'sales']);

export async function classifyTicket(request, apiKey) {
  const response = await fetch(ENDPOINT, {
    method: 'POST',
    headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(request),
    signal: AbortSignal.timeout(20_000),
  });
  if (response.status === 429 || response.status === 529) {
    // Back off; honor retry-after when present. Do not retry in a tight loop.
    const error = new Error('typesafe_retry_later');
    error.retryAfter = response.headers.get('retry-after');
    throw error;
  }
  if (!response.ok) throw new Error(`typesafe_http_${response.status}`);
  return response.json();
}

export function decideRoute(result) {
  const team = result.answers.team;
  const missing = result.answers.needs_details.noul;
  if (missing >= ASK_AT_MISSING) return { action: 'ask_customer', reason: 'missing_details' };
  if (!TEAMS.has(team.choice)) return { action: 'human_triage', reason: 'no_specific_team' };
  if (team.confidence < ROUTE_AT_CONFIDENCE) {
    return { action: 'human_triage', reason: 'low_confidence', suggestion: team.choice };
  }
  // Log the versioned model that answered, so threshold changes stay traceable.
  return { action: 'route', queue: team.choice, confidence: team.confidence, model: result.model };
}

3 つのしきい値は出発点の例で、推奨値ではありません。TypeSafe は confidence を高・中・低の範囲に分け、リスクに応じてしきい値を変えることを勧めています。担当の振り分けを誤っても損失は限られますが、自動返金のように影響の大きい操作には、より厳しい条件が必要です。ラベル付きデータで調整し、判断ごとに result.model を記録してください。しきい値を調整したら、jev-1.13.0 のようにバージョンを固定します。jev-latest は新しいモデルに切り替わることがあります。

6. 信頼する前に、小さなラベル付きデータを固定する

先に期待する結果を書き、そのあとでリクエストを実行して比べます。次の表は合成した問い合わせと、例のルールに従った場合の期待値です。モデルの結果ではありません。

合成した問い合わせ期待する担当(例のルール)情報不足?
請求書 INV-2291 を返金してください。更新日の前に解約しました。billingいいえ
今朝のアップデート以降、エクスポートボタンが 500 エラーを返します。technicalいいえ
年間プランで 40 席を契約すると割引はありますか?salesいいえ
決済ページがタイムアウトしたのに、カードには請求されていました。billing(ルール:発生済みの請求は billing)はい:どの請求か
今のプランを年払いに変更できますか? 今日請求されますか?billing(ルール:既存顧客は billing)いいえ
雑誌の記事のため、チームに取材をお願いしたいです。otherいいえ
動きません。判定しない:先に確認はい
それを別の宛先に送ってください。判定しない:先に確認はい(needs-clarification の例)

各問い合わせについて、選ばれた担当、confidence、Noul の値、そしてコードが振り分けたか、顧客に確認したか、人に回したかを記録します。担当ごとに不一致を数えて読み返すと、たいていは境界の文があいまいか、コードで処理すべきルールが見つかります。実際に届く言語の問い合わせも必ず含めてください。TypeSafe のモデルページ(2026-09-25 確認)では、英語が主な学習言語であり、ほかの言語は自社のデータで試すよう案内されています。

この考え方を使うプロジェクト

これらは 2026-09-18 に各 README で出典を確認したものです。Jev Atlas では実行、性能測定、セキュリティ監査を行っていません。

参考資料

TypeSafe のページは 2026-09-25 に確認しました。モデル、制限、料金は変わる可能性があるため、導入前に公式情報を確認してください。

試してみる

実験室で support-routing を開く · needs-clarification を開く · 判断しやすい質問の書き方