Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Advanced RAGをAmazon Bedrock Prompt Flowsで作成する

はじめに

夏本番のこの時期、皆様のご様子はいかがでしょうか。新人エンジニアの木介です。暑さにも負けず、毎日一歩一歩成長しています。
今回は先日紹介したPrompt Flows for Amazon Bedrockを使ったAdvanced RAGの実装方法についての紹介を行っていきます。
Prompt flowsを用いることでDifyと同じようにLLMとプロンプトを組み合わせたフローをGUIで作成でき、また、AWS上の各種サービスへ簡単に組み込むことが出来ます。

aws.amazon.com

acro-engineer.hatenablog.com

構築したアーキテクチャ

概要

本記事ではPrompt Flows for Amazon Bedrockを使って、以下の形でAdvanced RAGを実装します。
Advanced RAGについては後述します。

以下のAdvanced RAG について紹介されているAWS公式ブログを参考に実装を行っています。
一点変更点として、検証コストの削減のために、retriever(検索器)としてBedrock bases for Amazon Bedrockを利用しました。

aws.amazon.com

Prompt Flows for Amazon Bedrockとは

本記事ではGUIで生成ワークフローが作成できるPrompt Flows for Amazon Bedrockで実装を行っていきます。
詳細な説明については以下の記事で行っていますので、参考にしていただければと思います。

acro-engineer.hatenablog.com

今回利用するPrompt flowsの機能を以下に示します。
これらのNodeを組み合わせることで、上記のアーキテクチャを作成していきます。

Collector 配列に統合する反復
Iterator 次のNodeを各メンバーに反復的に適用
Lambda Lambdaによる処理が可能
Prompts Bedrockで利用できるFM(基盤モデル)やPrompt Managementにより回答
Knowledge base Bedrockで作成したKnowledge baseにより回答

Advanced RAGとは

Advance RAGでは、従来のただ質問から情報を検索するRAGに加えて、検索前後に検索結果の精度を高めるための工夫をしています。
追加する工夫としては、検索前処理では与えられた質問を様々な形に言い換えるクエリ拡張などがあり、検索後処理では検索結果を端的にまとめる要約や、質問と関連しない検索結果を除去する関連度評価などがあります。
これらの工夫により、従来のRAGではユーザーが期待する品質の回答を得られなかった場合でも、回答が出来るようになっています。

本記事では検索前処理、検索後処理として、以下の工夫を行い、Advanced RAGの実装を行っていきます。

  • 1. 検索前処理
    • クエリ拡張:与えられた質問を様々な形に言い換えることで、幅広い検索を行う。
  • 2. 検索後処理
    • 関連度評価:得られた検索結果を質問との関連度で評価し、不要な検索結果を削除する

Advanced RAGの構築方法

構築するワークフロー

まず以下に今回Prompt flowsで構築するワークフローを示します。


  1. クエリ拡張で与えられたクエリから複数パターンのクエリを生成する
  2. 拡張クエリを元に複数の検索結果を取得
  3. 関連度評価で検索結果を評価
  4. 質問と関連している検索結果(上図では検索結果1と3)を用いて回答を生成

上図のクエリ拡張、関連度評価、回答生成のそれぞれでLLMを利用し、今回はClaude3 Sonnetを利用していきます。

1. クエリ拡張

ではまず検索前処理として行うクエリ拡張について作成を行っていきます。
今回クエリ拡張は以下の図のようにクエリを入力として、指定した個数に拡張したクエリが入った配列を出力することを目標とします。
Lambdaを使ってクエリを整形する理由としては、Prompt flowsで繰り返しのためにIterator Nodeを使った処理を行う際の入力として配列のみしか受け付けていなかったためです。

クエリ拡張部分のフローは以下のようになります。
クエリ拡張用のPrompt Nodeとその出力を整形するためのLambdaを用いています。

クエリ拡張を行うLLMに与えるプロンプトは以下になります。

