Jev Recipe / コンプライアンス基盤

Jev で監査証跡を構築:すべての判断を記録・再生・説明できる形に

自動判断をコンプライアンス等級の証拠に変える:Jev の evaluate 呼び出しは毎回、較正済み信頼度付きの型付き回答を返すため、監査ログには契約・回答・ゲートを同時に記録できます——保存コストは一定、再生は決定論的、GDPR 第 22 条への回答も明示的。

判断監査証跡を構築する 6 ステップ

01回答ではなく契約を記録する。説明できない判断は負債です。すべてのレコードに、回答と並んでスキーマバージョン・questions オブジェクトのハッシュ・モデルバージョンを持たせます。questions オブジェクトは機械可読な判断ロジックそのもの(選択肢の criteria 込み)で、監査人やデータ主体が「なぜ」と問うたときに求められるものです。スキーマバージョンごとに 1 保存し残は参照でよいため、100 万件の判断も 1 件と同じ保存コストです。
02型付き回答を信頼度ごと保存する。回答は「何を選んだか」、較正済み信頼度は「その選択がどれだけ信頼に値するか」を示します。Jev の信頼度は RLCD 較正済みで、ログ上の 0.85 は 85% 精度の契約として振る舞います——規制当局や利用者が後日「この種の判断が正しかった頻度」を尋ねても、数字は意味を保ちます。Choice 質問では選択肢分布も保存します。落選した選択肢こそ、開発時に誰も思い付かなかった説明です。
032 軸でゲートする:信頼度 × 可逆性。返金承認の 0.97 と与信枠引き上げの 0.97 は別の判断です。前者はワンクリックで取消せるが、後者は人の財務的足跡を変えます。信頼度がゲートを超え「かつ」可逆性が低い場合のみ自動実行し、中間帯はレビューキューへ、可逆性が高い場合は高信頼度でも人間のサインオフを強制します。2 軸ルールは数行のコードですが、それが「ゲート」と「ゴム印」の違いです。
04重要な自動判断には第 22 条レベルのレコードを書く。GDPR 第 22 条は、法的効果または同様に重大な影響を及ぼす完全自動判断について、それを受けない権利や論理の説明を得る権利を保障します。それに応えるレコードは:主体参照、信頼度付きの判断、ロジックブロック(スキーマバージョン・questions ハッシュ・適用中のゲートしきい値)、人間の介入経路、保持期間。個々の判断が「重大」に当たるかは法務判断であり、ログの役割はどちらの答えも証明可能にすることです。
05マイグレーションではなくリプレイ。state と questions の両方が保存されているため、スキーマ更新後は全過去ケースを新契約で再判定できます——決定論的、ケースあたり 1 回の順伝播。リプレイは 1 つで 3 役です:移行チェック(新しいスキーマはどのレーンを変えたか?)、回帰スイート(ログ state はラベル付きデータセット)、説明エンジン(この判断は当時のルールで何と言ったか)。
06正確度だけでなく信頼度分布を監視する。自動実行比率・レビュー率・境界帯の流量を追跡します。較正は静かに劣化します——第三者監査は、実際にはずっと多く外れる回答に 30% 超の信頼度を報告する判断モデルをすでに捕捉しています——そして最初の症状は自分の分布の動きです。レビュー率の上昇はバグではなく、センサーが働いている証拠です。信頼度ゲート付きフォールバックチェーンがライブトラフィックに適用するのと同じドリフト規律を、ここでは履歴に適用します。
schema / 判断・可逆性・人間確認の契約
{
  "decision": {
    "type": "choice",
    "instructions": "公開ポリシーに基づきケースを裁定する",
    "criteria": {
      "approve": "ポリシー条件をすべて満たす——裁量の余地なし",
      "refer": "大半の条件を満たすが明示されたエッジケースに該当——理由を付してキューへ",
      "deny": "ハード条件を満たさない——該当条件を明示して拒否"
    }
  },
  "reversibility": {
    "type": "score",
    "instructions": "この判断が誤りだった場合、取下げのコストは?1(簡単に取消し可能、例:返金)から 4(人への不可逆的な害、例:信用機関に報告されるアカウント閉鎖)"
  },
  "needs_human_review": {
    "type": "noul",
    "instructions": "このケースと信頼度を踏まえ、発効前に人間の確認が必要か?"
  }
}
実際のケースを State として送ると、decision・reversibility・needs_human_review の較正済み信頼度を確認できます。

