[AI-103 Hands-On] 第2回: File Searchで基本的なRAGを実装する


こんにちは、Lena Nadir Blog 管理人です。

前回は Web Search を使って、Agentの基本的な作成〜Python SDKからの呼び出しまでを確認しました。

第2回では、Agentに独自のナレッジベースを持たせる「File Search」 を扱います。Web Searchが「外部の最新情報」を対象にするのに対し、File Searchは「自組織が保有する非公開ドキュメント」を対象にする点が対照的です。

2026年8月更新: Microsoft Foundryの最新名称に合わせて表記を見直しました。


1. 実装シナリオ(Case Study)

今回は、架空の自動車ディーラー「Velan Motors」が扱う車種「アストラ」シリーズの 取扱説明書(PDF) をナレッジベースとして持つ、ディーラースタッフ向け車両説明サポートAgentを作ります。アーキテクチャー図は以下の通りです。

File Search RAGのアーキテクチャ図。ユーザーがPythonからAI-Agentにプロンプトを送信し、AgentがFile Search ToolにSearch Queryを渡す。File Search Toolは事前にPDFがアップロード・インデックス化されたVector StoreからRetrieved Data Chunksを取得し、Agentが情報を抽出してユーザーに応答する

File Search RAGのアーキテクチャ: PDFはVector Storeにアップロード・インデックス化され、AgentはFile Search Tool経由でVector Storeを検索する

1.1. ドキュメント(取扱説明書PDF)

ナレッジベースとして、以下6種類のPDF取扱説明書を用意します(3グレード×2世代)。各説明書は「主要諸元」「外装」「内装」「機能装備」「安全装備・快適装備」「保証・アフターサービス」「定期メンテナンス」の7セクションで構成しています。

📝 注記: サンプルPDF(6ファイル)はこの記事のGitHubリポジトリからダウンロードしてください。各PDFの末尾には「本書はLLM(生成AI)によって作成されたフィクションであり、実在の車両・仕様とは一切関係ありません」という注釈を明記しています。

1.2. 対象ファイル一覧(Vector Store)

GradePositioning2026年モデル(現行)2021年モデル(一世代前)
アストラ プライムハイエンドastra-prime-2026.pdfastra-prime-2021.pdf
アストラ コアスタンダードastra-core-2026.pdfastra-core-2021.pdf
アストラ ベースエントリーastra-base-2026.pdfastra-base-2021.pdf

この6ファイルをそのままVector Storeにアップロードし、File Searchの検索対象とします。

  • アップロードした説明書の内容だけを根拠に回答できる。アストラは架空の車種なので、Web上の一般知識で「それらしく」答えてしまっていないか(ハルシネーションの有無)を判別しやすいのがポイント
  • 単一ファイル内のピンポイント検索と、複数ファイルを横断した比較の両方にも対応できる
  • 回答には file_citation で引用元のファイル名を提示できる

2. 事前準備

  • Microsoft Foundry プロジェクト(第1回と共通でOK)
  • Python環境(pip install azure-ai-projects azure-identity)
  • サンプルPDF/ソースコード: 以下のコマンドでgit cloneしてください
git clone https://github.com/lena0520/tech-hands-on-labs.git

3. Foundry PortalでFile Search Toolを設定する

  • 3.1. 第1回で作ったAgent(または新規Agent)の編集画面を開きます。 Tools セクションで File Search を追加します
  • 3.2. Vector Store(ナレッジベースの実体)を新規作成するか、もしくは既存のものをアタッチします
  • 3.3. 6つのPDF(astra-prime-2026.pdf など)をまとめてアップロードします(ドラッグ&ドロップ、またはファイル選択)
  • 3.4. インデックス化(embedding生成)の完了を待ち、ステータスを確認します

3.1. 「Add tools」から「Select a tool」ダイアログが開くので、一覧から File search を選択して Add tool をクリックします。

Agentの編集画面。InstructionsとTools内のAddドロップダウン(File search、Add tools)がハイライトされている

Agentの編集画面。Tools内のAddからFile Searchを追加する

📝 注記: 画面上部の Instructions については、この後の「Instructionsの設定」セクションで詳しく扱います。

3.2.-3.4. 「Attach files」ダイアログで「Create a new index」を選択したまま、6つのPDFをドラッグ&ドロップしてアップロードします。全ファイルのStatusが「Success」になれば、Vector Storeへのインデックス化は完了です。Attach後は、Agentの編集画面で保存(Save)を忘れずに行ってくださいSelect a toolダイアログ。File searchが選択済み(チェック付き)で、右下のAdd toolボタンがハイライトされている

「Select a tool」ダイアログでFile Searchを選択

Attach filesダイアログ。6つのアストラ取扱説明書PDFがすべてStatus「Success」でアップロード済みで、右下のAttachボタンがハイライトされている

6つのPDFをすべてアップロード完了(Status: Success)


4. Instructionsの設定

Instructionsにはまず、「アップロードされた資料の範囲内でのみ回答する」旨を明記します。あわせて「資料に記載がない場合はその旨を答える」といったハルシネーション対策の一文も入れておくと、Responsible AIの観点からも安心感のある設計になります。

