Azure OpenAI on your data で複数の独自データから回答を得る

### はじめに

Azure OpenAI on your data は ChatGPT や GPT-4 といった LLM に独自のデータを追加できるサービスです。  
[過去の記事](https://qiita.com/fsdg-honda/items/06323590ecb8fea204d9)では、Azure OpenAI Studio の ChatGPT プレイグラウンドから、独自データとしてローカルの 1 ファイルをアップロードする形式で動作を確認しました。  
この手順では、BLOB ストレージにあるのは 1 ファイル、Cognitive Search のインデックスも 1 個、ドキュメントも 1 個となっていました。
今回は下記のようなケースで動作を確認します。

- BLOB ストレージに複数のファイルを作成
- Cognitive Search に複数のインデックスを作成

:::note warn
本記事は 2023/6/27 時点の動作確認内容を記載しています。
Azure OpenAI on your data はプレビュー段階にあり、動作が変わる可能性があります。
:::

### 検証データ

[過去の記事](https://qiita.com/fsdg-honda/items/06323590ecb8fea204d9)で利用した架空のオフィスの FAQ を 2 種類作成、別の種類のデータとして、出張精算の FAQ を作成します。  
これらを BLOB ストレージに下記のような形式でアップロードします。

- コンテナー: office-faqs
  - BLOB: faq\_広島.docx
  - BLOB: faq\_大阪.docx
- コンテナー: business-travel
  - BLOB: faq\_出張精算.docx

### Cognitive Search へのインポート

BLOB ストレージの各コンテナーがそれぞれ Cognitive Search の 1 検索インデックスとなるようにデータをインポートします。  
ここでは、Azure portal でデータのインポート ウィザードを使用します。

Azure ポータルで Cognitive Search のリソースを開き、「データのインポート」ボタンを押します。  
「データに接続します」ページでは、データソースに「Azure BLOB ストレージ」を選択し、データソース名を「office-faqs」、接続文字列の指定では「規定の接続を選択します」ボタンから前述の BLOB ストレージを選択し、「office-faqs」コンテナーを選択します。
![スクリーンショット 2023-06-27 154829.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3104149/5b7eda02-cbd7-e3be-cac8-9f9f7f240b65.png)
他はデフォルトのまま次のページに進み、「コグニティブ スキルを追加します (省略可能)」ぺージは今回使用しないのでスキップします。
「対象インデックスをカスタマイズします」ページでは、インデックス名は「office-faqs-index」、フィールド名の「metadata_storage_name」を取得可能とし、他はデフォルトのまま次のページに進みます。
「インデクサーの作成」では、名前を「office-faqs-indexer」とし、「送信」します。
「インデクサー」タブでステータスが成功となるまで待ちます。
![スクリーンショット 2023-06-27 174151.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3104149/3ff1696d-8911-828e-aab1-2c9dbbd743b3.png)
「インデックス」タブから「office-faqs-index」を選択すると、ドキュメントが 2 個作成されていることが確認できます。  
ここで、クエリ文字列を「\*」として「検索」を実行すると、ドキュメントの詳細が確認できます。
![スクリーンショット 2023-06-27 174339.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3104149/4d5d6f42-f43a-ae94-3f22-4d9fdc10699c.png)
同様の手順を、BLOB ストレージの「business-travel」コンテナーについても実施し、「business-travel-index」を作成します。

### Azure OpenAI のデータソースの設定 (ChatGPT プレイグラウンド)

Azure OpenAI Studio の ChatGPT プレイグラウンドから上記で作成した「office-faqs-index」をデータソースとして設定し、回答が得られることを確認してみます。

ChatGPT プレイグラウンド (チャット) の「Add your data (preview)」タブを選択し、「Add a data source」ボタンを押します。  
「Select data source」に「Azure Cognitive Search」、「Azure Cognitive Search サービス」に作成した Cognitive Search リソース、「Azure Cognitive Search インデックス」に「office-faqs-index」を選択し、アカウント使用の同意チェックボックスをチェックして「次へ」ボタンを押します。
![スクリーンショット 2023-06-27 181516.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3104149/15c74620-1dea-efe3-0431-4d2e0cff4a65.png)
「Content data」を「content」のままとし、ファイル名に「metadata_storage_name」を指定して「次へ」を選択、Data Management はそのまま「次へ」を選択し、「保存して閉じる」ボタンを押します。

データソースが追加されましたので、チャットセッションから「office-faqs」の 2 ファイルに共通する質問 (回答は少し異なる) を送信してみます。

<details><summary>faq_大阪.docxのFAQ内容</summary>s

```
オフィスの入退室はどうすればいいですか。
ドアの横にある装置にセキュリティカードをかざしてください。入出時は装置のボタンを押して音が鳴ってからセキュリティカードを通してください。入室時、退出時ともに忘れずかざしてください。3箇所あるドアのいずれも同じ手順となります
```

</details>

<details><summary>faq_広島.docxのFAQ内容</summary>

```
オフィスの入退室はどうすればいいですか。
ドアの横にある装置にセキュリティカードをかざしてください。音が鳴り、ロックが解除されます。入室時、退出時ともに忘れずかざしてください。2箇所あるドアのいずれも同じ手順となります。
```

</details>

下記のように引用元としてはいずれのファイルも含まれています。回答はまとめられていますが、一部の情報は省略されているようです。  
![スクリーンショット 2023-06-27 183947.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3104149/5e2958e8-2d35-26d3-4787-3e5b720ec172.png)

### Azure OpenAI のデータソースの設定 (REST API)

[前回の記事](https://qiita.com/fsdg-honda/items/5807c2850b8c22b348ee#completions-extensions-api-%E3%81%AE%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88)で紹介した、Azure OpenAI の Completions extensions API を使用し、プレイグラウンドと同様、「office-faqs」の 2 ファイルに共通する質問を投げてみます。

リクエストボディの dataSources は下記のように指定します。

```
"dataSources": [
        {
            "type": "AzureCognitiveSearch",
            "parameters": {
                "endpoint": "https://xxx.search.windows.net",
                "key": "xxx",
                "indexName": "office-faqs-index",
                "fieldsMapping": {
                    "filepathField": "metadata_storage_name"
                }
            }
        }
    ],
```

レスポンスを確認すると、tool ロールの content に含まれる JSON は下記のようになりました。  
filepath フィールドにマッピングした「metadata_storage_name」の値が出力されており、2 ファイルとも引用されていることがわかります。

<details><summary>toolロールのcontent</summary>

```
{
  "citations": [
    {
      "content": "FAQ\nオフィスの入退室はどうすればいいですか。\nドアの横にある装置にセキュリティカードをかざしてください。入出時は装置のボタンを押して音が鳴ってからセキュリティカードを通してください。入室時、退出時ともに忘れずかざしてください。3箇所あるドアのいずれも同じ手順となります。\n出張時にセキュリティカードがない場合はどうすればいいですか。\n人事部（高橋）、または山田室長に連絡ください。一時利用のセキュリティカードをお渡しします。\n受付の電話を受けるにはどうすればいいですか。\n近くで鳴っている電話の受話器を取り、「*6」を押してください。\n荷物を発送するにはどうすればいいですか。\n人事部横の棚にある発送伝票や梱包材を使ってください。\nゴミはどこに捨てればよいですか。\n紙ゴミは近くの緑色のゴミ箱に捨ててください。ペットボトルやびん、缶はオフィスの東北角にあるゴミ箱の分類に従って捨ててください。\nゴミの収集日はいつですか。\n毎週水曜日です。\n\n\n\n\n\n\n\n\n",
      "id": null,
      "title": null,
      "filepath": "faq_大阪.docx",
      "url": null,
      "metadata": {
        "chunking": "orignal document size=580. Scores=8.343304 and None.Org Highlight count=106."
      },
      "chunk_id": "0"
    },
    {
      "content": "FAQ\nオフィスの入退室はどうすればいいですか。\nドアの横にある装置にセキュリティカードをかざしてください。音が鳴り、ロックが解除されます。入室時、退出時ともに忘れずかざしてください。2箇所あるドアのいずれも同じ手順となります。\n出張時にセキュリティカードがない場合はどうすればいいですか。\n人事部（中村）に連絡ください。一時利用のセキュリティカードをお渡しします。\n受付の電話を受けるにはどうすればいいですか。\n近くで鳴っている電話の受話器を取り、「*1」を押してください。\n荷物を発送するにはどうすればいいですか。\nコピー機横の棚にある発送伝票や梱包材を使ってください。\nゴミはどこに捨てればよいですか。\n紙ゴミは近くの緑色のゴミ箱に捨ててください。ペットボトルやびん、缶はオフィスの東北角にあるゴミ箱の分類に従って捨ててください。\nゴミの収集日はいつですか。\n毎週火曜日と金曜日の2回です。\n",
      "id": null,
      "title": null,
      "filepath": "faq_広島.docx",
      "url": null,
      "metadata": {
        "chunking": "orignal document size=546. Scores=8.162928 and None.Org Highlight count=102."
      },
      "chunk_id": "0"
    }
  ],
  "intent": "オフィスの入退室はどうすればいいですか。"
}
```

</details>

assistant ロールの content からも 2 ファイルが引用されていますが、内容のまとめ方には偏りがあるように思います。

<details><summary>assistantロールのcontent</summary>

```
[doc1]と[doc2]の情報によると、オフィスの入退室にはセキュリティーカードが必要であり、入室時にはカードをかざして音が鳴るまで待ち、退室時にはカードをかざして音が鳴るまで待つ必要があります。また、[doc1]によると、オフィスの入退室には3か所のドアがあり、それぞれ同じ手順で操作する必要があります。[doc2]によると、オフィスの入退室には中村さんに連絡する必要があります。以上の情報をまとめると、オフィスの入退室にはセキュリティーカードが必要であり、3か所のドアがあり、同じ手順で操作する必要があります。また、中村さんに連絡する必要があるかもしれません。[doc1][doc2]
```

</details>

### 複数のデータソースの設定

リクエストボディの dataSources は配列となっていますので、「office-faqs-index」だけではなく、「business-travel-index」も配列に含めて、先程と同じ質問を投げてみます。  
下記のような形式としています。

```
"dataSources": [
        {
            "type": "AzureCognitiveSearch",
            "parameters": {
                "indexName": "office-faqs-index",
                ...
            }
        },
        {
            "type": "AzureCognitiveSearch",
            "parameters": {
                "indexName": "business-travel-index",
                ...
            }
        }
    ],
```

すると、assistant ロールの content は「入退室に関する情報は、検索結果からは見つかりませんでした。申し訳ありませんが、回答することができません。」となりました。tool ロールの content には「business-travel-index」のドキュメントが格納されています。  
そこで、dataSources の順番を入れ替えると「office-faqs-index」のみの場合と同様の回答を得ることができました。　　
現時点では複数インデックスからの回答には対応していないのかもしれません。プレイグラウンドでも複数のデータソースを設定できないようです。  
Microsoft には Issue として報告を行いました。