この記事でできること
複数ソースから記事を集めてLLMに要約させるアプリで、一部のソースだけ本文(description)が取得できず、LLMがタイトルだけを見て要約を創作してしまう問題がありました。この記事は特定の実装コードではなく、「本文が無いデータにLLMが要約を書いてしまう」問題を設計する/見直すときに確認すべき5つの観点を整理したものです。要約に限らず、LLMに「取得できた情報だけを根拠に書かせたい」場面全般に当てはまります。
背景: なぜ気づきにくいか
複数の取得元(RSS、検索API、スクレイピングなど)からデータを集めて共通の分析処理に流す設計は、ソースが増えるほど「一部のソースだけ本文が空」という状態が起こりやすくなります。LLMへのプロンプトに「本文があれば使え、無ければ推測せよ」のような指示を書いていると、本文が無いケースでもエラーにはならず、それらしい文章が返ってきてしまいます。
出力が「もっともらしい文章」として返ってくるため、動作確認では気づきにくいのが厄介なところです。実際に元データと突き合わせて初めて「内容が全部でっち上げだった」と分かります。
観点1: プロンプトの指示だけに対策を任せない
「本文が無ければ推測するな、空にせよ」とプロンプトを直すことは対策の前提として必要ですが、それだけで十分とは考えないほうが安全です。プロンプトはあくまでLLMへのお願いであり、指示を無視して創作した文章を返してくることは起こり得ます。
保存・表示する直前の層に、機械的な判定(該当データの有無をコードでチェックし、無ければ出力を破棄する)を挟むことで、プロンプトが効かなかった場合でも創作物を素通ししない二重の防御になります。プロンプト側の「お願い」と、コード側の「強制」は役割が違うものとして両方用意するのが安全です。
観点2: 判定はデータの取得元ごとではなく共通の処理層に置く
「本文が空になるのは特定の1ソースだけ」と分かっていても、その対策を該当ソースの取得処理にだけ書くと、他の取得元でたまたま同じ状態(本文が空)のデータが来たときに素通ししてしまいます。
対策は「このソースだから」ではなく「本文が空かどうか」という共通の条件で、全ソースが通る共通の処理層(分析・保存の直前など)にまとめて置くべきです。これにより、対策を書いた時点では把握していなかった別ソースの穴も一緒に塞げます。
観点3: 「断定してはいけない項目」と「推定が許容できる項目」を分ける
LLMに生成させる項目が複数ある場合、それぞれを同じ強さで制限する必要はありません。
- 要約・具体的な内容の説明: 元データに書かれていないことを断定する形になるため、根拠データが無ければ生成しない
- カテゴリ・難易度などの分類: タイトルなど周辺情報からの推定でも、多少のずれで実害が小さい性質のものなら、根拠データが無くても許容してよい
すべての生成項目を一律に「本文が無ければ全部止める」としてしまうと、本来止めなくてよい項目まで欠落し、必要以上に機能を落とすことになります。「事実として断定する項目」だけを狙って制限をかけると、影響範囲を絞れます。
観点4: 対策を実装する前に、今取得できているデータをもう一度確認する
「本文が取れないなら追加の取得処理を新設する」と決め打つ前に、今すでに取得しているAPIレスポンスやデータの中に、実は使える情報が眠っていないか確認する価値があります。検索用・一覧取得用のAPIが、詳細取得用のAPIを別途叩かなくても本文相当のフィールドを既に返しているケースは珍しくありません。
追加のAPIコールを増やす前に、既存のレスポンスの中身を洗い直すだけで解決できることがあります。実装コストと外部APIへの負荷の両方を減らせる可能性があるため、確認する順番として「新しい取得処理を書く」より先に置く価値があります。
観点5: 「関連する情報」で安易に埋めない
本文が取れないデータを、関連はするが厳密には対象そのものではない情報(コメント、レビュー、周辺の言及など)で埋めたくなる場面があります。しかしこれをやると、「読者が対象そのものの内容だと信じる文章が、実際には対象に書かれていない」という、最初に対処しようとした問題と同じ構図が、形を変えて残ります。
要約や説明の根拠にできるのは、対象そのものの内容が確認できるデータに限定し、関連情報での代用は避けるべきです。どうしても情報を補いたい場合は、対象そのものの内容を別の手段(元ページのメタ情報取得など)で確保する方向で検討します。
番外: 既存データの移行を忘れない
ロジックを直しても、それが効くのはこれから新しく生成されるデータに対してだけです。すでに生成済みで保存されているデータ(創作された要約など)がキャッシュとして残る設計の場合、直す前に生成された分はロジック修正だけでは消えません。
「入力条件が揃わなければ再生成されない」仕組みなら、起動時などのタイミングで一度だけ実行する移行処理を用意し、条件に反する既存データ(本文が無いのに要約が入っている、など)を機械的に削除・修正する必要があります。ロジックの修正と、過去データの移行は別の作業として扱うべきです。
まとめ
- プロンプトの指示修正に加えて、保存・表示直前の層で機械的に判定する二重の防御を用意する
- 判定はデータの取得元ごとではなく、全ソース共通の処理層に置いて把握していない穴も塞ぐ
- 生成項目のうち「断定してはいけないもの」だけを狙って制限し、「推定が許容できるもの」まで一律に止めない
- 対策の実装前に、まず今取得できているデータをもう一度確認する。追加の取得処理が要らない場合がある
- 関連情報での代用は、同じ問題を形を変えて残すため避ける
- ロジック修正だけでは過去に生成された既存データは直らない。一度きりの移行処理を別途用意する
この判断の背景(なぜプロンプト修正だけで安心しなかったか、見送った案とその理由)はZenn版にまとめています。