メインコンテンツまでスキップ

新年なのでLLMとのチャットアプリをイチから作ってみた②Bedrockと接続

· 約15分
moritalous
お知らせ

過去にQiitaに投稿した内容のアーカイブです。

画面のモックができたので、AWSと接続していきましょう。

注記

これから説明する手順で進めると、ソースコード中にAWSの認証情報を含めずにBedrockにアクセスできます。

認証情報をベタ書きしてBedrockを呼び出したいところですがグッとこらえて順に進めてください。

目次

全3回に分けて投稿しています。

アーキテクチャの検討

フロントエンドからAWSのバックエンドのBedrockを呼ぶ場合、こういった構成を思い浮かべるのではないでしょうか?

この構成でも良いのですが、Amplifyを使うともっとシンプルな構成にすることができます。

Amplifyの認証機能はCognitoの機能で実現されています。Cognitoには、IDプールの認証情報からIAMの一時クレデンシャルを生成する機能があります。この機能を使うことでフロントエンド(ブラウザ)が一時クレデンシャルをもっている状態になり、ブラウザから直接AWSサービスを呼ぶことが可能になります。

ビジネスロジックをバックエンド側で実装したい場合など、API GatewayとLambdaを使用するケースももちろんあると思いますが、単純にAWSサービスを呼ぶだけであれば、Amplifyを使うと便利です。(API Gatewayにはペイロードサイズやタイムアウトの制限があるので、これらを回避するためにも有効です)

参考:Accessing AWS services using an identity pool after sign-in

他の応用例としてはこのようなものも考えられます。

  • S3に直接ファイルをアップロードする。署名付きURLを都度発行する必要なし。
  • API Gatewayを挟まず、Lambdaの関数URLを直接呼び出す。最大15分のバックエンド処理が可能。

Amplifyを導入

注記

2024/01/05時点でv5/v6/Gen2と3バージョン混在状態ですが、v6ですすめます。

Amplify DocumentationSet up Amplify CLICreate your applicationを参考に進めていきましょう。

  1. Amplify CLIをインストール

    npm install -g @aws-amplify/cli
  2. Amplify CLIの設定

    注記

    devcontainerで実行している場合、xdg-utilsをインストールすることで、URLが自動で開くようになります。

    sudo apt update
    sudo apt install xdg-utils

    ウィザードを進めていきます。

    1. AWSのマネジメントコンソールが表示されるのでログインします。
    2. リージョンを選択(ap-northeast-1)
    3. ドキュメントが開きます。
    4. IAMのユーザー作成画面が開きます。ドキュメントに従いAdministratorAccess-Amplifyポリシーをアタッチしたユーザーを作成し、認証情報を生成します。
    5. Access KeyとSecret access keyをウィザードに入力します。
    6. プロファイル名を入力(またはdefaultのまま)します。
  3. Amplify Backendの作成

    amplify init
    1. プロジェクト名を入力します。
    2. プロジェクトの設定を検知してくれるので、そのままYで進めます。
    3. 先程設定したプロファイルを指定します
  4. Amplifyライブラリーのインストール

    npm install aws-amplify
  5. +page.svelteのScriptタグ内に以下のコードを追加します。

    import { Amplify } from "aws-amplify";
    import amplifyconfig from "../amplifyconfiguration.json";
    Amplify.configure(amplifyconfig);

これでAmplifyの導入は完了です。

Amplifyの認証機能(Cognito)を追加

Cognitoの認証機能を有効化します。Cognitoにはログイン画面が予め用意されているのでこの機能を活用します。

参考: Add social provider sign-in AmplifyでCognitoのHosted UIを利用した認証を最低限の実装で動かしてみて動作を理解する Setting up and using the Amazon Cognito hosted UI and federation endpoints

注記

