Copilot Studio AI Searchと繋いでNaive RAGを組んでみる|基本的なRAGの構築

前回作成したAI Searchを使用し、Copilot StudioでNaive RAG(Retrieval-Augmented Generation)を組んでみた。

スポンサーリンク

Naive RAG

『Naive RAG』は、情報検索と生成モデルを組み合わせたシンプルな(最も基礎的な)RAG手法。

  1. ユーザーのクエリに基づき、外部データベースやドキュメントから関連する情報を取得
  2. 検索で得られた情報をもとに、生成モデル(例: GPTなど)が回答を生成

最近は『Advanced RAG』や、RAGを使用した『Agentic Workflow/Agentic Design Pattern』が主流だけど、ひとまず練習もかねて基本的な『Naive RAG』から開始。

Tips:公式ではナレッジを推奨

ちなみにAI Searchの公式ドキュメントには、「CopilotにSharePointをデータソースとしたRAGを入れる場合は、Copilot Studioの機能(ナレッジ)を使うこと」を推奨している旨書いている。

SharePoint データとチャットするためにカスタム Copilot/RAG (取得拡張生成) アプリケーションを作成する必要がある場合は、このプレビュー機能ではなく Microsoft Copilot Studio を使用することをお勧めします。
公式から抜粋

今回は実験なので自分で作るけど、本稼働の場合は「ナレッジを試す → 精度がいまいちな場合は自分で組む」くらいがちょうどよいかも。

構築

全体的なイメージはこんな感じ。
SPOには、ほどよく新しい情報をWikiから抽出し、事前にチャンク化して保存。
※古い情報だとLLM自体の知識で回答できちゃっておもしろくないため。

構築は以下の手順で行う。

  1. トピックの作成 → 検索ワードの生成
  2. 検索(AI Search呼び出し)
  3. 回答生成 → メッセージの送信
  4. 任意:Conversational boostingから呼び出し

手順1 : トピックの作成 → 検索ワードの生成

まずは新しくトピックを作成して、検索ワードの生成を「プロンプトアクション」で実施する。
プロンプトにはFew-shotを使用し、応答を後のノードで使いやすいようJSON出力を定義。
※今回はNaive RAGを組むこと自体が目的なので、精度は未考慮。

Here are examples of user questions and their corresponding search queries. Use these examples to guide your transformation of the input question."
Example Input 1: "Pythonでデータベースに接続する方法は?"
Example Output: "Python データベース 雪像方法"
Example Input 2: "気候変動が生態系に与える影響は?"
Example Output: "気候変動 生態系 影響"
Example Input 3: "AIの倫理的課題は何か?"
Example Output: "AI 倫理 課題"
Now, based on these examples, transform the following user question into an effective search query.

Input :  {input}

手順2 : 検索(AI Search呼び出し)

続いてAI Searchの呼び出し。今回はPower Automateを噛ませず、直接HTTPを投げる。

// 以下のURLにPOST
https://【AI Searchリソース名】.search.windows.net/indexes/【インデックス名】/docs/search?api-version=2024-11-01-preview
ヘッダはAPIキーとContent-type。
※サンプルなのでAPIキーを雑に扱ってます。
ボディは「生コンテンツ」を選んで、JSON関数で本文を作成。
※ひとまず検索結果の上位3件から回答を生成する。

JSON({
    search:Topic.queryOutput.structuredOutput.query,
    count:true,
    top:Topic.Top // 変数「Top」に3を代入済み
})
最後に受信スキーマを定義。定義しておくと後ろのノードで簡単に使えて便利。
※定義はAI Searchのインデックスによって変わるので、サンプルから生成するのが楽。

kind: Record
properties:
  @odata.context: String
  @odata.count: Number
  value:
    type:
      kind: Table
      properties:
        @search.score: Number
        content: String
        id: String
        metadata_spo_item_content_type: String
        metadata_spo_item_last_modified: String
        metadata_spo_item_name: String
        metadata_spo_item_path: String
        metadata_spo_item_size: Number

手順3 : 回答生成 → メッセージの送信

「ユーザーの質問」と「検索結果」を「プロンプトアクション」に渡し、回答を生成する。

// 今回は検索結果として「ファイル名」と「ファイルの中身」を渡す。
JSON(ForAll(
    Topic.search_result.value,
    {fileName:metadata_spo_item_name,content:content}
))
プロンプトアクションの中身はこんな感じ。こちらも応答を簡単に扱えるよう、JSON出力を利用する。

If the query cannot be answered based on the provided context, respond with '提供された情報ではこの質問に答えることができません。' .
Otherwise, generate a complete and accurate answer, and as an annotation, output the name of the referenced files at the end.

# query
{query}

# information
{information}
 

以上で「Naive RAG」のトピックの作成は完了。

手順4(任意):Conversational boostingから呼び出し

最後に、今後色々なRAG手法を試す予定なので、ユーザーのメッセージを「Conversational boosting」で受けるようにする。

メッセージを受け取ったら、「RAGの手法」を選ばせて、
選択に応じてリダイレクトする。

以上で構築は完了。

動作確認

こんな感じで質問してみると、正しい回答を返してくれる。
※ちなみに4oに聞くと普通に嘘をぶっこんでくる(おしいけど)。
ただ、本当に単純な構築なので、答えられない質問もたくさんある。

ということで、次回以降Advanced RAGをいくつか作って、性能の向上を試してみる。

今回の記事で使用したCopilot Studioの機能

コメント

タイトルとURLをコピーしました