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?

OpenAIのFileSearchToolを組み込む

0
Last updated at Posted at 2026-08-02

FileSearchTool とファイルアップロードを Streamlit に組み込む

OpenAI Agents SDK の Hosted tools にある FileSearchTool を使うと、Vector Store に載せたドキュメントをセマンティック検索し、エージェントがその内容をもとに回答できます。

この記事では、txt ファイルのアップロード → Vector Store への紐付け → FileSearchTool による検索 → 履歴表示 までを、Streamlit アプリ main.py を例に一通り説明します。


完成イメージ

ユーザーが 自分の Apple 株の保有状況 を書いた txtを chat_input に添付し、「私は Apple 株を何株持っていますか?」のように ファイルの中身に関する質問 をします。

コンポーネント 役割
FileSearchTool Vector Store 内のファイルを検索(Hosted)
upload_text_file txt → Files API → Vector Store
Runner.run_streamed エージェント実行 + ストリーミング
SQLiteSession 会話と tool 呼び出し履歴の永続化
render_history 保存済みメッセージをチャット UI に描画

Hosted tools とは

Agents SDK のツールのうち、OpenAI サーバー側で動く組み込みツール が Hosted tools です。

種類 実行場所
Hosted tools OpenAI サーバー WebSearchTool, FileSearchTool, CodeInterpreterTool
Function tools 自分の Python コード @function_tool で包んだ関数

FileSearchTool() を Agent の tools=[...] に渡すだけで、ファイル検索のインフラを自分で用意する必要はありません。検索ロジックは OpenAI 側が実行します。

公式ドキュメント — Hosted tools


Agent の定義 — FileSearchTool を載せる

Vector Store ID は定数として持ち、FileSearchTool に渡します。

from agents import Agent, FileSearchTool, WebSearchTool

VECTOR_STORE_ID = "vs_xxxxxxxx"  # ダッシュボードで作成した ID

agent = Agent(
    name="Assistant",
    instructions="""
    あなたはChatGPTのようなAIアシスタントです。

    あなたは以下のツールにアクセスできます:
    - WebSearchTool: 学習データに含まれない質問が来たときに使用してください。現在や将来の出来事についての質問、または答えが分からないと思ったときは、まずWebで検索してみてください。
    - FileSearchTool: ユーザーが自分自身に関連する質問をした時に、使用できるツール
    """,
    tools=[
        WebSearchTool(),
        FileSearchTool(
            vector_store_ids=[VECTOR_STORE_ID],
            max_num_results=3,
        ),
    ],
)

ポイント

  • vector_store_ids — 検索対象の Vector Store(複数指定可)
  • max_num_results — 返す検索結果の上限
  • instructionsいつ FileSearchTool を使うか を書くと、モデルが tool を選びやすい

Web 検索とファイル検索を両方載せる場合、instructions で使い分けを明示しておくのがおすすめです。

ツール 検索対象 向いている質問
WebSearchTool インターネット 天気、ニュース、最新情報
FileSearchTool Vector Store 内のファイル アップロードしたメモ・個人データ

ファイルのアップロード — Files API + Vector Store

FileSearchTool が検索できるようにするには、ファイルを Vector Store に載せる 必要があります。

  1. client.files.create — ファイル本体を OpenAI にアップロード
  2. client.vector_stores.files.create — その file ID を Vector Store に紐付け
from openai import OpenAI

client = OpenAI()

def upload_text_file(file) -> None:
    with st.chat_message("assistant"):
        with st.status("Analyzing file...") as status:
            uploaded_file = client.files.create(
                file=(file.name, file.getvalue()),
                purpose="user_data",
            )
            status.update(label="Attaching file...")
            client.vector_stores.files.create(
                vector_store_id=VECTOR_STORE_ID,
                file_id=uploaded_file.id,
            )
            status.update(label="File uploaded", state="complete")

注意: Store 作成 API とファイル追加 API は別

やりたいこと API
Vector Store を新規作成 client.vector_stores.create(...)
既存 Store にファイルを追加 client.vector_stores.files.create(vector_store_id=..., file_id=...)

ダッシュボードで Store を作ってある場合は、vector_stores.files.create だけ使えば十分です。vector_stores.createvector_store_id を渡そうとして失敗する、というミスがよくあります。


エージェント実行 — ストリーミングと status 表示

Runner.run_streamed でエージェントを動かし、raw_response_event から進行状況と回答テキストを受け取ります。

from agents import Runner

async def run_agent(message: str) -> str:
    with st.chat_message("assistant"):
        status_container = st.status("", expanded=False)
        text_placeholder = st.empty()
        response = ""

        stream = Runner.run_streamed(agent, message, session=session)
        async for event in stream.stream_events():
            if event.type == "raw_response_event":
                update_status(status_container, event.data.type)
                if event.data.type == "response.output_text.delta":
                    response += event.data.delta
                    text_placeholder.write(response.replace("$", "\\$"))

    return response

ファイル検索中は event.data.type に次のような値が流れます。

def update_status(status_container, event: str) -> None:
    status_messages = {
        "response.file_search_call.in_progress": ("🔍️ Starting file search", "running"),
        "response.file_search_call.searching": ("🔍️ File search in progress", "running"),
        "response.file_search_call.completed": ("✅ File Search Completed", "complete"),
        "response.completed": ("✅ Response Completed", "complete"),
    }

    if event in status_messages:
        label, state = status_messages[event]
        status_container.update(label=label, state=state)
event.data.type UI
response.file_search_call.in_progress ファイル検索開始
response.file_search_call.searching 検索中
response.file_search_call.completed 検索完了
response.output_text.delta 回答テキストのストリーミング

Hosted tool の進行表示は、イベント型を辞書にマップする のがシンプルです。function_tool 名をパースするより、API が返す event.data.type をそのまま使えます。

Web 検索も載せている場合は、response.web_search_call.* を同じ辞書に足すだけです。


実行

web-search toolとfile-search toolを同時に起動させてみる

2026-08-0223.08.50-ezgif.com-video-to-gif-converter.gif


まとめ

  • FileSearchTool(vector_store_ids=[...]) — Vector Store 上のドキュメントを Agent が検索できる
  • アップロードは 2 段階files.createvector_stores.files.create(Store 作成 API と混同しない)

FileSearchTool を載せると、LLM アプリが ユーザーが渡したドキュメント に基づいて答えられるようになります。Web 検索(WebSearchTool)と組み合わせれば、最新情報個人のファイル の両方に触れるチャットエージェントに触れます。


参考リンク

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?