エージェント基盤・プロトコル

Pydantic AIとは|JSONとして読めた8件のうち、6件は中身が壊れていた

Pydantic AIとは何をする枠組みなのか検証しないと何が起きるのか再実行はどこまで挟むべきか

AIに決まった形で返させても、読めるかどうかと、中身が正しいかどうかは別です。JSONとして成立していても、金額が負だったりします。

応答10件に検証を当てたところ、JSONとして読めたのは8件でした。ところがそのうち6件は中身が壊れています

この記事の要点

  • Pydantic AIは出力を型で検証してから受け取る枠組み
  • JSONとして読めた8件のうち、検証を通ったのは2件
  • 再実行を1回挟むと通る割合は20.2%から68.2%
  • 3回まで挟めば95.2%だが、呼び出しは平均2.24回

JSONとして読めた8件のうち、6件は中身が壊れていた

応答10件に検証を実際に当てました。JSONとして読めたのは8件で、そのうち検証を通ったのは2件です。

Pydantic AIが前提にしている「型で検証してから受け取る」という形が、どれだけ効くのかを実際に確かめました。用意したのは氏名と金額と日付を返させたときの応答10件です。

検証は本当に実行しています。応答も検証の条件もコードに書いてあり、通ったかどうかを機械で判定しました。

javascript
function validate(raw) {
  let o;
  try { o = JSON.parse(raw); } catch { return { ok: false, why: 'JSONとして読めない' }; }
  if (typeof o.name !== 'string' || o.name.length === 0) return { ok: false, why: '氏名が空か文字列でない' };
  if (typeof o.amount !== 'number') return { ok: false, why: '金額が数値でない' };
  if (!Number.isInteger(o.amount) || o.amount <= 0) return { ok: false, why: '金額が正の整数でない' };
  if (typeof o.date !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(o.date)) return { ok: false, why: '日付の形式が違う' };
  // 存在しない日付を弾く
  const [y, m, d] = o.date.split('-').map(Number);
  const dt = new Date(Date.UTC(y, m - 1, d));
  if (dt.getUTCFullYear() !== y || dt.getUTCMonth() + 1 !== m || dt.getUTCDate() !== d) {
    return { ok: false, why: '存在しない日付' };
  }
  return { ok: true, value: o };
}
text
応答(先頭40文字)                          検証
{"name":"佐藤","amount":12000,"date":"20…     通る
{"name":"佐藤","amount":"12000","date":"…     弾く: 金額が数値でない
{"name":"佐藤","amount":12000,"date":"20…     弾く: 日付の形式が違う
{"name":"","amount":12000,"date":"2026…     弾く: 氏名が空か文字列でない
{"name":"佐藤","amount":-500,"date":"202…     弾く: 金額が正の整数でない
{"name":"佐藤","amount":12000}                弾く: 日付の形式が違う
{"name":"佐藤","amount":12000,"date":"20…     弾く: JSONとして読めない
はい、こちらが結果です。{"name":"佐藤","amount":1200…     弾く: JSONとして読めない
{"name":"佐藤","amount":12000,"date":"20…     弾く: 存在しない日付
{"name":"佐藤","amount":1.2e4,"date":"20…     通る

検証を通った: 2 / 10
検証で弾いた: 8 / 10

検証しない場合、そのまま次の処理に流れる件数
  JSONとして読めた件数: 8 / 10
  そのうち中身が壊れているもの: 6件

ここが要点です。JSONとして読めた8件のうち、6件は中身が壊れています。読めることは、正しいことを保証しません。

読める壊れ方が厄介

読めなかった2件は、その場で例外になります。ですから気づけます。

困るのは残りです。amount-500 でも、date2026-13-45 でも、JSONとしては成立します。検証しなければ、そのまま次の処理に流れます

通ってしまう書き方もある

面白かったのが最後の1件です。1.2e4 という指数表記が通りました。読み込むと12000という整数になるためで、検証としては正しい判定です。

見た目は違っても値は同じなので、通ってよい例になります。逆に言えば、見た目を見ているのか値を見ているのかを、検証の条件で決めているということです。

読めることと正しいことは別。差の6件が黙って流れる。

JSONとして読めるか読める8読めない210件検証を通るか2810件−0%(0件)応答10件に実際に検証を当てた結果。読めた8件のうち6件は中身が壊れていた。
図1 ── 応答10件の内訳
出典pydantic/pydantic-ai README2026-08-18 確認
Pydantic AI is the Python AI SDK: a typed, extensible agent loop with every model a string swap away.
原文pydantic/pydantic-ai README この内容の有効期限2027-02-18

Pydantic AIとは何をする枠組みなのか

返ってくる形を型として宣言し、検証を通ったものだけを受け取ります。型がそのまま検証の条件になります。

Pydantic AIは、返ってくる形を型として書いておき、その型に合うものだけを受け取る枠組みです。READMEでは、型のついた、拡張できるエージェントの繰り返しだと説明されています。

型が検証の条件になる

特徴は、検証の条件を別に書かなくてよい点です。型を書けば、その型に合うかどうかが自動で確かめられます。

前の節では検証を手で書きましたが、あの条件のうち型と必須の部分は、型の宣言から出てきます。範囲や実在の確認だけを足す形になります。

扱う範囲

READMEでは、型のついた単純なデータの取り出しから、長く動く複数エージェントの協働までを対象に挙げています。取り出しだけの用途でも使える、という位置づけです。

返す形を宣言する考え方そのものはFunction callingの記事で扱っています。Pydantic AIは、そこに検証と再実行まで含めた形になります。

モデルの差し替え

同じREADMEでは、モデルを文字列の入れ替えで差し替えられるとも書かれています。共通の口をはさむ考え方はLangChainの記事でも扱っており、そちらでは1社増やすときの変更が5か所から1か所になりました。

余談 検証の条件は仕様書になる

使ってみて感じたのは、検証の条件を書く作業が、そのまま仕様を決める作業になることでした。金額は正の整数か、0を許すか。日付は実在を確かめるか。曖昧なまま進めていた部分が、型を書く段階で全部表に出てきます。

出典pydantic/pydantic-ai README2026-08-18 確認
What are you building? From simple typed data extraction to complex, long-running multi-agent collaboration, Pydantic AI and Pydantic AI Harness have got you covered.
原文pydantic/pydantic-ai README この内容の有効期限2027-02-18

弾いたあとの再実行をどこまで挟むか

1回挟むだけで通る割合は3倍以上になります。ただし回数を増やすほど伸びは鈍り、呼び出しは増えます。

Pydantic AIのような検証を入れると、次に決めるのが弾いたあとどうするかです。何が悪かったかを伝えて再実行させるのが一般的な形になります。

どこまで挟む価値があるのかを、10,000回の試行で確かめました。「弾いて指摘して再実行すると1回あたり60%で直る」という前提は置いた値です。

text
再実行の上限   最終的に通る割合   呼び出し回数の平均
       0回           20.2%              1.00回
       1回           68.2%              1.80回
       2回           87.0%              2.12回
       3回           95.2%              2.24回

1回挟むだけで効きます。20.2%が68.2%ですから、3倍以上です。

伸びは早く鈍る

2回目以降は伸びが落ちます。68.2%から87.0%、そこから95.2%。上限を1回から2回に増やすより、0回から1回にするほうがはるかに効きます

呼び出し回数のほうは1.80回から2.24回で、あまり増えません。1回目で通った分は再実行しないためです。

上限を決めておく

  1. 再実行の上限を決める。2回か3回が目安
  2. 超えた場合の行き先を決める。人に回すか、保留にする
  3. どの条件で落ちたかを記録する。偏りが見つかる
  4. 上限を決めずに繰り返す。止まらなくなる

3番目が改善につながります。同じ条件でばかり落ちているなら、指示のほうを直すほうが速いためです。依頼文を詰める作業はプロンプト設計の記事で扱っています。

0回から1回への1歩がいちばん効く。そこから先は鈍る。

最終的に通る割合(%)95.200回1回2回3回再実行の上限10,000回の試行。1回あたり60%で直るという前提を置いた。呼び出しは1.00回から2.24回。
図2 ── 再実行の上限と、最終的に通る割合
通ったことと正しいことも別検証を通っても、その値が事実として正しいとは限りません。金額が正の整数でも、金額そのものが間違っている場合があります。事実の確かめ方はツール利用の記事で扱っています。
出典pydantic/pydantic-ai README2026-08-18 確認
Pydantic AI Harness has everything an agent needs for complex, long-running work, snapped on as capabilities , from memory , sub-agents , and context management to a complete coding agent .
原文pydantic/pydantic-ai README この内容の有効期限2027-02-18

よくある質問

決まった形で返させれば検証は要りませんか
要ります。形が合っていても、金額が負だったり存在しない日付だったりします。この記事の計測では、読めた8件のうち6件が中身の問題で弾かれました。
検証で弾いたあとはどうしますか
何が悪かったかを伝えて再実行させるのが一般的です。この記事の試行では、1回の再実行で通る割合が20.2%から68.2%まで上がりました。
再実行は何回まで挟むべきですか
回数を増やすほど通る割合は上がりますが、伸びは鈍ります。2回から3回で87.0%から95.2%と、8ポイントぶんです。
型で書くと何が良いのですか
検証の条件が型の定義から自動で決まります。呼ぶ側も返ってくる形を前提にできるため、受け取ったあとの分岐が減ります。

まとめ

  • Pydantic AIは型で検証してから受け取る枠組み
  • 読めた8件のうち、検証を通ったのは2件
  • 再実行1回で通る割合は20.2%から68.2%
  • 3回まで挟めば95.2%だが、呼び出しは平均2.24回

今日から始められること

  1. AIに返させている項目の、型と範囲と形式を書き出す
  2. その条件を検証する処理を1つ書く
  3. 検証に落ちた応答を数え、どの条件で落ちているかを見る
  4. 再実行の上限を決めて、超えたら人に回す

実務で組んだPydantic AIのワークフローには、値段が付きます

同じ課題を持つ会社にとって、動いている設定は「作る時間」を買えるということです。ServiceDockは自作のワークフローやテンプレートを出品できるマーケットプレイスです。手数料や出品の流れは出品者向けページにまとまっています。

出品の仕組みを見る