はじめに
こんにちは、自動車・製造ソリューションアーキテクトの呉です。
昨今 RAG (Retrieval Augmented Generation, 検索拡張生成) が流行っています。RAG はここ数年の技術で流行り廃りが早く、RAG のテクニックはすぐ古新聞になってしまいますが、変わらないものも見えてきました。また、RAG においては「RAG システム出来た ! みんな使ってくれ !! 」から、思ったほど業務で利用できるレベルの回答を得られる確率が低く、「使い物にならん !! 誰が使うか !!」みたいな悲劇と失望も巷ではちらほら伺います。本稿では、その変わらないだろう部分にフォーカスし、どうすれば RAG プロジェクトを成功させられるか、あるいは素早く失敗してダメージ軽減をするかについて、体験談に基づいて紹介していきます。
次回は実際に検索を取り入れた時の Tips を紹介します。
builders.flash メールメンバー登録
あらためて RAG とは
弊社の公式メッセージから引用すると、以下の通りです。
検索拡張生成 (RAG) は、大規模な言語モデルの出力を最適化するプロセスです。そのため、応答を生成する前に、トレーニングデータソース以外の信頼できる知識ベースを参照します。大規模言語モデル (LLM) は、膨大な量のデータに基づいてトレーニングされ、何十億ものパラメーターを使用して、質問への回答、言語の翻訳、文章の完成などのタスクのためのオリジナルの出力を生成します。RAG は、LLM の既に強力な機能を、モデルを再トレーニングすることなく、特定の分野や組織の内部ナレッジベースに拡張します。LLM のアウトプットを改善するための費用対効果の高いアプローチであるため、さまざまな状況で関連性、正確性、有用性を維持できます。
正しいことを言っていますが、エンジニアからの「結局何なの ?」という端的な質問に答えるとするならば、
ユーザーの質問に答えるためのドキュメントを検索して
生成 AI にドキュメントとユーザーの質問をつっこんで回答させる
という 2 つのステップがメインで、昨今の RAG 界隈はこの 2 つのステップに様々なステップやいろいろな分岐処理、ループ処理などを混ぜ混ぜしてワッショイワッショイと技術のお祭り騒ぎをしていると捉えていただくと迷子にならずに済みます。
例えば、GraphRAG が流行っていますが、GraphRAG は 1 の検索するための Database(DB) に GraphDB (AWS であれば Amazon Neptune という Graph Database があります) を採用し、 GraphDB にドキュメントを突っ込んで検索結果を取ってくるものです。なぜ GraphDB がいいかというと、従来のドキュメント検索 (キーワード検索やベクトル検索) だと、キーワードが含まれているか、意味が近いか、だけしか評価されず (※) に、主語・述語・目的語といった文脈が失われやすいので、GraphDB を使って主語・述語・目的語を意識した検索をできるようにしよう、といった流れを汲んでいるわけです。
※ 例えばユーザーが「小学生でも作れるカレーの作り方は ?」というクエリを投げたとき、キーワードだと「小学生にバカ受け !人気 カレーレシピ 3 選」のような親が作るレシピを引っ掛けたり、ベクトルだと「8/1 小学 6 年生になったので、そろそろ料理の 1 つでも出来ないといけないかと思い、親と一緒にカレーを作りました。…」みたいな夏休みの絵日記を引っ掛けるかもしれません (絵日記にはもしかしたらレシピが載っているかもしれませんが)。そうではなく、GraphDB に「小学生が (主語) 作れる (述語) カレーの作り方 (目的語)」でインデックスしておくとストレートな検索が出来るかもしれません。
RAG のアーキテクチャ例
RAG 案件やるぜ ! うぉおおおおおお ! …っと手を動かし始める前に
RAG をやると決まったら何から手をつけるべきなのか
データ作成
情シスが AWS のドキュメントからコードを生成する例
情シスが社内システム開発を想定してコードを生成する例です。
ユーザーからの質問
「Amazon Nova Pro で「Amazon Nova Pro とはなんですか ?」というプロンプトを Python (boto3) でクエリするコードを出力してください。」
ドキュメント
boto3 の Converse API のドキュメント全文(API の叩き方)と What is Amazon Nova? (Mopel ID)の 2 つから論理的に導くことが可能です。
正解
いくつかあると思いますが、動けばよしとします。例えばこんなコードです。
import boto3
brt = boto3.client('bedrock-runtime')
model_id = 'amazon.nova-pro-v1:0'
response = brt.converse(
modelId=model_id,
messages=[
{
'role': 'user',
'content': [{'text': 'Amazon Nova Pro とはなんですか?'}]
}
]
)
調達部門が BOM を参照して必要な部品を取得する例
BOM の話をするといろんな BOM プロフェッショナルからそうじゃない、といった恐怖のツッコミが多々来そうで戦々恐々ですが、ここでは Bill of Material をただの部品表と捉えて (この時点ですでに怖い)、生成 AI で作ったグランドピアノの部品表の csv 形式を渡して、そこから使用している部品の数を聞いてみます (内容が合っているかは知りませんが、白鍵 52 + 黒鍵 36 鍵 = 88 鍵あるので良いことにしました)。

