Generative AI Use Case JP (GenU)

~ はじめての Contribution ガイド

2025-04-02
デベロッパーのためのクラウド活用方法

Author : 岡元 佑樹

皆さまこんにちは ! Amazon Software Development Engineer の岡元佑樹と申します。

生成 AI の業務活用に興味はあるものの、「どのように始めればよいのか」「セキュリティ面は大丈夫なのか」といった課題を抱えている方も多いのではないでしょうか。

Generative AI Use Cases JP (以降 GenU) は、そんな課題を解決するために AWS Japan の有志を中心に開発された生成 AI アプリケーションです。Amazon Bedrock や Amazon Kendra などの AWS のサービスを活用し、チャットボットや RAG (検索拡張生成)、画像生成など、すぐに業務で活用できる様々なユースケースを 1 つのアプリケーションとして提供しています。

GenU は OSS (オープンソースソフトウェア) として公開されており、誰でも自由に利用、カスタマイズ、contribution を行うことができます。詳細な機能や導入方法については、GitHub リポジトリ をご覧ください。

* 本記事で説明する内容は、2025 年 2 月時点の GenU に基づいています。

私自身 OSS への contribution は初めての経験でした。「コードを書いて Pull Request を出したい」という思いはあるものの、大規模なプロジェクトのコードベースを理解することや、contribution のワークフローに慣れることに最初は戸惑いを感じました。この記事では、同じように GenU contribution に挑戦したい開発初心者の方々に向けて、私の経験を共有させていただきます。

本記事の対象者

  • GenU のディレクトリ構成を理解したい開発者
  • GenU を利用中にエラーが発生し、トラブルシューティングの方法を知りたいユーザー
  • GenU の contribution に興味がある方

以下では、GenU のプロジェクト構造と開発環境のセットアップについて説明した後、実際の contribution 例を通じて Pull Request の作成プロセスを紹介します。また、GenU を利用する中でエラーに遭遇した場合の問題切り分けの方法についても触れていきます。各セクションは独立して理解できる構成になっているので、興味のある部分から読み進めていただけます。

ご注意

本記事で紹介する AWS サービスを起動する際には、料金がかかります。builders.flash メールメンバー特典の、クラウドレシピ向けクレジットコードプレゼントの入手をお勧めします。

*ハンズオン記事およびソースコードにおける免責事項 »


1. GenU プロジェクトの基本構造

* 理解しやすいよう省略ファイルがあります。

1-1. ディレクトリ構成の概要

npm workspaces を活用したモノレポ構造を採用しており、複数の独立したパッケージを単一リポジトリで管理しています。この設計により、フロントエンド、バックエンド、共有ライブラリなどのコンポーネント間の依存関係を効率的に管理しながら、各モジュールの開発独立性を確保しています。

generative-ai-use-cases-jp/
├── packages/
│   ├── cdk/           # インフラ・バックエンド
│   ├── common/        # 共有関数・モデル
│   ├── types/         # 共有型定義
│   └── web/           # フロントエンド
├── package.json       # プロジェクト設定
└── setup-env.sh       # 環境変数設定スクリプト

1-2. ディレクトリ構成の詳細

1-2-1. バックエンド (packages/cdk/lambda)

TypeScript を使用しています。
AWS Lambda 関数による API エンドポイント・Amazon DynamoDB の操作を行っています。

cdk/
└── lambda/
    ├── repository.ts  # DynamoDB 操作層
    └── *.ts           # 各 API エンドポイント実装

*.ts の例として、Chat メッセージの CRUD (Create/Read/Update/Delete) の 1 つである createChat.ts を紹介します。

createChat.ts を見ると、Amazon API Gateway からのリクエストを処理するハンドラー関数が実装されています。このハンドラーは、repository モジュールの createChat 関数を呼び出してデータベース操作を行います。他の CRUD 操作も同様に、対応する *.ts ファイルと repository.ts のペアで実装されています。

// createChat.ts
import { createChat } from './repository';

