チュートリアル: Gemini API を使用した関数呼び出し


ai.google.dev で表示 Google Colab で実行 GitHub でソースを表示

関数呼び出しを使用してカスタム関数を定義し、Gemini に渡します。モデルはこれらの関数を直接呼び出すのではなく、関数名と推奨される引数を指定する構造化データ出力を生成します。この出力により外部 API を呼び出せるようになり、結果として得られた API 出力をモデルに取り込むことができます。これにより、より包括的なクエリ レスポンスが可能になります。関数呼び出しにより、LLM はリアルタイムの情報や、データベース、顧客管理システム、ドキュメント リポジトリなどのさまざまなサービスとやり取りできるようになり、関連性の高いコンテキストに応じた回答を提供する能力が強化されます。Gemini モデルに関数の説明を提供できます。クエリを処理できるよう、関数を呼び出して結果を送り返すよう、モデルから求められる場合があります。

まだ理解していない場合は、関数呼び出しの概要で詳細をご確認ください。

セットアップ

Python SDK をインストールする

Gemini API 用の Python SDK は、google-generativeai パッケージに含まれています。pip を使用して依存関係をインストールします。

pip install -U -q google-generativeai

パッケージをインポートする

必要なパッケージをインポートします。

import pathlib
import textwrap
import time

import google.generativeai as genai

from IPython import display
from IPython.display import Markdown

def to_markdown(text):
  text = text.replace('•', '  *')
  return Markdown(textwrap.indent(text, '> ', predicate=lambda _: True))

API キーを設定する

Gemini API を使用するには、まず API キーを取得する必要があります。まだ作成していない場合は、Google AI Studio でワンクリックでキーを作成できます。

API キーを取得する

Colab で、左側のパネルにある [↘] の下にあるシークレット マネージャーにキーを追加します。API_KEY という名前を付けます。

API キーを取得したら、SDK に渡します。作成する方法は次の 2 つです。

  • キーを GOOGLE_API_KEY 環境変数に設定します(SDK は自動的にそこからキーを取得します)。
  • 鍵を genai.configure(api_key=...) に渡す
try:
    # Used to securely store your API key
    from google.colab import userdata

    # Or use `os.getenv('API_KEY')` to fetch an environment variable.
    GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')
except ImportError:
    import os
    GOOGLE_API_KEY = os.environ['GOOGLE_API_KEY']

genai.configure(api_key=GOOGLE_API_KEY)

関数呼び出しの基本

関数呼び出しを使用するには、GenerativeModel の作成時に関数のリストを tools パラメータに渡します。このモデルは、関数名、docstring、パラメータ、パラメータ型のアノテーションを使用して、その関数がプロンプトに対して最適に回答するかどうかを判断します。

def multiply(a:float, b:float):
    """returns a * b."""
    return a*b

model = genai.GenerativeModel(model_name='gemini-1.0-pro',
                              tools=[multiply])

model
genai.GenerativeModel(
    model_name='models/gemini-1.0-pro',
    generation_config={},
    safety_settings={},
    tools=<google.generativeai.types.content_types.FunctionLibrary object at 0x10e73fe90>,
)

チャット インターフェースを介して関数呼び出しを使用することをおすすめします。これは、関数呼び出しがユーザーとモデルの間のやり取りをキャプチャするため、マルチターン チャットに自然に収まるためです。Python SDK の ChatSession は、会話履歴が自動で処理されるため、チャットに適したインターフェースです。また、パラメータ enable_automatic_function_calling を使用すると、関数の呼び出しがさらに簡単になります。

chat = model.start_chat(enable_automatic_function_calling=True)

自動関数呼び出しを有効にすると、chat.send_message はモデルから要求された場合に自動的に関数を呼び出します。

単に正解を含むテキスト レスポンスを返すように見えます。

response = chat.send_message('I have 57 cats, each owns 44 mittens, how many mittens is that in total?')
response.text
'The total number of mittens is 2508.'
57*44
2508

チャットの履歴を調べて、会話のフローと、その中で関数呼び出しがどのように統合されているかを確認します。

ChatSession.history プロパティには、ユーザーと Gemini モデル間の会話の時系列レコードが格納されます。会話の各ターンは、次の情報を含む glm.Content オブジェクトで表されます。

  • Role: コンテンツの発信元が「ユーザー」か「モデル」かを識別します。
  • パート: メッセージの個々のコンポーネントを表す glm.Part オブジェクトのリスト。テキストのみのモデルの場合、これらの部分は次のようになります。
    • テキスト: 書式なしテキスト メッセージ。
    • 関数呼び出しglm.FunctionCall): 指定された引数を持つ特定の関数を実行するためのモデルからのリクエスト。
    • 関数のレスポンスglm.FunctionResponse): リクエストされた関数の実行後にユーザーが返す結果。

