💻

OpenAI の Function Calling を使って Microsoft Graph の Search API を呼び出す

2023/07/03に公開

はじめに

OpenAI の 2023/06/13 のアップデートで Function Calling の機能が搭載されました。Azure OpenAI Service ではまだのようですがすぐにこちらでも実装されるでしょう。 Function Calling についてはすでにいろいろな情報が出ているのでここでは詳しく触れませんが、簡単にいえば、任意の関数 (Web API を含む) を呼び出すためのパラメーターを生成し、また結果を渡すことで回答を得ることができる機能です。大事なのは、OpenAI 自身は関数の呼び出しは行わないので、Web API などの呼び出しは自前で実装する必要があるということです。これまでも、同様のことをプロンプトを駆使して行うことができたのですが、Function Calling ではより簡単にできるようになったということになります。

説明するより動くものを見たほうがいいと思うので早速やっていきましょう。今回は、Function Calling の呼び出し先として Microsoft Graph の Search API を使用し、Power Automate のフローから呼び出すようにします。

実装方法

全体像は以下のようになります。

Web API を実行するアクションが 3 つありますが、それぞれ以下のようなことをしています。

  • OpenAI の Function Calling を実行して Microsoft Search API を実行するためのパラメーターを作成する
  • 作成したパラメーターを指定して Microsoft Search API を実行して検索結果を得る
  • Microsoft Search API の検索結果を指定して OpenAI から回答を得る

「OpenAI を呼び出す 1」アクション

https://api.openai.com/v1/chat/completions に POST 要求を投げます。

要求の JSON は以下のような感じになります。functions 以下の内容は JSON スキーマになっていて、これにしたがって JSON が返却されます。

{
  "model": "gpt-3.5-turbo-0613",
  "messages": [
    {
      "role": "user",
      "content": "@{triggerBody()['text']}"
    }
  ],
  "functions": [
    {
      "name": "microsoft_search_api",
      "description": "Microsoft Search API",
      "parameters": {
        "type": "object",
        "properties": {
          "requests": {
            "type": "object",
            "properties": {
              "entityTypes": {
                "type": "array",
                "description": "検索の対象にするリソースの種類。不明な場合はすべての項目を含めます。",
                "items": {
                  "type": "string",
                  "enum": [
                    "site",
                    "list",
                    "listItem",
                    "drive",
                    "driveItem",
                    "message",
                    "event"
                  ]
                }
              },
              "query": {
                "type": "object",
                "properties": {
                  "queryString": {
                    "type": "string",
                    "description": "検索キーワード。半角スペース区切り。"
                  }
                }
              }
            }
          }
        }
      }
    }
  ],
  "function_call": "auto"
}

結果として以下のような JSON が返却されます。name が呼び出す関数名、arguments がパラメーターになります。

{
  "id": "chatcmpl-7YCG...",
  "object": "chat.completion",
  "created": 1688384659,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "function_call": {
          "name": "microsoft_search_api",
          "arguments": "{\n  \"requests\": [\n    {\n      \"entityTypes\": [\"driveItem\"],\n      \"query\": {\n        \"queryString\": \"karamem0\"\n      }\n    }\n  ]\n}"
        }
      },
      "finish_reason": "function_call"
    }
  ],
  "usage": {
    "prompt_tokens": 103,
    "completion_tokens": 46,
    "total_tokens": 149
  }
}

「Microsoft Search を呼び出す」アクション

HTTP with Azure AD アクションを使って Microsoft Graph を実行しています。これに関しては状況により HTTP アクションを使ってください。

結果として以下のような JSON が返却されます。