部品の数を聞く例
ユーザーからの質問
「白鍵を発注します。白鍵が手元に残り 15 鍵あります。グランドピアノを 1 つ作るのにあと何鍵発注する必要がありますか ?」
ドキュメント
部品番号,部品名,数量,単位
GP001,ピアノフレーム,1,個
GP002,響板,1,枚
GP003,弦セット,1,セット
GP004,ハンマーアクション,88,個
GP005,鍵盤(白),52,個
GP006,鍵盤(黒),36,個
GP007,ペダル,3,個
GP008,譜面台,1,個
GP009,蓋,1,個
GP010,脚,3,本
GP011,キャスター,3,個
GP012,ピンブロック,1,個
GP013,チューニングピン,230,個
GP014,ダンパー,88,個
GP015,ブリッジ,2,個
GP016,サウンドボード,1,枚
GP017,リム,1,個
GP018,フェルト,1,セット
GP019,仕上げ用ニス,1,缶
GP020,ネジ・ボルトセット,1,セット
正解
37 鍵 (52 - 15)
カスタマーサポートが製品の不具合に対して解決方法を示す例
ここでは、Amazon の echo の Alexa がリクエストを理解しない、または応答しない というページのドキュメントを食わせ、回答を生成させてみます。
解決方法を聞く例
ユーザーからの質問
「Echo が赤くなって反応しません。解決方法を教えてください。」
ドキュメント
Echo 端末が応答しない問題を解決する方法:
端末に付属されている充電器を使用していることを確認します。
インターネット接続が有効になっていることを確認します。
端末がミュートになっていないことを確認します。端末をミュートにすると、ライトインジケーターが赤色になります。
画面がない端末の場合は、アクションボタンを押して Echo 端末が応答するかどうかを確認します。
Alexa が音声を聞き取れるように、壁、他のスピーカー、または周囲の雑音から端末を遠ざけます。
自然な口調で、はっきりと話しかけてください。
質問を言い換えるか、より具体的な質問にします。たとえば、「パリ」という都市は世界中に複数あります。 フランスのパリの天気を知りたい場合は、「フランスのパリの天気は?」と聞きます。
「聞こえた ?」と話しかけてみてください。
端末の電源を抜き、再び差し込みます。
正解
ミュート状態を解除してください。
正しく回答できるか試す
さてここから作ったデータセットで回答を生成できるか試しましょう。
まずは環境を作る
試し方ですが、AWS には Amazon Bedrock という生成 AI の API サービスがあるので、Amazon Bedrock を使うのが簡単です。しかしRAG 検討時は、必ずしも情シス部門など社内で IT に関して手が動く人(= API を叩ける人) がやるのが最適とは限らず、生成結果が正しいかどうかが判断できる LoB の業務がわかっている人がやる方が最適な場合もあります。しかし、LoB の人が必ずしも API を叩けるとも限りません。
そんなときは、builders.flash で度々出てくる Generative AI Use Cases JP (通称 GenU) を使うと良いでしょう。GenU はコマンド 3 発 (cdk bootstrap → npm ci → cdk deploy、詳細は ドキュメントのデプロイ部分 をご参照ください) 実行するだけで、誰でもすぐに生成 AI が利用開始可能なアプリケーションです。