参考URLはソーシャルログインを使用する感じになってますが、Cognitoのユーザー管理機能だけをでも利用可能です。

  1. Amplify Authを追加

    amplify add auth

    サインインのリダイレクトURLとサインアウトのリダイレクトURLは、どちらもhttp://localhost:5173/と入力します。(末尾は必ず/で終わる必要があります)

    Using service: Cognito, provided by: awscloudformation

    The current configured provider is Amazon Cognito.

    Do you want to use the default authentication and security configuration? Default configuration with Social Provider (Federation)
    Warning: you will not be able to edit these selections.
    How do you want users to be able to sign in? Username
    Do you want to configure advanced settings? No, I am done.
    What domain name prefix do you want to use? myskeletonapp77ad9d4f-77ad9d4f
    Enter your redirect signin URI: http://localhost:5173/
    ? Do you want to add another redirect signin URI No
    Enter your redirect signout URI: http://localhost:5173/
    ? Do you want to add another redirect signout URI No
    Select the social providers you want to configure for your user pool:
    ✅ Successfully added auth resource myskeletonapp77ad9d4f locally

    ✅ Some next steps:
    "amplify push" will build all your local backend resources and provision it in the cloud
    "amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

    設定した内容を、AWS環境に反映します。

    amplify push
  2. ログインボタン、ログアウトボタンを追加

    Hubというユーティリティが用意されており、Hosted UIからのリダイレクトを上手に処理してくれます。

    以下をScriptタグ内に追加

    import { Hub } from "aws-amplify/utils";
    import {
    getCurrentUser,
    signInWithRedirect,
    signOut,
    } from "aws-amplify/auth";

    Hub.listen("auth", async ({ payload }) => {
    console.log(payload);
    switch (payload.event) {
    case "signInWithRedirect":
    getUser();
    break;
    }
    });

    function handleSignInClick() {
    signInWithRedirect();
    }

    function handleSignOutClick() {
    signOut();
    }

    let isAuthorizedUser = false;

    async function getUser() {
    try {
    const user = await getCurrentUser();
    if (user.userId) {
    isAuthorizedUser = true;
    }
    } catch (Exception) {
    isAuthorizedUser = false;
    }
    }

    getUser();

    HTML部分にヘッダーを追加し、ボタンを配置します。

    <AppBar
    gridColumns="grid-cols-2"
    slotDefault="place-self-left"
    slotTrail="place-content-end"
    >
    チャットアプリ
    <svelte:fragment slot="trail">
    <button
    type="button"
    class="btn btn-sm variant-filled-primary"
    on:click={handleSignOutClick}>ログアウト</button
    >
    <button
    type="button"
    class="btn btn-sm variant-filled-primary"
    on:click={handleSignInClick}>ログイン</button
    >
    </svelte:fragment>
    </AppBar>
  3. サインアップしてユーザーを作成

    devサーバーを起動して確認してみましょう。

    ログインボタンを押すと、Cognitoが用意したログイン画面に遷移します。Sign upリンクからユーザーの作成ができます。

    ログインが成功すると、元の画面に戻ってきます。

    注記

    このままでは誰でもサインアップできる状態なので、テストで使用するユーザーが作成できたら、セルフサインアップの機能を無効化することをおすすめします。 Amplifyから設定変更する方法が分からなかったので、マネジメントコンソールでの無効化手順です。

    1. Cognito User Poolの管理画面を開きます。
    2. 対象のユーザープール(おそらく最終更新時刻が最近のもの)を選択します。
    3. サインアップエクスペリエンスタブを選択します。
    4. セルフサービスのサインアップセクションの編集ボタンから、自己登録の無効化を行います。

ログイン状態によってチャット欄を非表示にしたりするコードを追加しました。(ヘッダー追加によるレイアウト崩れなどにも対応しました。)

認証されたユーザーにBedrockへのアクセス権限を付与

Amplifyで作成されるCognitoのリソースはユーザープールだけでなく、IDプールも作成されます。 CognitoのIDプールの機能で、認証済みユーザーに対してIAMロールが付与されます。(未認証ユーザーにも付与されます。)

このIAMロールにBedrockへアクセスするポリシーを追加します。

参考:Override Amplify-generated project-level IAM resources

  1. Amplifyプロジェクトを上書きするファイルを生成

    以下のコマンドでmy-skeleton-app/amplify/backend/awscloudformation/override.tsが生成されます。

    amplify override project
  2. 認証ユーザーのロールに、マネージドポリシーを追加します。

    override.tsに以下のコードを記述します。

    const authRole = resources.authRole;

    const baseManagedPolicy = Array.isArray(authRole.managedPolicyArns)
    ? authRole.managedPolicyArns
    : [authRole.managedPolicyArns];

    authRole.managedPolicyArns = [
    ...baseManagedPolicy,
    "arn:aws:iam::aws:policy/AmazonBedrockFullAccess"
    ]
  3. AWS側に反映します。

    amplify push

これでCognitoでログインしたユーザーに、Bedrockへのアクセス権限が付与されます。

Bedrockとの統合

