【Python × Langchain × Gemini】AI Agent の関数実行を試してみた
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 以外でも使用できるため、より柔軟なツール選択が可能だということが分かりました。
以下参考↓
天気を教えてくれるアプリを作ってみた(完成形)
/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 を作成
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 に実行してもらう関数を作成
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 インスタンスを生成
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 として登録
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
タイプでエージェントを生成
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
お天気エージェント呼び出し関数を定義
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
実行コマンド
-
仮想環境を作成して有効化します:
python -m venv venv && source venv/bin/activate
-
.envファイルを作成して、自身の Gemini APIキーを設定します:
GEMINI_API_KEY=YOUR_API_KEY
-
必要なパッケージをインストール:
pip install -r requirements.txt
-
実行結果
% 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 の魅力に触れることができます。ご興味のある方は、試してみてください!
Discussion