AWS Amplify AI Kitに入門して簡単なAIアプリを作ってみる

# はじめに
本記事では、2024年11月19日に利用可能となった **AWS Amplify AI Kit** というAWS Amplifyの機能を使用してみたいと思います。

https://aws.amazon.com/jp/about-aws/whats-new/2024/11/aws-amplify-full-stack-ai-kit-amazon-bedrock/

# 1. AWS Amplify AI kitについて
## 1.1. そもそもAWS Amplifyとは
[AWS Amplify](https://aws.amazon.com/jp/amplify/ "AWS Amplify")は、開発者がフルスタックアプリケーションを効率的に開発するための統合プラットフォームとなるサービスです。

### 特徴
- **迅速な開発プロセスを提供**
    - 開発者は、個々のAWSサービスを深く理解する必要なく、フロントエンドとバックエンドの両方を迅速に開発できます
- **幅広い機能を提供**
    - 先ほど統合プラットフォームと記載した通り、AWS Amplifyはアプリケーションの構築や開発からホスティングまで、包括的な機能を提供してくれます

### ユースケース
ユースケースを考えると以下のようなスピード感を求められたり、プロジェクトのリソースが限られる場合に有用と思います。
- プロトタイプ開発
- スタートアップでの迅速なサービス立ち上げ
- 限られたリソースでのプロジェクト推進

:::note warn
ただし、大規模アプリケーション開発では、バックエンドの詳細な理解と設計も重要になります
:::

## 1.2. AWS Amplify AI kitとは
[AWS Amplify AI kit](https://aws.amazon.com/jp/amplify/ai/ "AWS Amplify AI kit")は、AWS Amplifyが提供する機能の１つです。
「AI kit」とあるとおり、様々なAIモデルをAPI経由で利用できる**Amazon Bedrock**というサービスを活用し、AIを活用したWebアプリケーションを簡単に構築できます。

### 主要な機能
AWS Amplify AI kitでは、Amazon Bedrockとやり取りするため、２種類のAI機能(もしくはRoutes)を提供します。

| AI機能 | 概要 | ユースケース |
| - | - | - |
| Conversation | **★本記事で紹介する機能になります**<br>リアルタイムに複数回の会話のやり取り(マルチターン)を考慮したAI機能を提供します | 英会話のレッスンなど対話型のアプリ |
| Generation | 指定した定義に従って構造化されたデータを同期的に生成するAI機能を提供します | 文章の要約など |



### アーキテクチャ
AWS Amplify AI kitを使用すると、以下のAWSサービスがデプロイされます。いずれもサーバレスなサービスです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/51ad09be-ec5a-aacf-d0e3-e35d239feb1f.png)
　
| AWSサービス | 本アプリでの役割 |
| - | - |
| Amazon Cognito | ユーザー認証機能を提供するサービスです<br>ユーザプールを使用して、ユーザーの管理やユーザーの認証を行います
| AWS AppSync | GraphQLのAPIを提供するサービスです<br>クライアントからAppSyncのAPIを呼び出し、AppSyncが各 AWSサービスへのリクエストを行います |
| AWS Lambda | Lambdaは、イベントに応じて処理を実行できるサービスです<br>AppSyncから呼び出され、Bedrockとのやり取りを行います |
| Amazon Bedrock | 様々なAIモデルをAPI経由で利用できるサービスです<br>Labmdaから呼び出され、AIモデルを用いてレスポンスを生成します |
| Amazon DynamoDB | キーバリュー型でデータを保管するNoSQLデータベースのサービスです。<br>Bedrockとやり取りしたチャット履歴をデータベースで保管します |

# 2. 実際に使ってみた
以下、実際に作成したWebアプリケーションになります。

![aws_amplify_ai_kit_sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/4e570eb0-42b3-cc99-fe0f-2de6b166cde6.gif)

## 2.1. 事前準備：Amazon Bedrockでのモデルアクセス許可を申請

今回、AIモデルとして **claude 3 haiku** を使用します。

Amazon Bedrockを利用する際は、使用するモデルに対して事前にアクセス許可を付与しておく必要があります。

詳細は以下の公式のガイドを参照して、アクセス許可を申請してください。

https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/getting-started.html

申請が承認されると、アクセスのステータスが「アクセスが付与されました」になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/b4975d63-cd82-0023-bd38-0caad33b0bf2.png)

## 2.2. フロントエンドのプロジェクト設定

### Viteを使用してプロジェクトを初期化する
フロントエンド側の環境として、**Vite**というツールを使用し、 **React** と **TypeScript** のプロジェクトを作成します。

```
> npm create vite@latest
```

### 依存パッケージのインストール
プロジェクトディレクトリに移動し、必要な依存パッケージをインストールします。

```
> cd <プロジェクト名>
> npm install
```

### ローカル環境で起動
ローカル環境でアプリケーションを起動します。

```:アプリをローカル起動
> npm run dev
```

ブラウザでhttp://localhost:5173/ にアクセスし、以下の画面が表示されれば準備完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/311a8eca-151e-19d2-f4a2-b16fcf211bc0.png)