いよいよBedrockの出番です。

  1. AWS SDKを追加します。

    Bedrock RuntimeのSDKを追加します。(client-bedrockではなく、client-bedrock-runtimeです。)

    npm i @aws-sdk/client-bedrock-runtime
  2. Bedrockアクセス部分のコードを追加します。

    import {
    BedrockRuntimeClient,
    InvokeModelCommand,
    } from "@aws-sdk/client-bedrock-runtime";

    aws-amplify/authライブラリーのfetchAuthSession関数を使用することで、credentialsが取得できます。

    async function invokeBedrock(prompt: string): Promise<string> {
    const client = new BedrockRuntimeClient({
    region: amplifyconfig.aws_project_region,
    credentials: (await fetchAuthSession()).credentials,
    });

    const params = {
    modelId: "anthropic.claude-instant-v1",
    contentType: "application/json",
    accept: "*/*",
    body: JSON.stringify({
    prompt: `\n\nHuman: ${prompt}\n\nAssistant:`,
    max_tokens_to_sample: 1000,
    temperature: 0.5,
    top_k: 250,
    top_p: 1,
    stop_sequences: ["\n\nHuman:"],
    }),
    };

    const command = new InvokeModelCommand(params);
    const response = await client.send(command);

    return JSON.parse(response.body.transformToString("utf-8"))["completion"];
    }
    注記

    これで認証情報をベタ書きする必要がなくなりました

  3. 呼び出し元のaddMessageやaddAiMessageを合わせて修正します。

Bedrockとチャットができました!!

Amplifyでホスティング

Amplifyには、フロントエンドのコードをホスティングする機能もあります。作成したチャットアプリをAmplifyにホスティングしてみましょう。

SvelteKitのプロジェクトをAmplifyでホストするために、adapter-staticを使用する必要があるようです。

  1. adapter-staticをインストール

    npm i -D @sveltejs/adapter-static
  2. svelte.config.jsに設定を追加

    1行目のimport文を、adapter-staticを参照するように変更します。

    - import adapter from '@sveltejs/adapter-auto';
    + import adapter from '@sveltejs/adapter-static';

    adapter()を変更します。pagesとassetsの値は、amplify initの際にしれっと設定されていたdistを指定しましょう。

    - adapter: adapter()
    + adapter: adapter({
    + pages: 'dist',
    + assets: 'dist',
    + fallback: 'index.html',
    + })
  3. ソースコードをビルド

    buildコマンドでビルドします。

    npm run build

    distディレクトリにビルド結果が出力されます。

  4. Amplify Hostingの設定

    Amplify Hostingの設定を行います。ウィザードに従うだけです。

    amplify add hosting
    ✔ Select the plugin module to execute · Hosting with Amplify Console (Managed hosting with custom domains, Continuous deployment)
    ? Choose a type Manual deployment

    You can now publish your app using the following command:

    Command: amplify publish
  5. 公開する

    ソースをアップロードして公開します。

    amplify publish
    ✓ built in 9.75s
    ✔ Zipping artifacts completed.
    ✔ Deployment complete!
    https://dev.d2kjvugewtnasz.amplifyapp.com

    これで公開されますが、ログインするために、まだもうちょっとやることがあります。

  6. サインイン/サインアウト時のドメイン登録

    サインイン、サインアウトは事前に登録したドメインからでないと実施できません。Amplify Hostingで発行したドメインを追加します。

    amplify update auth

    ウィザードに従いながら、サインインとサインアウトにそれぞれドメインを登録します。(ドメインの末尾に/を付ける必要があるので注意)

    Please note that certain attributes may not be overwritten if you choose to use defaults settings.
    Using service: Cognito, provided by: awscloudformation
    What do you want to do? Add/Edit signin and signout redirect URIs
    Which redirect signin URIs do you want to edit?
    Do you want to add redirect signin URIs? Yes
    Enter your new redirect signin URI: https://dev.d2kjvugewtnasz.amplifyapp.com/
    ? Do you want to add another redirect signin URI No
    Which redirect signout URIs do you want to edit?
    Do you want to add redirect signout URIs? Yes
    Enter your new redirect signout URI: https://dev.d2kjvugewtnasz.amplifyapp.com/
    ? Do you want to add another redirect signout URI No
    ✅ Successfully updated auth resource myskeletonapp77ad9d4f locally

    ✅ Some next steps:
    "amplify push" will build all your local backend resources and provision it in the cloud
    "amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

    ✅ Successfully updated resource update locally

    ✅ Some next steps:
    "amplify push" will build all your local backend resources and provision it in the cloud
    "amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
  7. pushとpublish

    Cognitoのリソースを更新するためにamplify pushを、ソースコードを更新するためにamplify publishを実行します。

    amplify push
    amplify publish

これで完成です。スマートフォンからも見れます!

注記

単一ページの場合は問題ありませんが、複数ページ構成にした場合、トップページ以外にアクセスすると、エラーになります。

リダイレクト設定を行うことで、複数ページでも動作するようになります。

参考:Using redirects


最低限のチャットが作成できました。次回はもう少し見た目や使い勝手が良くなるように調整していきます。


ソースコードの全体はこちらで確認可能です。

https://github.com/moritalous/skeleton-chat/

  • 該当のソースコード

https://github.com/moritalous/skeleton-chat/blob/main/src/routes/v2/%2Bpage.svelte