6 つの判断、1 つの監査ログ

以下の各判断はすでに evaluate エンドポイントを通過済みです。2 つのゲート(自動実行の信頼度しきい値と人手引き継ぎしきい値)を動かし、レーンの再計算を確認してください。高い信頼度だけでは不十分です。与信枠の判断は信頼度 0.93 でもレビューに回ります。可逆性が第 2 の軸だからです。

自動実行 · 2レビュー · 2人手判断 · 2
判断回答と信頼度可逆性レーン

返金自動承認 · チケット #4812

dec_8f21 · audit-contract@1.3.0 · jev-1.13 · 96ms

承認0.97可逆 1/4自動実行

コンテンツ公開ゲート · 下書き #2214

dec_8f22 · audit-contract@1.3.0 · jev-1.13 · 88ms

ブロック0.88可逆 2/4自動実行

与信枠引き上げ · 顧客 #7741

dec_8f23 · audit-contract@1.3.0 · jev-1.13 · 102ms

引継ぎ0.93可逆 3/4Art. 22 記録レビュー

オファー配信 · 顧客 #2298

dec_8f24 · audit-contract@1.3.0 · jev-1.13 · 91ms

通常0.71可逆 1/4レビュー

チケット エスカレーション · #5190

dec_8f25 · audit-contract@1.3.0 · jev-1.13 · 84ms

false0.55可逆 2/4人手判断

アカウント凍結 · 顧客 #3306

dec_8f26 · audit-contract@1.3.0 · jev-1.13 · 99ms

凍結0.78可逆 4/4Art. 22 記録人手判断

デモデータのみ——6 件の模擬判断。レーンはレシピ本文と同じ 2 軸ルールで再計算されます。

判断監査の証拠:Jev 型付きログ vs 生成チャットログ vs ログなし

METRIC
Jev
チャットログ / ルール監査
ログに含まれるもの
型付き回答 + 較正済み信頼度 + スキーマバージョン + questions ハッシュ——固定長レコードで、永続保存も低コスト
自由テキストの段落(または信頼度なしの解析済み JSON);生成時のプロンプトバージョンは通常不明
判断の説明
criteria ブロックがそのまま説明——監査人は選択肢定義と選択肢分布を読むだけ
生成テキストへの事後的な正当化;同じ質問を 2 回すれば説明も変わる
証拠としての信頼度
RLCD 較正済み——ログ上の 0.85 は 85% 精度の契約として振る舞い、ゲートの挙動をログだけで証明可能
自己申告かつ未較正——独立監査は、実際にはずっと多く外れる回答に 30% 超の信頼度を報告する判断モデルを捕捉済み;ルールには信頼度がそもそもない
更新後のリプレイ
ログ state + バージョン化 questions で決定論的に再判定——全過去ケースが回帰テストとして再実行可能
プロンプトはドリフトし、モデルは非推奨化する——元の判断は再現できず、変更はブラインドで出荷される
ドリフト検知
信頼度分布・レビュー率・境界帯トラフィックは測定可能な時系列——較正劣化には初期症状がある
テキスト出力に相当する信号はなく、ドリフトは苦情や事故で表面化
人間引き継ぎの証拠
エスカレーションレーン・適用中のしきい値・レビュアーの操作が同じレコードに住む
承認はチケットやチャットに散らばり、発端となった判断と紐づかない

実装コード:TypeScript / Python の監査パイプライン

python / ベースライン:説明できないチャットログ
import logging
import os

import requests

logger = logging.getLogger("decisions")

def decide_with_chat_model(customer_id: str, case: dict) -> str:
    resp = requests.post(
        "https://api.openai.com/v1/chat/completions",
        headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"},
        json={
            "model": "gpt-4o-mini",
            "messages": [{
                "role": "user",
                "content": f"ポリシー v3 で裁定し、判断と根拠を返してください。\nCase: {case}",
            }],
        },
        timeout=30,
    )
    decision_text = resp.json()["choices"][0]["message"]["content"]

    # 監査ログが得るのは段落。しきい値設定もリプレイも説明もできず、
    # 再読できるだけ。この呼び出しはどのプロンプトバージョンで作られたか?
    # 「おそらく承認」は信頼度 0.8 のことだったのか?ログには答えられない。
    logger.info("decision for %s: %s", customer_id, decision_text)
    return decision_text
