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?

LangChain OpenWeatherMap

Last updated at Posted at 2025-01-04

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.参考

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?