はじめに
業務で使う帳票のチェックアプリをClaudeと設計していたとき、依頼文では25項目
だったチェック対象が、Claudeの最初の応答で27項目として定義されました。
問題はその後です。
この「27」は出所を確認されないまま確定値として扱われ、後続の設計や工数計算にも使われ続けました。
この記事では、AIの数え間違いそのものではなく、AIが生成した値を、どの時点で「事実」として扱ってよいのかをこの実例から考えます。
この記事で確認した記録の範囲
- 初回の依頼と、Claudeの最初の応答の全文
- 途中の業務確認に対するClaudeの回答
- 凍結時にClaudeが作成した記録
設計は約1か月続きましたが、途中の回(業務確認 v1、実測の回など)は手元の全文に含まれていませんでした。そのため、この記事の記述は 確認できた記録の範囲 に限定します。
1. ThinkingとMemory
今回の設計では、AIとのやり取りを次のように分けて扱っていました。
- Thinking:判断・推論・変換・検証
- Memory:事実・状態・設定・観測結果の保持
- Execution:Thinkingで決めた処理の実行
また、情報は次の2つに分けています。
- 定数:観測・実測で確認された事実、明示された仕様
- 変数:未確認事項、仮説、推測
設計の区切りでは、Claudeにその時点の判断結果をMarkdownとJSONで出力させ、私がObsidianなどへ保存していました。そして次のやり取りでは、その記録を前提情報として渡していました。
つまり、流れはこうなります。
入力
↓
Claudeによる判断・推論
↓
Markdown / JSONとして出力
↓
人間が保存
↓
次のやり取りの前提情報
ここで重要なのは、保存される情報がすべて元の入力に書かれていた事実とは限らないことです。
Claudeが推論や生成によって作った値も、そのまま保存すれば、次のやり取りでは前提情報として使われます。
そして今回、この境界で「25」が「27」になりました。
2. 「分からない」情報については、止まれていた
今回の依頼では、設計を始める前に次のルールを与えていました。
不足情報がある場合は、推測で補完せず追加質問を生成して停止してください。
Claudeはこのルールに従っています。最初の応答では、すぐに設計を進めず、次のような質問を10個挙げて停止しました。
| # | 質問(抜粋) |
|---|---|
| Q1 | チェック元・チェック先の媒体は?(紙/画面/PDF) |
| Q2 | 両票は同時に手元にあるか? |
| Q3 | 帳票は定型フォーマットか? |
| Q5 | 通信の可否、クラウドOCRへの送信は許容されるか? |
| Q9 | 成功の許容誤差は? |
媒体、フォーマット、通信制約など、依頼文に書かれていない情報については、推測で補わず「分からない」として扱えていました。
ところが、その同じ応答の中で、別の種類の値が確定情報として扱われていました。
チェック項目数です。
3. 25項目が27項目になった
ところが、その最初の応答には次の一行がありました。
チェック項目数 N = 27
私が依頼文で指定したチェック対象は、車型コード、初度登録、車名、グレード、走行距離、燃料、出品店など、全25項目でした。
依頼時に帳票画像などは添付していません。また、Claudeの応答にも「27」が何を数えた結果なのか、その内訳は示されていませんでした。
それでも「27」は、その後の記述ですでに前提として使われています。
- 成功条件:「27項目すべてについて『一致/不一致/判定不能』の三値判定が得られる」
- 停止条件:「iPhone単体で27項目全てを許容誤差内で取得できる構成が…」
- 質問Q7の説明:「無ければ全27項目等重みで進める」
前節で見たように、媒体や通信制約など、依頼文から分からないことについてClaudeは質問して停止していました。
一方、Claude自身が応答の中で生成した「27」については、出所を確認する質問はありませんでした。
この記事で考えたいのは、この違いです。
外から与えられていない情報では止まれたのに、Claude自身で生成した値では、なぜ止まらなかったのか。
4. そして27は「確定リスト」になった
最初の応答の最後で、Claudeは確認できた事実と未確認事項を整理しています。その「定数」の欄に、次の一行がありました。
定数(明示された事実)
- チェック項目27個は確定リスト
私がQ1〜Q10に回答した後、Claudeは定数を整理し直しました。その表にも、27が残っています。
| キー | 値 |
|---|---|
| 媒体 | 紙2枚(両票同時に手元) |
| ネットワーク | 社内LAN不可、クラウドOCR送信不可 |
| チェック項目数 | 27 |
さらに、最終的に出力されたJSONにも次の値が記録されました。
"check_item_count": 27
流れを図にすると、次のようになります。
入力(依頼文)
チェック項目:25
│
▼
Claudeの応答
「N = 27」 ← 内訳・出所なし
│
▼
事実として分類
「定数:チェック項目27個は確定リスト」
│
▼
外部記録
check_item_count: 27
Q1〜Q10で確認した内容は、私の回答という 出所 を持って定数になりました。
一方、「27」は出所が示されないまま、同じ「定数」の欄に並び、そのまま外部記録に保存されました。
5. 27を前提にした後続処理は、正しく進んだ
「27」が確定値として扱われた後の計算には、誤りがありません。
例えば、帳票2種類について項目ごとの座標を定義する案では、次のように工数を見積もっていました。
27項目 × 2フォーマット = 54項目
1項目5分 × 54項目 = 4.5時間
その後、業務仕様の確認によって「グレード」がチェック対象から外れました。
27項目 - グレード1項目 = 26項目
この計算も正しいです。
しかし、依頼文にあった25項目を起点にすれば、
25項目 - グレード1項目 = 24項目
になります。
確認できた記録の範囲では、「27」が「25」に戻った形跡はありませんでした。
ここで分けて考える必要があります。
| 状態 | |
|---|---|
| 計算そのもの | 正しい |
| 計算に使った「27」 | 出所が確認できない |
つまり、後段の処理が正しくても、その入力値まで正しいとは限りません。
さらに、確認できた記録には「27項目」「26項目」という個数は何度も登場しますが、それぞれが具体的にどの項目を指すのかを列挙したリストはありませんでした。
保持されていたのは、項目そのものではなく「個数」でした。
途中で問い直されたかどうか
凍結記録には、業務確認の結果として次の一行があります。
論点5: 27項目リストと実帳票差分は無視
この論点で何が「差分」として扱われたのかは、結論しか残っていません。項目数のずれ(25と27)が扱われたのか、実際の帳票にあってリストにない欄が扱われたのかは分かりません。
そのため、この記事では「誰も27を疑わなかった」とは書きません。書けるのは、
確認できた記録の範囲では、27の出所を問い直した形跡はない。
なお、27が判定ロジックの中身(項目ごとのルール)まで誤らせたかどうかも、記録からは分かりません。確認できる影響は、54座標、工数見積もり、「26」という個数までです。
6. 少なくとも私も、27を通していた
Claudeが「チェック項目27個は確定リスト」と書いた最初の応答に対して、私はそのまま質問事項へ回答し、設計を先へ進めています。27について指摘した記録はありません。
当時、私は項目数を確認しておらず、27という数字自体を認識していませんでした。今振り返ると、意識はClaudeから出された質問に答えることに向いていました。
さらに、Claudeが出力した設計内容は私が外部の記録へ貼り付けて保存し、次のやり取りでも使っていました。
つまり、AIの出力がそのまま自動的に保存されていたわけではありません。
Claudeの出力
↓
私が確認・保存
↓
次の設計の前提として再利用
この間には、人間である私が入っています。
それでも「27」は通過し、その後の設計の前提になりました。
少なくとも確認できた記録の範囲では、最初に「27」が生成されてから外部の記録に保存されるまで、その出所を確認した形跡はありません。
7. なぜ、定数/変数の分類では防げなかったのか
依頼文は、定数と変数を分けるよう明示的に求めていました。フェーズの説明にも「定数(確認済み事実)」「変数(未検証仮説)」と書いています。
それでも、27は定数に分類されました。
記録から観測できるのは、
27を生成した主体と、27を定数に分類した主体は、同じだった。
これを原因とは書きません。別の主体(別のモデルや人間)が分類していれば防げたのかは、検証していないからです。実際、6章のとおり、人間の私も通しています。
ただ、少なくともこれだけは言えます。
「定数」というラベルは、その値の出所とつながっていませんでした。 Q1〜Q10の回答には「私が答えた」という出所がありました。27にはありませんでした。それでも、ラベルの上では両者は区別されていません。
8. 必要なのはラベルではなく、出所への照合ではないか
では、Memoryに出所のラベルを付ければよいのでしょうか。たとえば次のような形です。
{
"value": 27,
"source": "model_inference",
"status": "unverified"
}
これだけでは弱いと考えています。
今回、Claudeは「定数/変数を分けよ」という指示を受けたうえで、27を定数に分類しました。同じモデルに source や status を自己申告させるだけでは、今回とは別の検証経路を追加したことにはなりません。 ラベルを増やしても、分類しているのは同じ主体だからです。
必要なのは、ラベルではなく、元の入力に戻って照合できる根拠 ではないか。これが、今回の記録から出てきた仮説です。
9. 元の入力へ戻って確認する
ここからは、今回の記録から直接実証されたことではなく、設計上の仮説です。
今回の事象から考えたのは、次の原則です。
AIが生成した値を確定値として使う前に、元の入力へ戻って確認する。
たとえば、AIが抽出した項目数を、AIが生成した項目リストの長さで確認しても、両方が同じ誤りを含んでいれば検出できません。
今回の入力は、25項目が明示されたリストでした。
入力
25項目のリスト
↓
AI
「27項目」
↓
そのまま確定値として保存
必要だった可能性があるのは、AIの推論をさらに重ねることではなく、「元のリストはいくつあるのか」と入力へ戻ることです。
しかも今回のように、1項目ずつ明確に列挙されているなら、AIに個数を判断させる必要すらありません。
source_items = parse_item_block(source_text)
item_count = len(source_items)
入力から機械的に取得できる値は、入力から取得する。
機械的に確認できない値は、根拠が得られるまで確定値として扱わない。
この仕組みで今回の事象を防げた、とまでは言えません。実装して検証したわけではないからです。
ただ、今回の25と27を振り返ると、必要だったのはより高度な推論ではなく、一度、元の入力へ戻ることだったのではないかと考えています。
おわりに:AIが生成した値は、いつ事実になるのか
この記事で、記録から確認できたことをまとめます。
- 依頼文のチェック項目は25だった
- Claudeは最初の応答で、内訳を示さずに27とし、「定数」に分類した
- 27はその後、54座標、工数見積もり、26という個数の計算に使われた
- 確認できた記録の範囲では25には戻らず、26項目の具体的なリストも残っていない
- 私自身も27を指摘せず、そのまま設計を進めた
一方で、分からないことも残っています。
- 27が生まれた原因
- 途中の確認で、25と27の差が扱われたか
- 元の入力との照合を入れていれば防げたか
「AIは間違えるから検証する」だけでは、この事例を十分に説明できません。
今回は、事実と未確認事項を分けるよう指示していたにもかかわらず、AI自身が生成した「27」が事実として分類され、人間の確認も通過し、その後の設計で使われ続けました。
残った問いは、これです。
AIが「これは事実です」と分類した値を、私たちは何を根拠に事実として受け入れるのか。
27×2=54は正しかった。
27の出所は、記録のどこにも書かれていませんでした。