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?

Function Calling(ツール呼び出し)をする会話型エージェントの構築 入門

0
Posted at

Function Calling(ツール呼び出し)をする会話型エージェントの構築

国立大学の情報工学科4年です。AIの研究室に所属しており、卒業研究で社会課題に対してAI、LLM、マルチエージェントといったものを用いて解決手法を実験・検証し、Webアプリケーションにまで仕上げたいと考えています。これまでテーマ選定に向け論文を読んできましたが、今回は実際にそれを実現する面にフォーカスした学習過程を投稿させていただきます。『LLMのプロンプトエンジニアリング GitHub Copilotを生んだ開発者が教える生成AIアプリケーション開発』(オライリー・ジャパン)を読み、その内容をもとに落とし込んだ理解と実装を記述しています。

Python3の仮想環境を構築

python3 -m venv venv

Python3の仮想環境を有効化

source venv/bin/activate

ライブラリのインストール

pip install openai

OpenAI Platformで取得したAPIキーを設定

export OPENAI_API_KEY="sk-〇〇〇〇〇〇〇〇〇〇〇〇"

プログラム実行

python3 conversational_agent.py

会話型エージェントのプログラム

import random,json
from openai import OpenAI
from openai.types.chat import ChatCompletionMessage

def get_room_temp():
    return str(random.randint(60,80))

def set_room_temp(temp):
    return "DONE"

def process_messages(client,messages):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        tools=tools,
    )
    response_message = response.choices[0].message

    messages.append(response_message)

    if response_message.tool_calls:

        for tool_call in response_message.tool_calls:
            function_name = tool_call.function.name
            function_to_call = available_functions[function_name]
            function_args = json.loads(tool_call.function.arguments)
            function_response = function_to_call(**function_args)

            messages.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response,
                }
            )
    return messages

def run_conversation(client):
    messages = [
        {
            "role": "system",
            "content": "あなたは、役に立つサーモスタットアシスタントです",
        }
    ]
    while True:
        user_input = input(">>")
        if user_input == "":
            break
        messages.append(
            {
                "role": "user",
                  "content": user_input,
            }
        )
        while True:
            new_messages = process_messages(client,messages)
            # messages = new_messages

            last_message = new_messages[-1]
            if not isinstance(last_message, ChatCompletionMessage):
                continue
            if last_message.content is not None:
                print(last_message.content)
                if last_message.tool_calls is None:
                    break
    return messages

tools = [
    {
        "type": "function",
        "function": {
            "name": "get_room_temp",
            "description": "華氏で部屋の温度を取得",
        },
    },
    {
        "type": "function",
        "function": {
            "name": "set_room_temp",
            "description": "華氏で部屋の温度を設定",
            "parameters": {
                "type": "object",
                "properties": {
                    "temp": {
                        "type": "integer",
                        "description": "華氏での望ましい部屋の温度",
                    },
                },
                "required": ["temp"],
            },
        },
    }
]

available_functions = {
    "get_room_temp": get_room_temp,
    "set_room_temp": set_room_temp,
}

client = OpenAI()
run_conversation(client)

会話型エージェント(LLMアプリケーション)との会話

get_room_temp()を呼び出す

スクリーンショット_2026-06-04_10.31.33.png

ユーザー:「部屋の温度を教えて」とメッセージをアプリケーションに送る

→ アプリケーション:ユーザーメッセージを追加し、プロンプトを作成。LLMに送る。

→ LLM:get_room_temp() を補完。アプリケーションに送る。

→ アプリケーション:ツール呼び出しを解析。LLMが出力した関数を呼び出し、ツールを呼び出す(ツール評価のリクエスト) 

→ ツール:リクエストされた処理を実行(ツール評価のレスポンス)。数値(温度)をアプリケーションに返す。 

→ アプリケーション:プロンプトにツール呼び出しを追加。LLMに送る。 

→ LLM:アシスタントメッセージ(「部屋の温度は71°Fです。」)を補完。 アプリケーションに送る。

