0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIの「読んだふり」を構造的に防ぐ:sha256と機械採点による検証システム

0
Posted at

AIの「読んだふり」を構造的に防ぐ

手抜き防止システムの設計と実装から得た知見

0. 何が問題なのか("読んだ"の定義がない)

LLMに「この文書を読んで要点をまとめて」と頼むと、もっともらしい文章は返ってくる。だが、そこに根本的な欠陥がある。

  • 本当に読んだのか?
  • 冒頭だけ見て推測していないか?
  • メタデータ(タイトル、見出し、ファイル名、サイズ)だけで雰囲気を作っていないか?

人間でも「読んだふり」はできる。LLMも同様に、最小の入力から"それっぽい出力"を作ることができる。問題は、その出力が「読んだ上での要約」なのか「推測の作文」なのかを、外部から区別できないことだ。

ここで必要なのは「誠実さ(プロセス)」の検証であって、「文章の上手さ(結果)」の検証ではない。

1. 方針:信頼ではなく、検証可能な証拠

1-1. LLMにLLMを採点させない

LLMに「要約の質を評価して」と頼むと、採点者も被採点者も同じ土俵に立つ。
うまい作文で迂回されるし、評価者も同種のバイアスを持つ。

だから設計判断はこれ:

採点は機械でやる(LLMを介さない)

ここでいう「機械採点」は、次のようなもの:

  • ハッシュ一致(sha256)
  • 文字列の完全一致
  • 正規表現でのパターン一致
  • 決められた位置(オフセット)から切り出した文字列一致

LLMが関与できない"硬い検証"だけを採用する。

2. コア技術:sha256による「実在証明」

2-1. sha256とは何か(あまり触れない人向け)

sha256はハッシュ関数で、任意のテキスト(バイト列)を固定長(256bit)の値に変換する。

重要な性質:

  • 同じ入力 → 必ず同じハッシュ
  • 入力が1文字でも違う → ほぼ確実に全く別のハッシュ
  • ハッシュから元の文章を復元できない(不可逆)

つまり「この引用文が原文と完全一致しているか」を、文章比較より堅牢に検証できる。

検証は超単純で:

  1. 原文から引用部分を切り出す
  2. その文字列のsha256を計算する
  3. Readerが提出したsha256と一致するかを見る

一致すれば「この文字列は原文のこの部分と同一」と言える。

2-2. context_sha256の意味("周辺も読んだ"を担保)

sha256だけだと、引用箇所だけを切り出して提出すれば通る。
それでは「引用部分だけ読む」ショートカットが残る。

そこで context_sha256 を入れる。

  • 引用部分の前後(例:±128文字、合計256文字)の文字列を取り
  • そのsha256も一致させる

これにより「引用の周辺も同じテキストを見ている」ことが機械的に証明される。
**"切り取り作文"**がやりにくくなる。

3. 「散らばり」:冒頭だけ読む手抜きを構造的に封じる

長文で最も起きやすいショートカットはこれ:

  • 文書の冒頭だけ読む
  • 見出しや結論っぽい箇所だけ見る
  • 全体を読んだかのようにまとめる

対策が head/middle/tail散らばり
文書を3区間に分け、必ず各区間から引用を出させる。

  • head:冒頭付近
  • middle:中盤付近
  • tail:終盤付近

これで「最初の1/3だけ読んで終わり」がほぼ不可能になる。
読む行為が"面で要求される"。

4. 監査質問:引用だけ読む最適化を潰す

4-1. verbatim_substring(直前N文字を答えよ)

これは「読まずに答えられない」質問を機械採点できる形に落としたもの。

例:

  • quote_spanの直前20文字を答えよ
  • Gateは原文から直前20文字を切り出して完全一致で採点

ポイント:

  • LLMの言い換えを許さない(完全一致)
  • "雰囲気"や"推測"が通らない

4-2. is_non_quote質問(非引用部の強制)

引用部分だけ精読して他を読まない最適化が起きる。
それを潰すのが is_non_quote

  • quote_spanに含まれない範囲からも質問する
  • 例:「chunk_002の冒頭50文字に"深夜アニメ"は含まれるか?」

