Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Azure OpenAI Service: LLMのゲームチェンジャー "Function C...

Azure OpenAI Service: LLMのゲームチェンジャー "Function Calling" でAIの可能性をさらに引き出そう / AOAI Function Calling

LLMアプリ開発の強力な武器 "Function Calling" の概要、メリット・デメリットをサンプルコードと共に解説しています。

2024/07/19 サイオステクノロジーエンジニアYouTubeチャンネル「現場で役立つAzure神小技10+α 〜生成AI,RAG,コスト削減など旬な技術満載のLT大会〜」の登壇資料です。

LT動画はこちら (2:47:34)
https://www.youtube.com/live/NUu41GQ-G9g?t=10054s

Yoshiaki Mizukura

July 22, 2024
Tweet

More Decks by Yoshiaki Mizukura

Other Decks in Programming

Transcript

  1. ╺ 水倉 良明 - アーキテクト - エンジニア組織のマネジャー - 仕事 ⬞

    クラウドネイティブなアプリケーション開発に従事 ⬞ 今年は特にweb3、生成AI、IoT領域に注力 - 好きなもの: 速いPC 2 About me
  2. 3 単純なChatbotからより高度なLLM活用へ ユーザー 生成AI AIに知識を求める単純なChatbot 例:素のLLMを利用したチャットアプリ Q&A・要約等 ユーザー 生成AI 自社データから知見を得たり、複雑な依頼が可能な対話

    型エージェント、コンシェルジュ 例:社内ナレッジを踏まえた回答、航空券の予約 自社データからの知見・ 高度な依頼 自社データ 外部システム/API 他AIモデル
  3. 4 生成AIのレスポンスはプログラム的に取り扱いづらい ユーザー Azure OpenAI 外部システム/API 他AIモデル 開発プログラム (難) 生成AIのレスポンスを判定

    して適切に処理を組み立てる ╺ 同じリクエストでも生成AIのレスポンスが変わる ╺ メタプロンプトでトライ&エラーを重ねる (相手が人だったら関係破綻する呪いのようなプロンプトの誕生) ╺ どれだけ頑張っても品質に自信が持てない。モデル更新するの怖すぎ - ユーザー:「で、大丈夫なんですよね?」 - エンジニア:「えーと、基本的には大丈夫ですが(略)」 (難) 期待したレスポンス形式を得るための 呪いのようなプロンプト
  4. ╺ 2023年6月 OpenAIがリリース (Azure OpenAIでは翌月から提供開始) ╺ ユーザーのプロンプトに対して、あらかじめ定義した関数を 呼び出すべきかGPTが判断してくれる機能。呼び出す関数 に渡す引数も生成してくれる ╺

    Chat Completions API、Assistants APIで利用可能 - Assistants APIはベータ版 (2024/07/19時点) ╺ 利用可能なモデル:gpt-4*、gpt-3.5* 6 Function Callingとは? 参考:「利用可能なモデル」https://platform.openai.com/docs/guides/function-calling/supported-models
  5. 7 Function Callingとは? ユーザー Azure OpenAI 天気取得API 開発プログラム 天気取得関数 ②天気取得関数の定義とセットで

    「八王子の天気は?」と送る ③ 「『八王子」を引数に天気取得 関数を呼び出してね』(関数に渡 せる引数もJSONで返してくれる) ④ 「八王子」を引数に天気取得関数を 呼び出して結果を取得する ⑤ 「八王子の天気は?」と 天気取得関数の結果を送る ⑥ 「八王子の天気は晴れ時々くもり です」という回答を取得する ① 八王子の天気は? <ポイント整理> • GPTが関数を呼び出すのではなく、関数を呼び出す必要 があるかを判断してくれる • 関数を呼び出す場合は関数に渡す引数データを一緒に生 成してくれる • Function Callingの本質は、自然言語を指定した構造化 データに変換してくれること • ちなみに、LangChainのOpenAI用出力パーサーで同様 のことができるが、Function Callingで機能実現している 晴れ時々くもり
  6. 9 # 天気取得関数 def get_current_weather(location: str, unit: str): # ダミー実装

    return “晴れ。現在の気温36℃" # 関数名から関数を取得するためのdictionary available_functions = { "get_current_weather": get_current_weather } # 関数の定義 tools = [ { "type": "function", "function": { "name": "get_current_weather", "description": "現在の天気を取得します", "parameters": { "type": "object", "properties": { "location": { "type": "string", “description”: “都道府県、都市。例:東京都八王子市", }, "unit": { "type": "string", "enum": ["摂氏", "華氏"], “description”: “気温の単位。指定されたlocationから 推測してください", }, }, "required": ["location", "unit"], }, } } ] 実装: 関数本体と関数定義
  7. 10 実装: AOAIクライアント import json import os from openai import

    AzureOpenAI # AOAIモデルデプロイ名 GPT_MODEL = "gpt4-o-20240513" client = AzureOpenAI( api_version = "2024-02-15-preview", azure_endpoint = os.getenv("OPENAI_ENDPOINT"), api_key = os.getenv("OPENAI_API_KEY") )
  8. 11 messages = [] # システムメッセージ messages.append({"role": "system", "content": "関数にどの値を入力するかについて仮定しないでください。

    ユーザーの要求が曖昧な場合は、明確化を求めてください。"}) # ユーザーメッセージ messages.append({"role": "user", "content": "今日の八王子市の天気は?"}) # 天気取得関数の定義と共にプロンプトをAOAIに送る first_response = client.chat.completions.create( model=GPT_MODEL, messages=messages, tools=tools, tool_choice="auto" ) # アシスタントメッセージ (AOAIからの回答) assistant_message = first_response.choices[0].message # AOAIからの回答をメッセージ配列に追加 messages.append(vars(assistant_message)) AOAIが呼び出してほしい関数 関数に渡す引数 も生成される 実装: プロンプトと関数定義をセットでAOAI呼び出し tools:関数定義の配列 tool_choise: 関数呼び出し要 否、呼び出す関数の選択をGPT に任せる (デフォルト”auto”) # AOAI回答の中身 ChatCompletionMessage( content=None, role='assistant', function_call=None, tool_calls=[ ChatCompletionMessageToolCall( id='call_JHD9aLlhoY6kmAUJE0HcEhEF', function=Function( arguments='{"location":"八王子市","unit":"摂氏"}', name='get_current_weather' ), type='function') ] )
  9. 12 # アシスタントメッセージ (AOAIからの回答) assistant_message = first_response.choices[0].message # AOAIからの回答をメッセージ配列に追加 messages.append(vars(assistant_message))

    # 天気取得関数を呼び出してほしいという場合にはtool_callsに値がセットされる tool_calls = assistant_message.tool_calls if tool_calls: for tool_call in tool_calls: # AOAIが実行してほしいと言っている関数名を取得する function_name = tool_call.function.name # AOAIが実行してほしいと言っている関数オブジェクトを取得する function_to_call = available_functions[function_name] # AOAIが生成した関数引数を取得する function_args = json.loads(tool_call.function.arguments) # AOAIが実行してほしいと言っている関数を実行する function_response = function_to_call( location=function_args.get("location"), unit=function_args.get("unit"), ) # 関数の実行結果をメッセージ配列に追加する messages.append( { "tool_call_id": tool_call.id, "role": "tool", "name": function_name, "content": function_response, } ) # 関数の実行結果を含むプロンプトをAOAIに送る second_response = client.chat.completions.create( model=GPT_MODEL, messages=messages ) 実装: AOAIが呼び出してほしい関数を実行する 関数の実行結果 関数の実行
  10. 13 ChatCompletion( id="chatcmpl-9mMupyd35oS0LVgJU3ub7okKYMEvK", choices=[ Choice( finish_reason="stop", index=0, logprobs=None, message=ChatCompletionMessage( content="今日の八王子市の天気は晴れで、気温は36℃です。外出の際は熱中症対策をお忘れなく。",

    role="assistant", function_call=None, tool_calls=None, ), content_filter_results={ "hate": {"filtered": False, "severity": "safe"}, "self_harm": {"filtered": False, "severity": "safe"}, "sexual": {"filtered": False, "severity": "safe"}, "violence": {"filtered": False, "severity": "safe"}, }, ) ], created=1721314859, model="gpt-4o-2024-05-13", object="chat.completion", service_tier=None, system_fingerprint="fp_abc28019ad", usage=CompletionUsage(completion_tokens=38, prompt_tokens=99, total_tokens=137), prompt_filter_results=[ { "prompt_index": 0, "content_filter_results": { "hate": {"filtered": False, "severity": "safe"}, "self_harm": {"filtered": False, "severity": "safe"}, "sexual": {"filtered": False, "severity": "safe"}, "violence": {"filtered": False, "severity": "safe"}, }, } ], ) プロンプトに関数実行結果を含めてAOAIを呼び出した結果
  11. ╺ 関数定義の分、トークン消費が増える。特に複数関数を渡す場合は影響大きくなってくる - シンプルな関数1つでこのボリューム 17 トークン消費量が増える { "type": "function", "function":

    { "name": "get_current_weather", "description": "現在の天気を取得します", "parameters": { "type": "object", "properties": { "location": { "type": "string", “description”: “都道府県、都市。例:東京都八王子市", }, "unit": { "type": "string", "enum": ["摂氏", "華氏"], "description": "使用する気温の単位。指定されたlocationから推測してください", }, }, "required": ["location", "unit"], }, } }
  12. ╺ Function Callingを2段階にして、最終的に使用する関数の関数定義のみを送る 18 トークン消費量への対策 参考サンプルコード: https://github.com/MaurerKrisztian/two-step-llm-tool-call Azure OpenAI 開発プログラム

    ① 利用可能な関数名の配列を引数に受け取る関数 (tool_descriptor) の関数定義と共にFunction Callingリクエスト ② 1つまたは複数の関数名を返す ③ 取得した1つまたは複数の関数定義と共にFunction Callingリクエスト ④ 関数の引数をJSON型で生成して返す <1回目のFunction Calling> <2回目のFunction Calling> <システムメッセージのイメージ> toolを使用する前にtool_descriptor toolを使用し てtoolをリクエストする必要があります。 重要:jsonスキーマを持っていないtoolを呼び出さ ないでください。 ※ tool_descriptor が定義する関数名やシステムメッセ ージは適宜調整が必要です
  13. ╺ Parallel Function Calling - gpt-4o や、gpt-3.5-turbo等で利用可能 - parallel_tool_callsで設定可能。デフォルト true。無効化したい場合は明示的にfalseを指

    定する必要あり 19 1回のターンで複数の関数を呼び出す 参考: 「利用可能なモデル」https://platform.openai.com/docs/guides/function-calling/supported-models
  14. 20 1回のターンで複数の関数を呼び出す # アシスタントメッセージ (AOAIからの回答) assistant_message = first_response.choices[0].message # AOAIからの回答をメッセージ配列に追加

    messages.append(vars(assistant_message)) # 天気取得関数を呼び出してほしいという場合にはtool_callsに値がセットされる tool_calls = assistant_message.tool_calls if tool_calls: for tool_call in tool_calls: # AOAIが実行してほしいと言っている関数名を取得する function_name = tool_call.function.name # AOAIが実行してほしいと言っている関数オブジェクトを取得する function_to_call = available_functions[function_name] # AOAIが生成した関数引数を取得する function_args = json.loads(tool_call.function.arguments) # AOAIが実行してほしいと言っている関数を実行する function_response = function_to_call( location=function_args.get("location"), unit=function_args.get("unit"), ) # 関数の実行結果をメッセージ配列に追加する messages.append( { "tool_call_id": tool_call.id, "role": "tool", "name": function_name, "content": function_response, } ) # 全ての関数の実行結果を含むプロンプトをAOAIに送る second_response = client.chat.completions.create( model=GPT_MODEL, messages=messages ) 呼び出す必要のある関数が複数の場合、複 数返ってくる。異なる関数はもちろん、同じ関 数で引数違いの場合もまとめて返ってくる 例1:「相模原市と八王子市の今の天気は?」 ① 相模原市を引数にした天気取得関数 ② 八王子市を引数にした天気取得関数 例2:「株式会社Aの株価と為替レートは?」 ① 株式会社Aを引数に株価取得関数 ② USドルと円を引数に為替レート取得関数 全ての関数の実行結果と共にプロンプトを送ると それらをもとに回答してくれる
  15. 1. GPTによって生成された関数呼び出しを検証する 2. 関数は信頼されたデータ・ツールを使用する 3. 関数は最小権限の原則とする 4. 関数のもたらす影響を考慮して注意深く機能を検討する (外部システム、DBへの変更、通知の送信など) 5.

    関数呼び出し前にユーザー確認ステップを入れる 21 「責任あるAI」のための設計考慮ポイント 参考: https://techcommunity.microsoft.com/t5/ai-azure-ai-services-blog/function-calling-is-now-available-in-azure- openai-service/ba-p/3879241