Hello SpringAI
SpringAIはSpringのAIアプリケーションフレームワークです。テキスト生成に限らず画像生成AIや音声生成AIにもサポートを広げています。
テキスト生成においては他のLangChain4jと同じように、さまざまな開発補助をしてくれます。
GPTなどの主要なLLMサービスには対応しており、簡単なコードの実装でLLMが動作するアプリを開発することができます。
ローカルLLMに対してはOllama経由で対応しています。
Ollamaやllama.cppについては、以下のとおりになります。
名前 | 説明 |
---|---|
llama.cpp | 「量子化」という技術をもって非力なコンピュータにおいても、それなりなサイズのLLMが動作できるようにしてくれる実行環境 |
Ollama | 実行可能になった言語モデルの管理、APIサーバーの自動起動などを行うツール |
Llama3、llama.cpp、Ollamaは名前が似ていますが別物なので注意が必要です。
基本的な扱い方
執筆時点での最新バージョンは「1.0.0-SNAPSHOT」です。
直近でも仕様が大きく変更になるなど、安定版ではないことをご留意願います。
APIドキュメントが古いままだったり、リファレンスが日本語として翻訳しきれていなかったりと不完全な状態です。場合によってはGitHubで最新の情報を仕入れた方が良いかもしれません。
基本的な扱い方は、
- コントローラークラスに、扱いたい言語モデルに対応したChatModel実装クラスを注入
- Promptオブジェクトを生成し、チャット内容を詰め込む
- 注入したChatModel型オブジェクトの
call(Prompt)
もしくはstream(Prompt)
を呼び出す - 戻り値としてChatResponseオブジェクトを受け取り、クライアント側へ渡す
です。
call(Prompt)
もしくはstream(Prompt)
についてはcall(String)
、stream(String)
とすることもでき、その場合は上記の「2.」の工程は省略できます。(Promptオブジェクトは自動生成される)
コードにしてみると以下のとおりになります。
公式リファレンスより引用(OllamaChatModelの場合のサンプルコード)
@RestController public class ChatController { private final OllamaChatModel chatModel; @Autowired public ChatController(OllamaChatModel chatModel) { this.chatModel = chatModel; } @GetMapping("/ai/generate") public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { return Map.of("generation", chatModel.call(message)); } @GetMapping("/ai/generateStream") public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { Prompt prompt = new Prompt(new UserMessage(message)); return chatModel.stream(prompt); } }
クラス構造
1.ChatModel
さまざまな言語モデルと対話するためのクラスです。
抜粋したクラス図は以下のとおりです。
返答の仕方として2種類、ChatModelインターフェースとStreamingChatModelインターフェースが用意されています。
公式に対応している言語モデルは実装クラスが用意されており、基本的には使いたい言語モデルのクラスを選択してコントローラークラスに注入します。
なにかしらの理由でカスタムしたい場合は、実装クラスの継承、もしくはインターフェースの実装を独自で行います。
代表的なメソッドは以下の通りです。
メソッド | 戻り値 | 説明 |
---|---|---|
call(Prompt prompt) |
ChatResponse | 通常のレスポンスを返す(まとめて1回) |
stream(Prompt prompt) |
Flux<ChatResponse> | レスポンスをストリーミングする |
2.Prompt
言語モデルに対してリクエストする際の情報をまとめたクラスです。
抜粋したクラス図は以下のとおりです。
PromptはMessage(AbstractMessage)とChatOptionsをカプセル化するModelRequestの実装クラスです。
Message(AbstractMessage)には「言語モデルに渡すテキストメッセージ」と「そのメッセージの種別(enum)」が格納されます。
ChatOptionsは言語モデルを使用する際の既定設定を上書きしたいときにオブジェクト生成をします。シンプルに使用したいときに意識する必要はありません。
UserMessageは、Message(AbstractMessage)オブジェクトの新規生成処理をラップします。メッセージ種別が「USER」であるオブジェクトを、new
するだけで新規生成してくれます。後述するAssistantMessageも同じようにメッセージ種別が「ASSISTANT」であるオブジェクトを生成してくれます。
通常においては直接Message(AbstractMessage)オブジェクトを生成するのではなく、UserMessageなどを用いて間接的に生成するのが良さそうです。
クラス | 説明 |
---|---|
Prompt | MessageとChatOptionsをカプセル化する |
Message(AbstractMessage) | 「テキストメッセージ情報」と「メッセージ種別(USERやASSISTANTなど)情報」を所有する |
ChatOptions | 上書きしたい既定設定の情報を所有する |
UserMessage | メッセージ種別が「USER」であるMessage型オブジェクトを新規に生成する |
3.ChatResponse
言語モデルからの返答はChatResponseオブジェクトで出力されます。
抜粋したクラス図は以下のとおりです。
本来はメタデータ用のクラスもありますが、図では省略しています。
ChatResponseにはGenerationオブジェクトのListが含まれています。
GenerationはAssistantMessage型のフィールドを所有しているため、AssistantMessageを経由してMessage(AbstractMessage)がGenerationに内包されていることになります。(Generationの中身はメッセージ種別が「ASSISTANT」のMessage)
生成されたレスポンスにアクセスしたい場合、構造上Listになっているので、ChatResponse#getResults()
に対してget(0)
を使います。(もしくはChatResponse#getResult()
を呼ぶことで自動的にget(0)
し、単一のGenerationを取得します)
よって、テキストのみを取得したい場合は、
@GetMapping("/generate")
public String generate() {
Prompt prompt = new Prompt(new UserMessage("Tell me a joke"));
ChatResponse response = CHAT_MODEL.call(prompt);
// 生成されたテキスト部分のみを抽出
return response.getResult().getOutput().getContent();
}
となります。