KINTO Tech Blog
General

Javaで生成AI(Azure OpenAI)を呼び出す

Cover Image for Javaで生成AI(Azure OpenAI)を呼び出す

この記事は KINTOテクノロジーズアドベントカレンダー2024 の9日目の記事です🎅🎄

はじめに

こんにちは、DX開発グループでアプリケーションエンジニアを行っている亀山です。

近年、生成AIはさまざまな分野で活用されており、私たちの開発チームでも生成AIを活用したシステムの構築が行われています。

さらに、私たちの開発チーム内で広く使用されているJavaは、既存の知見やツールを活かしながら生成AIのインターフェースを効率的に構築することができると考えました。本記事では、こうした背景を踏まえ、Javaを用いて生成AIを呼び出し、結果を処理する方法について解説します。

今回はその導入編として、Javaコードを用いてAzure OpenAIのライブラリを用いて、呼び出す基本的な実装について、シンプルなコード例を用いてお話したいと思います。Azure OpenAIはOpenAIに比べ、高いスケーラビリティや信頼性に優れ、規模の大きい業務システムとも親和性が高いプラットフォームとされています。

Azure Open AIのセットアップ

Azure サブスクリプションに登録します。

https://azure.microsoft.com/en-us/pricing/purchase-options/azure-account?icid=ai-services&azure-portal=true

あとは下記ページの説明に従ってエンドポイントとキーを取得します。

https://learn.microsoft.com/ja-jp/azure/ai-services/openai/chatgpt-quickstart?tabs=command-line%2Cjavascript-keyless%2Ctypescript-keyless%2Cpython-new&pivots=programming-language-java

取得先のAzureコンソールはこちらになります。
※先ほど登録したアカウントでのログインが必要なページになります。

OpenAIライブラリのセットアップ

今回Azure OpenAIをコールするにあたり、AzureのSDKライブラリを使用します。
Azure OpenAIではこのSDKライブラリによって簡単に生成AIを呼び出すためのコーディングを行うことができます。

Gradleの場合

dependencies {
    implementation 'com.azure:azure-ai-openai:1.0.0-beta.12'
    implementation 'com.azure:azure-core-http-okhttp:1.7.8'
}

Mavenの場合

<dependencies>
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-ai-openai</artifactId>
        <version>1.0.0-beta.12</version>
    </dependency>
    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-core-http-okhttp</artifactId>
        <version>1.7.8</version>
    </dependency>
</dependencies>

使用バージョンは執筆時点のものであるため、最新バージョンついては公式ドキュメントでご確認ください。

特に今回使用するAzure OpenAI client library for Javaは現在ベータ版であるため、今後安定版がリリースされた場合にはそちらを使用していただくことをおすすめします。

実際にAzure OpenAIのチャットモデルを呼び出してみる

参考: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/openai/azure-ai-openai

/src/main/resource/config.properties

endpoint=https://{リソース名}.openai.azure.com/
apiKey={APIキー}

取得したAzure OpenAIのエンドポイントとAPIキーを別ファイルで管理するためこちらに入力してください。
シークレット情報の管理方法はご自身またはチームの方針に合わせていただいても大丈夫です。

/src/main/java/com/sample/app/Main.java

package com.sample.app; // ご自身のパッケージ名に合わせてください

import com.azure.ai.openai.OpenAIClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.ai.openai.models.*;
import com.azure.core.credential.AzureKeyCredential;

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // プロパティファイルを読み込む ※別の方法でキー情報を管理する場合は適宜変更してください
        Properties properties = new Properties();
        try (InputStream input = Main.class.getClassLoader().getResourceAsStream("config.properties")) {
            if (input == null) {
                System.out.println("config.properties ファイルが見つかりません。");
                return;
            }
            properties.load(input);
        } catch (IOException ex) {
                System.out.println(ex.getMessage());
            return;
        }

        // プロパティから設定値を取得
        String endpoint = properties.getProperty("endpoint");
        String apiKey = properties.getProperty("apiKey");

        // OpenAIクライアントを作成
        var client = new OpenAIClientBuilder()
                .endpoint(endpoint)
                .credential(new AzureKeyCredential(apiKey))
                .buildClient();

        // プロンプトを準備
        List<ChatRequestMessage> messages = new ArrayList<>()
                .setTemperature(0.7)        // 応答のランダム性、高いほど多様(0.0~2.0)
                .setMaxTokens(100)          // 応答の最大トークン数
                .setFrequencyPenalty(0.0)   // 頻出する単語に対するペナルティ(-2.0~2.0)
                .setPresencePenalty(0.6);   // 既存のトピックに関連させるものに対するペナルティ(-2.0~2.0)
        messages.add(new ChatRequestSystemMessage("あなたは優秀なAIアシスタントです。"));
        messages.add(new ChatRequestUserMessage("初心者向けに、Javaのクラスとオブジェクトの違いを説明してください。"));

        // リクエストオプションを設定
        var options = new ChatCompletionsOptions(messages);
        var chatCompletions = client.getChatCompletions("gpt-4o", options); // 使用するデプロイ名または生成AIモデル名を指定してください

        // リクエストを送信して結果を取得
        for (ChatChoice choice : chatCompletions.getChoices()) {
            ChatResponseMessage message = choice.getMessage();
            System.out.printf("Index: %d, Chat Role: %s.%n", choice.getIndex(), message.getRole());
            System.out.println("Message:");
            System.out.println(message.getContent());
        }

    }
}