検索エンジンに入力するクエリを最適化し、様々な角度から検索を行うことで、より適切で幅広い検索結果が得られるようにします。 
具体的には、類義語や日本語と英語の表記揺れを考慮し、多角的な視点からクエリを生成します。

以下の<question>タグ内にはユーザーの入力した質問文が入ります。
この質問文に基づいて、{{n_queries}}個の検索用クエリを生成してください。
各クエリは30トークン以内とし、日本語と英語を適切に混ぜて使用することで、広範囲の文書が取得できるようにしてください。

生成されたクエリは、<format>タグ内のフォーマットに従って出力してください。

<enhance>
フォーマットに従った出力以外の余計なタグ等は絶対に出力しないでください
<enhance>

<example>
question: Knowledge Bases for Amazon Bedrock ではどのベクトルデータベースを使えますか?
query 1: Knowledge Bases for Amazon Bedrock vector databases engine DB 
query 2: Amazon Bedrock ナレッジベース ベクトルエンジン vector databases DB
query 3: Amazon Bedrock RAG 検索拡張生成 埋め込みベクトル データベース エンジン
</example>

<format>
{{output_format}}
</format> 

<question>
{{question}}
</question>

今回それぞれのLLMに与えるプロンプトはこちらの記事を参考に以下の工夫をしています。

  • 具体例を記載する
  • XMLタグを利用して詳細な指示を与える

aws.amazon.com

その他の設定については以下のようにし、Top Kは1にしました。


では次に拡張クエリを配列に整形するLambdaの設定を行っていきます。
まずAWS コンソールより新しいLambdaを作成します。
この際BedrockからLambdaを呼び出せるようにLambdaの設定>アクセス権限>リソースベースのポリーシーステートメントより外部からのアクセス権限を追加する必要があります。
以下の「リソースベースのポリシーステートメントより「アクセス権限の追加」を選択してください。

設定するポリシーステートメントとしては以下のように設定をしてください。

  1. サービス:Other
  2. ステートメントID: 任意のステートメントID
  3. プリンシパル: bedrock.amazonaws.com
  4. ソースARN: Prompt flowsのARN
  5. アクション: lambda: InvokeFunction

Lambdaの実装としては以下の通りです。
正規表現を用いて配列部分を抽出します。

import json
import re
import ast

def lambda_handler(event, context):
  # 入力を読み込む
    resource = event.get("node",{}).get("inputs",[])
    if len(resource)<=0:
        raise ValueError("%sに値が入っていません" % resource)
    input_value = resource[0].get("value","[]")
    # 正規表現を使ってリスト部分を抽出
    match = re.search(r'\[(.*?)\]', input_value, re.DOTALL)
    
    if match:
        list_string = match.group(0)  # マッチした部分全体を取得
        extracted_list = ast.literal_eval(list_string)  # 文字列をリストに変換
    else:
        raise ValueError("リストが見つかりませんでした")
    return {"data":extracted_list}

試しにクエリとして「食べ物」を入力した時の結果が以下になります。

クエリを拡張出来ていることが分かります。

2. Knowledge Basesの作成

今回はretriever(検索器)としてKnowledge Basesを用いています。
更に検証時のコストの削減のためにベクトルデータベースとしてPineconeを利用しています。

app.pinecone.io

詳しい構築方法については以下の記事を参考にしてください。

qiita.com

また、今回利用するドキュメントしては以下の2020 ~ 2023 年度の Amazon の株主向け年次報告書を選択し、S3に格納しました。

3. 関連度評価機能の作成

関連度評価機能の作成については以下のプロンプトで構築を行いました。

あなたは、ユーザーからの質問と検索で得られたドキュメントの関連度を評価する専門家です。
関連しないと評価したドキュメントをリストに含めないでください。
<excerpt>タグ内は、検索により取得したドキュメントの抜粋のリストです。

<excerpt>{{context}}</excerpt>