さらに「When answering:」以下では、グレード・年式を混同しない回答精度、比較質問での差分要約、そして根拠ファイル名の引用を指示しています。特に引用ルールは、後述の file_citation 検証(5. Playground (Foundry Portal) でテスト、7. 結果を確認する)の土台になります。

Instructionsのテンプレート案 (英語表記):

You are a product support assistant for Velan Motors dealership staff,
specialized in the uploaded Astra owner's manuals (6 PDFs covering 3
grades x 2 model years).

Answer only based on the uploaded manuals. If the answer isn't covered in the
manuals, say so explicitly instead of guessing or relying on general knowledge.

When answering:
- If asked about a specific grade and model year, answer with the exact
  specs from that document — do not mix up different grades or years
- If asked to compare grades or model years, check the relevant documents
  and summarize the differences clearly
- Always cite which manual (file name) each piece of information came from

5. Playground (Foundry Portal) でテスト

Playgroundに以下のような質問を投げ、説明書の内容だけで正確に答えられるかをテストします。

アストラ ベースのシート素材とホイールサイズを教えてください。
アストラの3グレード(2026年モデル)について、価格と内装装備を比較してください。
どれが一番お買い得ですか?
アストラの後継モデルの発売時期は?

Playgroundでの3つのテスト結果。黄色枠が投げた質問、緑枠が回答に付与されたfile_citation(引用元ファイル)。1問目はastra-base-2021.pdf/astra-base-2026.pdfなどを引用してシート素材・ホイールサイズを回答し、2問目はastra-base-2026.pdf/astra-core-2026.pdf/astra-prime-2026.pdfを引用して3グレードの価格・内装装備を表形式で比較、3問目(説明書に存在しない質問)はcitationなしで「取扱説明書には記載されていません」と回答している

Playgroundでの3つのテスト結果(黄色枠:投げた質問、緑枠:回答に付与されたfile_citation〈引用元ファイル〉)

  • 1問目は単一ファイル内のピンポイント検索、2問目は3グレードを横断した比較・要約、3問目は説明書に存在しない質問への耐性確認という、異なる検索パターンをそれぞれ確認します
  • 3問目は説明書に記載がないため、想定通りcitationなしで「記載がない」旨を回答しています

6. Python SDKから同じAgentを呼び出す

  • 第1回と同じ conversation 作成 → responses.create() の流れを流用
  • File Search特有の差分: annotations の種類が file_citation になる点
  • ストリーミングイベントハンドリングは第1回のコードをベースに、citation抽出部分だけ差分として提示

6.1. PythonコードでVector Storeを作成する場合

Foundry Portalで既に6つの説明書PDFをアップロードしてVector Storeを作成済みなら、このセクションはスキップして下さい。Foundry Portalの「Knowledge」タブに表示されているVector Store ID(vs_...)をそのままコピーして

VECTOR_STORE_ID = "vs_..."  # Foundry Portalの「Knowledge」タブで確認したIDをそのまま使う

と代入するだけでOKです。

Foundry Portalを使わず、コードだけでVector Storeを新規作成してPDFをアップロードしたい場合は、以下のコードを使う。

⚠️ 注意: Foundry Portalで作成済みの場合、以下コードの実行は不要です。同一内容のVector Storeが重複して作られるので注意してください。

vector_store = openai.vector_stores.create(name="astra-owners-manuals")
print(f"Vector store created (id: {vector_store.id})")

pdf_files = sorted(MANUALS_DIR.glob("*.pdf"))
print(f"Uploading {len(pdf_files)} manuals...")

for pdf_path in pdf_files:
    with open(pdf_path, "rb") as f:
        openai.vector_stores.files.upload_and_poll(
            vector_store_id=vector_store.id,
            file=f,
        )
    print(f"  uploaded + indexed: {pdf_path.name}")

VECTOR_STORE_ID = vector_store.id

6.2. PythonコードでAgentを定義する場合

Foundry Portalでの手動設定の代わりに、Python SDKだけでAgent自体を作成することもできます。このコードは VECTOR_STORE_ID が(上のいずれかの方法で)既にセットされている前提で動きます。

from azure.ai.projects.models import PromptAgentDefinition, FileSearchTool

agent = project.agents.create_version(
    agent_name=AGENT_NAME,
    definition=PromptAgentDefinition(
        model="gpt-4o",
        instructions=AGENT_INSTRUCTIONS,
        tools=[FileSearchTool(vector_store_ids=[VECTOR_STORE_ID])],
    ),
    description="Answers Velan Motors dealership staff questions using the Astra owner's manuals.",
)
print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})")

