AIハーネスエンジニアリングを実測する:JSON整形タスクで設定あり/なしを比較

リード

こんにちは、ぽまらのです。

今回は、AIの「ハーネスエンジニアリング」を、JSON整形タスクで実際に比較してみます。
テーマはシンプルで、同じタスクを「ハーネスなし」と「ハーネスあり」で実行すると、どれだけ差が出るかです。

この記事では、実験手順・プロンプト・評価基準を公開し、同じ条件で再現できる形にします。

herness sample

この記事でいう「ハーネス」とは

ここでいうハーネスは、次のような実行ガードのことです。

  • 出力形式を固定する(JSON schemaを定義)
  • バリデーションを通らない場合はリトライする
  • 必須キーや型をチェックする
  • 失敗理由をログに残す

要するに、AIの回答品質を「お願い」ではなく「検証可能な手順」で安定化させる仕組みです。


比較するタスク(JSON整形)

AIに、非構造テキストからJSONを生成してもらいます。

入力テキスト(固定)

注文ID: A-1042
顧客名: 田中 花子
商品: ワイヤレスマウス, USB-Cケーブル
合計金額: 4280円
配送希望日: 2026-05-30
支払い: クレジットカード
備考: 領収書希望

期待するJSON(キー定義)

  • order_id: string
  • customer_name: string
  • items: string[]
  • total_yen: number
  • delivery_date: string (YYYY-MM-DD)
  • payment_method: string
  • note: string

実験条件

条件A: ハーネスなし

  • 通常のプロンプトのみ
  • 出力の妥当性チェックなし
  • リトライなし

条件B: ハーネスあり

  • 下記 「実際に設定したハーネス」 の4点を適用
  • プロンプトに JSON schema を含める(後述「B. ハーネスありプロンプト」)
  • 出力後に schema で検証し、違反時は最大2回まで再実行
  • 最終出力のみ採用

実行回数

  • 各条件 3回(合計6回)

評価指標

  • 成功率(スキーマを満たした割合)
  • 平均実行時間
  • リトライ回数
  • フォーマット違反数

実際に設定したハーネス(条件B)

条件Bで使ったハーネスは、Cursor + Claude のチャット上 で次の4つをセットにしたものです。自動化スクリプトは使わず、プロンプト内の schema 定義 + 実行後の人手チェック + 必要なら再実行 という最小構成です。