export const handler = async (
  event: APIGatewayProxyEvent
): Promise<APIGatewayProxyResult> => {
  try {
    const userId: string =
      event.requestContext.authorizer!.claims['cognito:username'];
    const chat = await createChat(userId);
// repository.ts
export const createChat = async (_userId: string): Promise<Chat> => {
  const userId = `user#${_userId}`;
  const chatId = `chat#${crypto.randomUUID()}`;
  const item = {
    id: userId,
    createdDate: `${Date.now()}`,
    chatId,
    usecase: '',
    title: '',
    updatedDate: '',
  };

  await dynamoDbDocument.send(
    new PutCommand({
      TableName: TABLE_NAME,
      Item: item,
    })
  );

  return item;
};

この構造により、API リクエストの処理とデータベース操作の責務が明確に分離され、コードの可読性と保守性が向上しています。

1-2-2. インフラストラクチャ (packages/cdk)

AWS Cloud Development Kit (CDK) という Infrastructure as Code (IaC) ツールを使用し、インフラ構成をコードで管理しています。CDK を使用することで、手作業でのリソース構築ではなく、TypeScript などのプログラミング言語で AWS リソースを定義・管理できます。

Constructs と Stack については後述します。

cdk/
├── lib/
│   ├── construct/          # AWS サービス詳細設定
│   │   ├── api.ts          # API Gateway 設定と Lambda 統合
│   │   ├── auth.ts         # Cognito 認証
│   │   ├── database.ts     # DynamoDB テーブル
│   │   ├── rag.ts          # RAG 機能 (条件付きデプロイ)
│   │   └── web.ts          # S3 / CloudFront 設定
│   │
│   └── generative-ai-use-cases-stack.ts  # 全リソースの統合ポイント (メインスタック)
│
├── cdk.json                # デプロイ設定・環境変数
└── package.json            # バックエンド・インフラ依存関係

1-2-3. フロントエンド構造 (packages/web)

React / TypeScript / TailwindCSS を使用しています。ビルドツールとして Vite を採用しています。

web/
├── public/         # CloudFront から配信される静的コンテンツ
├── src/
│   ├── assets/     # ビルド時に最適化される画像やアイコン 
│   ├── components/ # 共通 UI コンポーネント
│   ├── hooks/      # API コール用カスタムフック
│   ├── pages/      # 画面単位のコンポーネント
│   ├── App.tsx     # アプリケーションルート
│   └── main.tsx    # エントリーポイント
└── package.json    # フロントエンド依存関係

2. GenU コードの理解の進め方

プロジェクトを理解するには、最初にインフラストラクチャから確認する必要があります。

2-1. AWS Cloud Deoployment Kit (AWS CDK)

Stack と Construct の関係性

GenU のインフラ構成は、AWS CDK を使用して AWS CloudFormation (CloudFormation) の Stack として管理されています。Stack は、CloudFormation におけるリソース管理の基本単位であり、デプロイ・更新・削除などの操作を Stack 単位で行います。

GenU のインフラ構成は以下の階層で管理されています:

  • Stack (generative-ai-use-cases-stack.ts など)
    • 複数の Construct を組み合わせて機能を実現
  • Construct (construct/*.ts)
    • 関連する複数のリソースをまとめた論理的なグループ (例えば、API Construct には API Gateway、関連する Lambda 関数、必要な IAM ロールなどが含まれる可能性があります)

こちらは Stack と Construct が親子関係になっていることを表す図です。

2-2. 機能の有効化 (cdk.json)

最初に packages/cdk/cdk.json を確認します。このファイルでプロジェクトのどの機能を有効にするかを設定します。
各設定パラメータの詳細な説明や利用可能なオプションについては、GenU 公式ドキュメント をご参照ください。

{
  "context": {
    "ragEnabled": true,            // RAG 機能の有効(true)/無効(false)
    "bedrockRegion": "us-east-1",  // 使用する AWS リージョン
    ...
  }
}

packages/cdk/parameter.ts により、環境に応じたパラメータを定義することが可能です。今記事では cdk.json を使用するため、parameter.ts については触れません。

2-3. Stack の設定

次に packages/cdk/lib/generative-ai-use-cases-stack.ts を確認します。

export class GenerativeAiUseCasesStack extends Stack {
  constructor(scope: Construct, id: string, props: GenerativeAiUseCasesStackProps) {
    super(scope, id, props);
    const params = props.params;

    // 基本リソースの設定
    const auth = new Auth();
    const api = new Api();
    
    const web = new Web(this, 'Api', {
      // 機能フラグの確認
      ragEnabled: params.ragEnabled,
    }

    // 条件付き機能の追加
    if (params.ragEnabled) {
      const rag = new Rag(this, 'Rag', {
        userPool: auth.userPool,
        api: api.api,
      });
    }
  }
}

前セクションで示した cdk.json の例では ragEnabledtrue となっているため、RAG 機能用のリソースがデプロイされます。

2-4. Construct の設定

最後に packages/cdk/lib/construct/ 配下の各ファイルで詳細設定を確認します。

construct/
├── api.ts      # API 設定 (エンドポイント、メソッドなど)
├── auth.ts     # 認証設定 (ユーザープール、認証フロー)
├── database.ts # データモデル (テーブル構造、インデックス)
├── rag.ts      # RAG 機能 (条件付きデプロイ)
└── web.ts      # フロントエンド配信設定

例えば、RAG 機能の Construct には以下のような設定が含まれています。

  • 使用する AWS サービス
  • API 設定
  • 必要な IAM ロール

これらの設定は機能が有効な場合のみデプロイされ、不要なリソースの作成を防ぎます。デプロイされたリソースは AWS マネジメントコンソール の CloudFormation から確認できます。デプロイされたアプリケーションは CloudFormation の GenerativeAiUseCasesStack 出力タブにある WebUrl からアクセスできます。

画像をクリックすると拡大します


3. ローカル開発環境のセットアップ

3-1. バックエンド開発と AWS デプロイ

GenU のバックエンドはAWSのマネージドサービス (Lambda、API Gateway、DynamoDB など) を直接利用する構成を採用しているため、ローカル環境での開発であっても AWS 環境へのデプロイが必要です。Docker コンテナなどでローカル完結型の開発が可能なケースとは異なる点にご注意ください。

README に記載 されている通りにデプロイします。

バックエンドを修正した際、再デプロイは以下のコマンドで実行します。

npm run cdk:deploy

Lambda 関数のコードのみを修正する場合は、CDK の hotswap 機能を利用することで高速デプロイが可能です。

npm -w packages/cdk run -- cdk deploy --hotswap --require-approval never --all

3-2. フロントエンド開発

ローカルでの開発環境構築手順です。正常に実行できない場合は こちら をご覧ください。

3-2-1. setup-env.sh を使用する方法 (Mac 向け)

開発環境のセットアップには jq (JSON パーサー) が必要です。setup-env.sh スクリプトで CloudFormation のアウトプット値を環境変数として設定する際に使用します。

brew install jq

Mac 以外で setup-env.sh を使用する場合は こちら をご確認ください。
フロントエンド開発用のスクリプトは package.json に定義されています。

{
  "scripts": {
    "web:devw": "source ./setup-env.sh ${npm_config_env} && VITE_APP_VERSION=${npm_package_version} npm -w packages/web run dev"
  }
}

開発サーバーの起動を行います。

npm run web:devw

このコマンドは以下の処理を実行します:

  • CloudFormation のアウトプット値を環境変数として設定 (setup-env.sh)
  • Vite 開発サーバーの起動

3-2-2. PowerShell スクリプトを使用する方法 (Windows 向け)

開発サーバーの起動を行います。

npm run web:devww

このコマンドは web_devw_win.ps1 という PowerShell スクリプトを実行し、jq のインストールは不要です。

3-2-3. その他のユーザーの場合

  1. プロジェクトのルートディレクトリに .env ファイルを作成します。
  2. AWS コンソールの CloudFormation 出力タブから必要な値をコピーします
  3. 以下の形式で .env ファイルに記述します。
VITE_APP_API_ENDPOINT=https://xxxxx.execute-api.us-east-1.amazonaws.com/api/
VITE_APP_REGION=us-east-1

VITE_APP_USER_POOL_ID=us-east-1_xxxxx
VITE_APP_USER_POOL_CLIENT_ID=xxxxx
VITE_APP_IDENTITY_POOL_ID=us-east-1:xxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

VITE_APP_PREDICT_STREAM_FUNCTION_ARN=arn:aws:lambda:us-east-1:xxxxx:function:xxxxx
VITE_APP_PROMPT_FLOW_STREAM_FUNCTION_ARN=arn:aws:lambda:us-east-1:xxxxx:function:xxxxx
VITE_APP_PROMPT_FLOWS=xxxxx

... 上記同様に CloudFormation 出力タブの値をコピー

フロントエンド開発用のスクリプトは package.json に定義されています。

{
  "scripts": {
    "web:dev": "VITE_APP_VERSION=${npm_package_version} npm -w packages/web run dev"
  }
}

開発サーバーを起動を行います。

{
  "scripts": {
    "web:dev": "VITE_APP_VERSION=${npm_package_version} npm -w packages/web run dev"
  }
}
npm run web:dev

開発サーバーが起動したら、ブラウザで http://localhost:5173 にアクセスしてください。

フロントエンドを本番環境にデプロイする際は、バックエンドと同様に以下のコマンドで実行します。

npm run cdk:deploy

クリックすると拡大します


4. GenU への Contribution 例

本セクションでは、実際の Issue を例に、GenU への contribution ワークフローを説明します。

チャットボットの bad フィードバック機能の改善」という Issue を解決する過程を通じて、実際の開発フローを見ていきます。React および Node.js の基本的な知識があることを前提とします。

4-1. Issue の概要

現状、チャットボットの応答に対して「bad」ボタンを押しても具体的なフィードバックを残せない仕様となっています。
この Issue では、以下の改善が必要です:

  • フィードバック理由の選択機能
  • 詳細なフィードバックを入力できるフォームの追加
  • 入力されたフィードバックのデータベースへの保存

4-2. 開発の流れ

4-2-1. リポジトリのフォークとセットアップ

  1. GitHub で GenU リポジトリをフォークします。
  2. 開発環境のセットアップを行います。
git clone [フォークしたリポジトリの URL]
cd generative-ai-use-cases-jp 

前述の手順 (ローカル開発環境のセットアップ) に従います。

3. 開発用ブランチの作成を行います。 (ここでは bad-button というブランチ名です。)

git checkout -b bad-button

4-2-2. フロントエンド開発

  1. 既存の LLM チャットボットの UI/UX を参考にデザインを検討します。
  2. フィードバックフォームの実装を行います。
// packages/web/src/components/FeedbackForm.tsx

export const FeedbackForm: React.FC<Props> = ({ ... }) => {
  // フィードバックフォームのコンポーネント実装
;

3. 既存のフィードバック機能との統合を行います。

packages/web/src/components/ChatMessage.tsx FeedbackForm コンポーネントを import し実装します。

// packages/web/src/components/ChatMessage.tsx

import FeedbackForm from './FeedbackForm';
export const ChatMessage: React.FC<Props> = () => {
  return (
    <div>
      {/* 既存のチャットメッセージUI */}      
      {showFeedbackForm && (
        <FeedbackForm
          onSubmit={handleFeedbackSubmit}
          onClose={() => setShowFeedbackForm(false)}
        />
      )}
    </div>
  );
};

