2022年のChatGPTをきっかけに広まりだしたAIは、今年に入ってさまざまな領域で実用的になってきているように見えます。現在のAIは、LLM
今回の短期連載では数回にわけて、JavaでAIエージェントを作る基本になるLLM操作のプログラムを作っていきます。
まずは手元でAIを動かそう
AIプログラミングをするときに、課金が必要なAPIを使うとちょっと試すことにも躊躇してしまいますね。そこで、プログラムが正しくLLMにアクセスできているかを確認するために、手元でLLMが動くようにしてみましょう。
手元でLLMを動かす環境としては、GUIベースのLM StudioやCUIベースのOllamaが代表的ですが、ここでは導入がわかりやすいLM Studioを使います。
LM Studioのインストール
次のURLにアクセスして、LM Studioをダウンロード、インストールしてください。
起動すると次のようになります。ここでは実行するLLMを指定したいので、右上の
LLMモデルのダウンロード
左のツールアイコンの虫眼鏡のDiscover(探索)を選ぶと、モデルの検索画面が開きます。
ローカルで動く手ごろな大きさのLLMとしては、Alibabaの開発したQwen3かGoogleの開発したGemma3がおすすめです。今回はQwen3 1.
Qwen3には0.
検索に
ファイルのダウンロードが終わると通知が出るので
モデル読み込みの設定の指定が表示されますが、そのまま
LLMの動作を確認する
では、LM Studioのチャット画面で
Qwen3はReasoningモデルといって、一旦Thinkingフェーズで考慮を行ってから返答を返すモデルになっています。現在のLLMはあくまで文章の続きを生成する仕組みなので、LLMの持つ知識を文章に書きだしておいてThinkingを開くと、何か英語で考え事をしていることがわかりますね。
しばらく待つと、考え事が終わって返答が日本語で始まります。
ここで出力されたJavaコードをファイルに保存してjavaコマンドで起動すると、運がよければ一発で起動しますが、1.import不足でエラーが出ます。今回はコンパイルエラーが出たので、そのエラーを貼り付けて、修正してもらいます。
実際にはjava.のimportが必要なので、もう一度修正してもらうと、ボタンを押すとメッセージが表示されるプログラムが動きました。
LLMからの返答はランダムなので、みなさんの手元では、別のプログラムが出力されていると思います。エラーが出たらエラーメッセージを渡してなるべくLLMに直させるようにしてみてください。
もっと具体的な指示を行えば、プログラムの確実度はあがります。例えば次のように指示してみます。
JavaのSwingでFlowLayoutとBorderLayoutを組み合わせて、ボタンを押すとテキストフィールドに入力した文字列がテキストエリアに表示されるサンプルを作って
そうすると、importの問題があったものの次のようなプログラムができました。思ったものとは違いますが、条件通りの動きになっています。
AIにプログラムを作らせるときは、動きや構造を具体的に指定したほうが求めるものが生成される可能性が高くなります。さすがに1.
また、Qwen3は/no_で始めると、Thinkingを行わずに返答が始まります。小さなモデルではThinkingが長くなってトークンを消費すると求める出力になりにくくなるので、論理的な問題を解くとき以外は/no_をつけるほうがいいかもしれません。
Javaからアクセスしてみる
それでは、LM Studioで読み込んだモデルをJavaのコードから呼び出してみましょう。
サーバー設定と確認
Developerタブを表示して、左上のStatusがRunningになっていることを確認してください。Stoppedになっていたら、トグルをクリックしてRunningになるようにします。
ブラウザで
Javaプログラムからのアクセス
今回はライブラリを使わず、直接HTTPアクセスをして試してみます。LM StudioではOpenAIと同じ形式でのAPI呼び出しが行えます。
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpRequest.BodyPublishers;
import java.nio.charset.StandardCharsets;
public class AIClient {
public static void main(String[] args) throws Exception {
// String endpoint = "https://api.openai.com/v1/chat/completions";
String endpoint = "http://localhost:1234/v1/chat/completions";
String jsonBody = """
{
"model": "qwen/qwen3-1.7b",
"messages": [
{ "role": "system", "content": "/no_think\\nあなたはユーザーの役にたつアシスタントです。" },
{ "role": "user", "content": "日本の首都は?" }
],
"temperature": 0.7
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
// .header("Authorization", "Bearer " + API_KEY) // OpenAIにアクセスする場合はAPI_KEYが必要
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(jsonBody, StandardCharsets.UTF_8))
.build();
HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println("Response Body:\n" + response.body());
}
}
この内容をAIClient.
LM Studioでは1234ポートで待ち受けを行うので、次のようなURLでアクセスします。
String endpoint = "http://localhost:1234/v1/chat/completions";
localhost:1234ではなくapi.
リクエストはJSONで指定します。
{
"model": "qwen/qwen3-1.7b",
"messages": [
{ "role": "system", "content": "/no_think\\nあなたはユーザーの役にたつアシスタントです。" },
{ "role": "user", "content": "日本の首都は?" }
],
"temperature": 0.7
}
modelに指定するモデル名は、LM Studioの開発者タブで
を押すとクリップボードにコピーされるものを使います。
OpenAIにアクセスする場合にはgpt-4oなどになります。
messagesには会話の履歴を与えます。ここでそれぞれのメッセージにはroleとして役割が、contentとしてメッセージ内容を指定します。
roleには次のようなものを指定します。
| role | 用途 |
|---|---|
| system | チャットの設定の指定 |
| user | ユーザーの入力 |
| assistant | AIからの出力 |
また、ここでシステムプロンプトに/no_を指定していますがQwen3以外のモデルを使う場合には不要です。
temperatureは返答を選ぶ幅で、0に近ければ確率の高いものだけを選び、1に近づくほど確率の低いものも選ぶようになり返答の多様性があがります。
アクセスにはHttpClientを使います。HttpClientは最初にHTTP/
HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
リクエストはPOSTで行います。OpenAIにアクセスする場合には、APIキーの指定が必要です。ただ、なるべくプログラムに埋め込まないよう、環境変数から取ってくるようにしてください。
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(endpoint))
// .header("Authorization", "Bearer " + API_KEY) // OpenAIにアクセスする場合はAPI_KEYが必要
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofString(jsonBody, StandardCharsets.UTF_8))
.build();
AiClient.contentの内容は異なるはずです。
>java AiClient.java
Response Body:
{
"id": "chatcmpl-elu0ckl7oswp9k7pwdklh",
"object": "chat.completion",
"created": 1752345165,
"model": "qwen/qwen3-1.7b",
"choices": [
{
"index": 0,
"logprobs": null,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "<think>\n\n</think>\n\n日本の首都は**東京都**です。"
}
}
],
"usage": {
"prompt_tokens": 35,
"completion_tokens": 13,
"total_tokens": 48
},
"stats": {},
"system_fingerprint": "qwen/qwen3-1.7b"
}
このJSONを処理してアプリケーションを作っていけばいいのですが、それは手間なので、次回はLangChain4jを使ってLLMの操作を行っていきます。
