OpenWeatherMapのAPIを使ってLLMに天気を聞く方法を記述します。
参考までに、MacGPTで、ChatGPT o1-miniに「東京の天気はどうですか?」と聞くとこんな感じの回答でした。
申し訳ありませんが、リアルタイムの天気情報にはアクセスできません。
最新の天気予報については、天気予報サイトやアプリをご利用ください。
おまけとして、気象庁API(非公式)で取得した東京の情報を使ったツールの作り方も記載しておきます
環境
Python 3.12.7
openai 1.59.3
langchain-openai 0.1.25
langchain 0.2.16
langchain-core 0.2.41
langchain-community 0.2.17
langgraph 0.2.26
langgraph-checkpoint 1.0.12
langsmith 0.1.147
pyowm 3.3.0
0.準備
1.OpenWeatherMap APIにアクセスして、ユーザー登録をします。
2.取得したAPIキーを、.envファイルに追記します
.env
# OpenWeatherMap API key
OPENWEATHERMAP_API_KEY = xxxxxxxxxxxxx
python
import os
from os.path import join, dirname, abspath
from dotenv import load_dotenv
dir_path = dirname(abspath("__file__"))
dotenv_path = join(dir_path, '../[your directory]/.env')
load_dotenv(dotenv_path, verbose=True)
#print(os.environ['OPENAI_API_KEY'])
#print(os.environ["OPENWEATHERMAP_API_KEY"])
1.OpenWeatherMapWrapper
以下公式ドキュメントに従って実施してみます
1. pyowmのインストールが必要です
# Please install it with `pip install pyowm`
%pip install pyowm
#Successfully installed PySocks-1.7.1 geojson-2.5.0 pyowm-3.3.0
2.環境変数の準備
環境変数を設定する必要があります:
API キーを OPENWEATHERMAP_API_KEY 環境変数に保存します
python
import os
from langchain_community.utilities import OpenWeatherMapAPIWrapper
# .envに記述しない場合
#os.environ["OPENWEATHERMAP_API_KEY"] = "your openweathermap api key"
weather = OpenWeatherMapAPIWrapper()
3.試験実行
東京
python
weather_data = weather.run("Tokyo,JP")
print(weather_data)
In Tokyo,JP, the current weather is as follows:
Detailed status: scattered clouds
Wind speed: 2.68 m/s, direction: 223°
Humidity: 41%
Temperature:
- Current: 6.3°C
- High: 7.59°C
- Low: 4.77°C
- Feels like: 4.3°C
Rain: {}
Heat index: None
Cloud cover: 48%
ロンドン
python
weather_data = weather.run("London,GB")
print(weather_data)
In London,GB, the current weather is as follows:
Detailed status: overcast clouds
Wind speed: 2.57 m/s, direction: 90°
Humidity: 90%
Temperature:
- Current: 2.27°C
- High: 3.13°C
- Low: 0.34°C
- Feels like: -0.4°C
Rain: {}
Heat index: None
Cloud cover: 100%
3.OpenWeatherMap with LangChain
LangChain公式によると簡単に使えるように記載があった
しかしながら、公式に記載のサンプルで利用するように記載がある、initialize_agentは
deprecatedの様なので、代わりに、create_react_agentを使った方法で実施する
LangChainDeprecationWarning:
The function `initialize_agent` was deprecated in LangChain 0.1.0 and will be removed in 1.0.
Use Use new agent constructor methods like create_react_agent, create_json_agent, create_structured_chat_agent, etc. instead.
agent_chain = initialize_agent(
python
import os
# LangChainDeprecationWarning:
# The function `initialize_agent` was deprecated in LangChain 0.1.0 and will be removed in 1.0.
#from langchain.agents import AgentType, initialize_agent, load_tools
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langgraph.prebuilt import create_react_agent
from langchain_openai import OpenAI
#os.environ["OPENAI_API_KEY"] = ""
#os.environ["OPENWEATHERMAP_API_KEY"] = ""
from langchain.agents import load_tools
owm_tools = load_tools(["openweathermap-api"])
llm = ChatOpenAI(temperature=0,model="gpt-4o-mini")
# プロンプトの定義
owm_prompt = ChatPromptTemplate.from_messages(
[('system','与えられたinputに従って天気の関数を呼び出してください',),
('placeholder', '{messages}'),])
owm_agent = create_react_agent(
model=llm,
tools=owm_tools,
state_modifier=owm_prompt
)
result = owm_agent.invoke({"messages":"東京の天気はどうですか?"})
print(result['messages'][-1].content)
東京の現在の天気は以下の通りです:
- 詳細な天候状況: くもり
- 風速: 2.33 m/s(方向: 262°)
- 湿度: 41%
- 温度:
- 現在: 6.1°C
- 最高: 7.02°C
- 最低: 4.77°C
- 体感温度: 4.35°C
- 雨: なし
- 雲のカバー: 55%
明日についても聞いてみる
result = owm_agent.invoke({"messages":"東京の明日の天気はどうですか?"})
print(result['messages'][-1].content)
現在の東京の天気は、曇りで気温は5.43°Cです。明日の天気についての具体的な情報は提供できませんが、
現在の気温の範囲は最高6.42°C、最低3.22°Cとなっています。風速は1.54 m/sで、湿度は44%です。
4.おまけ:気象庁API(非公式)を使ったツール作成
ツールとするAPIを自作する
python
# -*- coding:utf-8 -*-
import requests
import json
import datetime
from langchain_core.tools import tool
# toolの定義
@tool
def get_tokyo_forecast_weather(location):
"""
指定された地域名に「東京」を含む場合、東京の天気予報を取得してJSON形式で返します。
Args:
location (str): 地域名の文字列(例: "東京", "東京都")
Returns:
str: 天気予報データのJSON文字列。エラーが発生した場合はエラーメッセージを含むJSON。
"""
# 「東京」を含まない場合はエラーメッセージを返す
if "東京" not in location:
return json.dumps({"error": "入力された地域名に「東京」が含まれません。東京以外の天候には答えられません。"}, ensure_ascii=False, indent=4)
location_code = "130000" # 東京の地域コード
try:
# 現在の日付を取得し、フォーマットする
current_date = datetime.datetime.today().strftime("%Y年%m月%d日")
# 気象庁データの取得
url = f"https://www.jma.go.jp/bosai/forecast/data/forecast/{location_code}.json"
response = requests.get(url)
response.raise_for_status() # HTTPエラーが発生した場合例外を発生させる
data_json = response.json()
# 地域名の取得と整形
area_info = data_json[0]["timeSeries"][0]["areas"][0]["area"]["name"]
area = area_info.replace('地方', '')
# 日付の取得とフォーマット
time_defines = data_json[0]["timeSeries"][0]["timeDefines"]
if len(time_defines) < 2:
return json.dumps({"error": "十分な日付データが存在しません。"}, ensure_ascii=False, indent=4)
formatted_dates = [
datetime.datetime.fromisoformat(date_str).strftime("%Y年%m月%d日")
for date_str in time_defines[:2]
]
# 天候情報の取得と整形
weathers = data_json[0]["timeSeries"][0]["areas"][0]["weathers"]
if len(weathers) < 2:
return json.dumps({"error": "十分な天候データが存在しません。"}, ensure_ascii=False, indent=4)
formatted_weathers = [weather.replace('\u3000', ' ') for weather in weathers[:2]]
# 予報データの構築
forecast_data = {
"today": current_date,
"location": area,
"forecast": (
f"{formatted_dates[0]}の天気は「{formatted_weathers[0]}」で、"
f"{formatted_dates[1]}の天気は「{formatted_weathers[1]}」の予報です。"
),
}
return json.dumps(forecast_data, ensure_ascii=False, indent=4)
except requests.exceptions.RequestException as e:
# ネットワーク関連のエラー処理
error_message = f"データ取得中にエラーが発生しました: {e}"
return json.dumps({"error": error_message}, ensure_ascii=False, indent=4)
except (KeyError, IndexError, ValueError) as e:
# データ解析関連のエラー処理
error_message = f"データ解析中にエラーが発生しました: {e}"
return json.dumps({"error": error_message}, ensure_ascii=False, indent=4)
# 使用例
#if __name__ == "__main__":
# 「東京」を含む地域名を入力
# print(get_tokyo_forecast_weather("東京"))
# 「東京都」を含む地域名を入力
# print(get_tokyo_forecast_weather("東京都"))
# 「大阪」を含まない地域名を入力(エラーメッセージが返る)
# print(get_tokyo_forecast_weather("大阪"))
方法1 LangGraph(create_react_agent)
from langchain_core.tools import tool
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
#from langchain_core.output_parsers import StrOutputParser
# プロンプトの定義
weather_prompt = ChatPromptTemplate.from_messages(
[
('system','東京の天気を聞かれたら、天気を取得する関数を呼び出してください',),
('placeholder', '{messages}'), #('placeholder', '{messages}'),
]
)
# エージェントの作成(書き方1)
check_tools=[get_tokyo_forecast_weather]
llm = ChatOpenAI(model="gpt-4o-mini")
weather_agent = create_react_agent(
model=llm,
tools=check_tools,
state_modifier=weather_prompt
)
# エージェントの作成(書き方2)
#weather_agent = create_react_agent(
# model=ChatOpenAI(model='gpt-4o-mini'),
# tools=[get_tokyo_forecast_weather],
# state_modifier=weather_prompt #prompt
#)
# エージェントの実行
response = weather_agent.invoke({'messages': ['東京の天気は?']})
#print(response)
print(response['messages'][-1].content)
# '東京の天気は?'
#=> 東京の天気は、2025年01月04日が「晴れ 夜 くもり」で、2025年01月05日は「晴れ 時々 くもり」の予報です。
# '明日の東京の天気は?'
# => 明日の東京の天気は「晴れ 時々 くもり」の予報です。
# '今日の大阪の天気は?'
# => 申し訳ありませんが、東京以外の地域の天気予報を取得することはできません。東京の天気について知りたい場合はお知らせください。
方法2(非推奨)AgentExecutor(create_tool_calling_agent)
上記に以下の記載があるように非推奨のようです
警告
この実装は基礎となる ReAct 論文に基づいていますが、古いため本番アプリケーションには適していません。より堅牢で機能豊富な実装には、LangGraph ライブラリの create_react_agent 関数を使用することをお勧めします。詳細については、リファレンス ドキュメント を参照してください。
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
# toolの定義
#@tool
#def get_tokyo_forecast_weather(
# 省略
#)
# プロンプトの定義
weather_prompt2 = ChatPromptTemplate.from_messages(
[
('system','東京の天気を聞かれたら、天気を取得する関数を呼び出してください',),
('human', '{input}'), # human input
('placeholder', '{agent_scratchpad}'), # messagesではない
]
)
# エージェントを作成
weather_agent2 = create_tool_calling_agent(ChatOpenAI(model='gpt-4o-mini'), [get_tokyo_forecast_weather], weather_prompt2)
# エージェントを実行
agent_executor = AgentExecutor(agent=weather_agent2, tools=[get_tokyo_forecast_weather])
response2 = agent_executor.invoke({'input': '明日の東京の天気は?'})
print(response2)
# => {'input': '明日の東京の天気は?', 'output': '明日の東京の天気は「晴れ 時々 くもり」の予報です。'}
5.参考