このタイプは「引用を見れば答えられる」を防ぐ。
文書の別地点への注意を強制する。

5. 実装で詰まったポイントと "設計の学び"

5-1. JSON手打ちは必ず壊れる(特殊文字・エスケープ)

なぜ壊れるのか(丁寧に)

JSONは文字列を " で囲む。
だから本文中に " があると、JSONの構文そのものが壊れる

さらに日本語文章には以下が混ざる:

  • " "(U+201C/U+201D)
  • ' '(U+2018/U+2019)

人間は見た目で「ダブルクオート」と理解するが、JSONはただの文字なので、
生成時の扱いを誤ると簡単にパース不能になる。

対処:LLMにJSONを書かせない

結論はこれ:

LLMは意図(フレーズ)だけ出す。JSONはPythonが生成する。

build_extraction.py

  • エスケープ処理
  • sha256/context_sha256の計算
  • 位置(offset)の整合

を全部引き受ける。
LLMが触る余地を減らすほど堅牢になる。

5-2. "条件付き必須"はドキュメントではなくスキーマで強制

is_non_quote: true のとき chunk_id が必須。
ドキュメントに書いても漏れる。

ここで効くのが JSON Schema の if/then

JSON Schemaとは(丁寧に)

JSONの構造に「型・必須・制約」を与える仕様。
コードがなくても「このJSONは正しい/間違い」を機械で判定できる。

if/thenの意味

  • もし is_non_quote が true なら
  • その場合は chunk_id などを必須にする

これで「人間が忘れた」が機械で弾ける。

ドキュメント < スキーマ < コード
スキーマは"設計書"であり"強制力"。

5-3. 検索失敗:特殊引用符の揺れ

原文が "投資" で、検索語が "投資"(ASCII)だと一致しない。
逆も同様。見た目は同じでもコードポイントが違う。

対処:--normalize(正規化)

  • 検索時に " " を " に寄せる
  • ' ' を ' に寄せる
  • ただし原文そのものは変えない(忠実性を守る)

ここがポイント:
検索は正規化しても良いが、証拠(sha256)は原文のまま

6. 設計原則(落としてはいけないもの)

本質 理由
sha256 + context_sha256 「読んだ」の実在証明。核
head/middle/tail散らばり 冒頭だけ読む手抜きを封じる
機械採点(LLM不使用) 迂回されにくい・再現性がある
is_non_quote必須 引用部だけ読む最適化を封じる
rejectで差し戻す "通らないものは採用しない"を制度化

7. 削ってよかった非効率(ここが重要)

削ったもの 理由
手動sha256計算 誠実性ではなく作業ミス源。自動計算でよい
exact_match(文境界一致) Markdownで壊れる。目的は誠実性であって句読点ではない
JSON手打ち 壊れるのが自然。生成はコードで固定する
旧形式の後方互換 "いつまでも移行できない"を生む。rejectで強制移行

8. 得られた知見(実務的まとめ)

8-1. 「信頼するが検証する」

LLMを信頼しないのではない。
"読んだ"という主張を検証可能にすることで、使える領域が増える。

8-2. 抜け道は必ず見つかる(だから制度で潰す)

make_quote_span.pyは便利だが、便利は抜け道も作る。
だから「便利を捨てる」ではなく、is_non_quoteのような制度で押さえる

8-3. LLM=意図、Python=証拠

LLMにやらせるのは「どこが重要か」「何を抜きたいか」の意図。
証拠(sha/offset/JSON)はPythonが生成。
この分業が一番堅牢。

8-4. スキーマは"口約束"を排除する

「入れてください」は漏れる。
入れてないと通らないにすると漏れない。

付録:この先の拡張(任意)

  • Markdown構造に基づくchunk分割(見出し/段落境界で切る)
  • is_non_quote質問の自動生成(引用外領域から自動サンプリング)
  • traceの自動保存と差し戻しのワークフロー固定
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?