見出し画像

Gemini API の Function Calling を試す

「Gemini API」の「Function Calling」を試したので、まとめました。


1. Function Calling

「Function Calling」は、開発者が事前に関数定義を指定しておくことで、モデルが外部プログラムを呼び出すことを選択できるようにする機能です。

2. Gemini APIの準備

「Google Colab」での「Gemini API」の準備手順は、次のとおりです。

(1) パッケージのインストール。

# パッケージのインストール
!pip install -U -q google-generativeai

(2) 「Google AI Studio」でAPIキーを取得し、シークレットの「GOOGLE_API_KEY」に登録後、以下のセルを実行。

from google.colab import userdata
import google.generativeai as genai

# 環境変数の準備 (左端の鍵アイコンでGOOGLE_API_KEYを設定)
GOOGLE_API_KEY=userdata.get("GOOGLE_API_KEY")
genai.configure(api_key=GOOGLE_API_KEY)

3. Automatic Function Calling

Automatic Function Calling」の手順は、次のとおりです。

(1) 関数の定義。
計算 (加算、減算、乗算、除算) を行う関数を定義します。

def add(a:float, b:float):
    """returns a + b."""
    return a+b

def subtract(a:float, b:float):
    """returns a - b."""
    return a-b

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

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

(2) モデル生成時に関数リストを指定。

# モデル生成時に関数リストを指定
model = genai.GenerativeModel(
    model_name="models/gemini-1.5-flash-latest",
    tools=[add, subtract, multiply, divide]  # Toolsの設定
)
model

モデルは「関数名」「ドキュメント文字列」「パラメータ」「パラメータ型の注釈」から、応答する際に関数が必要かどうかを判断します。

関数のパラメータ型の注釈をAPIが理解できる形式 (glm.FunctionDeclaration) に変換します。 APIはパラメータ型の限られた選択のみをサポートし、「Python SDK」の自動変換はそのサブセットのみをサポートします。

AllowedTypes = int | float | bool | str | list['AllowedTypes'] | dict

(3) チャットの作成。
enable_automatic_function_calling=True で「Automatic Function Calling」を有効化しています。

# チャットの作成
chat = model.start_chat(enable_automatic_function_calling=True)

(4) 計算の利用を促す質問応答。
57x44=2508なので正しいです。

# 質問応答
response = chat.send_message("私は57匹の猫を飼っていて、それぞれが44個のミトンを持っています。ミトンは合計で何個になりますか?")
response.text
57匹の猫がいて、それぞれが44個のミトンを持っている場合、合計で2508個のミトンになります。

(5) 会話履歴の確認。
会話履歴から、会話の流れと関数の使われ方がわかります。

# 会話履歴の確認
for content in chat.history:
    print(content.role, "->", [type(part).to_dict(part) for part in content.parts])
    print('-'*80)
user -> [{'text': '私は57匹の猫を飼っていて、それぞれが44個のミトンを持っています。ミトンは合計で何個になりますか?'}]
--------------------------------------------------------------------------------
model -> [{'function_call': {'name': 'multiply', 'args': {'b': 44.0, 'a': 57.0}}}]
--------------------------------------------------------------------------------
user -> [{'function_response': {'name': 'multiply', 'response': {'result': 2508.0}}}]
--------------------------------------------------------------------------------
model -> [{'text': '57匹の猫がいて、それぞれが44個のミトンを持っている場合、合計で2508個のミトンになります。'}]
--------------------------------------------------------------------------------

会話の各ターンは、次の情報を含むコンポーネント(glm.Content)によって表されます。

・role : コンテンツ発信元 (user or model)
・parts : メッセージに含まれるコンポーネント(glm.Part)のリスト
 ・text : テキストメッセージ。
 ・function calling (glm.FunctionCall) : 指定された引数で特定の関数を実行するためのモデルからのリクエスト。
 ・function response (glm.FunctionResponse) : 要求された関数の実行後にユーザーによって返された結果。

状態遷移は次のとおりです。

4. Manual Function Calling

Manual Function Calling」では、モデルからの glm.FunctionCall リクエストを自分で処理できます。

次の場合に、「Manual Function Calling」になります。

・Chatをenable_automatic_function_calling=False (default) で使用。
・GenerativeModel.generate_content()を使用。

(1) 関数の定義。
次の関数を定義します。

# 気温の取得 (ダミー)
def get_temperature(location: str):
    """get current temperature."""
    if location == "東京":
        return "20度"
    else:
        return "10度"

(2) 関数を辞書で管理。
関数を辞書で管理することで、後で関数名で簡単に検索できるようになります。

# 関数を辞書で管理
functions = {
    "get_temperature": get_temperature,
}

(3) モデルの準備。

# モデルの準備
model = genai.GenerativeModel(
    model_name="models/gemini-1.5-flash-latest",
    tools=functions.values(),
)

(4) 質問応答。
呼び出すべき関数が返されます。「Automatic Function Calling」は有効化されてないため、関数を自分で呼び出す必要があります。

# 関数の利用を促す質問応答
prompt = "現在の東京と大阪の気温は?"
response = model.generate_content(prompt)
response.candidates[0].content.parts
[function_call {
  name: "get_temperature"
  args {
    fields {
      key: "location"
      value {
        string_value: "\346\235\261\344\272\254"
      }
    }
  }
}
, function_call {
  name: "get_temperature"
  args {
    fields {
      key: "location"
      value {
        string_value: "\345\244\247\351\230\252"
      }
    }
  }
}
]

(5) 関数呼び出しと関数レスポンス群の生成。

import google.ai.generativelanguage as glm

# 関数呼び出し
def call_function(function_call, functions):
    function_name = function_call.name
    function_args = function_call.args
    return functions[function_name](**function_args)

# 関数レスポンス群の生成
function_responses = []
for part in response.parts:
    # 関数の使用を選択したかどうかの確認
    if part.function_call:
        # 関数呼び出しの実行
        result = call_function(part.function_call, functions)

        # 関数レスポンスの生成
        function_response = glm.Part(function_response=glm.FunctionResponse(
            name=part.function_call.name, 
            response={"result": result}
        ))
        function_responses.append(function_response)
print(function_responses)
[function_response {
  name: "get_temperature"
  response {
    fields {
      key: "result"
      value {
        string_value: "20\345\272\246"
      }
    }
  }
}
, function_response {
  name: "get_temperature"
  response {
    fields {
      key: "result"
      value {
        string_value: "10\345\272\246"
      }
    }
  }
}
]

(6) 関数呼び出し結果をモデルに渡す。
最後に、関数呼び出し結果と会話履歴を次のgenerate_content()に渡して、モデルから最終的な応答を取得します。

# 会話履歴の作成
messages = [
    {'role':'user',
     'parts': [prompt]},
    {'role':'model',
     'parts': response.candidates[0].content.parts},
    {'role':'user',
     'parts': function_responses}
]

# 質問応答
response = model.generate_content(messages)
print(response.text)
東京は20度、大阪は10度です。



この記事が気に入ったらサポートをしてみませんか?