4-2-3. バックエンド開発

データモデルの拡張を行います。

注意:データモデルの変更は、システム全体に影響を与える可能性があります。

// packages/types/src/protocol.d.ts

export type UpdateFeedbackRequest
  createdDate: string;
  feedback: string;
  reasons?: string[];         // フィードバック理由 (複数選択可) 追加
  detailedFeedback?: string;   // 詳細なフィードバックコメント追加
}

この変更は既存のデータ構造を拡張するものであり、既存のフィールドには影響を与えません。

DynamoDB アクセスレイヤーの修正を行います。
packages/cdk/lambda/repository.ts でフィードバック内容を Dynamo DB に保存できるよう実装を追加します。

4-2-4. フロントエンドとバックエンドの統合

API クライアントの実装を行います。
packages/web/src/hooks/useChat.ts でフィードバック送信用のカスタムフックを実装します。

コンポーネントから API 呼び出しを実行します。
packages/web/src/components/ChatMessage.tsxuseChat コンポーネントを使用します。

4-3. Pull Request の作成

Pull Request を作成する前に、動作確認と以下のコマンドでコードの品質チェックを実施してください。

npm run lint
npm run cdk:test
// スナップショット差分がある場合は以下を実行してスナップショットを更新
npm run cdk:test:update-snapshot

