プリミティブ(質問)
プリミティブ(質問)
TypeSafe の三つの質問タイプ(Choice、Score、Noul)、それらが返す型付きの答え、その使い分け、複数を一度に尋ねる方法。
TypeSafe のプリミティブは、コード内で組み合わせる小さな型付きの部品です。それらは対になっています。質問が System One モデルに状態について下させる一つの判断を定義し、その答えが返ってくる型付きの値です。コード内で答えを組み合わせて意思決定を行います。質問タイプは三つあり、それぞれ異なる形の答えを返します。
| タイプ | 何に答えるか | 返る値 |
|---|---|---|
| Choice | これらの選択肢のどれ? | choice, probabilities, confidence |
| Score | どのレベル? | score, legend, probabilities, confidence |
| Noul | これは真? | noul (0 to 1) |
質問は一つでも、複数をまとめて送ることもできます。リクエスト内のすべての質問は同じ状態を見て、独立に評価され、自分で選んだ ID の下に型付きの答えを返します。
質問ごとに一つのひらめきの判断を求める
System One モデルは高速で焦点の絞られた判断のために作られています。適切なコンテキストがあれば知識のある人が一瞬で下せる判断を求めてください。「このメッセージは緊急性を伝えていますか?」は良い質問です。「このメッセージを分析し、最善の行動を判断してください」はそうではありません。それは遅い推論を必要とし、タスクを小さな質問に分解して答えをコードで組み合わせるべきだというサインです。
欲しい判断が複数の独立した要素に依存するなら、各要素について別々に尋ね、答えを自前のロジックで組み合わせます。「このスタートアップのピッチを評価して」ではなく、市場規模、技術的な実現可能性、差別化について尋ね、相対的な重要度に応じてコード内で重み付けします。優先順位が変わったら、プロンプトを書き直すのではなく重みの値を変えます。これをどう行うかは複数の質問をまとめて尋ねるで示します。
質問を定義する
すべての質問には ID、type、instructions があります。Choice と Score の質問は criteria も取ります。これは Choice 質問の選択肢、または Score のレベルを定義します。Noul 質問は criteria を、はい と いいえ が何を意味するかの任意の明確化として受け付けます。
- ID。自分で選ぶキーで、たとえば
refund_requestedです。応答内で答えを識別します。 type。choice、score、noulのいずれかです。instructions。状態について尋ねる質問です。評価ロジックはここに書きます。明確で具体的な質問として書くか、モデルに判断させる文として書きます。ほとんどの質問には文字列で十分です。オブジェクトや配列にもでき、その場合は質問を一つのフィールドに、それが参照するデータを他のフィールドに置きます。質問で構造を使うを参照してください。criteria。考えられる答えです。Choice 質問では選択肢のマップ、Score ではレベルの順序付きリスト、Noul では はい と いいえ の任意の説明です。各質問タイプのページでその形を説明しています。
この質問は、顧客が返金を求めたかどうかを尋ねます:
from typesafe_sdk import Noul
questions = {
"refund_requested": Noul(
instructions="Does the customer request a refund?",
),
}
質問タイプを選ぶ
必要な答えの形に合うタイプを選びます。
-
Choice は、答えが既知の選択肢集合のいずれかで、それらの間に順序がない場合に適します。チケットを部門にルーティングする、文書タイプを分類する、プログラミング言語を検出する、などです。選択肢の完全なリストを与え、リストがあらゆる入力をカバーしない可能性があるときは
otherやnone of the aboveの選択肢を加えます。 -
Score は、答えがスペクトル上にあり、そのスペクトル上の各点が何を意味するかを記述できる場合に適します。バグの重大度、顧客のいらだち、スキルレベルなどです。レベルは自分で定義し、モデルはその上のある位置を返します。
-
Noul は、確率そのものが有用な信号となる、明快な はい/いいえ の質問に適します。このメッセージに個人を特定できる情報が含まれるか、顧客は返金を求めているか、履歴書に分散システムの言及があるか。
二つのタイプがどちらも当てはまりそうなら、コードがそのまま行動できる答えの方を選んでください。refund、rebook、information の間の Choice は、そのまま三つのコード経路に対応します。顧客のいらだちの Score はしきい値に対応します。Noul は if に対応します。
何が返ってくるか
答えもまたプリミティブです。各質問タイプは、コードが比較・しきい値処理・並べ替え・さらなるロジックへの受け渡し・後続リクエストの状態への投入ができる型付きの値を返します(ある質問が別の質問に依存するとき参照)。
| タイプ | 答えのフィールド | 読み方 |
|---|---|---|
| Choice | choice, probabilities, confidence |
choice は選ばれた選択肢です。probabilities はすべての選択肢にわたる確率分布です。confidence はその分布がどれほど尖っているかを要約します。 |
| Score | score, legend, probabilities, confidence |
score はレベル上の位置で、二つのレベルの間に落ちることもあります。legend はレベルを番号で繰り返します。probabilities はレベルにわたる確率分布です。 |
| Noul | noul |
答えが はい である確率です。1 に近いほど強い はい、0 に近いほど強い いいえ、0.5 に近いほど不確かです。Noul には別個の confidence はありません。 |
これらの答えには、それらを組み合わせ可能にしている二つの性質があります:
- すべての答えは、与えた選択肢に制約されています。 モデルは選択肢やレベルにわたる確率分布を返し、それらの外の値を返すことはありません。コードが生成された文章から値を復元しなければならないことはありません。
- すべての答えは独立しています。 ある質問の答えが、別の質問の隠れたコンテキストになることはありません。他の質問の結果を変えずに質問を追加・削除できます。
信頼度は、confidence が probabilities からどう導かれるか、それをいつ自動で行動し、いつ人にエスカレーションするかの判断にどう使うかを説明しています。
特定のフィールドを参照する
評価される内容、すなわち状態は、会話、レコード、ポリシーといったいくつかの部分を持つ JSON オブジェクトであることがよくあります。質問がそれらの部分の一つについてであるときは、そのキーへのドットと添字のパスを、バッククォート込みで instructions に書いて名前を指定します。するとモデルは状態のどの部分を判断すべきかを知ります。
状態ページのサポート会話を例に取ります:
{
"ticket": {
"subject": "Duplicate charge",
"messages": [
{"from": "customer", "text": "I was charged twice for order A-104. Please refund the duplicate."},
{"from": "support", "text": "We are checking the charges."}
]
},
"order": {
"id": "A-104",
"charges": [
{"amount_usd": 49, "status": "captured"},
{"amount_usd": 49, "status": "captured"}
]
},
"refund_policy": "Duplicate charges are eligible for a refund."
}
次の二つの質問は、パスによって顧客のメッセージ、ポリシー、請求を指しています:
questions = {
"refund_requested": {
"type": "noul",
"instructions": "Does `ticket.messages[0].text` request a refund?",
},
"policy_supports_refund": {
"type": "noul",
"instructions": (
"Does `refund_policy` support the refund requested "
"in `ticket.messages[0].text`, given `order.charges`?"
),
},
}
明示的なパスは、構造化された状態のどの部分が各判断の材料になるべきかを明確にします。入力をどう構造化するかは状態を参照してください。
複数の質問をまとめて尋ねる
同じ状態を使うすべての質問を一つのリクエストで送ります。質問タイプは自由に混在させられます。System One モデルはリクエスト内のすべての質問を並列に評価します。質問を増やしても応答時間はほとんど変わらず、追加の質問のトークン分だけのコストで済み、それは安価です。必要かもしれない質問を尋ねることは、ほぼ無料です。
このリクエストは、顧客メッセージの分類、緊急性の確認、いらだちのスコアリングを一度に行います:
{
"state": "Our API integration started returning 500 errors on every request about 20 minutes ago, and we can't process any customer orders until this is fixed.",
"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"
}
},
"is_urgent": {
"type": "noul",
"instructions": "The message conveys urgency or time-sensitivity"
},
"frustration": {
"type": "score",
"instructions": "How frustrated the customer appears",
"criteria": [
"Calm, just stating facts",
"Frustrated but civil",
"Very angry, strong language"
]
}
}
}クライアント SDKは型付きの質問と答えを提供します。Python では、Choice、Noul、Score オブジェクトの questions 辞書を client.system_one(...) に渡します。このリクエストはチケットと返金ポリシーを一度送り、各質問について型付きの答えを得ます:
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
state = {
"ticket_message": "My flight was cancelled. Can I get a refund?",
"refund_policy": "Cancelled flights are eligible for a full refund.",
}
with TypeSafeClient() as client:
response = client.system_one(
state=state,
questions={
"refund_requested": Noul(
instructions="Does `ticket_message` request a refund?",
),
"request_type": Choice(
instructions="What is the main request in `ticket_message`?",
criteria={
"refund": "The customer wants money returned.",
"rebooking": "The customer wants a replacement flight.",
"information": "The customer is asking for information only.",
},
),
"frustration": Score(
instructions="How frustrated does the customer appear in `ticket_message`?",
criteria=[
"Calm and neutral.",
"Concerned but civil.",
"Very angry or using strong language.",
],
),
},
)
print(response.answers["refund_requested"].noul)
print(response.answers["request_type"].choice)
print(response.answers["frustration"].score)
あなたの言語でのインストールと使い方はクライアント SDKを参照してください。
投機的な質問をする
コードが必要とするかもしれないすべての質問を、答えがある入力の一部でしか意味を持たないものも含めて尋ね、どの答えを使うかはコードに決めさせます。チケットがバグ報告でないと分かったら、重大度の答えを無視します。これを私たちは投機的ファンアウトパターンと呼びます。並列質問クックブックでは、13 の質問を一つの呼び出しにまとめると、13 の個別呼び出しより 11.5 倍安く、9.6 倍速く、しかも答えは変わらないことを示しています。
複雑な判断を複数の質問に分割する
複数の事柄に依存する判断は、事柄ごとに一つの質問に分割するのが最善です。答えをコード内で組み合わせ、それぞれに相対的な重要度の重みを与えます。重みはあなたのものです。組み合わせた結果がチームの出す判断と合わないときは、コード内で重みを変えて再実行します。質問は一つのリクエスト内で並列に走るので、追加しても応答時間はほとんど変わりません。分割によるコストは、質問のトークンが少し増えるだけです。
たとえば、チケットの優先度は三つの Score 質問から組み立てられるかもしれません。バグがどれほど深刻か、顧客がどれほど不満か、報告がエンジニアにどれだけ材料を与えているか。Score ページでは、このリクエストと、答えを正規化して重み付けするコードを複雑な判断を複数の Score に分割するで順を追って説明しています。この手法は複合スコアリングパターンと呼ばれます。
ある質問が別の質問に依存するとき
同じリクエスト内の質問は独立です。ある答えが別の質問のコンテキストになることはありません。後続の判断が前の答えに依存するなら、コード内で二回目のリクエストを行います。依存が実在するのは、コードが最初の答えを得るまで二回目のリクエストを構築できないときだけです。つまり、状態のためのデータをさらに取得するためにその答えが必要な場合、状態が何で構成されるかを決めるために必要、または次の質問の選択肢を選ぶために必要、ということです。そうでなければ、質問をまとめて尋ね、答えをコードで組み合わせます。
二回のリクエストは例外であり、原則ではありません。二回目のリクエストの質問が元の状態に対して尋ねられたはずなら、それらを最初のリクエストで尋ね、コードに不要なものを無視させます。三つのクックブックが、本当の理由で二回目のリクエストを行っています。スキル提案は 182 のスキルを一度のリクエストでランキングし、次に上位三つの全文を取得して、そのより良い証拠に対して再び判断します。構造復元は各改行が文を分割したかを尋ね、その答えから行をブロックにまとめ、次にブロックを分類します。そのブロックは最初のリクエストが答えるまで存在しませんでした。階層分類は各 Choice の答えを使って、次のリクエストがどの選択肢を提示するかを決めます。
ワークフローを焦点の絞られた判断に分解する方法の指針はTypeSafe での構築方法を参照してください。
次のステップ
Choice
固定リストから一つの選択肢を選ぶ。
Score
状態を順序付きのレベルに沿って評価する。
Noul
ある命題が真である確率を得る。
これらのものがどうシステムアーキテクチャに組み上がるかを見るには、パターンへ進んでください。