はじめに

少し時間が経ってしまいましたが、先日 Knowledge base for Amazon Bedrock が GA しました。

Amazon Bedrock のナレッジベースの一般提供が開始

RAG の構築で必要なベクトル DB のセットアップがいい感じに隠蔽され、敷居がどんどん低くなっていますね。弊社ブログではまだこの話題に触れた記事がないようなので、触ってみました。

RAG (Retrieval Augmented Generation) とは

私が説明するまでもないですが、RAG とは LLM を素で使う場合に発生する以下のデメリットを解決あるいは軽減するための技術です。

  • 学習データに依存し、最新情報に基づく回答ができない
  • 同じ理由で、内部情報に基づく回答ができない
  • 正確性に欠けた回答をする (回答にハルシネーションを含む)

RAG はベクトルデータベースと LLM を統合することでこの問題を解決しようとします。

つくってみる

S3 バケットの準備とドキュメントのアップロード

さっそく作っていきます。まずは RAG に読み込ませたいドキュメントをアップロードするための S3 バケットを作ります。現状 Knowledge base はバージニア北部かオレゴンでしか使えないので、以降の作業はすべて us-east-1 で行います。

次にドキュメントをアップロードします。今回は私が自宅で使っている YAMAHA RTX 1200 というルーターのコマンドリファレンス、ユーザーガイド、設定例集をこちらから入手し、アップロードしてみます。

モデルアクセスの有効化

Amazon Bedrock では各モデルに対してアクセスをリクエストする必要があります。今回は以下をリクエストしました。

Anthropic のモデルはユースケースや会社名などを送信することで有効化されます。

Knowledge base の構築

そして Knowledge base の構築です。まずは名前、およびサービスロールの新規作成有無を設定します。

次にデータソースの設定です。さきほど用意した S3 バケットの URI を指定します。

続いてベクトルストアの設定です。Quick create a new vector store - Recommended を選択すれば、裏で Vector engine for OpenSearch Serverless が立ち上がります。埋め込みモデルはさきほどアクセスを有効化した Titan Embeddings G1 -Text になっています。

Embeddings とは単語、フレーズ、文などの自然言語表現を数値のベクトルに変換することで、Embedding Model はそれを行う言語モデルのことだと理解しています。

レビュー画面で確認し、問題なければ Create knowledge base をクリックして待ちます。最終的に以下のようなリソース画面になります。

データソースの同期

問題なく立ち上がったら、S3 バケット上のドキュメントをベクトル DB に同期する必要があります。

ここで同期エラーが発生した場合、サービスロールを確認してください。
理由は不明ですが、私の場合は自動生成された S3 アクセス用のポリシーが効いていませんでした。


