# -*- coding: utf-8 -*- """openai_function_calling_sample_code.ipynb Automatically generated by Colaboratory. Original file is located at https://colab.research.google.com/drive/1FBRyZ2hTn04o_nvNDaZFtroebmN4jiz- # Function Calling について LangChain Agent と比較しながら試してみた こちらの記事のサンプルコードになります:https://qiita.com/yu-Matsu/items/12b686fe4cab343f50b3 ## 必要なライブラリのインストール """ # !pip install openai==0.27.6 # !pip install langchain==0.0.205 """## 一部ライブラリのインポート、APIキーの設定""" import json import os import sys import openai import dotenv dotenv.load_dotenv(".env") openai.api_key = os.environ.get("OPENAI_API_KEY") # print("OPENAI_API_KEY: ", openai.api_key) print("""## 普通にChatGPTに天気を聞いてみる""") def chat_gpt_without_functions(text): response = openai.ChatCompletion.create( model="gpt-3.5-turbo-0613", messages=[ {"role": "user", "content": text}, ] ) content = response["choices"][0]["message"]["content"] print(content) return content print("""# 挨拶は普通に返ってくるが...""") chat_gpt_without_functions("こんにちは") print("""# 天気を聞いても返してくれない""") chat_gpt_without_functions("東京の天気を教えて") print("""## 今回利用する天気を返す関数""") print("""# locationに応じて固定値で天気を返すだけの簡単な関数""") def weather_function(location): match location: case "東京" | "Tokyo": weather = "晴れ" case "大阪" | "Osaka": weather = "曇り" case "北海道" | "Hokkaido": weather = "雪" case _ : weather = "不明" weather_answer = [ {"天気": weather} ] return json.dumps(weather_answer) print("""# 実際に Function callingを動かしてみる""") def chat_gpt_with_function(text): # AIが呼び出せる関数の定義 functions = [ # 何をする関数かについて記述 { "name": "weather", "description": "天気を調べる", "parameters": { "type": "object", "properties": { # location引数についての情報を記述 "location": { "type": "string", "description": "天気を知りたい場所を入力。例: 東京", }, }, "required": ["location"], }, } ] # ユーザーの入力から、Functions Callingが必要かどうか判断する response = openai.ChatCompletion.create( model="gpt-3.5-turbo-0613", messages=[ {"role": "user", "content": text}, ], functions=functions, function_call="auto", ) # Function Callingが必要なければ、そのままAIの回答になる message = response["choices"][0]["message"] # Functions Callingが必要な場合は、messageに関数名と引数を格納されている if message.get("function_call"): print("------function_callの中身------") print(message["function_call"]) print("--------------------------------------") # messageから実行する関数と引数を取得 function_name = message["function_call"]["name"] arguments = json.loads(message["function_call"]["arguments"]) # 関数を実行 if function_name == "weather": function_response = weather_function( location=arguments.get("location"), ) # 関数の実行結果を元にAIの回答を生成 second_response = openai.ChatCompletion.create( model="gpt-3.5-turbo-0613", messages=[ {"role": "user", "content": text}, message, { "role": "function", "name": function_name, "content": function_response, }, ], ) content = "AIの回答: " + second_response.choices[0]["message"]["content"] else: content = "AIの回答: " + message["content"] print(content) return content print("""# 挨拶をした場合は、Functionを呼び出す必要がないと判断される""") chat_gpt_with_function("こんにちは") print("""# 天気を聞いた場合、Functionを呼び出す必要があると判断され、関数名と引数の情報が「function_call」に格納されている""") chat_gpt_with_function("東京の天気を教えて") print("""## LangChain の Agent の場合""") from langchain.llms import OpenAI from langchain.agents import initialize_agent, Tool from langchain.agents.mrkl import prompt def lang_chain_agent(text): llm = OpenAI(model_name='gpt-3.5-turbo-0613') # toolsに利用したいToolを格納する。LangChainで用意されたToolを利用することも出来る。 # 代表的なTool一覧:https://book.st-hakky.com/docs/agents-of-langchain/ tools = [ Tool( name = "Weather", func=weather_function, description="天気を知りたい場所を入力。例: 東京", ) ] # エージェントの準備 agent = initialize_agent( tools, llm, agent="zero-shot-react-description", agent_kwargs=dict(suffix='Answer should be in Japanese.' + prompt.SUFFIX), verbose=True, return_intermediate_steps=True) response = agent({"input": text}) return response print(""" # 東京の天気について質問すると、toolsで用意した「Weather」が利用され、その結果を元にAIの回答が生成されていることが分かる # 動作が安定しない可能性があるため、失敗する場合は何度か実行してみて下さい lang_chain_agent("東京の天気を教えて") """) print("""## LangChain で Function Calling を利用してみる""") from langchain.schema import ( AIMessage, HumanMessage, FunctionMessage ) from langchain.chat_models import ChatOpenAI def lang_chain_with_function_calling(text): # AIが利用する関数の定義 functions = [ # 何をする関数かについて記述 { "name": "weather", "description": "天気を調べる", "parameters": { "type": "object", "properties": { # location引数についての情報を記述 "location": { "type": "string", "description": "天気を知りたい場所を入力。例: 東京", }, }, "required": ["location"], }, } ] # ユーザーの入力をmessagesに格納 messages=[HumanMessage(content=text)] llm=ChatOpenAI(model_name='gpt-3.5-turbo-0613') # ユーザーの入力内容から、Functions Callingが必要かどうか判断する # Function Callingが必要なければ、こちらの結果がAIの回答になる message = llm.predict_messages( messages, functions=functions ) print("==================") print(message) print("==================") # Functions Callingが必要な場合は、additional_kwargsに関数名と引数を格納されている if message.additional_kwargs: # messageから実行する関数と引数を取得 function_name = message.additional_kwargs["function_call"]["name"] arguments = json.loads(message.additional_kwargs["function_call"]["arguments"]) # 関数を実行 function_response = weather_function( location=arguments.get("location"), ) # 実行結果をFunctionMessageとしてmessagesに追加 function_message = FunctionMessage(name=function_name, content=function_response) messages.append(function_message) # FuncitonMessageを元に、AIの回答を取得 second_response = llm.predict_messages( messages=messages, functions=functions ) content = "AIの回答: " + second_response.content else: content = "AIの回答: " + message.content print(content) return content print("""# 挨拶の場合は、contentにAIのレスポンスが格納されており、Functionの情報は含まれていない""") lang_chain_with_function_calling("こんにちは") print("""# 天気を聞いた場合、contentにAIのレスポンスは含まれず、additional_kwgargsに呼び出すFunctionの情報が格納されている""") lang_chain_with_function_calling("東京の天気を教えて") print("""# Agent にも対応""") from langchain.agents import AgentType def lang_chain_agent_with_function_calling(text): llm = ChatOpenAI(model_name='gpt-3.5-turbo-0613') # カスタムツールの登録は従来のAgentと同様 tools = [ Tool( name = "Weather", func=weather_function, description="天気を知りたい場所を入力。例: 東京" ) ] # エージェントの準備 agent = initialize_agent( tools, llm, agent=AgentType.OPENAI_FUNCTIONS, # ここで、AgentType.OPENAI_FUNCTIONSを指定する verbose=True, return_intermediate_steps=True) response = agent({"input": text}) print(response) return response print("""# 挨拶の場合はFunctionが利用されていないことが実行結果(intermediate_steps)から分かる""") lang_chain_agent_with_function_calling("こんにちは") print("""# 天気を聞いた場合、intermediate_stepsにてAIMessageとしてFunctionが呼び出されていることが分かる""") lang_chain_agent_with_function_calling("今日の東京の天気を教えて")