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へ保存してくれます。

Python
  1. # agent.py
  2. from google.adk.apps import App
  3. from google.adk.plugins.save_files_as_artifacts_plugin import SaveFilesAsArtifactsPlugin
  4. app = App(
  5.     name=”my_agent_app”,
  6.     root_agent=root_agent,
  7.     plugins=[
  8.         SaveFilesAsArtifactsPlugin(), # 自動保存プラグイン
  9.     ],
  10. )

「これでインプットしたファイルは保存できるし、他のエージェントもファイルを参照できる」←そう確信していましたが、落とし穴がありました

発生した問題:ファイル名から内容を「創作」するAI

運用を開始して間もなく、ユーザーから「アップロードした内容と、AIの分析結果が全く噛み合っていない」という指摘を受けました。

ログを確認すると、エージェントは確かに動いているものの、ファイルの中身とは無関係な「それっぽい内容」を出力していました。つまり、ファイル名というわずかな手がかりから、AIが内容を勝手に捏造(ハルシネーション)していたのです。

最も厄介な点:ローカルでは再現しない

このバグの最大の問題は、ローカル開発環境(adk web)では正常に動作するという点です。

環境 動作状況 原因
ローカル  正常 ✅ アップロードファイルをローカルの一時領域から直接参照できるため。
Cloud (検証環境) 異常 ❌ ファイルはGCSにあるが、エージェントが中身を「読む」権限(ツール)を持っていない。

検証環境では、エージェントは「ファイルが存在すること」は認識していますが、中身にアクセスできません。その結果、ファイル名から推測して回答を生成してしまっていたのです。

原因:Artifactsの「書く」と「読む」は別物

ADKにおけるArtifactsの扱いは、保存と読み込みでインターフェースが明確に分かれています。

役割 使用する手段
GCSにArtifactとして保存する SaveFilesAsArtifactsPlugin
エージェントがArtifactを読み込む load_artifacts ツール(← これが必要!)

SaveFilesAsArtifactsPlugin を入れただけでは「書き込み」しかできません。エージェントが内容を理解するためには、明示的に load_artifacts ツールを渡す必要があります。

解決策:ツールの追加とプロンプトの修正

この問題を解決するために、以下の2ステップの修正を行いました。

1. エージェントのツールリストに load_artifacts を追加

ファイルを扱う可能性のあるすべてのエージェントに、ツールをインポートして渡します。

Python
  1. # sub_agent.py
  2. from google.adk.tools import load_artifacts
  3. # 修正後
  4. a_agent = Agent(
  5.     name=”a_agent_name”,
  6.     app = App(
  7.       model=os.getenv(“MODEL_NAME”),
  8.       instruction=A_AGENT_INSTRUCTION,
  9.       tools=[save_to_state, search_datastore, load_artifacts], # load_artifactsを追加
  10.     ),
  11. )

2. Instruction(プロンプト)でツールの使用を明示

ツールを渡すだけでなく、「最初にこれを使え」と指示を出すのが確実です。

Python
  1. # A_AGENT_INSTRUCTION.py
  2. ###  【利用可能なツール】
  3. *    `save_to_state` stateにデータを保存するためのヘルパー関数です。
  4. *    `load_artifacts` : ユーザーがアップロードした報告書や関連マニュアル、画像データをCloud Storageから取得します。# 利用可能なツールにload_artifactsを追加

なぜハルシネーション(幻覚)が起きたのか

load_artifacts がない状態でも、session.state にはファイル名などのメタデータだけは保存されるように実装していました。

JSON
  1. {
  2.   “artifacts”: [
  3.     {
  4.       “type”: “document”,
  5.       “file_name”: “0000年度_〇〇報告書.pdf”,
  6.       “summary”: “”
  7.     }
  8.   ]
  9. }

後続のエージェントはこの file_name しか見えません。LLMは非常に「親切」なので、情報が足りない場合に「情報がない」と答えるのではなく、ファイル名から推測して「中身を埋めてしまう」ことがあります。これがハルシネーションの正体です。

まとめ:同じミスを防ぐためのチェックリスト

  1. 保存と読み込みはセットで考える: SaveFilesAsArtifactsPlugin を使うなら、必ず load_artifacts もセットで導入しましょう。
  2. ローカルの挙動を過信しない: ADK webで動いても、本番(GCS経由)で動かないケースは多々あります。
  3. 「情報の欠落」はハルシネーションを招く: エラーが出ない時こそ、AIが勝手に嘘をついていないか警戒が必要です。
  4. プロンプトで手順を指定する: ツールを定義するだけでなく、使用するタイミングをInstructionに明記するのがベストプラクティスです。

便利なプラグインがあるがゆえの「思い込み」が生んだミスでしたが、ADKの仕様を深く理解する良い機会となりました。


最後まで読んでいただきありがとうございました。この記事が、Google ADKでのエージェント開発におけるトラブル解決の参考になれば幸いです。