Zenn
🦜

【Python × Langchain × Gemini】AI Agent の関数実行を試してみた

2025/03/31に公開

dotD で Web エンジニアをしている奥山です。今回は、LangChain で Gemini の AI Agent を作成して、関数を実行させる際に遭遇した課題と、その解決策について説明します。

Python のコードで AI の活用を検証するために、無料で使用できる Gemini を使いたいと思いました。しかし、Gemini では、使用する予定だった OPENAI_FUNCTIONS タイプの AI Agent が使用できませんでした。

OpenAI と Gemini の違い

OpenAI は、多くの開発者が利用するメジャーな AI モデルで、従量課金制となっています。Gemini は Google が提供する AI モデルで、ある程度までは無料で使用できるので、手元で簡単なアプリ制作を試すくらいであれば Gemini で十分です。そのため、今回は Gemini を選択しました。

OpenAI Functions とは

OPENAI_FUNCTIONS は、OpenAI の API を使用して関数呼び出しを可能にする機能です。これにより、単なるテキスト生成を超えて、AI モデルが自身で推論して、関数呼び出し、外部データベースへのアクセス、外部 API の呼び出し等、より高度なタスクを実行することが可能となります。

Gemini のインスタンスで OPENAI_FUNCTIONS は使えない

Gemini をインスタンス化して Agent を作成する場合、OpenAI ライブラリの機能を使用するOPENAI_FUNCTIONSタイプの Agent では、活用したかった関数呼び出し(Function Calling)機能が使用できません。

Gemini で利用できる Agent タイプ

OPENAI_FUNCTIONS は OpenAI の関数呼び出し機能を活用しており、特定の OpenAI モデルがサポートしている場合に使用できます。つまり、Gemini では使用できないのです。
一方、ZERO_SHOT_REACT_DESCRIPTION という Agent タイプがあり、こちらは OpenAI 以外でも使用できるため、より柔軟なツール選択が可能だということが分かりました。

以下参考↓

https://www.mattari-benkyo-note.com/2023/04/05/langchain_zero-shot-react-description/

天気を教えてくれるアプリを作ってみた(完成形)

/src/weather_agent.py
"""Gemini と LangChain を使用したお天気 Agent の実装"""
import os
from typing import Dict, Any
import sqlite3
from dotenv import load_dotenv
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain.agents import AgentType, initialize_agent
from langchain.tools import Tool

# 環境変数をロード
load_dotenv()

def setup_database():
    """weather テーブルを使用して SQLite データベースを初期化"""
    conn = sqlite3.connect("weather.db")
    c = conn.cursor()
    c.execute("""
        CREATE TABLE IF NOT EXISTS weather
        (id INTEGER PRIMARY KEY AUTOINCREMENT,
         location TEXT,
         result TEXT)
    """)
    conn.commit()
    conn.close()

def get_weather(location: str) -> str:
    """特定の場所の天気情報を取得"""
    # 天気取得 API を呼び出す(ここでは簡易的に"晴れ"固定で返す)
    return f"{location}の天気は晴れです。"

def save_to_db(result: str) -> None:
    """天気の結果をデータベースに保存"""
    conn = sqlite3.connect("weather.db")
    c = conn.cursor()
    location = result.split(" ")[0]
    c.execute("INSERT INTO weather (location, result) VALUES (?, ?)", (location, result))
    conn.commit()
    conn.close()

def create_weather_agent():
    """お天気 Agent を初期化"""
    # 環境変数から API キーを取得
    api_key = os.getenv("GEMINI_API_KEY")
    if not api_key:
        raise ValueError("GEMINI_API_KEY environment variable is not set")

    # API キーを使用して LLM インスタンスを作成
    llm = ChatGoogleGenerativeAI(
        model="gemini-1.5-pro",
        temperature=0,
        google_api_key=api_key
    )

    # ツールを定義
    tools = [
        Tool(
            name="Weather",
            func=get_weather,
            description="天気を知りたい場所の天気情報を取得します。入力: 場所の名前(例: 東京)"
        ),
        Tool(
            name="SaveToDB",
            func=save_to_db,
            description="天気情報をデータベースに保存します。入力: 保存したい天気情報の文字列(例: 東京の天気は晴れです)"
        )
    ]

    # エージェントを生成
    agent = initialize_agent(
        tools,
        llm,
        agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
        verbose=True,
        handle_parsing_errors=True,
        max_iterations=3,  # 無限ループを防ぐ
        return_intermediate_steps=True
    )

    return agent
/main.py
"""お天気 Agent のメイン script"""
from src.weather_agent import get_weather_info

def main():
    """お天気 Agent の例を実行"""
    try:
        # 天気情報を取得して保存
        response = get_weather_info("東京")
        print("Response:", response)
    except Exception as e:
        print(f"Error occurred: {e}")

