概要 / architecture
設計パターン
Jev は、より大きなシステムの中で判断を担う部品です。「複雑な振る舞いを、離散的で原子的な判断の組み合わせとして考える」ことが、使いこなしの鍵になります。
まず全体像:ワークフロー設計の7ステップ
要約すると、「普通のソフトウェアのワークフローを作り、AI が必要な場所にだけ System One を差し込む」。
コードでできることはコードで
決定的な仕事は安くて確実なコードに。days_overdue > 30 にモデルは要らない。エージェントの while ループも避ける。
入力 state を絞る
今の質問に関係する文脈だけを入れる。注意散漫と文脈の劣化を防ぐ。
state に構造を使う
入れ子の JSON にし、質問からはバッククォートのパスで特定の値を指す。
質問を分解する
できるだけ明示的で、狭く、具体的で、原子的な質問に。最も重要なステップ。
質問にも構造を使う
複数種類のガイダンスが要るときは、密な散文にせず名前付きフィールドに分ける。
たくさん質問する
同じ state への独立した質問を1リクエストに。コストあたりの知性を最大化する方法。
コードで合成する
決定的なルールか重み付き和で。学習させたいなら、確率を古典的 ML モデルの特徴量に。
不確かさで分岐する
確信のある答えとない答えで別の行動を。不確かなケースは人か、より高価な推論モデルへ。
Pattern 1 · cost, speed
投機的ファンアウト
システムが必要とする質問を、使うか分からないものも含めて1回のリクエストに全部入れ、どれが関係あるかは後からコードで決めます。全質問が並列に評価されるので、質問を足しても通常レイテンシは増えません。
if category.choice == "bug_report":
if bug_severity.score > 1.5 and bug_repro.noul > 0.6:
escalate_to_engineering(ticket_id, severity="high")
else:
add_to_bug_backlog(ticket_id)
elif category.choice == "billing":
if refund.noul > 0.7:
route_to_billing_with_flag(ticket_id, refund_likely=True)
else:
route_to_billing(ticket_id)
elif category.choice == "feature_request":
log_feature_request(ticket_id)
# いら立ちはカテゴリに関係なく役に立つ
if frustration.score > 1.5:
flag_for_priority_response(ticket_id)
GDPR の Wikipedia 記事に対する13問の規制ブリーフィング。13問を1回にまとめると、13回の個別呼び出しに比べてコストは 11.5〜12.2倍、速度は 9.6〜10.0倍改善し、答えは変わらなかった(公式ドキュメント内で記載箇所により数値が異なる)。
Pattern 2 · reliability, safety
確信度ゲート付きルーティング
confidence を第2の判断軸として使います。答えは「何を」、confidence は「実行してよいか」。
| intent.choice ↓ / confidence → | 0.6 未満 | 0.6 〜 0.85 | 0.85 超 |
|---|---|---|---|
check_balance低リスク | 人に回す | 残高を表示(最悪でも残高が読み上げられるだけ) | |
approve_transfer高リスク | 人に回す | ユーザーに確認してから | 送金を承認 |
other | 人に回す | ||
Pattern 3 · cost, reliability, speed
コンポジット・スコアリング
複数の基準で項目をランク付けしたいとき、判断を独立した次元に分けて別々に採点し、コード側で持つ重みで合成します。例は、エンジニア職の履歴書スクリーニングです。
プリセットの重みは公式パターンの値。候補者4名のスコアは説明用の架空データです。右の数値は重みを合計1に正規化したもの。Jev を呼び直さずに、順位だけが変わる点に注目してください。
py = response.answers["python_depth"].score / 4 lead = response.answers["team_leadership"].score / 4 arch = response.answers["system_design"].score / 4 general = response.answers["generalist"].score / 4 # Senior IC ic_score = (0.40 * py) + (0.10 * lead) + (0.40 * arch) + (0.10 * general) # Engineering Manager em_score = (0.15 * py) + (0.40 * lead) + (0.20 * arch) + (0.25 * general)
得られるのは順位だけではありません。最終スコアがどう計算されたかが完全に見えることが本質です。上位の候補者が期待と違えば、プロンプトを書き直すのではなく重みを調整します。
重みやしきい値、表示フィルタを変えても、証拠(state)と質問の意味が変わらない限り、推論をやり直す必要はありません。一度採点した生の判断は再利用できるデータです。
Pattern 4 · cost, speed
インテント・ルーティング
すべてのリクエストに同じ種類のハンドラは要りません。Jev を手前に置く高速・安価な分類器として使い、高価なリソースは本当に必要なリクエストにだけ使います。
+ complexity(Score)
def route_ticket(ticket_id, response):
intent = response.answers["intent"]
complexity = response.answers["complexity"]
if intent.confidence < 0.5:
return route_to_human_agent(ticket_id)
if intent.choice == "order_status":
handle_order_status(ticket_id)
elif intent.choice == "product_question":
handle_with_llm(ticket_id, PRODUCT_SPECIALIST)
elif intent.choice == "return_exchange":
handle_with_llm(ticket_id, RETURNS_SPECIALIST)
elif intent.choice == "complaint":
low_confidence = complexity.confidence < 0.5
# complexity.score が高いほど「エスカレーションが必要」側
if complexity.score > 1 or low_confidence:
route_to_human_agent(ticket_id)
else:
handle_with_llm(ticket_id, COMPLAINT_RESOLUTION)
その他の型:分類だけで終わらせない
公式のエージェント用スキルは、アーキテクチャを考えるとき「分類器」以上の発想を持つよう勧めています。
生成せず、選択する
候補の値やテキスト範囲は正規表現などコードで見つけ、Jev には「意図された1つ」を選ばせ、コードがそれをコピー・正規化する。原文どおりの値が得られる。
ルーティングして、引数も埋める
リクエストからハンドラを選ぶだけでなく、その型付き引数も、分岐ごとの質問を先に投機的に聞いて埋める(関数呼び出しクックブック)。
証拠を探し、判定する
候補を検索で集め、クエリへの関連度を比べ、有用な文脈を選ぶ。再ランクや階層分類。
検証して、エスカレーションする
特定の主張やフィールドを、その証拠と突き合わせて点検。不確か・不合格のものは人か推論モデルへ(mini → verify → reasoning のカスケード)。
判断を再利用可能なデータに
次元ごとに一度採点しておき、重み・しきい値・ランキング・ビューはコードや UI 側で変える。ラベルがあれば古典的 ML の特徴量に。
変化する状態に応答する
目標と観測はコードが保持し、新しい判断が次の一手を導く。推論された状態と観測された事実は区別し、結果を適用する前に鮮度を確認する。