4. 実物のリクエストとレスポンス
ここまでの話を、そのままの形で見てみましょう。POST https://api.typesafe.ai/v1/systemoneに、状況(state)と質問(questions)を送ります(APIキーは Authorization: Bearer … ヘッダーで渡します)。
送るもの(リクエスト)
{
"model": "jev-latest",
"state": {
"customer_message": "届いた冷蔵庫のドアが閉まりません。すぐに何とかしてください!",
"order": {
"item": "冷蔵庫",
"days_since_delivery": 3
},
"refund_policy": "到着後14日以内なら返品できます"
},
"questions": {
"category": {
"type": "choice",
"instructions": "`customer_message` は、どの種類の問い合わせか?",
"criteria": {
"repair": "壊れている・動かないので、修理や交換を求めている",
"return": "商品を返品して返金してほしい",
"other": "上のどれでもない"
}
},
"refundable": {
"type": "noul",
"instructions": "`order.days_since_delivery` と `refund_policy` から見て、この注文は返品できる期間内か?"
},
"urgency": {
"type": "score",
"instructions": "`customer_message` から読み取れる、顧客の急ぎ具合は?",
"criteria": [
"急いでいない",
"少し急いでいる",
"かなり急いでいる",
"今すぐ対応してほしい"
]
}
}
}stateは材料です。名前をつけた JSON で、お客さんの文章・注文・返品ルールを渡しています。questionsは質問の集まりです。category などの名前はコードが結果を受け取るための ID で、Jev には送られません。意味は instructionsに全部書きます。type が質問の種類です。choice は選択肢を criteriaに、score は段階の説明を配列で書きます。noul は instructionsだけで足ります。- 質問の中の
`order.days_since_delivery`のように、バッククォートで状況の場所を指しています。
返ってくるもの(レスポンス)
{
"model": "jev-1.13.0",
"answers": {
"category": {
"type": "choice",
"choice": "repair",
"confidence": 1.0,
"probabilities": {
"return": 0.0,
"other": 0.0,
"repair": 1.0
}
},
"refundable": {
"type": "noul",
"noul": 0.97
},
"urgency": {
"type": "score",
"score": 2.99,
"confidence": 0.99,
"legend": {
"0": "急いでいない",
"1": "少し急いでいる",
"2": "かなり急いでいる",
"3": "今すぐ対応してほしい"
},
"probabilities": {
"0": 0.0,
"1": 0.0,
"2": 0.0,
"3": 1.0
}
}
},
"usage": {
"input_tokens": 592,
"output_tokens": 71
}
}answers に、質問のID ごとの答えが入ります。3つの質問が、1回の呼び出しでまとめて返ってきました。- choice は
choice(選ばれたもの)と、選択肢ごとのprobabilities。noul は noul(当てはまる確率)だけ。 score は score(期待値)と、段階ごとの確率です。 confidenceは、確率がどれだけ1つに集中しているかを表します。「迷っているか」の目安にして、 自信が低いものだけ人に回す、といった使い方ができます。usage は使ったトークン数。料金の目安になります。
これは実際に送って返ってきた結果です。わかりやすい例だったので、確率が 0 か 1 に寄っています。迷う内容なら、確率がばらけます。
7. 5つのアプリで、どう使っている?
公式ドキュメントには、4つのパターンがあります。どのデモが、どのパターンを使っているかは、次のとおりです。
| パターン | ひとことで | 使っているデモ |
|---|
| Speculative Fan-Out | 使うか分からない質問も、1回でまとめて聞く | Car Picker(主)、問い合わせ振り分け、探してるものだけ表示、今夜なに作る?、ウケるかなパネル |
| Confidence-Gated Routing | 確信度で、実行 / 確認 / 人に回す を決める | 問い合わせ振り分け(主)、Car Picker、探してるものだけ表示(迷いの印) |
| Composite Scoring | 小さな判断を、コードの重みで合算する | Car Picker(主) |
| Intent Routing | 意図を分類して、処理先に振り分ける | 問い合わせ振り分け |
どのアプリも、同じ型で読めます。
やりたいこと → 渡す状況 → Jev に聞くこと → 流れ → コードがやること
使っているパターンSpeculative Fan-Out
やりたいこと「疲れた」「ご飯が進む和食がいい」といった一言から、今夜の献立を決めたい。
渡す状況(state)ユーザーの状況(自由入力)と、あなたのタスク(今夜の主菜を決める)。副菜を選ぶときは、選んだ主菜も加える。料理名は、料理ごとの質問のほうに入れる。
実際に Jev に送って、返ってきた答えの例です。1回のリクエストで、次の状況(state)に対して、3問をまとめて聞いています。
状況(state){
"ユーザーの状況": "疲れているので、ご飯が進む和食がいい",
"あなたのタスク": "今夜の夜ご飯の献立(主菜)を決める"
}聞いたことと、返ってきた答えnould…(サバの味噌煮)
今日の夜ご飯に、この料理はふさわしいか?
→ ふさわしい確率は 85%(1位)
nould…(親子丼)
今日の夜ご飯に、この料理はふさわしいか?
→ ふさわしい確率は 85%(2位)
nould…(ぶり大根)
今日の夜ご飯に、この料理はふさわしいか?
→ ふさわしい確率は 80%(12位)
アプリ全体では:主菜196品 × 1問 = 196問を、1リクエスト(約278ms、入力9,323トークン)。副菜・汁物も同じ形で、112問を1リクエスト
コードの仕事:「はい」の確率が高い順に並べるだけです。確信度(迷いのなさ)で選ぶと、「ふさわしくない」と自信満々に答えた料理が上に来てしまうので、順位には確率を使います。
- 自由入力 1文
- 料理ごとに1問(主菜196問)を、1リクエストに並べる
- 「ふさわしい」の確率
- 確率の高い順に並べる(副菜・汁物も同じ形で1リクエスト)
ポイント「探してるものだけ表示」と同じ形です。196品に1問ずつ聞いても1リクエストで、約0.3秒・入力約9,300トークンでした。順位は「はい」の確率で付けます。確信度(迷いのなさ)で選ぶと、「ふさわしくない」と自信満々に答えた料理が上に来てしまったので、確信度は順位には使いません。
コードがやること- 候補の料理の一覧を持つ(Jev に献立を考えさせない。決まった候補が、今夜にふさわしいかを聞く)
- 確率の高い順に並べ、1位の主菜に合わせて副菜・汁物をもう1回聞く
使っているパターンSpeculative Fan-Out
やりたいこと新規事業のアイデアに、いろんな立場の人がどのくらい興味を持つかを眺めたい。
渡す状況(state)新規事業のアイデア文。パネリスト(人物)の紹介は、質問のほうに入れる。
実際に Jev に送って、返ってきた答えの例です。1回のリクエストで、次の状況(state)に対して、2問をまとめて聞いています。
状況(state){
"新規事業のアイデア": "使わなくなった楽器を、近所の子どもに月額で貸し出すサービス"
}聞いたことと、返ってきた答えscorep001(1人目)
この人物は、このアイデアにどのくらい興味を持つ?
- 0 全く興味を示さず、自分には関係のないことだと考える3%
- 1 懐疑的で、うまくいかないだろうと考える57%
- 2 悪くはないと思うが、自分から積極的に関わろうとは思わない30%
- 3 関心を持ち、もっと詳しく知りたいと考える10%
- 4 強い興味を示し、自ら関わりたいと考える0%
→ 期待値は 1.47(0〜4)
noulp001__invest
この人物は、このアイデアに自分のお金を出す?
→ 当てはまる確率は 21%
アプリ全体では:パネリスト 100人 × 2問 = 200問
質問に、人物の名前・紹介・関心領域を入れています。同じ形の質問を100人分作って、200問をまとめて聞きます。
- アイデア 1文
- 100人 × 2問 = 200問
- 興味の度合いと確率
- 陣地に並べる
ポイント200問を、分けずに1回で投げます。Jev はまとめて並列に答えるので、1.5秒ほどで100人分が返ってきます。速さと並列性を見せるデモです。
コードがやること- パネリストの一覧を持つ
- 結果に合わせて、アバターを陣地に並べて動かす
⚠ 実在の人物がモデルでも、これは AI による推定です。本人の考えではありません。
使っているパターンSpeculative Fan-Out、Confidence-Gated Routing
やりたいことAmazon の検索結果には、探していない商品が混ざる。検索したものだけが出てほしい。
渡す状況(state)検索キーワードだけ。商品のタイトルは、商品ごとの質問のほうに入れる。
実際に Jev に送って、返ってきた答えの例です。1回のリクエストで、次の状況(state)に対して、3問をまとめて聞いています。
状況(state){
"search_query": "ipad pro スマートキーボード"
}聞いたことと、返ってきた答えchoicep0
この商品は、検索した人が探しているものと、どういう関係にある?
- 本命 探しているものそのもの。全条件を満たす44%
- 代わり 同じ種類だが、条件のどれかが違う56%
- おまけ アクセサリなど、一緒に使うもの0%
- 無関係 探しているものと関係がない0%
→ 選ばれたのは「代わり」(確信度 0.40、正解ラベルは「本命」)
choicep1
この商品は、検索した人が探しているものと、どういう関係にある?
- 本命 探しているものそのもの。全条件を満たす28%
- 代わり 同じ種類だが、条件のどれかが違う71%
- おまけ アクセサリなど、一緒に使うもの1%
- 無関係 探しているものと関係がない0%
→ 選ばれたのは「代わり」(確信度 0.61、正解ラベルは「代わり」)
choicep5
この商品は、検索した人が探しているものと、どういう関係にある?
- 本命 探しているものそのもの。全条件を満たす71%
- 代わり 同じ種類だが、条件のどれかが違う28%
- おまけ アクセサリなど、一緒に使うもの1%
- 無関係 探しているものと関係がない0%
→ 選ばれたのは「本命」(確信度 0.62、正解ラベルは「本命」)
アプリ全体では:16商品 × 1問 = 16問を、1リクエスト(約251ms)。全24キーワードでも24リクエスト
コードの仕事:本命と判定された商品を「探してるもの」として残し、それ以外には 🚫 を付けます。確信度が 0.6 未満の判定(上の例では p0 の 0.40)には「Jev が迷った」と印を付けます。0.6 未満の判定は正解率が約5割、それ以上は約8割でした。
- 検索キーワード 1つ
- 商品ごとに1問(16〜27問)を、1リクエストに並べる
- 確率と確信度
- 探してるもの(緑)と、探してないもの(🚫)。迷いは点線で表示
ポイント同じ検索キーワード(state)に対する質問を、商品ごとに1問ずつ、まとめて1回で聞きます。395商品でも24リクエストです(商品ごとに分けた場合は395回)。本命と判定された商品だけを「探してるもの」として残し、確信度が低い判定には「Jev が迷った」と印を付けます。
コードがやること- 商品のタイトルを質問に入れる、質問の組み立てと、受け取った確率の集計
- 「探してるもの」かどうかの判定と、確信度による「迷い」の印(しきい値はコード側の定数)
- 検索結果の取得(このデモでは、あらかじめ用意したデータ)
使っているパターンIntent Routing、Confidence-Gated Routing、Speculative Fan-Out
やりたいことお客さんの問い合わせを分類して、自動で対応するか、確認するか、人に回すかを決めたい。
渡す状況(state)問い合わせの文、お客さんの注文と会員プラン、返金のルール。質問は、パス(`customer.orders[0]` など)で指す。
実際に Jev に送って、返ってきた答えの例です。1回のリクエストで、次の状況(state)に対して、4問をまとめて聞いています。
状況(state){
"message": "イヤホンを返金してほしいです。あと、プレミアム会員も今月で解約したいです。",
"customer": {
"plan": "プレミアム会員(月額)",
"orders": [
{
"id": "A-1001",
"item": "ワイヤレスイヤホン",
"status": "配達済み",
"days_since_delivery": 6
},
{
"id": "A-1002",
"item": "モバイルバッテリー",
"status": "発送済み(まだ届いていない)",
"days_since_delivery": null
}
]
},
"refund_policy": "到着後14日以内なら返品・返金できます"
}聞いたことと、返ってきた答えchoiceintent
この顧客が、このメッセージで一番求めていること(主な用件)はどれか?(「その他」の逃げ道あり。選択肢を逆の並びにした intent_rev も同時に聞く)
- 注文状況 注文・配送・到着について具体的に尋ねている0%
- 返金 返品・返金・交換を具体的に求めている100%
- 解約 会員プランや定期サービスをやめたい0%
- 商品の質問 仕様・使い方などを質問している0%
- クレーム 不満を伝えているが、手続きは求めていない0%
- アカウント ログインできない・ロックされた0%
- その他 上のどれでもない・用件が読み取れない0%
→ 選ばれたのは「返金」(確信度 1.00。逆の並びも同じ答え)
scorefrustration
顧客の、サービスに対する不満・怒りの強さは?(3段階)
- 0 不満はない(普通の問い合わせ・依頼)94%
- 1 不満や困惑がある(丁寧な言葉づかいのまま)6%
- 2 強い怒り・非難(強い言葉、責める口調)0%
→ 期待値は 0.06(0〜2)、確信度 0.91
noulmultiple_requests
互いに異なる2つ以上の依頼(例: 返金と解約)を同時に求めている?
→ 当てはまる確率は 98%
noulrefund_in_policy
返金を求めている注文は、配達済みで、`customer.orders` の日数が `refund_policy` の期間内に収まっている?(返金の依頼のときだけ使う、先回りの質問)
→ 当てはまる確率は 96%
アプリ全体では:全9問を1リクエスト(下はその一部。約206ms、入力2129トークン)
コードの仕事:返金は危険度が高いので、自動で実行するには、意図の確信度 0.85 以上、かつ「期限内」の確率 0.85 以上が必要です。ここでは両方を満たしましたが、「複数の依頼」の確率が高い(98%)ので、自動実行はせず「確認する」に格下げします。注文状況の自動返信のような低リスクの処理は、0.6 以上で自動です。しきい値は画面で変えられて、変えても Jev は呼び直しません。
- 問い合わせ 1通
- 9問を一度に(意図、緊急度、不満、返金の期限内か、など)
- 確率と確信度
- 自動で実行 / 確認する / 人に回す
ポイント処理の危険度で、必要な確信度を変えます。注文状況の自動返信は 0.6 以上、返金と解約は 0.85 以上で自動です。中間は確認、低ければ人に回します。不審なメッセージと法的な脅しは、意図に関係なく人に回します。選択肢を逆の並びにした同じ質問で、順番の偏りも確かめます。
コードがやること- 意図に応じた処理先の選択と、危険度ごとのしきい値、確信度の「最も弱い環」の計算
- 返金期限の計算はしない。日数は state に入れ、ルールの文と照らし合わせるだけにする
- 実際の返金や解約は実行しない(このデモは、判定までを見せる)
使っているパターンSpeculative Fan-Out、Confidence-Gated Routing、Composite Scoring
やりたいこと「家族4人で乗れるセダン、赤、自動ブレーキ」のようなふわっとした希望から、車を選びたい。
渡す状況(state)ユーザーの要望文だけ。車の情報はカタログ側にあり、Jev には渡さない。
実際に Jev に送って、返ってきた答えの例です。1回のリクエストで、次の状況(state)に対して、5問をまとめて聞いています。
状況(state){
"request": "家族四人(小学生2人)で乗れるセダン、ボディカラーは赤で、自動ブレーキで止まるやつ"
}聞いたことと、返ってきた答えnoulbodyType_stated
この人は、車のボディタイプについて希望を述べている?(「言及があるか」を別の質問にしています)
→ 言及している確率は 98%
choicebodyType
この人が希望しているのは、どのボディタイプ?(「言及なし」の選択肢はありません)
- コンパクト 小さめで運転しやすいコンパクトカー・軽快な小型車0%
- セダン セダン(トランクのある4ドアの乗用車)100%
- ワゴン ステーションワゴン(乗用車の形のまま荷室が広い車)0%
- SUV SUV・クロスオーバー(車高が高くアウトドア向き)0%
- ミニバン ミニバン(スライドドアや3列シートのある背の高い車)0%
→ 選ばれたのは「セダン」
choicebodyType_reversed
同じ質問を、選択肢を逆の並びにして、もう一度聞く(順番の偏りの確認)
- ミニバン ミニバン(スライドドアや3列シートのある背の高い車)0%
- SUV SUV・クロスオーバー(車高が高くアウトドア向き)0%
- ワゴン ステーションワゴン(乗用車の形のまま荷室が広い車)0%
- セダン セダン(トランクのある4ドアの乗用車)100%
- コンパクト 小さめで運転しやすいコンパクトカー・軽快な小型車0%
→ 選ばれたのは「セダン」
scorebudget
月額の安さを、どのくらい重視している?(3段階)
- 0 価格や予算に触れていない、または価格より中身を重視している100%
- 1 予算は気にしている(「手頃な」「予算内で」「コスパ」など)0%
- 2 安さが最優先(「とにかく安く」「節約したい」「お金がない」など)0%
→ 期待値は 0(0〜2)
noulkidsOnBoard
小さな子ども(乳幼児・未就学児・小学生)が乗る?
→ 当てはまる確率は 95%
アプリ全体では:全30問を1リクエスト(下はその一部)
「言及があるか」(_stated)と「どの値か」を別の質問にしているので、要望に書かれていない項目を、Jev が無理に埋めません。コードは、言及の確率に応じてその項目の影響を弱めます。確信度が低い項目があれば、「ミニバン? SUV?」と聞き返し、Jev を呼び直さずに並べ直します。
- 要望 1文
- 30問を一度に
- 確率と確信度
- おすすめ順 + 迷った項目の聞き返し
ポイント「言及があるか」と「どの値か」を別の質問にします。書かれていない項目を、Jev が無理に埋めません。あとで使うかもしれない質問も最初にまとめて聞くので(投機的ファンアウト)、往復は1回です。確信度の低い項目は聞き返し、答えが決まったら Jev を呼び直さずに並べ直します。
コードがやること- 価格や装備などの事実は、カタログから取る(Jev に数字を作らせない)
- 言及の確率に応じて、項目の影響を弱める。決め手になった答えのうち、一番確信度が低いものを全体の確信度にする
- 車種が決まったら、聞いておいた答えのうち必要なものだけを使ってオプションを選ぶ。重みを変えるスライダーも、コードだけで並べ直す