python / jev:1 回の evaluate 呼び出し、1 件の監査レコード
import hashlib
import json

import requests

JEV_ENDPOINT = "https://api.typesafe.ai/v1/jev/evaluate"
AUTO_EXECUTE_CONFIDENCE = 0.85  # ゲート超過 かつ 可逆性 <= 2 -> 自動実行
HUMAN_CONFIDENCE = 0.60         # 未満、または可逆性 4 -> 人手

QUESTIONS = {
    "decision": {
        "type": "choice",
        "instructions": "公開ポリシーに基づきケースを裁定する",
        "criteria": {
            "approve": "ポリシー条件をすべて満たす",
            "refer": "明示されたエッジケースに該当",
            "deny": "ハード条件を満たさない——該当条件を明示",
        },
    },
    "reversibility": {
        "type": "score",
        "instructions": "誤りだった場合の取下げコスト?1 = 簡単、4 = 人への不可逆的な害",
    },
    "needs_human_review": {
        "type": "noul",
        "instructions": "発効前に人間の確認が必要か?",
    },
}

def decide_and_record(subject_ref: str, state: dict) -> dict:
    payload = {"state": state, "questions": QUESTIONS}
    resp = requests.post(JEV_ENDPOINT, json=payload, timeout=5)
    resp.raise_for_status()
    data = resp.json()

    decision = data["decision"]
    reversibility = data["reversibility"]["answer"]
    if data["needs_human_review"]["answer"] or reversibility == 4:
        lane = "human_decision"
    elif decision["confidence"] >= AUTO_EXECUTE_CONFIDENCE and reversibility <= 2:
        lane = "auto_executed"
    else:
        lane = "review_queue"

    # レコードが監査証跡:契約・回答・ゲート——1 行の固定長レコードで、
    # 任意の将来スキーマバージョンでリプレイ可能。
    return {
        "subject_ref": subject_ref,
        "decision": decision["answer"],
        "confidence": decision["confidence"],
        "reversibility": reversibility,
        "lane": lane,
        "logic": {
            "schema_version": "audit-contract@1.3.0",
            "questions_hash": hashlib.sha256(
                json.dumps(payload["questions"], sort_keys=True).encode()
            ).hexdigest()[:16],
            "model_version": "jev-1.13",
        },
        "human_intervention_path": (
            "available_on_request"
            if lane == "auto_executed"
            else "mandatory_before_effect"
        ),
    }
typescript / ベースライン:構造化出力、非構造化の証拠
import { z } from "zod";
import OpenAI from "openai";

const Decision = z.object({ decision: z.enum(["approve", "refer", "deny"]) });
const openai = new OpenAI();

export async function decideCase(caseData: unknown) {
  const resp = await openai.chat.completions.create({
    model: "gpt-4o-mini",
    response_format: { type: "json_object" },
    messages: [
      { role: "user", content: `ポリシー v3 で裁定: ${JSON.stringify(caseData)}` },
    ],
  });
  const { decision } = Decision.parse(
    JSON.parse(resp.choices[0].message.content!),
  );

  // 形状は保証されるが、証拠はそうではない。信頼度なし・スキーマバージョンなし・
  // 分布なし——6 か月後の監査が得られるのは「何」だけで、「なぜ」と
  // 「どのくらい正しかったか」は永遠に得られない。
  return { decision, auditRecord: { decision } };
}
typescript / jev:2 軸ゲート、終端まで型付き
const JEV_ENDPOINT = "https://api.typesafe.ai/v1/jev/evaluate";
const AUTO_EXECUTE_CONFIDENCE = 0.85; // ゲート超過 かつ 可逆性 <= 2
const HUMAN_CONFIDENCE = 0.6; // 未満、または可逆性 4 -> 人手

type Lane = "auto_executed" | "review_queue" | "human_decision";

const QUESTIONS = {
  decision: {
    type: "choice",
    instructions: "公開ポリシーに基づきケースを裁定する",
    criteria: {
      approve: "ポリシー条件をすべて満たす",
      refer: "エッジケースに該当——理由を付してキューへ",
      deny: "ハード条件を満たさない——該当条件を明示",
    },
  },
  reversibility: {
    type: "score",
    instructions: "誤りだった場合の取下げコスト?1 = 簡単、4 = 不可逆的な害",
  },
  needs_human_review: {
    type: "noul",
    instructions: "発効前に人間の確認が必要か?",
  },
} as const;