前述のミトンの計算例では、履歴には次のシーケンスが表示されます。

  1. ユーザー: 手袋の総数について質問します。
  2. モデル: 乗算関数は有用であると判断し、ユーザーに FunctionCall リクエストを送信します。
  3. ユーザー: ChatSession は関数を自動的に実行し(enable_automatic_function_calling が設定されているため)、計算結果とともに FunctionResponse を返します。
  4. モデル: 関数の出力を使用して最終的な回答を定式化し、それをテキスト レスポンスとして提示します。
for content in chat.history:
    part = content.parts[0]
    print(content.role, "->", type(part).to_dict(part))
    print('-'*80)
user -> {'text': 'I have 57 cats, each owns 44 mittens, how many mittens is that in total?'}
--------------------------------------------------------------------------------
model -> {'function_call': {'name': 'multiply', 'args': {'a': 57.0, 'b': 44.0} } }
--------------------------------------------------------------------------------
user -> {'function_response': {'name': 'multiply', 'response': {'result': 2508.0} } }
--------------------------------------------------------------------------------
model -> {'text': 'The total number of mittens is 2508.'}
--------------------------------------------------------------------------------

一般に、状態図は次のようになります。

モデルは常にテキストまたは FunctionCall で応答できます。モデルが FunctionCall を送信した場合、ユーザーは FunctionResponse で応答する必要がある

このモデルは、テキストのレスポンスを返す前に複数の関数呼び出しで応答できます。また、関数呼び出しはテキスト レスポンスの前に来ます。

この処理はすべて自動的に行われますが、より詳細に管理する必要がある場合は、次の方法があります。

  • デフォルトの enable_automatic_function_calling=False のままにして、glm.FunctionCall レスポンスを自分で処理します。
  • または、チャットの履歴も管理する必要がある GenerativeModel.generate_content を使用します。

並列関数呼び出し

前述の基本的な関数呼び出しに加えて、1 回のターンで複数の関数を呼び出すこともできます。このセクションでは、並列関数呼び出しの使用方法の例を示します。

ツールを定義する。

def power_disco_ball(power: bool) -> bool:
    """Powers the spinning disco ball."""
    print(f"Disco ball is {'spinning!' if power else 'stopped.'}")
    return True


def start_music(energetic: bool, loud: bool, bpm: int) -> str:
    """Play some music matching the specified parameters.

    Args:
      energetic: Whether the music is energetic or not.
      loud: Whether the music is loud or not.
      bpm: The beats per minute of the music.

    Returns: The name of the song being played.
    """
    print(f"Starting music! {energetic=} {loud=}, {bpm=}")
    return "Never gonna give you up."


def dim_lights(brightness: float) -> bool:
    """Dim the lights.

    Args:
      brightness: The brightness of the lights, 0.0 is off, 1.0 is full.
    """
    print(f"Lights are now set to {brightness:.0%}")
    return True

次に、指定されたすべてのツールを使用できる命令を使用してモデルを呼び出します。

# Set the model up with tools.
house_fns = [power_disco_ball, start_music, dim_lights]

model = genai.GenerativeModel(model_name="gemini-1.5-pro-latest", tools=house_fns)

# Call the API.
chat = model.start_chat()
response = chat.send_message("Turn this place into a party!")

# Print out each of the function calls requested from this single call.
for part in response.parts:
    if fn := part.function_call:
        args = ", ".join(f"{key}={val}" for key, val in fn.args.items())
        print(f"{fn.name}({args})")
power_disco_ball(power=True)
start_music(energetic=True, loud=True, bpm=120.0)
dim_lights(brightness=0.3)

出力された各結果には、モデルがリクエストした 1 つの関数呼び出しが反映されます。結果を返送するには、リクエストと同じ順序でレスポンスを含めます。

# Simulate the responses from the specified tools.
responses = {
    "power_disco_ball": True,
    "start_music": "Never gonna give you up.",
    "dim_lights": True,
}

# Build the response parts.
response_parts = [
    glm.Part(function_response=glm.FunctionResponse(name=fn, response={"result": val}))
    for fn, val in responses.items()
]