問題がないことを確認したら、以下の内容を Pull Request として作成します:

  • Issue の説明
  • 実装の詳細

5. トラブルシューティングガイド

GenU の利用中にバックエンドでエラーが発生し、正常に動作しない場合があります。このセクションでは、そのような場合のトラブルシューティングの方法について解説します。

5-1. エラーの特定

トラブルシューティングの基本的な最初のステップは、ブラウザの開発者ツールでエラーメッセージを確認することです。ここでは Chrome ブラウザと VSCode エディタを使用して説明します。

Chrome 開発者ツールを開きます。

Chrome ブラウザ内で右クリックし、「検証」を選択します。

Chrome 画面から引用
(クリックすると拡大します)

Console タブを選択します。

開発者ツールのコンソールで、2 つの API で 500 Internal Server Error が発生していることが確認できます。このエラーは、フロントエンド側の問題ではなく、バックエンド側の API 処理中に問題が発生していることを示しています。

1. POST /api/predict/title
   エンドポイント: {API_ENDPOINT}/api/predict/title 

2. POST /api/chats/{何かしらのID}/messages
   エンドポイント: {API_ENDPOINT}/api/chats/{chatId}/messages

Chrome 画面から引用
(クリックすると拡大します)

5-2. 問題の API を特定

VSCode を使用してコードベース内で API エンドポイントを検索します。