生成AIの呼び出しにあたり、様々なパラメータを設定することができます。普段使用するChatGPTアプリケーションでは現在設定できないパラメータで、こういったパラメータを調整できるのもプログラムから生成AIを呼び出すメリットの1つです。今回は4つのパラメータ(temperature、maxTokens、frequencyPenalty、presencePenalty)を設定しましたが、他にも様々なパラメータがあります。詳細はこちらを参照してください。

また、messagesの部分で下記2種類のメッセージをセットしました。前者のChatRequestSystemMessageはセットしなくても実行可能です。

  • ChatRequestSystemMessage

    生成AIモデルの振る舞いや役割を設定するためのメッセージで、会話のトーンや応答の仕方を定義します。

  • ChatRequestUserMessage

    ユーザーからの具体的な質問や指示をAIに伝えるためのメッセージで、このメッセージに対する回答が返却値としてOpenAIから返されます。

getChatCompletionsの第1引数はデプロイ名またはモデル名を入力します。
デプロイ名はAzureポータルで取得します。Azure以外のOpenAIを使用する場合はモデル名「gpt-4o」「gpt-3.5-turbo」などを入力します(上記の例だとモデル名を入力しています)。

.gitignore

/src/main/resources/config.properties

今回ご説明するように/src/main/resource/config.propertiesで管理する場合は.gitignoreに上記1行を追加してください。

特にリポジトリで管理する際はAPIキーなどのシークレット情報の取り扱いにはくれぐれもご注意ください

実行結果

下記のようなレスポンスをOpenAIから得ることができました。(実際にはMarkdown形式の文字列です)

Index: 0, Chat Role: assistant.
Message:
Javaにおけるクラスとオブジェクトの違いは、初めてプログラミングを学ぶ人にとって重要な概念です。以下に分かりやすく説明します。

クラス

  • 設計図: クラスはオブジェクトを作成するための設計図やテンプレートと考えることができます。クラスにはオブジェクトの属性(フィールド)や動作(メソッド)が定義されています。
  • 宣言: Javaではクラスを定義するために`class`キーワードを使用します。例えば、車を表すクラスは以下のように定義できます。
public class Car {
    // フィールド(属性)
    String color;
    int year;
    
    // メソッド(動作)
    void drive() {
        System.out.println("The car is driving");
    }
}

オブジェクト

  • インスタンス: オブジェクトは、クラスから生成された実体(インスタンス)です。オブジェクトは特定のデータを持ち、そのデータに対する操作を行うことができます。
  • 生成: Javaでは`new`キーワードを使用してクラスからオブジェクトを生成します。例えば、`Car`クラスからオブジェクトを作成する場合は次のようになります。
public class Main {
    public static void main(String[] args) {
        // Carクラスのインスタンスを作成
        Car myCar = new Car();
        myCar.color = "Red";
        myCar.year = 2020;
        
        // オブジェクトのメソッドを呼び出す
        myCar.drive();
    }
}

まとめ

  • クラスはオブジェクトを作成するためのテンプレートであり、属性や動作を定義しています。
  • オブジェクトはそのクラスの実際のインスタンスであり、具体的なデータを持ち、定義された動作を実行できます。

この基本的な関係を理解することで、より複雑なプログラム構築を始めることができます。

終わりに

今回の記事では、JavaでAzure OpenAIを利用する基本的な方法について紹介しました。

JavaによるOpenAIの利用に関する情報はまだ少ないため、本記事が皆様のお役に立てれば幸いです。

次回はより高度な活用方法について解説していきたいと思っておりますので、引き続きよろしくお願いいたします。

Facebook

関連記事 | Related Posts

We are hiring!

生成AIエンジニア/生成AI活用PJT/東京・名古屋・大阪

生成AI活用PJTについて生成AIの活用を通じて、KINTO及びKINTOテクノロジーズへ事業貢献することをミッションに2024年1月に新設されたプロジェクトチームです。生成AI技術は生まれて日が浅く、その技術を業務活用する仕事には定説がありません。

【スクラッチ開発エンジニア】プラットフォームG/東京・大阪

プラットフォームグループについてAWS を中心とするインフラ上で稼働するアプリケーション運用改善のサポートを担当しています。

イベント情報

【さらに増枠】AWSコミュニティHEROと学ぶ!Amazon Bedrock勉強会&事例共有会
製造業でも生成AI活用したい!名古屋LLM MeetUp#4