→ アプリケーション:スレッドにアシスタントメッセージを追加。ユーザーにアシスタントメッセージ(「部屋の温度は71°Fです。」)を送る。

set_room_temp()を呼び出す

スクリーンショット_2026-06-04_9.35.40.png

ツールを呼ぶべきでない質問

スクリーンショット_2026-06-04_9.37.39.png

ツールを呼ばずに、普通のLLM回答になる。

境界ケース

LLMが正しく判断できるか試す

スクリーンショット_2026-06-04_10.00.50.png

気づき

スクリーンショット_2026-06-04_10.31.33.png

さっき部屋の温度を68度に変更したのに、部屋の温度が71度になってしまった。原因は、get_room_temp()関数で乱数を返してるから。

def get_room_temp():
    return str(random.randint(60,80))

ここから学んだことは、「LLM ≠ 記憶」ということ。LLMは会話履歴は持てる。でも、”アプリケーションの状態”は別で管理する必要がある。

自分の研究におけるマルチエージェントでも

  • 過去の議論
  • 信頼度
  • 参照データ

をどこかに保存する必要がある。

つまり、

ツール呼び出し

状態管理

エージェント

という流れになる。調べた結果、AIエージェント設計での重要な考え方だと知った。

アプリケーションで温度を保存するために、ツール定義部分を変更

room_temp = 72

def get_room_temp():
    return str(room_temp)

def set_room_temp(temp):
    global room_temp
    room_temp = temp
    return "DONE"

これで再度確認。

スクリーンショット_2026-06-04_10.57.35.png

温度がアプリケーションで保持されてることを確認!

修正後のプログラム

import random,json
from openai import OpenAI
from openai.types.chat import ChatCompletionMessage

#ツール定義
room_temp = 72

def get_room_temp():
    return str(room_temp)

def set_room_temp(temp):
    global room_temp
    room_temp = temp
    return "DONE"

#メッセージ処理機能
def process_messages(client,messages):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages,
        tools=tools,
    )
    response_message = response.choices[0].message

    messages.append(response_message)

    if response_message.tool_calls:

        for tool_call in response_message.tool_calls:
            function_name = tool_call.function.name
            function_to_call = available_functions[function_name]
            function_args = json.loads(tool_call.function.arguments)
            function_response = function_to_call(**function_args)

            messages.append(
                {
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": function_name,
                    "content": function_response,
                }
            )
    return messages

def run_conversation(client):
    messages = [
        {
            "role": "system",
            "content": "あなたは、役に立つサーモスタットアシスタントです",
        }
    ]
    while True:
        user_input = input(">>")
        if user_input == "":
            break
        messages.append(
            {
                "role": "user",
                  "content": user_input,
            }
        )
        while True:
            new_messages = process_messages(client,messages)
            # messages = new_messages

            last_message = new_messages[-1]
            if not isinstance(last_message, ChatCompletionMessage):
                continue
            if last_message.content is not None:
                print(last_message.content)
                if last_message.tool_calls is None:
                    break
    return messages

#OpenAIがプロンプトでツールの関数を表現できるようにJSONスキーマでツールを定義
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_room_temp",
            "description": "華氏で部屋の温度を取得",
        },
    },
    {
        "type": "function",
        "function": {
            "name": "set_room_temp",
            "description": "華氏で部屋の温度を設定",
            "parameters": {
                "type": "object",
                "properties": {
                    "temp": {
                        "type": "integer",
                        "description": "華氏での望ましい部屋の温度",
                    },
                },
                "required": ["temp"],
            },
        },
    }
]
#OpenAIがツール呼び出しを処理できるように関数をPythonで定義
available_functions = {
    "get_room_temp": get_room_temp,
    "set_room_temp": set_room_temp,
}

client = OpenAI()
run_conversation(client)

OpenAIプラットフォームのトークン消費は、4.99 Credit baranceのまま。モデル「gpt-4o-mini」はコストが低いらしい。今回の会話型エージェントの仕組みを学ぶためのプログラム程度なら十分。

スクリーンショット 2026-06-04 11.08.48.png

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?