Foundry Portalで行った「Tools → Add → File search → Attach files」の操作は、コード上では tools パラメータに集約されています。

  • tools=[FileSearchTool(vector_store_ids=[VECTOR_STORE_ID])]: PromptAgentDefinitiontools はAgentに持たせるツールのリストです。ここに FileSearchTool を渡すとFile Searchが有効になります。vector_store_ids はリスト形式になっており、事前にFoundry Portalまたはコードで作成したVector StoreのID(vs_...)をここで紐づけます。リストなので、複数のVector Storeを同時に指定することも可能です(例: 取扱説明書用とFAQ用でVector Storeを分けて、両方を検索対象にする、など)
  • instructions=AGENT_INSTRUCTIONS: 前段で定義したInstructionsのテンプレートをそのまま渡します
  • project.agents.create_version(agent_name=AGENT_NAME, ...): 指定した名前のAgentに対して新しいバージョンを作成する呼び出しです。Foundry Portalで作ったAgentと同じ設定をコードで再現したい場合や、Agentの定義自体をコードでバージョン管理・CI/CDに載せたい場合に使います

Foundry Portal操作でもこのコードでも、出来上がるのは同じ「File Search Toolが有効なAgent」であり、どちらか一方で設定すれば十分です(両方行うと同名Agentの新しいバージョンが重複して作られるだけなので注意してください)。


7. 結果を確認する

  • file_citation から参照ファイル名・該当箇所を取り出して表示するコード
  • Foundry Portalでのテスト結果と一致するかを確認

8. まとめ

  • Foundry PortalでFile Search ToolとVector Store(ナレッジベース)をノーコードで設定した
  • Instructionsで「アップロード資料に基づく回答」を徹底させた
  • Python SDKから呼び出し、file_citation で参照元を検証した

次回は、LLMのレスポンスをプログラムで扱いやすくする「Structured Outputs(構造化出力)」を扱います。


確認テスト(AI-103形式)

AI-103本番の出題形式(シナリオ設定+最適な選択肢を選ぶ形式)に寄せた3問です。今回の内容の理解度をチェックしてみましょう。


Q1. あなたは、社内のディーラースタッフ向けに、自社が保有する非公開の車両取扱説明書(PDF)だけを根拠に、正確な仕様回答を行うAgentを構築しています。Web上の一般知識に頼らず、アップロード済みドキュメントの範囲内でのみ回答させるために、Agentに追加すべきツールはどれですか。

  • A Web Search
  • B File Search
  • C Code Interpreter
  • D Function Calling
解答を見る

正解: B. File Search

File Searchは、自組織がアップロードした非公開ドキュメントを検索対象にするツールで、「アップロード済み資料の範囲内だけで回答させたい」という要件に合致します。Web Searchは外部の最新Web情報を検索するツールのため、社内限定の取扱説明書のような非公開情報を根拠にする要件には適しません。


Q2. あなたはFile Searchツールを有効化したAgentに、6つのPDF取扱説明書を検索対象として認識させたいと考えています。アップロードしたファイルをEmbedding化し、意味的な検索を可能にする実体として、Foundry Portalであらかじめ作成し、ファイルのアップロード先として指定する必要があるリソースはどれですか。

  • A Conversation
  • B Thread
  • C Vector Store
  • D Fine-tuned Model
解答を見る

正解: C. Vector Store

Vector Storeは、アップロードされたファイルをEmbedding化して格納し、意味的な検索(セマンティック検索)を可能にする実体です。File Searchツールは、この vector_store_ids を参照してアップロード済みドキュメントを検索します。ConversationやThreadは会話の文脈を保持するオブジェクトであり、ファイル検索の実体とは異なります。


Q3. File Searchを使うAgentの回答に、引用元となった取扱説明書のファイル名を含めたいと考えています。Web Searchの url_citation に相当する、File Search利用時にレスポンスのannotationとして返される引用の種類と、そこから実際のファイル名を取得する方法の組み合わせとして正しいものはどれですか。

  • A url_citation が返され、annotationの url属性からそのままファイル名を取得できる
  • B file_citation が返され、annotationの filename属性からそのままファイル名を取得できる
  • C file_citation が返され、annotationの file_id を openai.files.retrieve() に渡してファイル名を取得する
  • D web_search_call というOutput itemから直接ファイル名を取得する
解答を見る

正解: C

File Search利用時、annotationの種類は file_citation になりますが、そこに含まれるのはファイル名そのものではなく file_id です。人が読める形式のファイル名を得るには、openai.files.retrieve(file_id).filename のように、別途ファイル情報を取得する呼び出しが必要です。Web Searchの url_citation はannotationに url を直接含む点が対照的です。


コード一式

この記事で使用したコードは、GitHubリポジトリの azure/ai-103/episode-02-file-search-rag/ に公開しています。

👉 tech-hands-on-labs (GitHub)


💡 本番前に、実力を確認したい方へ

一通り手を動かした後、自分の理解度が試験レベルに達しているかを確認したい方向けに、Udemyで『【2026年版】AI-103 模擬試験集|良問厳選・Azure AI アプリ&エージェント開発 試験対策』を公開しています。

🎟 期間限定クーポン: AI103BLOG1000YENOFF(1,000円オフ、2026/09/08まで) → クーポン適用リンクはこちら


© 2026 Lena Nadir. All rights reserved.