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の“自信満々”は、正しさの保証じゃない — ハルシネーション(もっともらしい嘘)を、根拠づけと出力検証で“捕まえる”技術

0
Posted at

はじめに — 流暢さと、正しさは、別物です

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)

※本記事のコードは仕組みを説明するための汎用サンプルです。挙動はモデル・バージョン・設定で変わります。本番利用前に、必ずご自身の環境で検証してください。

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?