#設定内容
1出力スキーマJSON Schema をプロンプトに明示(下記)
2バリデーション出力を schema と照合して合否判定
3リトライ失敗時は同じプロンプトで再実行(最大2回
4ログ成功/失敗・時間・リトライ回数・理由を表に記録

出力スキーマ(JSON Schema)

プロンプトにそのまま埋め込んだ schema です。additionalProperties: false により、日本語キー(注文ID など)は 不合格 になります。

{
  "type": "object",
  "required": ["order_id","customer_name","items","total_yen","delivery_date","payment_method","note"],
  "properties": {
    "order_id": {"type": "string"},
    "customer_name": {"type": "string"},
    "items": {"type": "array", "items": {"type": "string"}},
    "total_yen": {"type": "number"},
    "delivery_date": {"type": "string", "pattern": "^\\d{4}-\\d{2}-\\d{2}$"},
    "payment_method": {"type": "string"},
    "note": {"type": "string"}
  },
  "additionalProperties": false
}

バリデーション(合否判定ルール)

各 run の出力について、次をすべて満たせば 成功 としました。

  • ルートが JSON オブジェクトである(前後に説明文・Markdown がない)
  • required の7キーが すべて英字キー名 で存在する
  • items文字列の配列
  • total_yen数値(文字列 "4280" は不可)
  • delivery_dateYYYY-MM-DD 形式
  • schema にないキー(日本語キー等)が 含まれない

リトライ条件

  • 上記チェックで 1つでも不一致 → 同じプロンプトで再実行
  • 1 run あたり最大2回 まで(初回 + リトライ2回)
  • 最終的に schema を満たした出力だけを採用

※ 今回の3 run では、schema 付きプロンプトだけで初回成功したため、リトライは0回 でした。

ログの取り方

実行のたびに次を記録しました。

  • run 番号(1〜3)
  • 条件(ハーネスなし / あり)
  • 成功 or 失敗
  • 実行時間(ms・概算)
  • リトライ回数
  • メモ(キー名が日本語、型不一致 など)

実際に使ったプロンプト

条件Bで使ったハーネスは、Cursor + Claude のチャット上 で次の4つをセットにしたものです。自動化スクリプトは使わず、プロンプト内の schema 定義 + 実行後の人手チェック + 必要なら再実行 という最小構成です。

A. ハーネスなしプロンプト

次のテキストをJSONに整形してください。
必ずJSONだけを返してください。

注文ID: A-1042
顧客名: 田中 花子
商品: ワイヤレスマウス, USB-Cケーブル
合計金額: 4280円
配送希望日: 2026-05-30
支払い: クレジットカード
備考: 領収書希望

B. ハーネスありプロンプト

次のテキストを、以下のJSON schemaを満たすJSONとして返してください。
JSON以外の文字は出力しないでください。

Schema:
{
  "type": "object",
  "required": ["order_id","customer_name","items","total_yen","delivery_date","payment_method","note"],
  "properties": {
    "order_id": {"type":"string"},
    "customer_name": {"type":"string"},
    "items": {"type":"array","items":{"type":"string"}},
    "total_yen": {"type":"number"},
    "delivery_date": {"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},
    "payment_method": {"type":"string"},
    "note": {"type":"string"}
  },
  "additionalProperties": false
}

Input:
注文ID: A-1042
顧客名: 田中 花子
商品: ワイヤレスマウス, USB-Cケーブル
合計金額: 4280円
配送希望日: 2026-05-30
支払い: クレジットカード
備考: 領収書希望

代表出力

実行時の代表的な出力を、条件A/Bで1つずつ載せます。

A. ハーネスなしの代表出力(失敗例)

{
  "注文ID": "A-1042",
  "顧客名": "田中 花子",
  "商品": ["ワイヤレスマウス", "USB-Cケーブル"],
  "合計金額": 4280,
  "配送希望日": "2026-05-30",
  "支払い": "クレジットカード",
  "備考": "領収書希望"
}

JSONとしては妥当ですが、今回の要件(order_id など英字キー)に合わないため失敗判定です。

B. ハーネスありの代表出力(成功例)

{
  "order_id": "A-1042",
  "customer_name": "田中 花子",
  "items": ["ワイヤレスマウス", "USB-Cケーブル"],
  "total_yen": 4280,
  "delivery_date": "2026-05-30",
  "payment_method": "クレジットカード",
  "note": "領収書希望"
}

必須キー・型・日付フォーマットがschemaに一致しており、成功判定です。


実行ログ

以下に、実行時の結果をそのまま記録します。

run条件成功/失敗実行時間(ms)リトライ回数メモ
1ハーネスなし失敗40000JSONとしては妥当だがキー名が日本語(schema不一致)
2ハーネスなし失敗30000同上。order_id など必須キーを満たさない
3ハーネスなし失敗30000同上。出力は安定だが要求仕様は未達
1ハーネスあり成功20000schemaどおりのキー・型で出力
2ハーネスあり成功40000schemaどおり。1行圧縮形式でも問題なし
3ハーネスあり成功30000schemaどおり。再現性あり

集計結果

指標ハーネスなしハーネスあり差分
成功率0% (0/3)100% (3/3)+100pt
平均実行時間3,333ms3,000ms-333ms
リトライ回数00±0
フォーマット違反数30-3

所感

今回の結果では、最も差が出たのは 仕様準拠率 でした。ハーネスなしは3回とも日本語キーで返ってきて、JSONとしては正しくても、今回のschema要件では全失敗になりました。一方でハーネスありは3回とも成功し、期待したキー・型で揃いました。

良かった点は次の3つです。

  • 成功率の安定: 0% → 100% になり、運用判断がしやすい
  • 検証可能性: 「なんとなく正しい」ではなく、schemaで合否判定できる
  • 再現性: 出力フォーマットがぶれず、後段処理に渡しやすい

微妙だった点(注意点)もあります。

  • 今回は入力が単純で、実行時間の差は小さい(-333ms)
  • モデルが賢いほど「それっぽいJSON」を返してくるため、ハーネスなしでも一見うまく見える
  • 実運用では、フォーマット以外(欠損値、業務ルール違反)も別途チェックが必要

結論として、ハーネスは「精度を魔法のように上げる」より、失敗を見える化して、運用可能な形に揃えるための仕組み だと感じました。


まとめ

同じJSON整形タスクでも、ハーネスの有無で安定性は変わります。
「たまたまうまくいく」状態から、「検証して運用できる」状態に寄せるのが、ハーネスエンジニアリングの価値だと感じました。

次は、JSON整形以外のタスク(コード修正や要件付き要約)でも同じ比較を試してみる予定です。


コメント