Gemini APIの構成的関数呼び出しでマルチホップQAを試す
Gemini APIのドキュメントを読んでいたところ、「構成的関数呼び出し(compositional function calling)」という機能があることに気がついた。この機能を使うと、LLMが関数を順番に呼び出しながら、段階的に複雑な要求を処理できる。たとえば「現在地の気温」を尋ねられた場合、まず現在地を取得する関数を呼び出し、その結果を用いて天気を取得する関数を実行する、といった流れを自動で組み立ててくれる。
似たようなことはResponses APIでも実現できるが、Geminiの構成的関数呼び出しでは呼び出しの連鎖をより自動的かつシンプルに扱えるように見える。 つまり、アプリ側で明示的なループ制御や状態管理を書く必要がほとんどなく、少ないコードでマルチステップの推論を実現できる。
そこで今回は、この機能を使ってマルチホップQAを解くことを試みる。マルチホップQAとは、複数の情報源や文脈を段階的に推論して答えを導く質問応答のことである。たとえば「ルーヴル美術館が所在する都市の市長の名前」という質問なら、
- まず「ルーヴル美術館がある都市=パリ」であることを特定し、
- 次に「パリの市長」を調べる、
という二段階の推論が必要になる。ちなみに、この例は日本語のマルチホップ QA データセットであるJEMHopQAの論文から取っている。
この記事では、Geminiと検索API(Tavily)を組み合わせて、このようなマルチホップQAを簡単に実装できるかを試してみる。
準備
まず、必要なパッケージをインストールする。検索にはTavilyを使用する。
pip install -q google-genai tavily-python
実装
次に実装を示す。特別な設定はなく、search関数をツールとして登録しているだけだが、Geminiが自動的に関数呼び出しを行ってくれる。
import os from google import genai from google.genai import types from tavily import TavilyClient # TavilyClientの用意 tavily_client = TavilyClient(api_key="") def search(query: str) -> str: """Perform a web search and return the relevant context.""" print(f"クエリ: {query}") context = tavily_client.get_search_context(query=query) return context # Geminiのクライアントを用意 client = genai.Client(api_key="") config = types.GenerateContentConfig( tools=[search], ) # リクエスト content = "ルーヴル美術館が所在する都市の市長の名前は?" response = client.models.generate_content( model="gemini-2.5-flash", contents=content, config=config, ) # 出力の表示 print(f"回答 : {response.text}")
「ルーヴル美術館が所在する都市の市長の名前は?」という質問を実行すると、Geminiは次のように関数を順に呼び出した。
クエリ: 都市 ルーヴル美術館 クエリ: パリ市長の名前 回答 : ルーヴル美術館が所在する都市、パリの市長はアンヌ・イダルゴ氏です。
最初に「ルーヴル美術館がある都市」を検索し、その結果「パリ」であると判断。次に「パリ市長の名前」を検索し、最終的に「アンヌ・イダルゴ」と導いている。Mayors of Europeによると、実行時点ではこの回答は正確だった。
まとめ
この記事では、構成的関数呼び出しを使ってマルチホップQAを解けるかを試した。今回の例のようにWeb検索をするだけなら、Responses API組み込みのweb_searchツールを使って実現することもできるが、自前の関数を呼び出すときに簡潔に実装できそうな点が魅力といえる。