以下のようなポリシーができるのですが、応急処置として Condition 要素を削除することでリカバリできました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "S3ListBucketStatement",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::<bucket-name>"],
      "Condition": {
        "StringEquals": {
          "aws:ResourceAccount": "<account-id>"
        }
      }
    },
    {
      "Sid": "S3GetObjectStatement",
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::<bucket-name>/*"],
      "Condition": {
        "StringEquals": {
          "aws:ResourceAccount": "<account-id>"
        }
      }
    }
  ]
}

テスト

ここまでくればテストが可能です。マネコン右にいるプロンプトでチャットしてみましょう。現在は Anthropic のモデルしか使えないようです。

YAMAHA RTX 1200 で IPSec VPN をセットアップする手順を聞いてみましょう。

ちゃんと DB から情報を検索していますね。画面では改行がないので見づらいですが、コピーすると改行されています。以下のようにソースも提示されます。

RetrieveAndGenerate API

では boto3 で RetrieveAndGenerate API を使ってリクエストしてみたいと思います。以下のようなスクリプトです。こちらを参考にしました。

import os
import sys
import json
import boto3


def check_keys():
    access_kye_id = os.getenv("AWS_ACCESS_KEY_ID")
    if not access_kye_id:
        raise EnvironmentError("Environment variable not set: AWS_ACCESS_KEY_ID")
    aws_session_token = os.getenv("AWS_SESSION_TOKEN")
    if not aws_session_token:
        raise EnvironmentError("Environment variable not set: AWS_SESSION_TOKEN")


def run():
    client = boto3.client("bedrock-agent-runtime", region_name="us-east-1")
    response = client.retrieve_and_generate(
        input={
            "text": "YAMAHA RTX 1200 でIPSec VPN接続をセットアップするコマンド手順をステップバイステップで教えてください。",
        },
        retrieveAndGenerateConfiguration={
            "type": "KNOWLEDGE_BASE",
            "knowledgeBaseConfiguration": {
                "knowledgeBaseId": "XXXXXXXXXX",
                "modelArn": "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-v2",
            },
        },
    )
    print(json.dumps(response, indent=2, ensure_ascii=False))


def main():
    try:
        check_keys()
        run()
    except Exception as e:
        print(f"error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == "__main__":
    main()

以下の回答が返ってきました。

{
  ...
  "output": {
    "text": "YAMAHA RTX1200でIPSec VPN接続を設定するには、まずIKE(Internet Key Exchange)による事前共有鍵を設定します。 次に、対向のセキュリティゲートウェイのIPアドレスをipsec ike remote addressコマンドで設定します。 さらに、使用するモードに応じて、メインモードならipsec ike remote name、アグレッシブモードならipsec ike local nameを設定します。 最後に、ポリシーとキーの有効期間などをipsec sa policyコマンドとipsec ike durationコマンドで設定します。"
  },
  "citations": [
    {
      "generatedResponsePart": {
        "textResponsePart": {
          "text": "YAMAHA RTX1200でIPSec VPN接続を設定するには、まずIKE(Internet Key Exchange)による事前共有鍵を設定します。",
          "span": {
            "start": 0,
            "end": 76
          }
        }
      },
      "retrievedReferences": [
        {
          "content": {
            "text": "RTX830 は、Rev.15.02.10 以降で使用可能。   [適用モデル] RTX1220, RTX1210, RTX830   17.15 トンネルインタフェースの変換種別の設定   [書式] tunnel translation type no tunnel translation [type]   コマンドリファレンス | トンネリング | 297        [設定値及び初期値] • type   • [設定値] :   設定値 説明   nat46 NAT46 トンネル   • [初期値] : -   [説明] トンネルインタフェースの変換種別を設定する。   [ノート]   tunnel encapsulation コマンドとの併用はできず、後から入力したコマンドが有効となる。   RTX830 Rev.15.02.20 以降で使用可能。   RTX1220 Rev.15.04.04 以降で使用可能。   [適用モデル] RTX1220, RTX830   298 | コマンドリファレンス | トンネリング        第 18 章 IPsec の設定   RT250i 以外の機種では、暗号化により IP 通信に対するセキュリティを保証する IPsec 機能を実装しています。IPsec では、鍵交換プロトコル IKE(Internet Key Exchange) を使用します。必要な鍵は IKE により自動的に生成されますが、   鍵の種となる事前共有鍵は ipsec ike pre-shared-key コマンドで事前に登録しておく必要があります。この鍵はセキ   ュリティ・ゲートウェイごとに設定できます。また、鍵交換の要求に応じるかどうかは、ipsec ike remote address コ マンドで設定します。   鍵や鍵の寿命、暗号や認証のアルゴリズムなどを登録した管理情報は、SA(Security Association) で管理します。SA を区別する ID は自動的に付与されます。SA の ID や状態は show ipsec sa コマンドで確認することができます。SA には、鍵の寿命に合わせた寿命があります。SA の属性のうちユーザが指定可能なパラメータをポリシーと呼びま   す。またその番号はポリシー ID と呼び、ipsec sa policy コマンドで定義し、ipsec ike duration ipsec-sa、ipsec ike duration isakmp-sa コマンドで寿命を設定します。   SA の削除は ipsec sa delete コマンドで、SA の初期化は ipsec refresh sa コマンドで行います。ipsec auto refresh コマ   ンドにより、SA を自動更新させることも可能です。   IPsec による通信には、大きく分けてトンネルモードとトランスポートモードの 2 種類があります。   トンネルモードは IPsec による VPN(Virtual Private Network) を利用するためのモードです。"
          },
          "location": {
            "type": "S3",
            "s3Location": {
              "uri": "s3://<bucket-name>/Cmdref.pdf"
            }
          }
        }
      ]
    },
    {
      "generatedResponsePart": {
        "textResponsePart": {
          "text": "次に、対向のセキュリティゲートウェイのIPアドレスをipsec ike remote addressコマンドで設定します。",
          "span": {
            "start": 78,
            "end": 138
          }
        }
      },
      "retrievedReferences": [
        {
          "content": {
            "text": "RTX830 は、Rev.15.02.10 以降で使用可能。   [適用モデル] RTX1220, RTX1210, RTX830   17.15 トンネルインタフェースの変換種別の設定   [書式] tunnel translation type no tunnel translation [type]   コマンドリファレンス | トンネリング | 297        [設定値及び初期値] • type   • [設定値] :   設定値 説明   nat46 NAT46 トンネル   • [初期値] : -   [説明] トンネルインタフェースの変換種別を設定する。   [ノート]   tunnel encapsulation コマンドとの併用はできず、後から入力したコマンドが有効となる。   RTX830 Rev.15.02.20 以降で使用可能。   RTX1220 Rev.15.04.04 以降で使用可能。   [適用モデル] RTX1220, RTX830   298 | コマンドリファレンス | トンネリング        第 18 章 IPsec の設定   RT250i 以外の機種では、暗号化により IP 通信に対するセキュリティを保証する IPsec 機能を実装しています。IPsec では、鍵交換プロトコル IKE(Internet Key Exchange) を使用します。必要な鍵は IKE により自動的に生成されますが、   鍵の種となる事前共有鍵は ipsec ike pre-shared-key コマンドで事前に登録しておく必要があります。この鍵はセキ   ュリティ・ゲートウェイごとに設定できます。また、鍵交換の要求に応じるかどうかは、ipsec ike remote address コ マンドで設定します。   鍵や鍵の寿命、暗号や認証のアルゴリズムなどを登録した管理情報は、SA(Security Association) で管理します。SA を区別する ID は自動的に付与されます。SA の ID や状態は show ipsec sa コマンドで確認することができます。SA には、鍵の寿命に合わせた寿命があります。SA の属性のうちユーザが指定可能なパラメータをポリシーと呼びま   す。またその番号はポリシー ID と呼び、ipsec sa policy コマンドで定義し、ipsec ike duration ipsec-sa、ipsec ike duration isakmp-sa コマンドで寿命を設定します。   SA の削除は ipsec sa delete コマンドで、SA の初期化は ipsec refresh sa コマンドで行います。ipsec auto refresh コマ   ンドにより、SA を自動更新させることも可能です。   IPsec による通信には、大きく分けてトンネルモードとトランスポートモードの 2 種類があります。   トンネルモードは IPsec による VPN(Virtual Private Network) を利用するためのモードです。"
          },
          "location": {
            "type": "S3",
            "s3Location": {
              "uri": "s3://<bucket-name>/Cmdref.pdf"
            }
          }
        }
      ]
    },
    {
      "generatedResponsePart": {
        "textResponsePart": {
          "text": "さらに、使用するモードに応じて、メインモードならipsec ike remote name、アグレッシブモードならipsec ike local nameを設定します。",
          "span": {
            "start": 140,
            "end": 223
          }
        }
      },
      "retrievedReferences": [
        {
          "content": {
            "text": "RTX830 は、Rev.15.02.10 以降で使用可能。   [適用モデル] RTX1220, RTX1210, RTX830   17.15 トンネルインタフェースの変換種別の設定   [書式] tunnel translation type no tunnel translation [type]   コマンドリファレンス | トンネリング | 297        [設定値及び初期値] • type   • [設定値] :   設定値 説明   nat46 NAT46 トンネル   • [初期値] : -   [説明] トンネルインタフェースの変換種別を設定する。   [ノート]   tunnel encapsulation コマンドとの併用はできず、後から入力したコマンドが有効となる。   RTX830 Rev.15.02.20 以降で使用可能。   RTX1220 Rev.15.04.04 以降で使用可能。   [適用モデル] RTX1220, RTX830   298 | コマンドリファレンス | トンネリング        第 18 章 IPsec の設定   RT250i 以外の機種では、暗号化により IP 通信に対するセキュリティを保証する IPsec 機能を実装しています。IPsec では、鍵交換プロトコル IKE(Internet Key Exchange) を使用します。必要な鍵は IKE により自動的に生成されますが、   鍵の種となる事前共有鍵は ipsec ike pre-shared-key コマンドで事前に登録しておく必要があります。この鍵はセキ   ュリティ・ゲートウェイごとに設定できます。また、鍵交換の要求に応じるかどうかは、ipsec ike remote address コ マンドで設定します。   鍵や鍵の寿命、暗号や認証のアルゴリズムなどを登録した管理情報は、SA(Security Association) で管理します。SA を区別する ID は自動的に付与されます。SA の ID や状態は show ipsec sa コマンドで確認することができます。SA には、鍵の寿命に合わせた寿命があります。SA の属性のうちユーザが指定可能なパラメータをポリシーと呼びま   す。またその番号はポリシー ID と呼び、ipsec sa policy コマンドで定義し、ipsec ike duration ipsec-sa、ipsec ike duration isakmp-sa コマンドで寿命を設定します。   SA の削除は ipsec sa delete コマンドで、SA の初期化は ipsec refresh sa コマンドで行います。ipsec auto refresh コマ   ンドにより、SA を自動更新させることも可能です。   IPsec による通信には、大きく分けてトンネルモードとトランスポートモードの 2 種類があります。   トンネルモードは IPsec による VPN(Virtual Private Network) を利用するためのモードです。"
          },
          "location": {
            "type": "S3",
            "s3Location": {
              "uri": "s3://<bucket-name>/Cmdref.pdf"
            }
          }
        }
      ]
    },
    {
      "generatedResponsePart": {
        "textResponsePart": {
          "text": "最後に、ポリシーとキーの有効期間などをipsec sa policyコマンドとipsec ike durationコマンドで設定します。",
          "span": {
            "start": 225,
            "end": 292
          }
        }
      },
      "retrievedReferences": [
        {
          "content": {
            "text": "RTX830 は、Rev.15.02.10 以降で使用可能。   [適用モデル] RTX1220, RTX1210, RTX830   17.15 トンネルインタフェースの変換種別の設定   [書式] tunnel translation type no tunnel translation [type]   コマンドリファレンス | トンネリング | 297        [設定値及び初期値] • type   • [設定値] :   設定値 説明   nat46 NAT46 トンネル   • [初期値] : -   [説明] トンネルインタフェースの変換種別を設定する。   [ノート]   tunnel encapsulation コマンドとの併用はできず、後から入力したコマンドが有効となる。   RTX830 Rev.15.02.20 以降で使用可能。   RTX1220 Rev.15.04.04 以降で使用可能。   [適用モデル] RTX1220, RTX830   298 | コマンドリファレンス | トンネリング        第 18 章 IPsec の設定   RT250i 以外の機種では、暗号化により IP 通信に対するセキュリティを保証する IPsec 機能を実装しています。IPsec では、鍵交換プロトコル IKE(Internet Key Exchange) を使用します。必要な鍵は IKE により自動的に生成されますが、   鍵の種となる事前共有鍵は ipsec ike pre-shared-key コマンドで事前に登録しておく必要があります。この鍵はセキ   ュリティ・ゲートウェイごとに設定できます。また、鍵交換の要求に応じるかどうかは、ipsec ike remote address コ マンドで設定します。   鍵や鍵の寿命、暗号や認証のアルゴリズムなどを登録した管理情報は、SA(Security Association) で管理します。SA を区別する ID は自動的に付与されます。SA の ID や状態は show ipsec sa コマンドで確認することができます。SA には、鍵の寿命に合わせた寿命があります。SA の属性のうちユーザが指定可能なパラメータをポリシーと呼びま   す。またその番号はポリシー ID と呼び、ipsec sa policy コマンドで定義し、ipsec ike duration ipsec-sa、ipsec ike duration isakmp-sa コマンドで寿命を設定します。   SA の削除は ipsec sa delete コマンドで、SA の初期化は ipsec refresh sa コマンドで行います。ipsec auto refresh コマ   ンドにより、SA を自動更新させることも可能です。   IPsec による通信には、大きく分けてトンネルモードとトランスポートモードの 2 種類があります。   トンネルモードは IPsec による VPN(Virtual Private Network) を利用するためのモードです。"
          },
          "location": {
            "type": "S3",
            "s3Location": {
              "uri": "s3://<bucket-name>/Cmdref.pdf"
            }
          }
        }
      ]
    }
  ]
}

参照先の情報も保持するところがいいですね。社内アプリなどで、出典まで提示してくれるのは重宝するケースも多そうです。

おわりに

LangChain でも試そうと思ったのですが、資料が少なくトラブルシューティングしきれなかったため、本記事では断念しました。このあたりが実装だと思うので、もう少し掘り下げてみたいと思います。

今後は CFn や CDK なども順次対応されると思うので、IaC を活用してインフラとアプリを一緒に管理するような形も試せればと思います。