<question>タグ内は、ユーザーからの質問です。

<question>{{question}}</question>
  
このドキュメントの抜粋は、ユーザーの質問に回答するための正確な情報を含んでいるかを慎重に判断してください。
正確な情報を含んでいる場合は そのままドキュメントの抜粋をリストに含め、含んでいない場合は リストに含めないでください。
評価結果ではなく、<enhance>正確な情報を含んでいると判断したドキュメントを全て返してください</enhance>。
以下の<ouptut_format>で余計なものは出力しないでください
<enhance>タグ(<output_format>)も絶対に出力しないでください</enhance>
  
<output_format>array</output_format>

またその他の設定については以下のようにし、Top Kは1にしました。


試しにクエリとして「食べ物は?」とし、検索結果として「"自転車", "リンゴ","バナナ"」を評価したときの結果が以下になります。

食べ物のみを選択出来ていることが分かります。

4. 回答生成器の作成

最後に回答生成器の作成を行います。
まずプロンプトとしては以下のように設定しました。

あなたは親切で知識豊富なチャットアシスタントです。
<excerpts>タグには、ユーザーが知りたい情報に関連する複数のドキュメントの抜粋が含まれています。

<excerpts>{{context}}</excerpts>

これらの情報をもとに、<question>タグ内のユーザーの質問に対する回答を提供してください。

<question>{{question}}</question>

まず、質問に対して<excerpts>タグ内にある情報で答えられるかを考え、<related>true</related>、もしくは、<related>false</related>の形式で答えてください。

質問に答えるための情報がない場合は、「情報が不十分で回答できません」と答えてください。
また、質問への回答は以下の点に留意してください:

- <excerpts>タグの内容を参考にするが、回答に<excerpts>タグを含めないこと。
- 簡潔に3つ以内のセンテンスで回答すること。
- 日本語で回答すること。
- 質問への回答は<answer></answer>タグに含めること。

またその他の設定については以下のようにし、Top Kは1にしました。



5. 全体像

以上で今回作成するAdvanced RAGの各機能の作成が完了しました。
これらの機能をつなげ合わせた全体像が以下となります。

クエリ拡張によって取得した拡張クエリ配列に対して、Iterator NodeとCollector Nodeを利用することで各拡張クエリに一つ一つについての検索を行っています。

以上でPrompt flowsによるAdvanced RAGの構築が完了しました。
Lambdaを使う必要はありましたが、Bedrockの機能についてはGUIで容易に組み込むことが出来ました。

作成したワークフローを試してみる

では最後に作成したワークフローを試してみましょう。
まず、与えたドキュメント内から検索が出来ているかの確認のために以下のクエリを与えました。
結果が以下になります。

与えたドキュメントから情報を取得できていることが分かります。

次にドキュメントと関係のないクエリを与えた場合について試してみます。
以下の結果となりました。

Amazon株主総会」⇒「Azure株主総会」に変更したのみですが、ハルシネーションが防げていることが分かります。

以上が通常のRAGよりも回答精度の高いAdvanced RAGをPrompt flowsで実装するまでの流れになります。
実装の殆どをGUI上で完結でき、Bedrockとの連携も容易に行えるため、簡単にAdvanced RAGの構築が出来たと思います。

まとめ

今回はGUIで生成AIワークフローを構築可能なPrompt Flows for Amazon BedrockでAdvanced RAGを構築する方法について紹介をしました。
Advanced RAGとして取り入れたクエリ拡張と関連度評価についてもGUIで構築することが出来ました。
Prompt flowsを利用すればS3といったAWS上のサービスへのアクセスも簡単に行えますのでAdvanced RAGのサービスへの実装も簡単になりそうです。



Acroquest Technologyでは、キャリア採用を行っています。
  • Azure OpenAI/Amazon Bedrock等を使った生成AIソリューションの開発
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • マイクロサービス、DevOps、最新のOSSクラウドサービスを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
www.wantedly.com