<details><summary>この時点のディレクトリ構成</summary>

```
aws_amplify_ai_kit_app/
├── amplify/   ★フォルダが追加
├── node_modules/
├── public/
├── src/
├── .gitignore
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── README.md
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.js
```

</details>

## 2.3. バックエンドの設定
### AWS Amplifyプロジェクトの初期化

バックエンド用のAWS Amplifyプロジェクトを作成します。

```
> npm create amplify@latest
```

### サンドボックス環境でのデプロイ

作成したプロジェクトをサンドボックス環境にデプロイします。
```
cd .\amplify\
npx ampx sandbox
```

:::note info
**AWS Amplifyのサンドボックス環境とは**
実際のAWSアカウント上に開発用リソースを作成しますが、本番環境とは分離された開発・テスト環境を構築できる機能です。Amplifyのコードを書き替えて保存すると、随時、AWS環境に反映されます。
:::

### AWS Amplify AI kitを使用してバックエンド構築
`./app/amplify/`フォルダを見ると、`auth`と`data`フォルダがあります。

AWS Amplify AI Kitの機能を設定するためには、`data`フォルダの中のコードを修正します。

```typescript:./app/amplify/data/resource.ts
import { type ClientSchema, a, defineData } from '@aws-amplify/backend';

const schema = a.schema({
  chat: a.conversation({
    aiModel: a.ai.model('Claude 3 Haiku'),
    systemPrompt: 'You are a helpful assistant',
  })
  .authorization((allow) => allow.owner()),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: 'userPool',
  },
});
```
これでAWS Amplify AI Kitを使用して、以下のバックエンド部分が構築されます。
- AWS AppSync
- AWS Lambda
- Amazon Bedrock
- Amazon DynamoDB


次にAmazon Cognitoの設定は、`auth`フォルダが該当しますが、Amplifyのインストール時に自動生成されたコードをそのまま使用します。

```typescript:./amplify/amplify/auth/resource.ts
import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
  },
});

```

## 2.4. フロントエンドの設定
### 必要なライブラリのインストール
フロントエンドの設定に使用する各種ライブラリをインストールします。
- aws-amplify
    - AWS Amplifyのコアライブラリ
- @aws-amplify/ui-react-ai
    - AIチャット機能用のReactコンポーネント
- @aws-amplify/ui-react:
    - AWS Amplify用の基本的なUIコンポーネント


```:インストール
npm add aws-amplify @aws-amplify/ui-react-ai @aws-amplify/ui-react
```

### クライアントインスタンスの設定
フロントエンドとバックエンドとの通信を確立するため、以下のクライアント設定ファイルを作成します。
またUIコンポーネントからAI機能を利用するためのフックを設定します。

```typescript:.app/src/client.ts
import { generateClient } from "aws-amplify/api";
import { createAIHooks } from "@aws-amplify/ui-react-ai";
import type { Schema } from "../amplify/amplify/data/resource";

export const client = generateClient<Schema>({ authMode: "userPool" });
export const { useAIConversation } = createAIHooks(client);
```

:::note info
**generateClient**
generateClientでバックエンドとフロントエンドがAPI通信するためのインスタンスを作成します。
引数の`authMode: userPool` は、Amazon Cognitoのユーザープールを使用して、ユーザー認証を処理することを設定しています。
:::

:::note info
**createAIHooks**
createAIHooksは、UIコンポーネントからAI機能を利用するためのフックを提供します。
:::

### フロントエンドからAWS Amplifyを利用する設定

アプリケーションの起動時にAWS Amplifyを初期化するため、`Amplify.configure()` にamplify_outputs.jsonファイルを設定します。

```typescript:./app/src/main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { Amplify } from "aws-amplify";
import "@aws-amplify/ui-react/styles.css";
import outputs from "../amplify/amplify_outputs.json";
import './index.css'
import App from './App.tsx'

Amplify.configure(outputs);

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

```

### チャットUIの実装
メインのコンポーネントでは、`<AIConversation>`コンポーネントを使用してチャットのUIを実装します。


```typescript:./app/src/App.tsx
import { AIConversation } from "@aws-amplify/ui-react-ai";
import { useAIConversation } from "./client";

function App() {
  const [
    {
      data: { messages },
      isLoading,
    },
    handleSendMessage,
  ] = useAIConversation("chat");

  return (
    <AIConversation
      messages={messages}
      isLoading={isLoading}
      handleSendMessage={handleSendMessage}
    />
  );
}

export default App
```

## 2.5. 認証機能UIの実装
`<Authenticator>`コンポーネントを使用してログイン、ユーザ登録といった認証機能のUIを実装します。

:::note info
この認証機能の設定は、AWS Amplify AI kitの機能ではなく、どちらかというとAWS Amplifyの標準搭載された機能です。
なので、AIアプリに認証機能を組み込みたい際に、これらのコンポーネントを組み合わせて使用します。
:::


