Nakatatsu Tech Notes

生成AI × AWS × IaC でインフラ構築を自動化するクラウドエンジニアのブログ

AIの活躍範囲を大きく広げる可能性を持つFunction Calling

スクリプトAPI判断でより柔軟に実行するFunction Callingがあります。Function CallingはAIモデルが適切な関数と引数を起動する仕組みです。自然言語で指示することで関数を起動させられます。

動作としてはリフレクションが近いのですが、AIが何を呼び出すか判定する点が特徴です。

Sample

import json
import os

from openai import OpenAI

CHATGPT_MODEL = "gpt-4o"


def save(file_path: str, content: str) -> None:
    with open(file_path, "w") as f:
        f.write(content)


# OpenAI APIキー設定
client = OpenAI(
    api_key=os.environ.get("OPENAI_API_KEY"),
)


# 関数定義
def greet_tanaka() -> str:
    return "いらっしゃい, 田中さん!"


def greet_unknown(name: str) -> str:
    return f"待って、あなた誰?(あなたの名前: {name})"


# Function Callingで登録する関数リスト
functions = [
    {
        "name": "greet_tanaka",
        "description": "田中さんに対して特別な挨拶をする",
        "parameters": {"type": "object", "properties": {}},
    },
    {
        "name": "greet_unknown",
        "description": "田中さん以外の人物に対して、誰かを確認する挨拶をする",
        "parameters": {
            "type": "object",
            "properties": {"name": {"type": "string", "description": "挨拶する相手の名前"}},
            "required": ["name"],
        },
    },
]


def hello(name: str):
    # ユーザーからの指示を送る
    response = client.chat.completions.create(
        model=CHATGPT_MODEL,
        messages=[{"role": "user", "content": f"{name}さんに挨拶して"}],
        functions=functions,
        function_call="auto",
    )

    # モデルの返答を取り出し
    message = response.choices[0].message

    if message.function_call:
        func_name = message.function_call.name
        arguments = json.loads(message.function_call.arguments or "{}")  # argumentsがない場合は空dict

        print("関数が呼び出されました:", func_name)

        # 関数マッピング
        function_map = {
            "greet_tanaka": greet_tanaka,
            "greet_unknown": greet_unknown,
        }

        if func_name in function_map:
            func = function_map[func_name]
            if arguments:
                result = func(**arguments)
            else:
                result = func()
            print("実行結果:", result)
        else:
            print("未知の関数が呼び出されました:", func_name)

    else:
        print("関数呼び出しは提案されませんでした。")


hello("田中")
hello("吉田")

実行結果

> python .\test.py
関数が呼び出されました: greet_tanaka
実行結果: いらっしゃい, 田中さん!
関数が呼び出されました: greet_unknown
実行結果: 待って、あなた誰?(あなたの名前: 吉田さん)

注意点

柔軟性をとても引き上げる仕組みなのですが危険もあります。もし重大な結果(外部送金、ユーザー削除、課金処理など)を持つ関数を登録してしまうとモデルの提案次第でそれらが実行されうるのです。重大な結果を持つ関数を登録しないか、あるいは必ず実施前に人間の承認を別途必要とするプロセスを追加しておくなどの対策が必須です。