VSCode で ⌘ + Shift + F (Windows の場合は Ctrl + Shift + F) を使用して、predict/title を検索します。

検索結果から predictTitleFunction を確認します。( ⌘ or Ctrl キーを押しながらクリックで定義箇所へジャンプ)

クリックすると拡大します

検索の結果、predictTitle という名前の Lambda 関数が実装されていることが分かります。

クリックすると拡大します

5-3. Amazon CloudWatch でログを確認

確認したい Lambda 関数のログを確認することで、エラーの詳細を把握できます。

Lambda 関数の確認

AWS コンソール上で Lambda コンソールを開いて、検索バーに predictTitle と入力すると該当する関数が表示されるので、関数のリンクをクリックします。

クリックすると拡大します

ログの確認手順

モニタリング」タブを選択して、「CloudWatch ログの表示」をクリックします。

クリックすると拡大します

最新のログストリームをクリックします。

クリックすると拡大します

エラー内容の確認

エラーログの内容から以下のことが分かります:

  • エラー種別:スロットリングエラー
  • 原因:Bedrock の使用制限超過
  • 解決策:しばらく時間をおいて再実行

クリックすると拡大します

このエラーは一時的なもので、Bedrock 使用量制限によるものであるので、問題ないことがわかります。

Tips

Internal Server Error 500 は多くの場合 Lambda の実行エラーに起因します。CloudWatch ログを確認することで、効率的に原因特定と解決策の検討が可能です。


6. まとめ

本記事では、GenU のプロジェクト構造から実際の開発フロー、トラブルシューティングについて解説しました。

私自身、初めての OSS contribution で戸惑うことも多くありましたが、一つ一つの機能を理解しながら進めることで、無事に Pull Request を作成することができました。GenU は生成 AI の実用的なユースケースを学べるだけでなく、OSS へのcontribution を始めるきっかけとしても最適なプロジェクトです。

本記事が、GenU を利用される方々のトラブルシューティングの助けとなり、また開発に挑戦したい方々の一助となれば幸いです。


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

岡元 佑樹 (Yuki Okamoto)
アマゾンジャパン合同会社
ソフトウェアディベロップメントエンジニア

Amazon ポイントの開発をしているエンジニア。AWS の生成 AI 関連の技術が好きで GenU の開発に携わっています。趣味はボクシングと IPA ビールを飲むことです。

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する