response = chat.send_message(response_parts)
print(response.text)
Let's get this party started! I've turned on the disco ball, started playing some upbeat music, and dimmed the lights. 🎶✨  Get ready to dance! 🕺💃

(省略可)低レベルのアクセス権

Python 関数からのスキーマの自動抽出は、すべての場合で機能しない場合があります。たとえば、ネストされた辞書オブジェクトのフィールドを記述するケースは処理されませんが、API はこれをサポートしています。この API では、次のいずれかのタイプを記述できます。

AllowedType = (int | float | bool | str | list['AllowedType'] | dict[str, AllowedType]

google.ai.generativelanguage クライアント ライブラリを使用すると、低レベルのタイプにアクセスして、すべてを管理できます。

import google.ai.generativelanguage as glm

まず、モデルの _tools 属性の内部を見ると、モデルに渡した関数がどのように記述されているかを確認できます。

def multiply(a:float, b:float):
    """returns a * b."""
    return a*b

model = genai.GenerativeModel(model_name='gemini-1.0-pro',
                             tools=[multiply])

model._tools.to_proto()
[function_declarations {
   name: "multiply"
   description: "returns a * b."
   parameters {
     type_: OBJECT
     properties {
       key: "b"
       value {
         type_: NUMBER
       }
     }
     properties {
       key: "a"
       value {
         type_: NUMBER
       }
     }
     required: "a"
     required: "b"
   }
 }]

API に送信される glm.Tool オブジェクトのリストが返されます。印刷形式に馴染みがないのは、これらが Google の protobuf クラスだからです。各 glm.Tool(この場合は 1)には、関数とその引数を記述する glm.FunctionDeclarations のリストが含まれます。

以下に、glm クラスを使用して記述した同じ乗算関数の宣言を示します。

これらのクラスは API の関数を記述するだけで、関数の実装は含まれていません。そのため、これを使用しても自動関数呼び出しでは機能しませんが、関数には常に実装が必要になるとは限りません。

calculator = glm.Tool(
    function_declarations=[
      glm.FunctionDeclaration(
        name='multiply',
        description="Returns the product of two numbers.",
        parameters=glm.Schema(
            type=glm.Type.OBJECT,
            properties={
                'a':glm.Schema(type=glm.Type.NUMBER),
                'b':glm.Schema(type=glm.Type.NUMBER)
            },
            required=['a','b']
        )
      )
    ])

同様に、これは JSON 互換オブジェクトとして記述できます。

calculator = {'function_declarations': [
      {'name': 'multiply',
       'description': 'Returns the product of two numbers.',
       'parameters': {'type_': 'OBJECT',
       'properties': {
         'a': {'type_': 'NUMBER'},
         'b': {'type_': 'NUMBER'} },
       'required': ['a', 'b']} }]}
glm.Tool(calculator)
function_declarations {
  name: "multiply"
  description: "Returns the product of two numbers."
  parameters {
    type_: OBJECT
    properties {
      key: "b"
      value {
        type_: NUMBER
      }
    }
    properties {
      key: "a"
      value {
        type_: NUMBER
      }
    }
    required: "a"
    required: "b"
  }
}

どちらの場合も、glm.Tool またはツールのリストの表現を

model = genai.GenerativeModel('gemini-pro', tools=calculator)
chat = model.start_chat()

response = chat.send_message(
    f"What's 234551 X 325552 ?",
)

前の例と同様に、モデルは計算機の multiply 関数を呼び出す glm.FunctionCall を返します。

response.candidates
[index: 0
content {
  parts {
    function_call {
      name: "multiply"
      args {
        fields {
          key: "b"
          value {
            number_value: 325552
          }
        }
        fields {
          key: "a"
          value {
            number_value: 234551
          }
        }
      }
    }
  }
  role: "model"
}
finish_reason: STOP
]

自分で関数を実行します。

fc = response.candidates[0].content.parts[0].function_call
assert fc.name == 'multiply'

result = fc.args['a'] * fc.args['b']
result
76358547152.0

結果をモデルに送信して、会話を続けます。

response = chat.send_message(
    glm.Content(
    parts=[glm.Part(
        function_response = glm.FunctionResponse(
          name='multiply',
          response={'result': result}))]))

まとめ

基本的な関数呼び出しは SDK でサポートされています。チャット モードを使用すると、やり取りが自然に行われるので管理しやすくなります。実際に関数を呼び出して結果をモデルに送り返し、テキスト レスポンスを生成する必要があります。