GenU
GenU では 11 月にユースケースビルダーという新しい機能をリリースしました。どんな機能かは動画を見ていただくのが早いです。
ユースケース編集
RAG のドキュメントを injection して回答を生成するためのプロンプトテンプレートとしてユースケースビルダーを使用できます。ユースケースビルダーを詳しく説明したブログ記事は こちら ですのでぜひご参照ください。

プロンプトテンプレート
今回はこのようなプロンプトテンプレートを用意しました。
あなたはユーザーからの問い合わせに答えるチャットボット AI です。
ユーザーはチャットボット AI に対して <query> タグで質問を、<document> タグでユーザーの質問に答えるためのドキュメントを与えます。AI は <document> から与えられる情報のみを使って <query> に対する回答をしてください。ただし、<rules> タグで囲ったルールを遵守してください。
<query>
{{text:ユーザーの質問}}
</query>
<document>
{{text:参照ドキュメント1}}
</document>
<document>
{{text:参照ドキュメント2}}
</document>
<rules>
* AI が持つ知識で回答してはいけません。<document> タグで与えられる知識から論理的に導ける内容のみを回答してください。
* <document> の内容ではユーザーの回答に答えられない場合は、「情報が不足しているため答えられません」と回答してください。
* 回答を出す前に AI の思考過程を出力を必ず出力してください。
* 可能性ではなく確定的な情報だけを出力してください。
</rules>
結果確認
早速作ったデータセットを入れて結果を確認します。
こんな感じで出力されました。

情シスが AWS のドキュメントからコードを生成する例
テンプレートとデータセットに従って添付のように回答生成をしました。

回答例
得た回答は以下の通りです (生成 AI はランダム性があるため、まったく同じ結果が得られるとは限りませんので参考まで)。
import boto3
# BedrockRuntimeクライアントの作成
bedrock_runtime = boto3.client('bedrock-runtime')
# Converse APIを使用してクエリを実行
response = bedrock_runtime.converse(
modelId='amazon.nova-pro-v1:0',
messages=[
{
'role': 'user',
'content': [
{
'text': 'Amazon Nova Pro とはなんですか?'
}
]
}
]
)
# レスポンスの出力
print(response['output']['message']['content'][0]['text'])
コード実行結果
このコードを実行してみたところ、与えたプロンプト通りの結果を得たので正解としています (生成結果は間違っていますが、Amazon Nova Pro がリリースされる前のデータで学習したモデルなので仕方ありません)。

調達部門が BOM を参照して必要な部品を取得する例
このとおり、52-15 = 37 の演算を行い、 37 鍵と回答できています。

カスタマーサポートが製品の不具合に対して解決方法を示す例
少し冗長 (赤灯がミュートは自明なので、ミュート解除だけのガイドでも良い) ですが答えられています。

結果を得てどうするのか
次回予告
乞うご期待 !!
筆者プロフィール
呉 和仁 (Go Kazuhito / @kazuneet)
アマゾン ウェブ サービス ジャパン合同会社
自動車・製造ソリューションアーキテクト
IoT の DWH 開発、データサイエンティスト兼業務コンサルタントを経て現職。
プログラマの三大美徳である怠惰だけを極めてしまい、モデル構築を怠けられる AWS の AI サービスをこよなく愛す。

Did you find what you were looking for today?
Let us know so we can improve the quality of the content on our pages