NRIネットコム社員が様々な視点で、日々の気づきやナレッジを発信するメディアです

注目のタグ

    Amazon Q Developerの無料利用枠を使い倒してHello worldを表示させよう!

    はじめに

    こんにちは!2024年度新入社員の松澤武志です!

    実はこの度 AWS AI Practitioner試験を受験することにしました!(実はブログ執筆時点では5日前…ブログ書いている暇ないかも)

    そこで、AWS SageMakerAmazon Bedrockなど、生成AI機械学習にまつわるAWSサービスについて勉強していて、その中でもAmazon Qにとても興味を持ちました!そこで、今回はAmazon Qを用いてアプリケーションを構築してみることにしました。

    aws.amazon.com


    Amazon Q とは

    どのようなサービスかといいますと、対話型の生成AIサービスです。なんだn番煎じか~と思ったそこのあなた、いや全然違うんです。もちろんプロンプトに入力した質問を生成AIが返してくれるという点では同じですが、ビジネスという観点において、Amazon Qは物凄く力を発揮します。 Amazon QはBusinessとDeveloperに大別され、それぞれ業務を手助けしてくれるサービスです。この記事ではAmazon Q Developerを用いてアプリケーションを作成していきます。
    ↓Amazon Qの説明動画です!

    www.youtube.com

    Amazon Q Business

    こちらは、その名前の通りビジネス向けのサービスとなっています。生成AIを活用したアシスタントで、企業のシステム内のデータや情報に基づいて、質問への回答・要約の提供・コンテンツの生成・タスクの安全な実行を行えます。 中でも特に注目するべきポイントは2点あります。

    1. エンタープライズ内のデータや情報に基づいて、質問することができます
      ex) 「明日のミーティングは何時から」→「13時からです」みたいに答えてくれます。
      AWSの情報を学習した結果はもちろん、JiraやConfluence等のサードパーティ製のアプリケーションから会社の情報を学習した結果も併せて答えてくれます。
    2. アプリケーションを作ってくれます
      ex) プロンプトに「新規チケットを連携するアプリケーションを作って」と入力すると、Amazon Q Appsの中にアプリケーションが生成されます。
      Amazon Q Appsという専用のアプリの中限定ですが、コード補完とかすっとばしてアプリケーションを作れます。

    Amazon Q Develper

    Developerはその文字の通り、開発におけるあらゆるタスクをサポートすることができます。

    • アプリケーションのコーディング
    • テスト
    • レガシーなコード等のアップグレード
    • エラー診断
    • セキュリティスキャン
    • AWSリソースの最適化

    とてもいろんなことができて便利ですね~。

    VSCodeやJetBrains社のIDE等にもプラグインとしてインストールすることができます。
    エンジニアの「あったらいいな」を具現化したサービスなのではないでしょうか。

    こちらのAmazon Q Developerですが、他のサービスと同様にお金のかからない無料利用枠と、有料で様々なサービスを受けることができるAmazon Q Developer Proが存在します。今回は無料利用枠の範囲で使ってみようと思います。

    公式ページによると、

    無料利用枠ではソフトウェア開発のための Amazon Q Developer Agentの場合、1ヶ月あたり5回呼び出すことができます。 (Proの場合は、1か月あたり30回呼び出すことができます) コード変換のための Amazon Q Developer Agent の場合、1,000 行のコード/月を無料で変換してくれます。

    とのことですので、後述する/devコマンドは月に5回使用できることになります。

    Amazon Q Developerの使い方

    Amazon Q Developerは、プロンプトに入力するときに以下の4つのコマンドを指定します。

    • /dev:コードやファイルを生成してくれます。今回メインで使用するコマンドです。
    • /transform:古いバージョンのコードをアップグレードさせたりなど、コードを変換してくれます。
    • /help:Amazon Qに関するヘルプコマンドです。
    • /clear:セッションを切断します。

    また、別途Explain selected codeなどの一般的な質問も用意されており、ワンタッチで質問に回答してくれます。

    執筆時はまだAmazon Q Developerは日本語に対応していないため、別途翻訳ツールを使用して英語に変換してからプロンプトに入力するものとします。


    事前準備

    Amazon Qプラグインのインストール

    任意のエディタやIDEのプラグインでAmazon Q を選択し、インストールします。公式ページからもインストール可能です。今回はJetBrains社のIntelliJにインストールします。

    エディタやIDEのAmazon Qタブをクリックすると、「Amazon Q Chat」というチャット欄が出現します。こちらのsign-in optionを選択するとAWSの認証画面に遷移するので、そこでログインすればAmazon Qを使用できます。

    Spring InitializerでSpring Bootアプリケーションの作成

    まず初めにプロジェクトを作成します。

    今回は無料利用枠のコード生成コマンド5回使用以内にとどめるために下記の方針で進めます。

    • UI上で「Hello World」を表示させる簡単なアプリケーションを作成
    • 余った質問でAPIを作成

    Amazon Q DeveloperはIntelliJ上ではプロジェクトに入らないと使用できないので、とりあえずSpring Initializerで(amazonq)という名前のSpring Boot Applicationプロジェクトを作成します。Initializerの設定は以下のようにしましたが、今回の論旨から外れるため説明は省略します。

    こちらの設定でSpring Boot Applicationプロジェクトを作成することができました!
    別途SDKにAmazon Corretto17を指定したりしました。
    しかし、このままではControllerがないので、Whitelabel Error Pageが表示されてしまいます。

    ※ ページ表示時の環境によりポート番号が8081となっています。


    いざ使ってみよう!

    1. HelloWorldを表示させて

    まず初めにHello Worldを表示させるコントローラーを作成します。したがって、以下の文章を入力しました。

    HelloWorldを表示させるコントローラーを作成してください

    プロンプトに入力すると、体感1分ほど経過した後に、Amazon Qがコードを生成してくれます!

    今回のAmazon Qからの返信は以下の通りです。

    Generating code ...
    
    I'll share updates here as I work on this.
    
    **Summary of changes**
    
    1. Need to check content of "AmazonqApplication.java" first and then create a new controller class.
    2. I need to create a new controller class to handle the HTTP request and return "HelloWorld!" 
     as the response. I'll create a new HelloWorldController.java file in the appropriate package structure.
    3. I have successfully created a HelloWorldController with a GET endpoint at "/hello" that returns 
     "HelloWorld!" as requested. The Spring Boot application will automatically detect and register this 
     controller.
    
    **Files used**
    
    *These fields can change throughout code generation*
    
    - Reviewed: 1
        - src\main\java\com\amazon\amazonq\AmazonqApplication.java
    - Created: 1
        - src/main/java/com/amazon/amazonq/controller/HelloWorldController.java
    - Changed: 0
    - Deleted: 0
    

    HelloWorldController.javaを生成してくれました。

    package com.amazon.amazonq.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloWorldController {
    
        @GetMapping("/hello")
        public String sayHello() {
            return "HelloWorld!";
        }
    }
    

    コントローラーを作成したので▶ボタンでAmazonQApplicationを実行して
    いざ実行!
    しかし起動しませんでした…

    2. 起動方法を教えて

    次に起動方法を教えてもらうためにプロンプトに下記を入力しました。

    このアプリケーションを起動させてください

    そうすると、起動はしてもらえませんでしたが代わりにAction.mdに起動方法を記載してくれました。
    アプリケーションの実装構成にかかわらずとも、説明書を生成してくれるんですね~。
    Action.md

    # How to Activate the Application
    
    This is a Spring Boot application that can be activated using Gradle. Follow these steps to run the application:
    
    1. Open a terminal in the project root directory
    
    2. Run the application using the Gradle wrapper:
       - On Windows: `.\gradlew.bat bootRun`
       - On Linux/Mac: `./gradlew bootRun`
    
    The application will start and be accessible through:
    - The default Spring Boot port (8080)
    - You can test it by accessing `http://localhost:8080` in your web browser
    
    Note: Make sure you have Java installed on your system before running the application.
    

    こちらによると、ターミナルで.\gradlew.bat bootRunを実行すれば実行できるとのことです。▶の実行ボタンとは違う起動方法を教えてくれました。
    いざ実行!
    してみましたが、まだ起動しませんでした…

    エラーを見るとorg.springframework.boot.docker.compose.core.DockerProcessStartException: Unable to start docker process. Is docker correctly installed?とありました。

    そういえばDockerを起動していませんでしたので、デフォルトのcompose.yamlを参照すると、services:しか記載されていませんでした。

    3. compose.yamlを追記して

    次に、compose.yamlにコンテナのポート番号等を記載してもらうために、プロンプトに下記を入力しました。

    このアプリケーションをlocalhost:8080で起動させるために必要なコンテナを起動させる情報をcompose.yamlに記載してください

    すると、compose.yamlが下記のように修正されました。

    services:
      app:
        build: .
        ports:
          - "8080:8080"
        environment:
          - SERVER_PORT=8080
    

    Dockerイメージをビルドするためにdocker-compose -f compose.yaml buildをターミナルに入力したのですが、またもやエラーとなってしまいました… 私の事前知識不足でもあるのですが、Dockerイメージを出力するためにはDockerfileが必要でした。

    4. Dockerファイルを作成して

    次に、Dockerfileを作成してもらうために、プロンプトに下記を入力しました。

    Dockerファイルを作成し、compose.ymlでDockerファイルを指定してください

    すると、新規のDockerfileが作成されました!

    FROM eclipse-temurin:17-jdk-alpine
    WORKDIR /app
    COPY build/libs/*.jar app.jar
    EXPOSE 8080
    ENTRYPOINT ["java", "-jar", "/app/app.jar"]

    docker-compose -f compose.yaml buildをターミナルに入力したのですが、またもやエラーとなってしまいました。

    ここからは、残りの限られた質問回数で起動させられるか不安だったこともあり、手作業で環境を変更しました。DockerfileのFROMで指定するDockerイメージを変更したり、COPY句のパスを変更したり、ポート番号を8081に変更したり、いろいろ変更した結果起動することができました!

    ブラウザにhttp://localhost:8081/helloを入力し、
    いざ実行!
    すると、無事にHelloWorld!を表示させることに成功しました!

    5. タスクをINSERTするAPIを作成して

    次に、APIを作成してもらいます。taskテーブルが存在し、タスク期限及びタスク名を格納するという体でPOSTリクエストを受け付けるAPIを作成します。
    したがって、プロンプトに下記を入力しました。

    タスク、日付が情報として格納されるPOSTリクエストを受け付け、taskテーブルにデータを格納するAPIを作成してください

    すると、エンティティ、リポジトリ、コントローラー、アプリケーションクラス、H2DBに接続するためのapplication.propertiesまで作成してくれました!

    Task.java

    package com.example.task;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import java.time.LocalDate;
    
    @Entity
    public class Task {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String task;
        private LocalDate date;
    
        // Default constructor
        public Task() {}
    
        // Constructor with parameters
        public Task(String task, LocalDate date) {
            this.task = task;
            this.date = date;
        }
    
        // Getters and setters
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getTask() {
            return task;
        }
    
        public void setTask(String task) {
            this.task = task;
        }
    
        public LocalDate getDate() {
            return date;
        }
    
        public void setDate(LocalDate date) {
            this.date = date;
        }
    }
    

    TaskRepository.java

    package com.example.task;
    
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface TaskRepository extends JpaRepository<Task, Long> {
    }
    

    TaskController.java

    package com.example.task;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;
    import java.time.LocalDate;
    
    @RestController
    @RequestMapping("/api/tasks")
    public class TaskController {
    
        @Autowired
        private TaskRepository taskRepository;
    
        @PostMapping
        public ResponseEntity<Task> createTask(@RequestBody TaskRequest request) {
            Task task = new Task(request.getTask(), request.getDate());
            Task savedTask = taskRepository.save(task);
            return ResponseEntity.ok(savedTask);
        }
    }
    
    class TaskRequest {
        private String task;
        private LocalDate date;
    
        // Getters and setters
        public String getTask() {
            return task;
        }
    
        public void setTask(String task) {
            this.task = task;
        }
    
        public LocalDate getDate() {
            return date;
        }
    
        public void setDate(LocalDate date) {
            this.date = date;
        }
    }
    

    Application.java

    package com.example.task;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }
    

    application.properties

    # H2 Database Configuration
    spring.datasource.url=jdbc:h2:mem:taskdb
    spring.datasource.driverClassName=org.h2.Driver
    spring.datasource.username=sa
    spring.datasource.password=
    spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
    
    # Enable H2 Console
    spring.h2.console.enabled=true
    spring.h2.console.path=/h2-console
    
    # JPA/Hibernate properties
    spring.jpa.hibernate.ddl-auto=update
    spring.jpa.show-sql=true

    しかし、この内容には下記の課題がありました。

    • アプリケーションクラスは既存とは別で実装されてしまったこと
    • import javax.persistence.Entity;等のjavaxライブラリは既存の環境では使えないこと
    • コントローラ、リポジトリなどを別のパッケージに格納してほしかったが、同一パッケージに格納されてしまったこと
    • H2DBが.application.propertiesの設定では使用できなかったこと

    Hello worldを表示させるコントローラーやAPIに関しては大枠を簡単に作れましたが、importするライブラリや環境設定のところでAmazon Qは少し間違えた出力をしてしまうということが解りました。

    これにて無料利用枠を使い切りました!(完)


    まとめ

    ここまで見てくださりありがとうございました!

    私がAmazon Q Developerを使ってみた主な感想はこの3点ですね。

    • 「APIを作ってください」など大雑把な入力に対してより効果を発揮できる
      • API作成時に、コントローラー層からリポジトリ層まで作ってくれたので、コードを書く量を減らしてくれたというメリットが大きい。
    • 逆に細かな動作はAmazon Qに任せずに自分でコードを書いたほうが速い
      • importするライブラリが間違っていたり、依存関係が解消できなかったりと、環境設定の分野に関しては間違った設定がされることが多いのがデメリット。
    • プロンプトエンジニアリングの技量も試される
      • ある程度プロンプトで指定しないと、間違ったパッケージにクラスが配置されたり、不要なクラスも作成されてしまう。

    Chat GPTが登場した時にも言われていましたが、Amazon Qでも生成したコードの後処理やプロンプトエンジニアリング等の技術が必要になってくるので、エンジニアが必要なくなるなんてことはなさそうです!

    Amazon Q Businessは今年、2024年の12月から日本語版がリリースされるようです。ますます勢いを増していくAmazon Q、皆さんもぜひ使ってみてください!

    ソースコード

    こちらに、今回作成したアプリケーションのソースコードを記載しています!(起動はしませんのでご注意を)
    https://github.com/18takeshi/amazonq/tree/main

    執筆者 松澤武志

    2025 Japan AWS Jr. Champion
    趣味でAWSをいじるネイティブアプリエンジニア(.NET/C#/Java/Angular)

    ・執筆記事一覧: https://tech.nri-net.com/archive/author/t-matsuzawa
    ・X:https://x.com/2357_takeshi
    ・Speaker Deck:https://speakerdeck.com/matsuzawatakeshi
    ・Qiita:https://qiita.com/takeshi18