Google ADK(Agent Development Kit)を使ってAIエージェントを開発している際、非常に厄介な挙動に遭遇しました。ユーザーがアップロードしたファイルの内容を、AIが全く異なる内容として読み取ってしまう「ハルシネーション(もっともらしい嘘)」が発生したのです。
原因を探ってみると、load_artifacts というツールの存在を見落としていたこと、そして「ローカル環境では正常に動いてしまう」という巧妙な罠が隠されていました。
本記事では、実体験をもとにこのトラブルの全容と解決策を技術解説します。同じ構成で開発されている方の参考になれば幸いです。
開発していたシステムの概要
構築していたのは、ユーザーがPDFやドキュメントをアップロードし、複数のAIエージェントが連携して内容を分析するシステムです。
アップロードされたファイルの保存先には Google Cloud Storage (GCS) を使用し、ADKの Artifacts機能 を活用する構成にしました。
- ワークフロー: ユーザーがファイルをアップロード → GCSにArtifactとして保存 → a_agent → b_agent → c_agent とリレー形式で処理。
実装:まず「保存」の設定を行った
ADKには SaveFilesAsArtifactsPlugin という便利なプラグインが用意されています。これを使用すると、ユーザーがアップロードしたファイルを自動的にGCSへ保存してくれます。
- # agent.py
- from google.adk.apps import App
- from google.adk.plugins.save_files_as_artifacts_plugin import SaveFilesAsArtifactsPlugin
- app = App(
- name=”my_agent_app”,
- root_agent=root_agent,
- plugins=[
- SaveFilesAsArtifactsPlugin(), # 自動保存プラグイン
- ],
- )
「これでインプットしたファイルは保存できるし、他のエージェントもファイルを参照できる」←そう確信していましたが、落とし穴がありました
発生した問題:ファイル名から内容を「創作」するAI
運用を開始して間もなく、ユーザーから「アップロードした内容と、AIの分析結果が全く噛み合っていない」という指摘を受けました。
ログを確認すると、エージェントは確かに動いているものの、ファイルの中身とは無関係な「それっぽい内容」を出力していました。つまり、ファイル名というわずかな手がかりから、AIが内容を勝手に捏造(ハルシネーション)していたのです。
最も厄介な点:ローカルでは再現しない
このバグの最大の問題は、ローカル開発環境(adk web)では正常に動作するという点です。
| 環境 | 動作状況 | 原因 |
| ローカル | 正常 ✅ | アップロードファイルをローカルの一時領域から直接参照できるため。 |
| Cloud (検証環境) | 異常 ❌ | ファイルはGCSにあるが、エージェントが中身を「読む」権限(ツール)を持っていない。 |
検証環境では、エージェントは「ファイルが存在すること」は認識していますが、中身にアクセスできません。その結果、ファイル名から推測して回答を生成してしまっていたのです。
原因:Artifactsの「書く」と「読む」は別物
ADKにおけるArtifactsの扱いは、保存と読み込みでインターフェースが明確に分かれています。
| 役割 | 使用する手段 |
| GCSにArtifactとして保存する | SaveFilesAsArtifactsPlugin |
| エージェントがArtifactを読み込む | load_artifacts ツール(← これが必要!) |
SaveFilesAsArtifactsPlugin を入れただけでは「書き込み」しかできません。エージェントが内容を理解するためには、明示的に load_artifacts ツールを渡す必要があります。
解決策:ツールの追加とプロンプトの修正
この問題を解決するために、以下の2ステップの修正を行いました。
1. エージェントのツールリストに load_artifacts を追加
ファイルを扱う可能性のあるすべてのエージェントに、ツールをインポートして渡します。
- # sub_agent.py
- from google.adk.tools import load_artifacts
- # 修正後
- a_agent = Agent(
- name=”a_agent_name”,
- app = App(
- model=os.getenv(“MODEL_NAME”),
- instruction=A_AGENT_INSTRUCTION,
- tools=[save_to_state, search_datastore, load_artifacts], # load_artifactsを追加
- ),
- )
2. Instruction(プロンプト)でツールの使用を明示
ツールを渡すだけでなく、「最初にこれを使え」と指示を出すのが確実です。
- # A_AGENT_INSTRUCTION.py
- ### 【利用可能なツール】
- * `save_to_state` stateにデータを保存するためのヘルパー関数です。
- * `load_artifacts` : ユーザーがアップロードした報告書や関連マニュアル、画像データをCloud Storageから取得します。# 利用可能なツールにload_artifactsを追加
なぜハルシネーション(幻覚)が起きたのか
load_artifacts がない状態でも、session.state にはファイル名などのメタデータだけは保存されるように実装していました。
- {
- “artifacts”: [
- {
- “type”: “document”,
- “file_name”: “0000年度_〇〇報告書.pdf”,
- “summary”: “”
- }
- ]
- }
後続のエージェントはこの file_name しか見えません。LLMは非常に「親切」なので、情報が足りない場合に「情報がない」と答えるのではなく、ファイル名から推測して「中身を埋めてしまう」ことがあります。これがハルシネーションの正体です。
まとめ:同じミスを防ぐためのチェックリスト
- 保存と読み込みはセットで考える:
SaveFilesAsArtifactsPluginを使うなら、必ずload_artifactsもセットで導入しましょう。 - ローカルの挙動を過信しない: ADK webで動いても、本番(GCS経由)で動かないケースは多々あります。
- 「情報の欠落」はハルシネーションを招く: エラーが出ない時こそ、AIが勝手に嘘をついていないか警戒が必要です。
- プロンプトで手順を指定する: ツールを定義するだけでなく、使用するタイミングをInstructionに明記するのがベストプラクティスです。
便利なプラグインがあるがゆえの「思い込み」が生んだミスでしたが、ADKの仕様を深く理解する良い機会となりました。
最後まで読んでいただきありがとうございました。この記事が、Google ADKでのエージェント開発におけるトラブル解決の参考になれば幸いです。