{
  "value": [
    {
      "searchTerms": [
        "karamem0"
      ],
      "hitsContainers": [
        {
          "hits": [
            {
              "hitId": "0122...",
              "rank": 1,
              "summary": "",
              "resource": {
                "@odata.type": "#microsoft.graph.driveItem",
                "size": 13979,
                "fileSystemInfo": {
                  "createdDateTime": "2023-03-24T00:33:11Z",
                  "lastModifiedDateTime": "2023-03-24T00:33:12Z"
                },
                "listItem": {
                  "@odata.type": "#microsoft.graph.listItem",
                  "fields": {},
                  "id": "e6dd..."
                },
                "id": "0122...",
                "createdBy": {
                  "user": {
                    "displayName": "0#.f",
                    "email": "..."
                  }
                },
                "createdDateTime": "2023-03-24T00:33:11Z",
                "lastModifiedBy": {
                  "user": {
                    "displayName": "0#.f",
                    "email": "..."
                  }
                },
                "lastModifiedDateTime": "2023-03-24T00:33:12Z",
                "name": "Welcome.fluid",
                "parentReference": {
                  "driveId": "b!WP...",
                  "id": "0122...",
                  "sharepointIds": {
                    "listId": "dc5c...",
                    "listItemId": "4",
                    "listItemUniqueId": "e6dd...."
                  },
                  "siteId": "..."
                },
                "webUrl": "https://example.sharepoint.com/contentstorage/CSP_999bf058-c20f-47f7-8e36-d1f58f1e5fe2/ドキュメント ライブラリ/LoopAppData/Welcome.fluid"
              }
            },
            ...
          ],
          "total": 3,
          "moreResultsAvailable": false
        }
      ]
    }
  ],
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(microsoft.graph.searchResponse)"
}

「OpenAI を呼び出す 2」アクション

再び https://api.openai.com/v1/chat/completions に POST 要求を投げます。前回の内容に加えて、関数の結果も含めるようにします。

要求の JSON は以下のようになります。

{
  "model": "gpt-3.5-turbo-0613",
  "messages": [
    {
      "role": "user",
      "content": "@{triggerBody()['text']}"
    },
    {
      "role": "function",
      "content": "@{body('Microsoft_Search_を呼び出す')}",
      "name": "microsoft_search"
    }
  ],
  "functions": [
    {
      "name": "microsoft_search_api",
      "description": "Microsoft Search API",
      "parameters": {
        "type": "object",
        "properties": {
          "requests": {
            "type": "object",
            "properties": {
              "entityTypes": {
                "type": "array",
                "description": "検索の対象にするリソースの種類。不明な場合はすべての項目を含めます。",
                "items": {
                  "type": "string",
                  "enum": [
                    "site",
                    "list",
                    "listItem",
                    "drive",
                    "driveItem",
                    "message",
                    "event"
                  ]
                }
              },
              "query": {
                "type": "object",
                "properties": {
                  "queryString": {
                    "type": "string",
                    "description": "検索キーワード。半角スペース区切り。"
                  }
                }
              }
            }
          }
        }
      }
    }
  ]
}

結果として回答が得られます。いい感じですね!

{
  "id": "chatcmpl-7YCG...",
  "object": "chat.completion",
  "created": 1688384662,
  "model": "gpt-3.5-turbo-0613",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "以下のドキュメントが見つかりました:\n\n1. [Welcome.fluid](https://example.sharepoint.com/contentstorage/CSP_999bf058-c20f-47f7-8e36-d1f58f1e5fe2/ドキュメントライブラリ/LoopAppData/Welcome.fluid)\n2. [Get Inspired.fluid](https://karamem0.sharepoint.com/contentstorage/CSP_999bf058-c20f-47f7-8e36-d1f58f1e5fe2/ドキュメントライブラリ/LoopAppData/Get%20Inspired.fluid)\n3. [Check the Basics.fluid](https://karamem0.sharepoint.com/contentstorage/CSP_999bf058-c20f-47f7-8e36-d1f58f1e5fe2/ドキュメントライブラリ/LoopAppData/Check%20the%20Basics.fluid)\n\n詳細な情報については、リンクをクリックしてください。"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 1715,
    "completion_tokens": 243,
    "total_tokens": 1958
  }
}

おわりに

OpenAI の API はデータが学習に使われることがあるため、実際にこれを運用に使うことはできませんが、Azure OpenAI Service でも利用できるようになれば、かなり簡単に社内データ検索を ChatGPT を使って実装できるのではないかと思います。

Discussion