はじめに — 流暢さと、正しさは、別物です
AIに何か聞いたとき、めちゃくちゃ流暢に、自信たっぷりに答えが返ってきますよね。
存在しない関数を「これで動きます」と言われて貼ったら動かなかった。出典として挙げられたURLを開いたら404だった。実在しない論文のタイトルを、著者名つきで堂々と教えられた。…こういう経験、一度はないですか。
僕はこれを何度かやらかして、あるとき気づいたんです。AIの“自信”は、正しさの証明にはなっていない。 ただ「それっぽさ」が高いだけで、流暢さと正確さは、まったく別の軸なんやなと。
この「もっともらしいけど事実じゃない出力」のことを、ハルシネーション(hallucination=幻覚) と呼びます。日本語にすると「もっともらしい嘘」。AIが悪意で嘘をついてるわけじゃなくて、仕組み上どうしても出てしまう、っていうのがポイントです。
そしてもうひとつ大事な言葉を先に置いておきます。グラウンディング(grounding) =「答えを、ちゃんとした根拠(出どころ)に紐づけること」。今日の記事は、ざっくり言うと「AIの答えを、根拠に縛りつけて、検証で捕まえる」話です。
この記事では、
- なぜAIは“堂々と”間違えるのか(最近の研究でかなりスッキリ説明がついてきました)
- ハルシネーションは「消す」んじゃなくて「減らして・捕まえる」もの、という考え方
- 明日から仕事で使える 3層の防御 (プロンプト例3本+コード例2本つき)
- 人間がどこを設計し、どこを判断し、どこをAIに任せるか
をできるだけ噛み砕いて書きます。AIにまだ慣れてない方でも、「なるほど、最初にこれをやればいいのか」が分かる状態を目指します。
なぜAIは“堂々と”間違えるのか — 「分かりません」が0点になる世界
まず、ここが一番おもしろいところです。
「AIが間違えるのはまだ賢くないから、もっと賢くなれば消えるんでしょ?」と思いがちですよね。でも、最近の研究を読むと、どうやらそれだけじゃないんです。
2025年9月にOpenAIの研究者らが出した論文「Why Language Models Hallucinate」(arXiv:2509.04664)が、すごく腑に落ちる説明をしています。要点をめちゃくちゃ噛み砕くと、こうです。
いまのAIは、「分かりません」と言うより「当てずっぽうで答える」方が“成績が良くなる”ように育てられている。
どういうことか。AIの賢さを測るテスト(ベンチマーク)の多くは、正解なら1点、不正解なら0点、そして「分かりません」も0点 という採点なんですね。
ここで、学生時代のテストを思い出してください。空欄で出すと確実に0点。でも、何か書いておけば「まぐれで当たる」かもしれない。だったら…とりあえず埋めますよね。
AIもまったく同じ構造に置かれているんです。「分からない」と正直に言っても0点なら、自信ありげに当てにいった方が期待点が高くなる。 だから、知らないことでも、それっぽく埋めてくる。これがハルシネーションの大きな正体のひとつ、というわけです。
ここで肩の力が抜けると思うんです。ハルシネーションは、AIが壊れてるとか、サボってるとか、そういう話じゃない。 学習と評価の設計の、自然な“帰結”なんです。
だとしたら、責めても仕方ない。責めるかわりに、こっちが「検証できる仕組み」を設計すればいい。 これが今日いちばん伝えたい姿勢です。
勘違いを正す — ハルシネーションは「消す」ものじゃなく「減らして・捕まえる」もの
ここで大事な注意を、先に置いておきます。
ネットで「ハルシネーション 対策」と調べると、「これで完全になくなる」みたいな見出しが出てきます。でも、正直に言いましょう。現時点で、ハルシネーションを完全にゼロにする魔法はありません。
研究の世界でも、2025〜2026年のサーベイ論文(arXiv:2510.06265 など)が口を揃えて言っているのは、「単一の手法では穴が残る。複数を層で重ねるのが一番マシ」ということです。
なので、この記事のゴールは「嘘をゼロにする」じゃなくて、こうです。
- 減らす … そもそも嘘が出にくい渡し方・聞き方をする
- 捕まえる … 出てしまった嘘を、人間の目に届く前に検知して止める
健康診断にたとえると分かりやすいかもしれません。病気を100%予防はできないけど、生活習慣で減らして、検査で早く捕まえる。 AIの出力も同じで、「減らす設計」と「捕まえる検証」をセットで持つ。これが現実的な勝ち筋です。
3層の防御 — どこで嘘を止めるかの地図
では具体的に、どこで止めるのか。僕は 3つの層 で考えると整理しやすいと思っています。
| 層 | 一言でいうと | ここでやること |
|---|---|---|
| ① 入力層(根拠を渡す) | 「想像で答えさせない」 | 答えの材料になる正しい資料を一緒に渡す(グラウンディング/RAG) |
| ② プロンプト層(聞き方) | 「逃げ道と引用を用意する」 | 「分からないなら分からないと言って」「出典を示して」と頼む |
| ③ 出力検証層(受け取り方) | 「鵜呑みにせず照合する」 | 返ってきた答えを、機械的に根拠と突き合わせる |
順番にいきます。
① 入力層 — そもそも「想像で答えさせない」
一番効くのに、見落とされがちなのがここです。
AIは、何も資料を渡さないと「記憶(学習した知識)」から答えます。この記憶は曖昧で、古いことも多い。だから 答えの材料になる一次情報(社内ドキュメント、APIの仕様、該当コードなど)を一緒に渡してあげる。 これだけで、想像で埋める余地がガクッと減ります。
この「関連資料を検索して、それを材料に答えさせる」仕組みを、かっこよく言うと RAG(Retrieval-Augmented Generation=検索で補強した生成) と呼びます。難しく聞こえますが、最初の一歩は超シンプルで、「該当しそうなドキュメントを、プロンプトに貼って一緒に渡す」 だけでも立派なグラウンディングです。
② プロンプト層 — 「逃げ道」と「引用」を用意する
さっきの研究を思い出してください。AIは「分かりません」が0点だと、当てにいく。だったら、こっちのプロンプトで 「分からないと言ってもいいよ」という逃げ道を、明示的に作ってあげればいい んです。
これが効きます。プロンプト例を3本、置いておきます。そのままコピペして調整して使ってください。
プロンプト例1: 棄権を許可して、引用を強制する(基本形)
あなたは事実確認に厳格なアシスタントです。
以下の<資料>に書かれている内容『だけ』を根拠に、質問に答えてください。
# ルール
- <資料>に根拠が見つからないことは、推測で埋めず「資料からは判断できません」と答える。
- 主張する文の末尾には、必ず [出典: 資料の見出し or 該当箇所] を付ける。
- 出典を付けられない文は、書かない。
<資料>
{ここに該当ドキュメントを貼る}
</資料>
# 質問
{聞きたいこと}
ポイントは「資料に無いことは『判断できません』と言っていい」と 逃げ道を作っている ことと、「文ごとに出典を付けさせている」こと。出典を付けられない=根拠がない、なので、嘘が混ざりにくくなります。
プロンプト例2: 自分の答えを自分で点検させる(自己検証 / Chain-of-Verification)
AIに一度答えさせたあと、もう一度「いまの答え、根拠ある?」と振り返らせる手です。意外と自分で気づいてくれます。
あなたが直前に書いた回答を、1文ずつ点検してください。
# 手順
1. 回答を1文ごとに分解する。
2. 各文について、<資料>のどこに根拠があるかを対応づける。
3. 根拠が見つからない文を「未確認」として一覧にする。
4. 「未確認」の文をすべて削除した、安全な修正版の回答を出力する。
根拠の薄い文を残すより、短くても確実な回答にしてください。
プロンプト例3: 確信度ラベルで「ここ怪しい」を可視化させる
全部を疑うのは大変なので、AIに「ここは自信ある/ない」を申告させて、人間が見るべき場所を絞る作戦です。
回答の各項目に、確信度ラベルを付けてください。
- [確信度:高] … 資料に明確な根拠がある
- [確信度:中] … 資料から推論したが、解釈の余地がある
- [確信度:低] … 一般知識からの推測(資料に根拠なし)
[確信度:低] の項目には、必ず「確認方法(どの資料・コマンドで検証できるか)」を併記してください。
ここで大事なのは、これらはあくまで「減らす」工夫 だということ。プロンプトだけで安心しきってはいけません。AIは指示を無視して、それっぽい出典を“でっち上げる”こともあります。だから次の③が要ります。
③ 出力検証層 — 鵜呑みにせず、機械で照合する
ここがエンジニアの腕の見せどころです。「AIが出典を付けた」ことと「その出典が本当に主張を裏付けている」ことは、別問題。 なので、返ってきた答えをコードで突き合わせます。
「答えが、ちゃんと出典に書いてある内容か?」を確かめることを、専門用語で 含意(entailment)チェック とか groundedness(根拠への忠実さ)の検証 と言います。難しそうですが、考え方は「その文、ほんまに出典に書いてある?を機械で確認する」だけです。
ここからコード例です。汎用的なダミーで書くので、ご自分の環境に合わせて調整してください(挙動はモデルやバージョンで変わるので、必ず手元で検証を)。
コードで「捕まえる」 — 2つの検証ゲート
コード例1: 構造化出力 × 引用スパン照合ゲート
まず一番堅いやつから。AIに 「主張」と「その根拠になった原文の引用」をセットでJSON出力させ、その引用が本当に資料の中に存在するかをプログラムで照合 します。引用が資料に見つからなければ、その主張はブロック(不採用)。
これは外部APIも判定モデルも要らない、一番安くて確実な第一歩 です。
import json
import unicodedata
def normalize(text: str) -> str:
"""全角半角・空白のゆらぎを吸収して比較しやすくする"""
text = unicodedata.normalize("NFKC", text)
return "".join(text.split()) # 空白・改行をすべて除去
def verify_citations(source_text: str, model_json: str) -> dict:
"""
AIには次の形式で答えさせる想定:
{
"claims": [
{"statement": "主張の文", "quote": "資料からの抜き出し(原文ママ)"},
...
]
}
quote が source_text に実在するかを照合し、
実在しない(=でっち上げ)主張をブロックする。
"""
data = json.loads(model_json)
norm_source = normalize(source_text)
verified, blocked = [], []
for claim in data.get("claims", []):
quote = claim.get("quote", "")
# 引用が空、または資料に存在しない → 根拠なしとみなす
if quote and normalize(quote) in norm_source:
verified.append(claim)
else:
blocked.append(claim)
return {
"verified": verified, # 出典が実在した主張だけ
"blocked": blocked, # 根拠を確認できなかった主張
"is_safe": len(blocked) == 0, # 1件でも怪しければ False
}
# --- 使用イメージ ---
source = "返金は購入後14日以内に限り可能です。送料は購入者負担となります。"
model_output = json.dumps({
"claims": [
{"statement": "14日以内なら返金できる", "quote": "返金は購入後14日以内に限り可能です"},
{"statement": "返金時の送料は当社が負担する", "quote": "送料は当社が全額負担します"}, # 資料に無い=でっち上げ
]
}, ensure_ascii=False)
result = verify_citations(source, model_output)
print("安全に出せるか:", result["is_safe"]) # → False
print("ブロックされた主張:", [c["statement"] for c in result["blocked"]])
# → ['返金時の送料は当社が負担する']
ポイントは、「AIが何と言ったか」ではなく「資料に何が書いてあるか」を真実の基準(source of truth)にしている ところ。AIの自己申告を信じず、原文との一致だけを信じる。これだけで、でっち上げ出典のかなりの部分を機械的に弾けます。
もちろん、これは「言い換え」には弱いです(原文と表現が違うと一致しない)。そこを強くしたいときが、次のコードです。
コード例2: LLM-as-a-judge で「含意しているか」を採点する
引用が言い換えられていても、「主張は資料から導けるか?」を別のAI(判定役)に含意チェックさせる方法です。AIの出力を、もう一体のAIに採点させるので LLM-as-a-judge(審判としてのLLM) と呼びます。
# 疑似コード: client は任意のLLM SDK(社内のものでOK)
def is_grounded(statement: str, source_text: str, client) -> dict:
judge_prompt = f"""
次の<主張>が、<資料>から論理的に導ける(=資料に書かれている、または明確に推論できる)かを判定してください。
<資料>
{source_text}
</資料>
<主張>
{statement}
</主張>
# 出力(JSONのみ)
{{
"verdict": "supported | not_supported | partially",
"evidence": "判断の根拠になった資料中の箇所(無ければ空文字)",
"reason": "判定理由を一文で"
}}
""".strip()
raw = client.complete(judge_prompt, temperature=0) # 判定はブレ防止で低温度
return json.loads(raw)
def guard(statement, source_text, client):
"""supported 以外は人間レビューに回す"""
v = is_grounded(statement, source_text, client)
if v["verdict"] != "supported":
return {"action": "HUMAN_REVIEW", "detail": v} # 自動で出さず、人に渡す
return {"action": "PASS", "detail": v}
ここで心配性の自分が顔を出します。判定役のAIだって間違えます。 judgeを過信して全自動にすると、「AIの嘘を、別のAIが“OK”と太鼓判」みたいな事故も起きうる。
だから設計の鉄則はこうです。supported 以外は、人間レビューに回す。 judgeは「全部を人が見るのは無理だから、怪しいものだけ人に上げる“仕分け係”」として使う。最終責任は人間が持つ。ここは絶対に握っておくところです。
開発フローのどこに、検証を挟むか
「で、自分の仕事のどこで使うん?」という話を、表にしておきます。AIを使う開発フローの各段階で、“鵜呑みポイント”はだいたい決まっています。
| 開発フロー | AIがやりがちなハルシネーション | 挟むべき検証 |
|---|---|---|
| 調査・技術選定 | 実在しないライブラリ名・古いAPI・捏造URL | 公式ドキュメントを資料として渡す/URLは実際に開いて確認 |
| 設計・仕様整理 | 要件に無い前提を勝手に追加 | 「資料に無い前提は『要確認』と明記」させる |
| 実装 | 存在しない関数・引数を“それっぽく”使う | 型チェック・lint・テスト実行で機械的に弾く |
| コードレビュー | 「問題ありません」と中身を見ず太鼓判 | 「指摘には該当行番号と根拠を必須」にする |
| 障害対応 | ログに無い原因を断定 | 「ログの該当行を引用しない推論は推測と明記」させる |
| ドキュメント生成 | コードと食い違う説明を自然な文で書く | 実際の関数シグネチャと突き合わせて検証 |
共通しているのは、「自然言語の説得力」ではなく「機械で照合できる事実」を基準にする こと。コードなら型・テスト・lintという最強の審判がもともと居ます。文章なら出典との照合。“確かめられる形”に落とすほど、ハルシネーションは捕まえやすくなる んです。
人間がどこを設計し、どこを判断し、どこを任せるか
ここまでを、役割で整理しておきます。これがこの記事の背骨です。
- AIに任せる: 大量の下書き、要約、候補出し、一次レビュー、引用つきドラフトの生成。スピードが要るところ。
- 人間が設計する: 「どの資料を根拠にするか」「何を検証するか」「どこを自動で弾き、どこを人に上げるか」という 仕組み(ゲート)の設計。
- 人間が判断する: 検証で “怪しい” と上がってきたもの、確信度が低いもの、そして 高リスクな領域(お金・医療・法務・セキュリティ・公開情報)の最終OK。
言い換えると、エンジニアの仕事は「AIに正解を出させること」から、「AIの出力を、安く・確実に検証できる流れを設計すること」 に移ってきている気がします。賢いモデルを待つんじゃなくて、いまあるモデルを“信頼できる部品”として組み込む設計力。ここが、これからめっちゃ価値になると思うんです。
おわりに — 責めない。明日の自分が“あざっす”と言える検証を、今日仕込む
最初に書いたとおり、ハルシネーションはAIが壊れてるからじゃなくて、学習と評価の設計の、自然な帰結 でした。
だから、AIを責めても、AIに振り回された自分を責めても、あんまり意味がないんですよね。責める軸じゃなくて、思いやりの軸で考えたいなと。
僕がよく自分に問いかけるのは、「これ、明日の自分が“あざっす”って言ってくれるかな?」 という一言です。
- 今日、出典を強制するプロンプトに1行足しておく → 明日の自分が、捏造URLを資料に貼らずに済む。あざっす。
- 今日、引用照合のゲートを20行だけ書いておく → 来週の自分が、嘘混じりの回答をお客さんに出さずに済む。あざっす。
- 今日、「高リスクは人間レビュー」と決めておく → 半年後の自分が、静かな事故を防げてる。あざっす。
大げさなことじゃなくていいんです。完璧な対策(嘘ゼロ)を目指さなくていい。 今日、小さな検証をひとつ仕込む。それだけで、明日の自分は「無理せずありがとう、あざっす」と言ってくれます。
AIの“自信満々”は、正しさの保証じゃない。でも、こっちが検証を仕込めば、AIの速さを 堂々と 使えるようになります。怖くて使えない、でも止まれない…という宙ぶらりんから、一歩抜け出せる。
まずは、いつものプロンプトの最後に、この一文を足すところからどうですか。
「資料に根拠がないことは、推測で埋めず『判断できません』と答えてください。」
ここから始めれば、十分です。明日の自分が、きっと“あざっす”って言ってくれます。
参考にした主な情報源
- OpenAI / Kalai, Nachum, Vempala, Zhang「Why Language Models Hallucinate」(arXiv:2509.04664, 2025) — 評価が「当てずっぽう」を「分かりません」より報酬づける問題
- LLMハルシネーション緩和に関するサーベイ (arXiv:2510.06265, 2025–2026) — Prompt / Retrieval / Reasoning / Model-centric の4分類とハイブリッドの有効性
- 実務における引用検証・groundedness採点・LLM-as-a-judge のパターン解説(各種技術記事, 2025–2026)
※本記事のコードは仕組みを説明するための汎用サンプルです。挙動はモデル・バージョン・設定で変わります。本番利用前に、必ずご自身の環境で検証してください。