langchain-function-calling / openai_function_calling_sample_code.py
shigeru saito
init
04b2d94
raw
history blame
10.1 kB
# -*- 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("今日の東京の天気を教えて")