export async function decideAndRecord(subjectRef: string, state: object) {
  const resp = await fetch(JEV_ENDPOINT, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ state, questions: QUESTIONS }),
  });
  if (!resp.ok) throw new Error("Jev evaluate failed");
  const data = await resp.json();

  const { answer, confidence } = data.decision as {
    answer: string;
    confidence: number;
  };
  const reversibility = data.reversibility.answer as number;
  const lane: Lane =
    data.needs_human_review.answer || reversibility === 4
      ? "human_decision"
      : confidence >= AUTO_EXECUTE_CONFIDENCE && reversibility <= 2
        ? "auto_executed"
        : "review_queue";

  return {
    subject_ref: subjectRef,
    decision: answer,
    confidence,
    reversibility,
    lane,
    logic: { schema_version: "audit-contract@1.3.0", model_version: "jev-1.13" },
    human_intervention_path:
      lane === "auto_executed" ? "available_on_request" : "mandatory_before_effect",
  };
}
// 第 22 条レコード = このオブジェクト。リプレイ = 保存 state を新しい
// スキーマバージョンで再送し、レーンを差分。

判断監査証跡 FAQ

判断監査証跡とは何ですか?

システムが行うすべての自動判断の、タイムスタンプ付きで照会可能な記録です:何が決定されたか、どの信頼度で、どのスキーマとモデルバージョンの下で、どのゲートを経由し、人間の介入経路は何か。Jev ではこの記録は evaluate レスポンスからほぼ無料で手に入ります——型付き回答・較正済み信頼度・選択肢分布はすでに構造化されているため、ログは段落ではなく固定長の行になります。

GDPR 第 22 条はこれを要求しますか?

第 22 条は、法的効果または同様に重大な影響を及ぼす完全自動判断について、それを受けない権利や(例外適用時に)論理に関する有意義な情報を得る権利を個人に与えます。個々の判断がこれに該当するかは、ログライブラリではなくチームの法的判断です。このレシピが提供するのは証拠レイヤーです:ある判断を重大と扱うなら第 22 条レコード(主体・判断・信頼度・ロジックバージョン・人間の介入経路・保持)は 1 オブジェクトですし、重大でないと判断するなら、その判断を一貫して防御するのがログなのです。

1 件の判断レコードには何を含めるべきですか?

6 フィールドです:主体参照(可能なら仮名化)、信頼度付きの判断、ロジックブロック(スキーマバージョン・questions ハッシュ・モデルバージョン・適用中のゲートしきい値)、Choice 質問の選択肢分布、ゲートが割り当てたレーン、人間の介入経路(介入があればレビュアーの操作も)。主体とレビュアーの操作を除くすべてが、1 回の evaluate レスポンスから来ます。

通常のアプリケーションログとの違いは?

アプリログは「コードが何をしたか」に答え、監査証跡は「システムが何を判断し、どれだけ確信し、どのルールの下でか」に答えます。違いは構造です:型付き判断レコードはしきい値集計(信頼度 0.9 未満の自動実行は何件?)、リプレイ(新しいスキーマなら何と判断する?)、集計(信頼度分布はドリフトしているか?)ができます——自由テキストのログ行ではどれもできません。

スキーマ更新後に過去ケースを再判定できますか?

はい、それがリプレイで、決定論的です。state とバージョン化 questions の両方が保存されているため、契約の更新はログ済みの全 state を新しいスキーマに再送信しレーンを差分することです。チームはリプレイを移行チェック(更新は自動実行判断を変えたか?)、回帰スイート(ログ state は履歴ラベル付きデータ)、説明エンジン(当時のルールは今日何と言うか)として使います。

なぜ較正済み信頼度が監査に重要なのですか?

信頼度の数字は、現実と追従してこそ証拠だからです。Jev の信頼度は RLCD 較正済みで、ログ上の 0.85 ゲートは測定可能な精度契約に対応します——自分のログから、0.85 の判断がどのくらい正しかったかを計算できます。未較正の自己申告信頼度はこれを支えられません:独立監査は、実際にはずっと多く外れる回答に 30% 超の信頼度を報告する判断モデルを発見しており、それはすべてのしきい値を飾りにします。較正があるからこそドリフトも可視化されます——分布が動けば、レビュー率が利用者より先に知らせます。

コンプライアンスとゲート運用を広げる