```typescript:./app/src/App.tsx
import { AIConversation } from "@aws-amplify/ui-react-ai";
import { Authenticator } from "@aws-amplify/ui-react";
import { useAIConversation } from "./client";

function App() {
  const [
    {
      data: { messages },
      isLoading,
    },
    handleSendMessage,
  ] = useAIConversation("chat");

  return (
    <Authenticator>
      <AIConversation
        messages={messages}
        isLoading={isLoading}
        handleSendMessage={handleSendMessage}
      />
    </Authenticator>
  );
}

export default App
```


## 2.6. UIをカスタマイズする

### チャット上のアイコンと名称をカスタマイズする
`<AIConversation>`コンポーネントの`avatars`を指定することで、チャット上のアイコン画像や名前をカスタマイズすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/a9c6abda-a8c4-de0c-67f9-f32376698032.png)

```typescript:./app/src/App.tsx (抜粋)
          <AIConversation
            messages={messages}
            isLoading={isLoading}
            handleSendMessage={handleSendMessage}
            avatars={{
              user: {
                avatar: <Avatar src="/man_icon.jpg" />,
                username: "あなた",
              },
              ai: {
                avatar: <Avatar src="/ai_icon.jpg" />,
                username: "AI"
              }
            }}
          />
```

### チャット上の日時表示をカスタマイズする
`<AIConversation>`コンポーネントの`displayText`に`getMessageTimestampText`を指定することで、日時表をカスタマイズできます。今回はJavaScriptの`DateTimeFormat`で日本時間に変更しています。

```typescript:./app/src/App.tsx (抜粋)
          <AIConversation
            messages={messages}
            isLoading={isLoading}
            handleSendMessage={handleSendMessage}
            displayText={{
              getMessageTimestampText: (date) => new Intl.DateTimeFormat('ja-JP', {
                dateStyle: 'full',
                timeStyle: 'short',
                hour12: true,
                timeZone: 'Asia/Tokyo'
              }).format(date)
            }}
          />
```

### ウェルカムメッセージをカスタマイズする
`<AIConversation>`コンポーネントの`welcomeMessage`にコンポーネントを指定することで、ウェルカムメッセージをカスタマイズできます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/6a9bbce1-196f-ee6f-19ba-077fcc684aaa.png)

```typescript:./app/src/App.tsx (抜粋)
          <AIConversation
            messages={messages}
            isLoading={isLoading}
            handleSendMessage={handleSendMessage}
            welcomeMessage={
              <WellcomeMessageCard/>
            }
          />
        </Card>
```

### `<AIConversation>`のCSSを直接カスタマイズする

細かなデザインを指定したい場合は、CSSを指定してデザインをカスタマイズできます。以下が主要なCSSクラス名です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/3f68ac66-df27-8968-f3ef-96c1e6051ccf.png)


```typescript:./app/src/App.css (抜粋)
.amplify-ai-conversation {
  align-items: center;
  width: 600px;
}

.amplify-ai-conversation__message__list {
  align-items: center;
  width: 600px;
}

.amplify-ai-conversation__message--assistant {
  background-color: bisque;
  border-radius: 0.5rem;
  width: 600px;
}

.amplify-ai-conversation__message--user {
  background-color: yellowgreen;
  margin: 1rem 0;
  border-radius: 0.5rem;
  width: 600px;
}

.amplify-ai-conversation__form {
  background-color: white;
  position: fixed;
  bottom: 0;
  width: 600px;
  padding: 16px;
}

```

### 全体のコード
最終的なコードは以下のGitを参照ください。

https://github.com/KMiya84377/amplify_ai_kit_app


## 2.7. 後始末
`Ctrl + C`キー で Amplify Sandboxを終了します。その後、以下のコマンドでAWS上のリソースを削除します。
```
npx ampx sandbox delete
```

# 3. まとめ

AWS Amplify AI kitを使用してみると、少ないコードでAmazon Bedrock含むバックエンド環境を構築することが出来て、良い意味で驚きました。

### メリット
- **爆速でWebアプリケーションを構築出来る**
    - フロントエンドからAIモデルまでのインフラ構築が自動的に作られるので、バックエンドを深く考えなくても構築できるかなという印象です

### デメリット
- **デプロイされたAWSリソースの詳細な設定内容が把握しづらい**
    - AWS Amplifyが良い感じにデプロイしてくれるのは嬉しいのですが、実際にデプロイされた内容はブラックボックスなので、結局は一定のバックエンド知識が必要だなという印象です
- **すべてを理解するには学習コストが高い**
    - 製品などサービスでの利用には、AWS Amplifyの知識に加えて、前述したとおりデプロイされるリソースの詳細な理解が必要そうという印象です

（どちらかというと、AWS Amplify自体の所感になってしまいました..）

### 今後の展望
今回はAWS Amplify AI kitの一部機能のみを使用しましたが、今後は他の機能も触ってみたいと思います。

またAmazon Bedrock自体の理解を深めることで、AWS Amplify AI kitをより使いこなせると思うので、Bedrockも入門してみたいと思います。



## 参考記事

https://aws.amazon.com/jp/blogs/mobile/build-fullstack-ai-apps-in-minutes-with-the-new-amplify-ai-kit/

https://github.com/aws-samples/amplify-ai-examples

https://docs.amplify.aws/react/ai/