if __name__ == "__main__":
    main()
/.env
GEMINI_API_KEY="YOUR_API_KEY"
/requirements.txt
pytest>=7.4.0
black>=23.7.0
flake8>=6.1.0
mypy>=1.5.0
langchain>=0.1.0
google-generativeai>=0.3.0
openai>=1.3.0
python-dotenv>=1.0.0

結果を保存する SQLite BD を作成

/src/weather_agent.py
def setup_database():
    """weather テーブルを使用して SQLite データベースを初期化"""
    conn = sqlite3.connect("weather.db")
    c = conn.cursor()
    c.execute("""
        CREATE TABLE IF NOT EXISTS weather
        (id INTEGER PRIMARY KEY AUTOINCREMENT,
         location TEXT,
         result TEXT)
    """)
    conn.commit()
    conn.close()

Agent に実行してもらう関数を作成

/src/weather_agent.py

def get_weather(location: str) -> str:
    """特定の場所の天気情報を取得"""
    # 天気取得 API を呼び出す(ここでは簡易的に"晴れ"固定で返す)
    return f"{location}の天気は晴れです。"

def save_to_db(result: str) -> None:
    """天気の結果をデータベースに保存"""
    conn = sqlite3.connect("weather.db")
    c = conn.cursor()
    # '東京の天気は晴れです。' から '東京' を抽出
    location = result.split('の天気')[0]
    c.execute("INSERT INTO weather (location, result) VALUES (?, ?)", (location, result))
    conn.commit()
    conn.close()

Gemini の LLM インスタンスを生成

/src/weather_agent.py
import os
from langchain_google_genai import ChatGoogleGenerativeAI

def create_weather_agent():
    """お天気 Agent を初期化"""
    # 環境変数から API キーを取得
    api_key = os.getenv("GEMINI_API_KEY")
    if not api_key:
        raise ValueError("GEMINI_API_KEY environment variable is not set")

    # API キーを使用して LLM インスタンスを作成
    llm = ChatGoogleGenerativeAI(
        model="gemini-1.5-pro",
        temperature=0,
        google_api_key=api_key
    )

関数をエージェントが使用する Tool として登録

/src/weather_agent.py
from langchain.tools import Tool

    # ツールを定義
    tools = [
        Tool(
            name="Weather",
            func=get_weather,
            description="天気を知りたい場所の天気情報を取得します。入力: 場所の名前(例: 東京)"
        ),
        Tool(
            name="SaveToDB",
            func=save_to_db,
            description="天気情報をデータベースに保存します。入力: 保存したい天気情報の文字列(例: 東京の天気は晴れです)"
        )
    ]

ZERO_SHOT_REACT_DESCRIPTION タイプでエージェントを生成

/src/weather_agent.py
from langchain.agents import AgentType, initialize_agent
from langchain.tools import Tool

    # エージェントを生成
    agent = initialize_agent(
        tools,
        llm,
        agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
        verbose=True,
        handle_parsing_errors=True,
        max_iterations=3,  # 無限ループを防ぐ
        return_intermediate_steps=True
    )

    return agent

お天気エージェント呼び出し関数を定義

/src/weather_agent.py
def get_weather_info(location: str) -> Dict[str, Any]:
    """天気情報を取得し、データベースに保存"""
    setup_database()
    agent = create_weather_agent()
    prompt = f"""あなたは次の2つのツールを使って天気情報を処理するエージェントです:
1. Weather: 場所を入力すると天気情報を返します
2. SaveToDB: 天気情報の文字列を入力するとデータベースに保存します

以下のタスクを順番に実行してください:
1. Weather ツールを使用して{location}の天気を取得してください
2. 取得した天気情報(例: 東京の天気は晴れです)をそのままSaveToDBツールに渡してデータベースに保存してください
3. 各ステップの結果を確認してください

必ず両方のツールを使用し、結果を確認してください。"""
    
    response = agent({"input": prompt})
    return response

実行コマンド

  1. 仮想環境を作成して有効化します:

    python -m venv venv && source venv/bin/activate
    
  2. .envファイルを作成して、自身の Gemini APIキーを設定します:

    GEMINI_API_KEY=YOUR_API_KEY
    
  3. 必要なパッケージをインストール:

    pip install -r requirements.txt
    
  4. 実行結果

