Spaces:
Runtime error
Runtime error
| # -*- 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("今日の東京の天気を教えて") | |