% python main.py
/Users/sayuri/Documents/code/sukugiru-p/src/weather_agent.py:70: LangChainDeprecationWarning: LangChain agents will continue to be supported, but it is recommended for new use cases to be built with LangGraph. LangGraph offers a more flexible and full-featured framework for building agents, including support for tool-calling, persistence of state, and human-in-the-loop workflows. For details, refer to the `LangGraph documentation <https://langchain-ai.github.io/langgraph/>`_ as well as guides for `Migrating from AgentExecutor <https://python.langchain.com/docs/how_to/migrate_agent/>`_ and LangGraph's `Pre-built ReAct agent <https://langchain-ai.github.io/langgraph/how-tos/create-react-agent/>`_.
  agent = initialize_agent(
/Users/sayuri/Documents/code/sukugiru-p/src/weather_agent.py:97: LangChainDeprecationWarning: The method `Chain.__call__` was deprecated in langchain 0.1.0 and will be removed in 1.0. Use :meth:`~invoke` instead.
  response = agent({"input": prompt})


> Entering new AgentExecutor chain...
Thought: I need to get the weather in Tokyo using the Weather tool, then save that information to the database using the SaveToDB tool.

Action: Weather
Action Input: 東京
Observation: 東京の天気は晴れです。
Thought:Question: あなたは次の2つのツールを使って天気情報を処理するエージェントです:
1. Weather: 場所を入力すると天気情報を返します
2. SaveToDB: 天気情報の文字列を入力するとデータベースに保存します

以下のタスクを順番に実行してください:
1. Weather ツールを使用して東京の天気を取得してください
2. 取得した天気情報(例: 東京の天気は晴れです)をそのままSaveToDBツールに渡してデータベースに保存してください
3. 各ステップの結果を確認してください

必ず両方のツールを使用し、結果を確認してください。
Thought: I need to get the weather in Tokyo using the Weather tool, then save that information to the database using the SaveToDB tool.

Action: Weather
Action Input: 東京
Observation: 東京の天気は晴れです。
Thought:Thought: I have the weather information for Tokyo. Now I need to save it to the database using the SaveToDB tool.

Action: SaveToDB
Action Input: 東京の天気は晴れです。
Observation: None
Thought:

> Finished chain.
Response: {
'input':
    'あなたは次の2つのツールを使って天気情報を処理するエージェントです:\n
    1. Weather: 場所を入力すると天気情報を返します\n
    2. SaveToDB: 天気情報の文字列を入力するとデータベースに保存します\n
    \n
    以下のタスクを順番に実行してください:\n
    1. Weather ツールを使用して東京の天気を取得してください\n
    2. 取得した天気情報(例: 東京の天気は晴れです)をそのままSaveToDBツールに渡してデータベースに保存してください\n
    3. 各ステップの結果を確認してください\n
    \n
    必ず両方のツールを使用し、結果を確認してください。',
'output':
    'Agent stopped due to iteration limit or time limit.',
'intermediate_steps':
    [(AgentAction(
        tool='Weather',
        tool_input='東京',
        log='Thought:
            I need to get the weather in Tokyo using the Weather tool,
            then save that information to the database using the SaveToDB tool.\n
        \n
        Action: Weather\n
        Action Input: 東京'
        ), '東京の天気は晴れです。'),
    (AgentAction(
        tool='Weather',
        tool_input='東京',
        log='Question:
            あなたは次の2つのツールを使って天気情報を処理するエージェントです:\n
                1. Weather: 場所を入力すると天気情報を返します\n
                2. SaveToDB: 天気情報の文字列を入力するとデータベースに保存します\n
                \n
            以下のタスクを順番に実行してください:\n
                1. Weather ツールを使用して東京の天気を取得してください\n
                2. 取得した天気情報(例: 東京の天気は晴れです)をそのままSaveToDBツールに渡してデータベースに保存してください\n
                3. 各ステップの結果を確認してください\n
                \n
            必ず両方のツールを使用し、結果を確認してください。\n
            Thought: I need to get the weather in Tokyo using the Weather tool,
            then save that information to the database using the SaveToDB tool.\n
            \n
        Action: Weather\n
        Action Input: 東京'
    ), '東京の天気は晴れです。'),
    (AgentAction(
        tool='SaveToDB',
        tool_input='東京の天気は晴れです。',
        log='Thought:
            I have the weather information for Tokyo.
            Now I need to save it to the database using the SaveToDB tool.\n
        \n
        Action: SaveToDB\n
        Action Input: 東京の天気は晴れです。'),
     None)]}

DB に保存されているか確認

% sqlite3 -header weather.db "SELECT * FROM weather;"
id|location|result
1|東京|東京の天気は晴れです。

まとめ

ZERO_SHOT_REACT_DESCRIPTION を使用することで、Gemini の AI Agent に関数実行を指示して実行することができました。これにより、無料枠のある Gemini を使用して、AI Agent の魅力に触れることができます。ご興味のある方は、試してみてください!

dotD Tech Blog

Discussion

ログインするとコメントできます