From 13d5b3be20e3ac9ba0580bbd12106135fccbf848 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Mon, 26 May 2025 14:48:23 -0400 Subject: [PATCH 01/21] support github Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/README.md | 26 ++- jakartaee-microprofile-example/pom.xml | 5 + .../langchain4j/example/chat/ChatAgent.java | 37 +--- .../example/chat/util/ModelBuilder.java | 160 ++++++++++++++++++ .../example/rest/ModelResource.java | 82 +++------ .../META-INF/microprofile-config.properties | 7 +- .../dev/langchan4j/example/ChatServiceIT.java | 3 +- .../langchan4j/example/ModelResourceIT.java | 10 +- .../java/it/dev/langchan4j/example/Util.java | 16 ++ 9 files changed, 239 insertions(+), 107 deletions(-) create mode 100644 jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java create mode 100644 jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java diff --git a/jakartaee-microprofile-example/README.md b/jakartaee-microprofile-example/README.md index 3dbacf65..43af1c31 100644 --- a/jakartaee-microprofile-example/README.md +++ b/jakartaee-microprofile-example/README.md @@ -4,11 +4,15 @@ This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application ## Prerequisites: - [Java 21](https://developer.ibm.com/languages/java/semeru-runtimes/downloads) -- Hugging Face API Key - - Sign up and log in to https://huggingface.co. - - Go to [Access Tokens](https://huggingface.co/settings/tokens). - - Create a new access token with `read` role. - +- Either of the following API Keys + - Hugging Face + - Sign up and log in to https://huggingface.co. + - Go to [Access Tokens](https://huggingface.co/settings/tokens). + - Create a new access token with `read` role. + - Github + - Sign up and sign in to https://github.com. + - Go to your [Settings](https://github.com/settings/profile)/[Developer Settings](https://github.com/settings/developers)/[Persional access tokens](https://github.com/settings/personal-access-tokens). + - Generate a new token ## Environment Set Up @@ -18,13 +22,21 @@ To run this example application, navigate to the `jakartaee-microprofile-exampl cd langchain4j-examples/jakartaee-microprofile-example ``` -Set the following environment variables: - +Set the `JAVA_HOME` environment variable: ``` export JAVA_HOME= +``` + +Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face: +``` export HUGGING_FACE_API_KEY= ``` +Set the `GITHUB_API_KEY` environment variables if using Github: +``` +export GITHUB_API_KEY= +``` + ## Start the application Use the Maven wrapper to start the application by using the [Liberty dev mode](https://openliberty.io/docs/latest/development-mode.html): diff --git a/jakartaee-microprofile-example/pom.xml b/jakartaee-microprofile-example/pom.xml index b2302dcd..11b88563 100644 --- a/jakartaee-microprofile-example/pom.xml +++ b/jakartaee-microprofile-example/pom.xml @@ -39,6 +39,11 @@ langchain4j-hugging-face 1.0.1-beta6 + + dev.langchain4j + langchain4j-github-models + 1.0.1-beta6 + org.slf4j slf4j-reload4j diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java index cdb1bb08..cdef60d5 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java @@ -1,11 +1,10 @@ package dev.langchain4j.example.chat; -import static java.time.Duration.ofSeconds; - import org.eclipse.microprofile.config.inject.ConfigProperty; +import dev.langchain4j.example.chat.util.ModelBuilder; import dev.langchain4j.memory.chat.MessageWindowChatMemory; -import dev.langchain4j.model.huggingface.HuggingFaceChatModel; +import dev.langchain4j.model.chat.ChatModel; import dev.langchain4j.service.AiServices; import dev.langchain4j.service.MemoryId; import dev.langchain4j.service.UserMessage; @@ -16,24 +15,7 @@ public class ChatAgent { @Inject - @ConfigProperty(name = "hugging.face.api.key") - private String HUGGING_FACE_API_KEY; - - @Inject - @ConfigProperty(name = "chat.model.id") - private String CHAT_MODEL_ID; - - @Inject - @ConfigProperty(name = "chat.model.timeout") - private Integer TIMEOUT; - - @Inject - @ConfigProperty(name = "chat.model.max.token") - private Integer MAX_NEW_TOKEN; - - @Inject - @ConfigProperty(name = "chat.model.temperature") - private Double TEMPERATURE; + private ModelBuilder modelBuilder; @Inject @ConfigProperty(name = "chat.memory.max.messages") @@ -45,16 +27,9 @@ interface Assistant { private Assistant assistant = null; - public Assistant getAssistant() { + public Assistant getAssistant() throws Exception { if (assistant == null) { - HuggingFaceChatModel model = HuggingFaceChatModel.builder() - .accessToken(HUGGING_FACE_API_KEY) - .modelId(CHAT_MODEL_ID) - .timeout(ofSeconds(TIMEOUT)) - .temperature(TEMPERATURE) - .maxNewTokens(MAX_NEW_TOKEN) - .waitForModel(true) - .build(); + ChatModel model = modelBuilder.getChatModelForWeb(); assistant = AiServices.builder(Assistant.class) .chatModel(model) .chatMemoryProvider( @@ -64,7 +39,7 @@ public Assistant getAssistant() { return assistant; } - public String chat(String sessionId, String message) { + public String chat(String sessionId, String message) throws Exception { String reply = getAssistant().chat(sessionId, message).trim(); int i = reply.lastIndexOf(message); return i > 0 ? reply.substring(i) : reply; diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java new file mode 100644 index 00000000..991a0367 --- /dev/null +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java @@ -0,0 +1,160 @@ +package dev.langchain4j.example.chat.util; + +import static dev.langchain4j.model.github.GitHubModelsChatModelName.GPT_4_O_MINI; +import static dev.langchain4j.model.github.GitHubModelsChatModelName.PHI_3_MINI_INSTRUCT_4K; +import static dev.langchain4j.model.github.GitHubModelsEmbeddingModelName.TEXT_EMBEDDING_3_SMALL; +import static dev.langchain4j.model.huggingface.HuggingFaceModelName.SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2; +import static java.time.Duration.ofSeconds; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.model.github.GitHubModelsChatModel; +import dev.langchain4j.model.github.GitHubModelsEmbeddingModel; +import dev.langchain4j.model.huggingface.HuggingFaceChatModel; +import dev.langchain4j.model.huggingface.HuggingFaceEmbeddingModel; +import dev.langchain4j.model.huggingface.HuggingFaceLanguageModel; +import dev.langchain4j.model.language.LanguageModel; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +@ApplicationScoped +public class ModelBuilder { + + @Inject + @ConfigProperty(name = "hugging.face.api.key") + private String HUGGING_FACE_API_KEY; + + @Inject + @ConfigProperty(name = "github.api.key") + private String GITHUB_API_KEY; + + @Inject + @ConfigProperty(name = "hugging.language.model.id") + private String HUGGING_FACE_LANGUAGE_MODEL_ID; + + @Inject + @ConfigProperty(name = "hugging.chat.model.id") + private String HUGGING_FACE_CHAT_MODEL_ID; + + @Inject + @ConfigProperty(name = "chat.model.timeout") + private Integer TIMEOUT; + + @Inject + @ConfigProperty(name = "chat.model.max.token") + private Integer MAX_NEW_TOKEN; + + @Inject + @ConfigProperty(name = "chat.model.temperature") + private Double TEMPERATURE; + + private LanguageModel languageModel = null; + private EmbeddingModel embeddingModel = null; + private ChatModel chatModelForResource = null; + private ChatModel chatModelForWeb = null; + + public boolean usingHuggingFace() { + return HUGGING_FACE_API_KEY.startsWith("hf_"); + } + + public boolean usingGithub() { + return GITHUB_API_KEY.startsWith("ghp_"); + } + + public LanguageModel getLanguageModel() throws Exception { + if (languageModel == null) { + if (usingHuggingFace()) { + languageModel = HuggingFaceLanguageModel.builder() + .accessToken(HUGGING_FACE_API_KEY) + .modelId(HUGGING_FACE_LANGUAGE_MODEL_ID) + .timeout(ofSeconds(120)) + .temperature(1.0) + .maxNewTokens(30) + .waitForModel(true) + .build(); + } else if (usingGithub()) { + throw new Exception("LangChain4J Github APIs do not support language model"); + } else { + throw new Exception("No available platform to access model"); + } + } + return languageModel; + } + + public EmbeddingModel getEmbeddingModel() throws Exception { + if (embeddingModel == null) { + if (usingHuggingFace()) { + embeddingModel = HuggingFaceEmbeddingModel.builder() + .accessToken(HUGGING_FACE_API_KEY) + .modelId(SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2) + .timeout(ofSeconds(120)) + .waitForModel(true) + .build(); + } else if (usingGithub()) { + embeddingModel = GitHubModelsEmbeddingModel.builder() + .gitHubToken(GITHUB_API_KEY) + .modelName(TEXT_EMBEDDING_3_SMALL) + .timeout(ofSeconds(120)) + .build(); + } else { + throw new Exception("No available platform to access model"); + } + } + return embeddingModel; + } + + public ChatModel getChatModelForResource() throws Exception { + if (chatModelForResource == null) { + if (usingHuggingFace()) { + chatModelForResource = HuggingFaceChatModel.builder() + .accessToken(HUGGING_FACE_API_KEY) + .modelId(HUGGING_FACE_LANGUAGE_MODEL_ID) + .timeout(ofSeconds(120)) + .temperature(1.0) + .maxNewTokens(200) + .waitForModel(true) + .build(); + } else if (usingGithub()) { + chatModelForResource = GitHubModelsChatModel.builder() + .gitHubToken(GITHUB_API_KEY) + .modelName(PHI_3_MINI_INSTRUCT_4K) + .timeout(ofSeconds(120)) + .temperature(1.0) + .maxTokens(200) + .build(); + } else { + throw new Exception("No available platform to access model"); + } + } + return chatModelForResource; + } + + public ChatModel getChatModelForWeb() throws Exception { + if (chatModelForWeb == null) { + if (usingHuggingFace()) { + chatModelForWeb = HuggingFaceChatModel.builder() + .accessToken(HUGGING_FACE_API_KEY) + .modelId(HUGGING_FACE_CHAT_MODEL_ID) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .maxNewTokens(MAX_NEW_TOKEN) + .waitForModel(true) + .build(); + } else if (usingGithub()) { + chatModelForWeb = GitHubModelsChatModel.builder() + .gitHubToken(GITHUB_API_KEY) + .modelName(GPT_4_O_MINI) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .maxTokens(MAX_NEW_TOKEN) + .build(); + } else { + throw new Exception("No available platform to access model"); + } + } + return chatModelForWeb; + } + +} diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/rest/ModelResource.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/rest/ModelResource.java index 1a3409ac..b6c761c4 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/rest/ModelResource.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/rest/ModelResource.java @@ -1,13 +1,23 @@ package dev.langchain4j.example.rest; +import static dev.langchain4j.data.segment.TextSegment.textSegment; +import static dev.langchain4j.store.embedding.CosineSimilarity.between; +import static dev.langchain4j.store.embedding.RelevanceScore.fromCosineSimilarity; + +import java.util.List; +import java.util.Properties; + +import org.eclipse.microprofile.openapi.annotations.Operation; + import dev.langchain4j.data.embedding.Embedding; import dev.langchain4j.data.message.AiMessage; import dev.langchain4j.data.message.SystemMessage; import dev.langchain4j.data.message.UserMessage; import dev.langchain4j.data.segment.TextSegment; -import dev.langchain4j.model.huggingface.HuggingFaceChatModel; -import dev.langchain4j.model.huggingface.HuggingFaceEmbeddingModel; -import dev.langchain4j.model.huggingface.HuggingFaceLanguageModel; +import dev.langchain4j.example.chat.util.ModelBuilder; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.model.language.LanguageModel; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.GET; @@ -15,58 +25,13 @@ import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.eclipse.microprofile.openapi.annotations.Operation; - -import java.util.List; -import java.util.Properties; - -import static dev.langchain4j.data.segment.TextSegment.textSegment; -import static dev.langchain4j.model.huggingface.HuggingFaceModelName.SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2; -import static dev.langchain4j.store.embedding.CosineSimilarity.between; -import static dev.langchain4j.store.embedding.RelevanceScore.fromCosineSimilarity; -import static java.time.Duration.ofSeconds; @ApplicationScoped @Path("model") public class ModelResource { @Inject - @ConfigProperty(name = "hugging.face.api.key") - private String HUGGING_FACE_API_KEY; - - @Inject - @ConfigProperty(name = "language.model.id") - private String LANGUAGE_MODEL_ID; - - private HuggingFaceLanguageModel languageModel = null; - private HuggingFaceEmbeddingModel embeddingModel = null; - - private HuggingFaceLanguageModel getLanguageModel() { - if (languageModel == null) { - languageModel = HuggingFaceLanguageModel.builder() - .accessToken(HUGGING_FACE_API_KEY) - .modelId(LANGUAGE_MODEL_ID) - .timeout(ofSeconds(120)) - .temperature(1.0) - .maxNewTokens(30) - .waitForModel(true) - .build(); - } - return languageModel; - } - - private HuggingFaceEmbeddingModel getEmbeddingModel() { - if (embeddingModel == null) { - embeddingModel = HuggingFaceEmbeddingModel.builder() - .accessToken(HUGGING_FACE_API_KEY) - .modelId(SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2) - .timeout(ofSeconds(120)) - .waitForModel(true) - .build(); - } - return embeddingModel; - } + private ModelBuilder modelBuilder; @GET @Produces(MediaType.TEXT_PLAIN) @@ -75,9 +40,9 @@ private HuggingFaceEmbeddingModel getEmbeddingModel() { summary = "Use the language model.", description = "Provide a sequence of words to a large language model.", operationId = "languageModelAsk") - public String languageModelAsk(@QueryParam("question") String question) { + public String languageModelAsk(@QueryParam("question") String question) throws Exception { - HuggingFaceLanguageModel model = getLanguageModel(); + LanguageModel model = modelBuilder.getLanguageModel(); String answer; try { @@ -98,16 +63,9 @@ public String languageModelAsk(@QueryParam("question") String question) { description = "Assume you are talking with an agent that is knowledgeable about " + "Large Language Models. Ask any question about it.", operationId = "chatModelAsk") - public List chatModelAsk(@QueryParam("userMessage") String userMessage) { + public List chatModelAsk(@QueryParam("userMessage") String userMessage) throws Exception { - HuggingFaceChatModel model = HuggingFaceChatModel.builder() - .accessToken(HUGGING_FACE_API_KEY) - .modelId(LANGUAGE_MODEL_ID) - .timeout(ofSeconds(120)) - .temperature(1.0) - .maxNewTokens(200) - .waitForModel(true) - .build(); + ChatModel model = modelBuilder.getChatModelForResource(); SystemMessage systemMessage = SystemMessage.from( "You are very knowledgeable about Large Language Models. Be friendly. Give concise answers."); @@ -137,9 +95,9 @@ private Properties getProperties(String value, Embedding embedding) { operationId = "similarity") public Properties similarity( @QueryParam("text1") String text1, - @QueryParam("text2") String text2) { + @QueryParam("text2") String text2) throws Exception { - HuggingFaceEmbeddingModel model = getEmbeddingModel(); + EmbeddingModel model = modelBuilder.getEmbeddingModel(); List textSegments = List.of(textSegment(text1), textSegment(text2)); List embeddings = model.embedAll(textSegments).content(); diff --git a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties index c606861f..c6671e59 100644 --- a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties +++ b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties @@ -1,8 +1,9 @@ hugging.face.api.key=set it by env variable -#chat.model.id=meta-llama/Llama-3.2-1B-Instruct -chat.model.id=mistralai/Mistral-Nemo-Instruct-2407 +github.api.key=set it by env variable +hugging.chat.model.id=mistralai/Mistral-Nemo-Instruct-2407 +hugging.language.model.id=microsoft/Phi-3-mini-4k-instruct + chat.model.timeout=120 chat.model.max.token=200 chat.model.temperature=1.0 chat.memory.max.messages=20 -language.model.id=microsoft/Phi-3-mini-4k-instruct \ No newline at end of file diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java index 3c87269d..dce62755 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java @@ -28,7 +28,8 @@ public void testChat() throws Exception { public static void verify(String message) { assertNotNull(message); - assertTrue(message.contains("2023"), message); + assertTrue(message.contains("2022") || message.contains("2023"), + message); countDown.countDown(); } diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java index 0fea238f..2c852ba9 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java @@ -29,6 +29,9 @@ public void teardown() { @Test public void testLanguageMode() { + if (Util.usingGithub()) { + return; + } String url = baseUrl + "language?question=When was Hugging Face launched?"; Response response = client.target(url).request().get(); String answer = response.readEntity(String.class); @@ -40,7 +43,8 @@ public void testChatMode() { String url = baseUrl + "chat?userMessage=Which are the most used Large Language Models?"; Response response = client.target(url).request().get(); String answer = response.readEntity(String.class); - assertTrue(answer.contains("BERT"), "actual: " + answer); + assertTrue(answer.contains("BERT") || answer.contains("GPT") || answer.contains("LaMDA"), + "actual: " + answer); } @Test @@ -52,10 +56,10 @@ public void testEmbeddingMode() { JsonObject json = response.readEntity(JsonObject.class); double score = json.getJsonNumber("relevance-score").doubleValue(); - assertTrue(score > 0.69 && score < 0.70, "actual score: " + score); + assertTrue(score > 0.63 && score < 0.70, "actual score: " + score); double similarity = json.getJsonNumber("similarity").doubleValue(); - assertTrue(similarity > 0.38 && similarity < 0.39, + assertTrue(similarity > 0.27 && similarity < 0.39, "actual similarity: " + similarity); } diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java new file mode 100644 index 00000000..51bece9e --- /dev/null +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java @@ -0,0 +1,16 @@ +package it.dev.langchan4j.example; + +public class Util { + + private static String hfApiKey = System.getenv("HUGGING_FACE_API_KEY"); + private static String githubApiKey = System.getenv("GITHUB_API_KEY"); + + public static boolean usingHuggingFace() { + return hfApiKey != null && hfApiKey.startsWith("hf_"); + } + + public static boolean usingGithub() { + return githubApiKey != null && githubApiKey.startsWith("ghp_"); + } + +} From a562b88ec49b857a9054d3eca442becb9ae08420 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Mon, 26 May 2025 14:50:23 -0400 Subject: [PATCH 02/21] support github Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jakartaee-microprofile-example/README.md b/jakartaee-microprofile-example/README.md index 43af1c31..af122c7a 100644 --- a/jakartaee-microprofile-example/README.md +++ b/jakartaee-microprofile-example/README.md @@ -32,7 +32,7 @@ Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face: export HUGGING_FACE_API_KEY= ``` -Set the `GITHUB_API_KEY` environment variables if using Github: +Set the `GITHUB_API_KEY` environment variable if using Github: ``` export GITHUB_API_KEY= ``` From c0e9056cd997b380c6c347ce03f29bf2b477a202 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Wed, 28 May 2025 17:38:44 -0400 Subject: [PATCH 03/21] support ollama Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/README.md | 27 +++- jakartaee-microprofile-example/pom.xml | 5 + .../example/chat/util/ModelBuilder.java | 151 ++++++++++++------ .../META-INF/microprofile-config.properties | 9 +- .../dev/langchan4j/example/ChatServiceIT.java | 2 +- .../langchan4j/example/ModelResourceIT.java | 2 +- .../java/it/dev/langchan4j/example/Util.java | 5 + 7 files changed, 146 insertions(+), 55 deletions(-) diff --git a/jakartaee-microprofile-example/README.md b/jakartaee-microprofile-example/README.md index af122c7a..bcfff8ae 100644 --- a/jakartaee-microprofile-example/README.md +++ b/jakartaee-microprofile-example/README.md @@ -1,10 +1,10 @@ # LangChain4j in Jakarta EE and MicroProfile -This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application on Open Liberty. The application is a chatbot built with LangChain4J and uses Jakarta CDI, Jakarta RESTful Web Services, Jakarta WebSocket, MicroProfile Config, MicroProfile Metrics, and MicroProfile OpenAPI features. +This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application on Open Liberty. The application is a chatbot built with LangChain4J and uses Jakarta CDI, Jakarta RESTful Web Services, Jakarta WebSocket, MicroProfile Config, MicroProfile Metrics, and MicroProfile OpenAPI features. The application allows to use models from either Hugging Face, Github, or Ollama. ## Prerequisites: - [Java 21](https://developer.ibm.com/languages/java/semeru-runtimes/downloads) -- Either of the following API Keys +- Either one of the following model providers: - Hugging Face - Sign up and log in to https://huggingface.co. - Go to [Access Tokens](https://huggingface.co/settings/tokens). @@ -13,6 +13,13 @@ This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application - Sign up and sign in to https://github.com. - Go to your [Settings](https://github.com/settings/profile)/[Developer Settings](https://github.com/settings/developers)/[Persional access tokens](https://github.com/settings/personal-access-tokens). - Generate a new token + - Ollama + - Download and install [Ollama](https://ollama.com/download) + - see the [README.md](https://github.com/ollama/ollama/blob/main/README.md#ollama) + - Pull the following models + - `ollama pull llama3.2` + - `ollama pull all-minilm` + - `ollama pull tinydolphin` ## Environment Set Up @@ -27,16 +34,27 @@ Set the `JAVA_HOME` environment variable: export JAVA_HOME= ``` -Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face: +Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face. ``` +unset GITHUB_API_KEY +unset OLLAMA_BASE_URL export HUGGING_FACE_API_KEY= ``` -Set the `GITHUB_API_KEY` environment variable if using Github: +Set the `GITHUB_API_KEY` environment variable if using Github. ``` +unset HUGGING_FACE_API_KEY +unset OLLAMA_BASE_URL export GITHUB_API_KEY= ``` +Set the `OLLAMA_BASE_URL` environment variable if using Ollama. Use your Ollama URL if not using the default. +``` +unset HUGGING_FACE_API_KEY +unset GITHUB_API_KEY +export OLLAMA_BASE_URL=http://localhost:11434 +``` + ## Start the application Use the Maven wrapper to start the application by using the [Liberty dev mode](https://openliberty.io/docs/latest/development-mode.html): @@ -72,7 +90,6 @@ Navigate to the the [OpenAPI UI](http://localhost:9080/openapi/ui) URL for the f - Alternatively, run the following `curl` command from a command-line session: - ``` curl 'http://localhost:9080/api/model/language?question=When%20was%20Hugging%20Face%20launched%3F' - ``` - [HuggingFaceChatModel](https://github.com/langchain4j/langchain4j/blob/main/langchain4j-hugging-face/src/main/java/dev/langchain4j/model/huggingface/HuggingFaceChatModel.java) - expand the GET `/api/model/chat` API diff --git a/jakartaee-microprofile-example/pom.xml b/jakartaee-microprofile-example/pom.xml index 11b88563..c3ed0dd7 100644 --- a/jakartaee-microprofile-example/pom.xml +++ b/jakartaee-microprofile-example/pom.xml @@ -44,6 +44,11 @@ langchain4j-github-models 1.0.1-beta6 + + dev.langchain4j + langchain4j-ollama + 1.0.1-beta6 + org.slf4j slf4j-reload4j diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java index 991a0367..aaa1e932 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java @@ -1,11 +1,12 @@ package dev.langchain4j.example.chat.util; -import static dev.langchain4j.model.github.GitHubModelsChatModelName.GPT_4_O_MINI; import static dev.langchain4j.model.github.GitHubModelsChatModelName.PHI_3_MINI_INSTRUCT_4K; import static dev.langchain4j.model.github.GitHubModelsEmbeddingModelName.TEXT_EMBEDDING_3_SMALL; import static dev.langchain4j.model.huggingface.HuggingFaceModelName.SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2; import static java.time.Duration.ofSeconds; +import java.util.logging.Logger; + import org.eclipse.microprofile.config.inject.ConfigProperty; import dev.langchain4j.model.chat.ChatModel; @@ -16,20 +17,21 @@ import dev.langchain4j.model.huggingface.HuggingFaceEmbeddingModel; import dev.langchain4j.model.huggingface.HuggingFaceLanguageModel; import dev.langchain4j.model.language.LanguageModel; +import dev.langchain4j.model.ollama.OllamaChatModel; +import dev.langchain4j.model.ollama.OllamaEmbeddingModel; +import dev.langchain4j.model.ollama.OllamaLanguageModel; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @ApplicationScoped public class ModelBuilder { + private static Logger logger = Logger.getLogger(ModelBuilder.class.getName()); + @Inject @ConfigProperty(name = "hugging.face.api.key") private String HUGGING_FACE_API_KEY; - @Inject - @ConfigProperty(name = "github.api.key") - private String GITHUB_API_KEY; - @Inject @ConfigProperty(name = "hugging.language.model.id") private String HUGGING_FACE_LANGUAGE_MODEL_ID; @@ -38,6 +40,22 @@ public class ModelBuilder { @ConfigProperty(name = "hugging.chat.model.id") private String HUGGING_FACE_CHAT_MODEL_ID; + @Inject + @ConfigProperty(name = "github.api.key") + private String GITHUB_API_KEY; + + @Inject + @ConfigProperty(name = "github.chat.model.id") + private String GITHUB_CHAT_MODEL_ID; + + @Inject + @ConfigProperty(name = "ollama.base.url") + private String OLLAMA_BASE_URL; + + @Inject + @ConfigProperty(name = "ollama.chat.model.id") + private String OLLAMA_CHAT_MODEL_ID; + @Inject @ConfigProperty(name = "chat.model.timeout") private Integer TIMEOUT; @@ -56,16 +74,20 @@ public class ModelBuilder { private ChatModel chatModelForWeb = null; public boolean usingHuggingFace() { - return HUGGING_FACE_API_KEY.startsWith("hf_"); + return HUGGING_FACE_API_KEY.startsWith("hf_"); } public boolean usingGithub() { - return GITHUB_API_KEY.startsWith("ghp_"); + return GITHUB_API_KEY.startsWith("ghp_"); + } + + public boolean usingOllama() { + return OLLAMA_BASE_URL.startsWith("http"); } public LanguageModel getLanguageModel() throws Exception { if (languageModel == null) { - if (usingHuggingFace()) { + if (usingHuggingFace()) { languageModel = HuggingFaceLanguageModel.builder() .accessToken(HUGGING_FACE_API_KEY) .modelId(HUGGING_FACE_LANGUAGE_MODEL_ID) @@ -74,10 +96,18 @@ public LanguageModel getLanguageModel() throws Exception { .maxNewTokens(30) .waitForModel(true) .build(); - } else if (usingGithub()) { - throw new Exception("LangChain4J Github APIs do not support language model"); - } else { - throw new Exception("No available platform to access model"); + logger.info("using Hugging Face " + HUGGING_FACE_LANGUAGE_MODEL_ID + " language model"); + } else if (usingGithub()) { + throw new Exception("LangChain4J Github APIs do not support language model"); + } else if (usingOllama()) { + languageModel = OllamaLanguageModel.builder() + .baseUrl(OLLAMA_BASE_URL) + .modelName("tinydolphin") + .temperature(1.0) + .build(); + logger.info("using Ollama tinydolphin language model"); + } else { + throw new Exception("No available platform to access model"); } } return languageModel; @@ -85,21 +115,30 @@ public LanguageModel getLanguageModel() throws Exception { public EmbeddingModel getEmbeddingModel() throws Exception { if (embeddingModel == null) { - if (usingHuggingFace()) { - embeddingModel = HuggingFaceEmbeddingModel.builder() + if (usingHuggingFace()) { + embeddingModel = HuggingFaceEmbeddingModel.builder() .accessToken(HUGGING_FACE_API_KEY) .modelId(SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2) .timeout(ofSeconds(120)) .waitForModel(true) .build(); - } else if (usingGithub()) { - embeddingModel = GitHubModelsEmbeddingModel.builder() - .gitHubToken(GITHUB_API_KEY) - .modelName(TEXT_EMBEDDING_3_SMALL) + logger.info("using Hugging Face " + SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2 + " embedding model"); + } else if (usingGithub()) { + embeddingModel = GitHubModelsEmbeddingModel.builder() + .gitHubToken(GITHUB_API_KEY) + .modelName(TEXT_EMBEDDING_3_SMALL) + .timeout(ofSeconds(120)) + .build(); + logger.info("using Github " + TEXT_EMBEDDING_3_SMALL + " embedding model"); + } else if (usingOllama()) { + embeddingModel = OllamaEmbeddingModel.builder() + .baseUrl(OLLAMA_BASE_URL) + .modelName("all-minilm") .timeout(ofSeconds(120)) .build(); - } else { - throw new Exception("No available platform to access model"); + logger.info("using Ollama all-minilm embedding model"); + } else { + throw new Exception("No available platform to access model"); } } return embeddingModel; @@ -107,8 +146,8 @@ public EmbeddingModel getEmbeddingModel() throws Exception { public ChatModel getChatModelForResource() throws Exception { if (chatModelForResource == null) { - if (usingHuggingFace()) { - chatModelForResource = HuggingFaceChatModel.builder() + if (usingHuggingFace()) { + chatModelForResource = HuggingFaceChatModel.builder() .accessToken(HUGGING_FACE_API_KEY) .modelId(HUGGING_FACE_LANGUAGE_MODEL_ID) .timeout(ofSeconds(120)) @@ -116,25 +155,35 @@ public ChatModel getChatModelForResource() throws Exception { .maxNewTokens(200) .waitForModel(true) .build(); - } else if (usingGithub()) { - chatModelForResource = GitHubModelsChatModel.builder() - .gitHubToken(GITHUB_API_KEY) - .modelName(PHI_3_MINI_INSTRUCT_4K) - .timeout(ofSeconds(120)) - .temperature(1.0) - .maxTokens(200) - .build(); - } else { - throw new Exception("No available platform to access model"); - } + logger.info("using Hugging Face " + HUGGING_FACE_LANGUAGE_MODEL_ID + " chat model"); + } else if (usingGithub()) { + chatModelForResource = GitHubModelsChatModel.builder() + .gitHubToken(GITHUB_API_KEY) + .modelName(PHI_3_MINI_INSTRUCT_4K) + .timeout(ofSeconds(120)) + .temperature(1.0) + .maxTokens(200) + .build(); + logger.info("using Github " + PHI_3_MINI_INSTRUCT_4K + " chat model"); + } else if (usingOllama()) { + chatModelForResource = OllamaChatModel.builder() + .baseUrl(OLLAMA_BASE_URL) + .modelName(OLLAMA_CHAT_MODEL_ID) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .build(); + logger.info("using Ollama " + OLLAMA_CHAT_MODEL_ID + " chat model"); + } else { + throw new Exception("No available platform to access model"); + } } return chatModelForResource; } public ChatModel getChatModelForWeb() throws Exception { if (chatModelForWeb == null) { - if (usingHuggingFace()) { - chatModelForWeb = HuggingFaceChatModel.builder() + if (usingHuggingFace()) { + chatModelForWeb = HuggingFaceChatModel.builder() .accessToken(HUGGING_FACE_API_KEY) .modelId(HUGGING_FACE_CHAT_MODEL_ID) .timeout(ofSeconds(TIMEOUT)) @@ -142,17 +191,27 @@ public ChatModel getChatModelForWeb() throws Exception { .maxNewTokens(MAX_NEW_TOKEN) .waitForModel(true) .build(); - } else if (usingGithub()) { - chatModelForWeb = GitHubModelsChatModel.builder() - .gitHubToken(GITHUB_API_KEY) - .modelName(GPT_4_O_MINI) - .timeout(ofSeconds(TIMEOUT)) - .temperature(TEMPERATURE) - .maxTokens(MAX_NEW_TOKEN) - .build(); - } else { - throw new Exception("No available platform to access model"); - } + logger.info("using Hugging Face " + HUGGING_FACE_CHAT_MODEL_ID + " chat model for the web"); + } else if (usingGithub()) { + chatModelForWeb = GitHubModelsChatModel.builder() + .gitHubToken(GITHUB_API_KEY) + .modelName(GITHUB_CHAT_MODEL_ID) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .maxTokens(MAX_NEW_TOKEN) + .build(); + logger.info("using Github " + GITHUB_CHAT_MODEL_ID + " chat model for the web"); + } else if (usingOllama()) { + chatModelForWeb = OllamaChatModel.builder() + .baseUrl(OLLAMA_BASE_URL) + .modelName(OLLAMA_CHAT_MODEL_ID) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .build(); + logger.info("using Ollama " + OLLAMA_CHAT_MODEL_ID + " chat model for the web"); + } else { + throw new Exception("No available platform to access model"); + } } return chatModelForWeb; } diff --git a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties index c6671e59..5dc60387 100644 --- a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties +++ b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties @@ -1,7 +1,12 @@ hugging.face.api.key=set it by env variable -github.api.key=set it by env variable hugging.chat.model.id=mistralai/Mistral-Nemo-Instruct-2407 -hugging.language.model.id=microsoft/Phi-3-mini-4k-instruct +hugging.language.model.id=microsoft/Phi-3-mini-4k-instruct.base. + +github.api.key=set it by env variable +github.chat.model.id=gpt-4o-mini + +ollama.base.url=set it by env variable +ollama.chat.model.id=llama3.2 chat.model.timeout=120 chat.model.max.token=200 diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java index dce62755..492b4f0c 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java @@ -28,7 +28,7 @@ public void testChat() throws Exception { public static void verify(String message) { assertNotNull(message); - assertTrue(message.contains("2022") || message.contains("2023"), + assertTrue(message.contains("2021") || message.contains("2022") || message.contains("2023"), message); countDown.countDown(); } diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java index 2c852ba9..98d4e738 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java @@ -35,7 +35,7 @@ public void testLanguageMode() { String url = baseUrl + "language?question=When was Hugging Face launched?"; Response response = client.target(url).request().get(); String answer = response.readEntity(String.class); - assertTrue(answer.contains("2018"), "actual: " + answer); + assertTrue(answer.contains("2015") || answer.contains("2018"), "actual: " + answer); } @Test diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java index 51bece9e..4323dd2f 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java @@ -4,6 +4,7 @@ public class Util { private static String hfApiKey = System.getenv("HUGGING_FACE_API_KEY"); private static String githubApiKey = System.getenv("GITHUB_API_KEY"); + private static String ollamaBaseUrl = System.getenv("OLLAMA_BASE_URL"); public static boolean usingHuggingFace() { return hfApiKey != null && hfApiKey.startsWith("hf_"); @@ -13,4 +14,8 @@ public static boolean usingGithub() { return githubApiKey != null && githubApiKey.startsWith("ghp_"); } + public static boolean usingOllama() { + return ollamaBaseUrl != null && ollamaBaseUrl.startsWith("http"); + } + } From 3f00bccb74b9508cf20e1ad60410cf5735424127 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Mon, 9 Jun 2025 11:14:53 -0400 Subject: [PATCH 04/21] update instructions Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/README.md | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/jakartaee-microprofile-example/README.md b/jakartaee-microprofile-example/README.md index bcfff8ae..4edba694 100644 --- a/jakartaee-microprofile-example/README.md +++ b/jakartaee-microprofile-example/README.md @@ -1,14 +1,10 @@ # LangChain4j in Jakarta EE and MicroProfile -This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application on Open Liberty. The application is a chatbot built with LangChain4J and uses Jakarta CDI, Jakarta RESTful Web Services, Jakarta WebSocket, MicroProfile Config, MicroProfile Metrics, and MicroProfile OpenAPI features. The application allows to use models from either Hugging Face, Github, or Ollama. +This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application on Open Liberty. The application is a chatbot built with LangChain4J and uses Jakarta CDI, Jakarta RESTful Web Services, Jakarta WebSocket, MicroProfile Config, MicroProfile Metrics, and MicroProfile OpenAPI features. The application allows to use models from either Github, Ollama, or Hugging Face. ## Prerequisites: - [Java 21](https://developer.ibm.com/languages/java/semeru-runtimes/downloads) - Either one of the following model providers: - - Hugging Face - - Sign up and log in to https://huggingface.co. - - Go to [Access Tokens](https://huggingface.co/settings/tokens). - - Create a new access token with `read` role. - Github - Sign up and sign in to https://github.com. - Go to your [Settings](https://github.com/settings/profile)/[Developer Settings](https://github.com/settings/developers)/[Persional access tokens](https://github.com/settings/personal-access-tokens). @@ -20,6 +16,10 @@ This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application - `ollama pull llama3.2` - `ollama pull all-minilm` - `ollama pull tinydolphin` + - Hugging Face + - Sign up and log in to https://huggingface.co. + - Go to [Access Tokens](https://huggingface.co/settings/tokens). + - Create a new access token with `read` role. ## Environment Set Up @@ -34,13 +34,6 @@ Set the `JAVA_HOME` environment variable: export JAVA_HOME= ``` -Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face. -``` -unset GITHUB_API_KEY -unset OLLAMA_BASE_URL -export HUGGING_FACE_API_KEY= -``` - Set the `GITHUB_API_KEY` environment variable if using Github. ``` unset HUGGING_FACE_API_KEY @@ -55,6 +48,13 @@ unset GITHUB_API_KEY export OLLAMA_BASE_URL=http://localhost:11434 ``` +Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face. +``` +unset GITHUB_API_KEY +unset OLLAMA_BASE_URL +export HUGGING_FACE_API_KEY= +``` + ## Start the application Use the Maven wrapper to start the application by using the [Liberty dev mode](https://openliberty.io/docs/latest/development-mode.html): @@ -82,7 +82,7 @@ Use the Maven wrapper to start the application by using the [Liberty dev mode](h Navigate to the the [OpenAPI UI](http://localhost:9080/openapi/ui) URL for the following 3 REST APIs: -- [HuggingFaceLanguageModel](https://github.com/langchain4j/langchain4j/blob/main/langchain4j-hugging-face/src/main/java/dev/langchain4j/model/huggingface/HuggingFaceLanguageModel.java) +- [LanguageModel](https://javadoc.io/doc/dev.langchain4j/langchain4j-core/latest/dev/langchain4j/model/language/LanguageModel.html) - Expand the GET `/api/model/language` API. 1. Click the **Try it out** button. 2. Type `When was Hugging Face launched?`, or any question, in the question field. @@ -91,7 +91,7 @@ Navigate to the the [OpenAPI UI](http://localhost:9080/openapi/ui) URL for the f - ``` curl 'http://localhost:9080/api/model/language?question=When%20was%20Hugging%20Face%20launched%3F' ``` -- [HuggingFaceChatModel](https://github.com/langchain4j/langchain4j/blob/main/langchain4j-hugging-face/src/main/java/dev/langchain4j/model/huggingface/HuggingFaceChatModel.java) +- [ChatModel](https://javadoc.io/doc/dev.langchain4j/langchain4j-core/latest/dev/langchain4j/model/chat/ChatModel.html) - expand the GET `/api/model/chat` API 1. Click the **Try it out** button. 2. Type `Which are the most used Large Language Models?`, or any question, in the question field. @@ -100,7 +100,7 @@ Navigate to the the [OpenAPI UI](http://localhost:9080/openapi/ui) URL for the f - ``` curl 'http://localhost:9080/api/model/chat?userMessage=Which%20are%20the%20most%20used%20Large%20Language%20Models%3F' | jq ``` -- [InProcessEmbeddingModel](https://github.com/langchain4j/langchain4j-embeddings) +- [EmbeddingModel](https://javadoc.io/doc/dev.langchain4j/langchain4j-core/latest/dev/langchain4j/model/embedding/EmbeddingModel.html) - expand the GET `/api/model/similarity` API 1. Click the **Try it out** button. 2. Type `I like Jakarta EE and MicroProfile.`, or any text, in the the **text1** field. From bd82716d906c30436e3187660906a4ef37cf0851 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:18:37 -0400 Subject: [PATCH 05/21] Bump org.junit.jupiter:junit-jupiter from 5.12.2 to 5.13.0 in /jakartaee-microprofile-example (#20) * use dependabot to update jee-mp-example * Bump org.junit.jupiter:junit-jupiter in /jakartaee-microprofile-example Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.12.2 to 5.13.0. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.12.2...r5.13.0) --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter dependency-version: 5.13.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/dependabot.yml | 7 +++++++ jakartaee-microprofile-example/pom.xml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..288e045f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: +- package-ecosystem: maven + directory: "/jakartaee-microprofile-example" + schedule: + interval: monthly + open-pull-requests-limit: 50 diff --git a/jakartaee-microprofile-example/pom.xml b/jakartaee-microprofile-example/pom.xml index c3ed0dd7..e6c03b2b 100644 --- a/jakartaee-microprofile-example/pom.xml +++ b/jakartaee-microprofile-example/pom.xml @@ -63,7 +63,7 @@ org.junit.jupiter junit-jupiter - 5.12.2 + 5.13.0 test From a38b6f426f874d561131125494cc999fc6ca9685 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:19:57 -0400 Subject: [PATCH 06/21] Bump org.slf4j:slf4j-reload4j from 2.0.16 to 2.0.17 in /jakartaee-microprofile-example (#18) * use dependabot to update jee-mp-example * Bump org.slf4j:slf4j-reload4j in /jakartaee-microprofile-example Bumps org.slf4j:slf4j-reload4j from 2.0.16 to 2.0.17. --- updated-dependencies: - dependency-name: org.slf4j:slf4j-reload4j dependency-version: 2.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 3bc3d600087ab8fead08e6faa855edab91c822bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:20:21 -0400 Subject: [PATCH 07/21] Bump org.jboss.resteasy:resteasy-client from 6.2.11.Final to 6.2.12.Final in /jakartaee-microprofile-example (#17) * use dependabot to update jee-mp-example * Bump org.jboss.resteasy:resteasy-client Bumps [org.jboss.resteasy:resteasy-client](https://github.com/resteasy/resteasy) from 6.2.11.Final to 6.2.12.Final. - [Release notes](https://github.com/resteasy/resteasy/releases) - [Commits](https://github.com/resteasy/resteasy/compare/6.2.11.Final...v6.2.12.Final) --- updated-dependencies: - dependency-name: org.jboss.resteasy:resteasy-client dependency-version: 6.2.12.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 445a7a5a65185bc92c5ec810f15f366605cd4556 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:20:52 -0400 Subject: [PATCH 08/21] Bump io.openliberty.tools:liberty-maven-plugin from 3.11.2 to 3.11.3 in /jakartaee-microprofile-example (#16) * use dependabot to update jee-mp-example * Bump io.openliberty.tools:liberty-maven-plugin Bumps [io.openliberty.tools:liberty-maven-plugin](https://github.com/OpenLiberty/ci.maven) from 3.11.2 to 3.11.3. - [Release notes](https://github.com/OpenLiberty/ci.maven/releases) - [Commits](https://github.com/OpenLiberty/ci.maven/compare/liberty-maven-3.11.2...liberty-maven-3.11.3) --- updated-dependencies: - dependency-name: io.openliberty.tools:liberty-maven-plugin dependency-version: 3.11.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From fe4fe05692d02993ce59a0d773c41c5c2d73cc6d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:21:14 -0400 Subject: [PATCH 09/21] Bump org.slf4j:slf4j-api from 2.0.16 to 2.0.17 in /jakartaee-microprofile-example (#14) * use dependabot to update jee-mp-example * Bump org.slf4j:slf4j-api in /jakartaee-microprofile-example Bumps org.slf4j:slf4j-api from 2.0.16 to 2.0.17. --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-version: 2.0.17 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 2ef5a6412802f8007205c6768447602a1d433f47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:21:51 -0400 Subject: [PATCH 10/21] Bump org.eclipse.jetty.websocket:websocket-jakarta-client from 11.0.24 to 11.0.25 in /jakartaee-microprofile-example (#15) * use dependabot to update jee-mp-example * Bump org.eclipse.jetty.websocket:websocket-jakarta-client Bumps org.eclipse.jetty.websocket:websocket-jakarta-client from 11.0.24 to 11.0.25. --- updated-dependencies: - dependency-name: org.eclipse.jetty.websocket:websocket-jakarta-client dependency-version: 11.0.25 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 6288b451a5e7c8fce55b63b76f2a05c9d34d7c89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:22:11 -0400 Subject: [PATCH 11/21] Bump org.apache.maven.plugins:maven-failsafe-plugin from 3.5.2 to 3.5.3 in /jakartaee-microprofile-example (#13) * use dependabot to update jee-mp-example * Bump org.apache.maven.plugins:maven-failsafe-plugin Bumps [org.apache.maven.plugins:maven-failsafe-plugin](https://github.com/apache/maven-surefire) from 3.5.2 to 3.5.3. - [Release notes](https://github.com/apache/maven-surefire/releases) - [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.5.2...surefire-3.5.3) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-failsafe-plugin dependency-version: 3.5.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From ec194cfd3f12f8244cdcc98b6d69d9faab6d81dd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 11:22:39 -0400 Subject: [PATCH 12/21] Bump org.jboss.resteasy:resteasy-json-binding-provider from 6.2.11.Final to 6.2.12.Final in /jakartaee-microprofile-example (#12) * use dependabot to update jee-mp-example * Bump org.jboss.resteasy:resteasy-json-binding-provider Bumps org.jboss.resteasy:resteasy-json-binding-provider from 6.2.11.Final to 6.2.12.Final. --- updated-dependencies: - dependency-name: org.jboss.resteasy:resteasy-json-binding-provider dependency-version: 6.2.12.Final dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --------- Signed-off-by: dependabot[bot] Co-authored-by: Gilbert Kwan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> From 22146c552696425489c6fc3b6b4def329bfc893e Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Mon, 9 Jun 2025 11:23:32 -0400 Subject: [PATCH 13/21] remve dependabot action Signed-off-by: Gilbert Kwan --- .github/dependabot.yml | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 288e045f..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: 2 -updates: -- package-ecosystem: maven - directory: "/jakartaee-microprofile-example" - schedule: - interval: monthly - open-pull-requests-limit: 50 From d3e891a2fcf04df21dea5b575250f61a3a99203c Mon Sep 17 00:00:00 2001 From: Andrew Sasmito <98786007+AndrewSasmito@users.noreply.github.com> Date: Mon, 9 Jun 2025 13:46:06 -0400 Subject: [PATCH 14/21] Update ModelResourceIT.java (#19) * Update ModelResourceIT.java Added more possible answers * Update ModelResourceIT.java Shortened the line * Don't remove instance of message from response * Don't add ellipsis when agent message ends with punctuation --------- Co-authored-by: George Zhang --- .../src/main/java/dev/langchain4j/example/chat/ChatAgent.java | 4 +--- .../java/dev/langchain4j/example/chat/ChatMessageEncoder.java | 2 +- .../test/java/it/dev/langchan4j/example/ModelResourceIT.java | 3 ++- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java index cdef60d5..e85d190e 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatAgent.java @@ -40,9 +40,7 @@ public Assistant getAssistant() throws Exception { } public String chat(String sessionId, String message) throws Exception { - String reply = getAssistant().chat(sessionId, message).trim(); - int i = reply.lastIndexOf(message); - return i > 0 ? reply.substring(i) : reply; + return getAssistant().chat(sessionId, message).trim(); } } diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatMessageEncoder.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatMessageEncoder.java index 52cfd867..16b150d6 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatMessageEncoder.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/ChatMessageEncoder.java @@ -8,7 +8,7 @@ public class ChatMessageEncoder implements Encoder.Text { @Override public String encode(String message) throws EncodeException { - if (!message.endsWith(".")) { + if (!message.endsWith(".") && !message.endsWith("!") && !message.endsWith("?")) { message += " ..."; } diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java index 98d4e738..54a22f96 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java @@ -35,7 +35,8 @@ public void testLanguageMode() { String url = baseUrl + "language?question=When was Hugging Face launched?"; Response response = client.target(url).request().get(); String answer = response.readEntity(String.class); - assertTrue(answer.contains("2015") || answer.contains("2018"), "actual: " + answer); + assertTrue(answer.contains("2015") || answer.contains("2016") || + answer.contains("2017") || answer.contains("2018"), "actual: " + answer); } @Test From f69300303bc9c88e9ba9a2c65f96ab51ba9b8900 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Mon, 9 Jun 2025 14:14:06 -0400 Subject: [PATCH 15/21] update for Hugging Face Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/README.md | 1 + .../langchain4j/example/chat/util/ModelBuilder.java | 4 ++-- .../resources/META-INF/microprofile-config.properties | 4 ++-- .../java/it/dev/langchan4j/example/ChatServiceIT.java | 11 ++++++++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/jakartaee-microprofile-example/README.md b/jakartaee-microprofile-example/README.md index 4edba694..819a1025 100644 --- a/jakartaee-microprofile-example/README.md +++ b/jakartaee-microprofile-example/README.md @@ -53,6 +53,7 @@ Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face. unset GITHUB_API_KEY unset OLLAMA_BASE_URL export HUGGING_FACE_API_KEY= +export HUGGING_FACE_CHAT_MODEL_ID= ``` ## Start the application diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java index aaa1e932..d785db66 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java @@ -33,11 +33,11 @@ public class ModelBuilder { private String HUGGING_FACE_API_KEY; @Inject - @ConfigProperty(name = "hugging.language.model.id") + @ConfigProperty(name = "hugging.face.language.model.id") private String HUGGING_FACE_LANGUAGE_MODEL_ID; @Inject - @ConfigProperty(name = "hugging.chat.model.id") + @ConfigProperty(name = "hugging.face.chat.model.id") private String HUGGING_FACE_CHAT_MODEL_ID; @Inject diff --git a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties index 5dc60387..408058be 100644 --- a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties +++ b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties @@ -1,6 +1,6 @@ hugging.face.api.key=set it by env variable -hugging.chat.model.id=mistralai/Mistral-Nemo-Instruct-2407 -hugging.language.model.id=microsoft/Phi-3-mini-4k-instruct.base. +hugging.face.chat.model.id=mistralai/Mistral-Nemo-Instruct-2407 +hugging.face.language.model.id=microsoft/Phi-3-mini-4k-instruct github.api.key=set it by env variable github.chat.model.id=gpt-4o-mini diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java index 492b4f0c..d598acde 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java @@ -27,9 +27,14 @@ public void testChat() throws Exception { } public static void verify(String message) { - assertNotNull(message); - assertTrue(message.contains("2021") || message.contains("2022") || message.contains("2023"), - message); + if (Util.usingHuggingFace()) { + System.out.println("Skipped for Hugging Face"); + } else { + assertNotNull(message); + assertTrue(message.contains("2020") || message.contains("2021") || + message.contains("2022") || message.contains("2023"), + message); + } countDown.countDown(); } From 24c64e1f066868ec31beec497642192aed742329 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Mon, 9 Jun 2025 14:53:18 -0400 Subject: [PATCH 16/21] update for Hugging Face Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/README.md | 1 - .../META-INF/microprofile-config.properties | 2 +- .../it/dev/langchan4j/example/ChatServiceIT.java | 12 ++++-------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/jakartaee-microprofile-example/README.md b/jakartaee-microprofile-example/README.md index 819a1025..4edba694 100644 --- a/jakartaee-microprofile-example/README.md +++ b/jakartaee-microprofile-example/README.md @@ -53,7 +53,6 @@ Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face. unset GITHUB_API_KEY unset OLLAMA_BASE_URL export HUGGING_FACE_API_KEY= -export HUGGING_FACE_CHAT_MODEL_ID= ``` ## Start the application diff --git a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties index 408058be..94d8f733 100644 --- a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties +++ b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties @@ -1,5 +1,5 @@ hugging.face.api.key=set it by env variable -hugging.face.chat.model.id=mistralai/Mistral-Nemo-Instruct-2407 +hugging.face.chat.model.id=HuggingFaceH4/zephyr-7b-beta hugging.face.language.model.id=microsoft/Phi-3-mini-4k-instruct github.api.key=set it by env variable diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java index d598acde..3f96c6de 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ChatServiceIT.java @@ -27,14 +27,10 @@ public void testChat() throws Exception { } public static void verify(String message) { - if (Util.usingHuggingFace()) { - System.out.println("Skipped for Hugging Face"); - } else { - assertNotNull(message); - assertTrue(message.contains("2020") || message.contains("2021") || - message.contains("2022") || message.contains("2023"), - message); - } + assertNotNull(message); + assertTrue(message.contains("2020") || message.contains("2021") || + message.contains("2022") || message.contains("2023"), + message); countDown.countDown(); } From 2670d8f9cc1487d7cd880a3b1109e08ec78b2c31 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Tue, 10 Jun 2025 11:20:33 -0400 Subject: [PATCH 17/21] support mistral ai Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/README.md | 15 ++ jakartaee-microprofile-example/pom.xml | 5 + .../example/chat/util/ModelBuilder.java | 148 ++++++++++++------ .../META-INF/microprofile-config.properties | 11 +- .../langchan4j/example/ModelResourceIT.java | 6 +- .../java/it/dev/langchan4j/example/Util.java | 5 + 6 files changed, 131 insertions(+), 59 deletions(-) diff --git a/jakartaee-microprofile-example/README.md b/jakartaee-microprofile-example/README.md index 4edba694..98b04f57 100644 --- a/jakartaee-microprofile-example/README.md +++ b/jakartaee-microprofile-example/README.md @@ -16,6 +16,10 @@ This example demonstrates LangChain4J in a Jakarta EE / MicroProfile application - `ollama pull llama3.2` - `ollama pull all-minilm` - `ollama pull tinydolphin` + - Mistral AI + - Sign up and log in to https://console.mistral.ai/home. + - Go to [Your API keys](https://console.mistral.ai/api-keys). + - Create a new key. - Hugging Face - Sign up and log in to https://huggingface.co. - Go to [Access Tokens](https://huggingface.co/settings/tokens). @@ -38,6 +42,7 @@ Set the `GITHUB_API_KEY` environment variable if using Github. ``` unset HUGGING_FACE_API_KEY unset OLLAMA_BASE_URL +unset MISTRAL_AI_API_KEY export GITHUB_API_KEY= ``` @@ -45,13 +50,23 @@ Set the `OLLAMA_BASE_URL` environment variable if using Ollama. Use your Ollama ``` unset HUGGING_FACE_API_KEY unset GITHUB_API_KEY +unset MISTRAL_AI_API_KEY export OLLAMA_BASE_URL=http://localhost:11434 ``` +Set the `MISTRAL_AI_API_KEY` environment variable if using Mistral AI. +``` +unset GITHUB_API_KEY +unset OLLAMA_BASE_URL +unset MISTRAL_AI_API_KEY +export MISTRAL_AI_API_KEY= +``` + Set the `HUGGING_FACE_API_KEY` environment variable if using Hugging Face. ``` unset GITHUB_API_KEY unset OLLAMA_BASE_URL +unset MISTRAL_AI_API_KEY export HUGGING_FACE_API_KEY= ``` diff --git a/jakartaee-microprofile-example/pom.xml b/jakartaee-microprofile-example/pom.xml index e6c03b2b..65b826f3 100644 --- a/jakartaee-microprofile-example/pom.xml +++ b/jakartaee-microprofile-example/pom.xml @@ -49,6 +49,11 @@ langchain4j-ollama 1.0.1-beta6 + + dev.langchain4j + langchain4j-mistral-ai + 1.0.1-beta6 + org.slf4j slf4j-reload4j diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java index d785db66..0b2338ad 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java @@ -3,6 +3,8 @@ import static dev.langchain4j.model.github.GitHubModelsChatModelName.PHI_3_MINI_INSTRUCT_4K; import static dev.langchain4j.model.github.GitHubModelsEmbeddingModelName.TEXT_EMBEDDING_3_SMALL; import static dev.langchain4j.model.huggingface.HuggingFaceModelName.SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2; +import static dev.langchain4j.model.mistralai.MistralAiChatModelName.MISTRAL_SMALL_LATEST; +import static dev.langchain4j.model.mistralai.MistralAiEmbeddingModelName.MISTRAL_EMBED; import static java.time.Duration.ofSeconds; import java.util.logging.Logger; @@ -17,6 +19,8 @@ import dev.langchain4j.model.huggingface.HuggingFaceEmbeddingModel; import dev.langchain4j.model.huggingface.HuggingFaceLanguageModel; import dev.langchain4j.model.language.LanguageModel; +import dev.langchain4j.model.mistralai.MistralAiChatModel; +import dev.langchain4j.model.mistralai.MistralAiEmbeddingModel; import dev.langchain4j.model.ollama.OllamaChatModel; import dev.langchain4j.model.ollama.OllamaEmbeddingModel; import dev.langchain4j.model.ollama.OllamaLanguageModel; @@ -26,7 +30,7 @@ @ApplicationScoped public class ModelBuilder { - private static Logger logger = Logger.getLogger(ModelBuilder.class.getName()); + private static Logger logger = Logger.getLogger(ModelBuilder.class.getName()); @Inject @ConfigProperty(name = "hugging.face.api.key") @@ -56,6 +60,14 @@ public class ModelBuilder { @ConfigProperty(name = "ollama.chat.model.id") private String OLLAMA_CHAT_MODEL_ID; + @Inject + @ConfigProperty(name = "mistral.ai.api.key") + private String MISTRAL_AI_API_KEY; + + @Inject + @ConfigProperty(name = "mistral.ai.chat.model.id") + private String MISTRAL_AI_MISTRAL_CHAT_MODEL_ID; + @Inject @ConfigProperty(name = "chat.model.timeout") private Integer TIMEOUT; @@ -73,10 +85,6 @@ public class ModelBuilder { private ChatModel chatModelForResource = null; private ChatModel chatModelForWeb = null; - public boolean usingHuggingFace() { - return HUGGING_FACE_API_KEY.startsWith("hf_"); - } - public boolean usingGithub() { return GITHUB_API_KEY.startsWith("ghp_"); } @@ -85,9 +93,28 @@ public boolean usingOllama() { return OLLAMA_BASE_URL.startsWith("http"); } + public boolean usingMistralAi() { + return MISTRAL_AI_API_KEY.length() > 30; + } + + public boolean usingHuggingFace() { + return HUGGING_FACE_API_KEY.startsWith("hf_"); + } + public LanguageModel getLanguageModel() throws Exception { if (languageModel == null) { - if (usingHuggingFace()) { + if (usingGithub()) { + throw new Exception("LangChain4J Github APIs do not support language model"); + } else if (usingOllama()) { + languageModel = OllamaLanguageModel.builder() + .baseUrl(OLLAMA_BASE_URL) + .modelName("tinydolphin") + .temperature(1.0) + .build(); + logger.info("using Ollama tinydolphin language model"); + } else if (usingMistralAi()) { + throw new Exception("LangChain4J Mistral AI APIs do not support language model"); + } else if (usingHuggingFace()) { languageModel = HuggingFaceLanguageModel.builder() .accessToken(HUGGING_FACE_API_KEY) .modelId(HUGGING_FACE_LANGUAGE_MODEL_ID) @@ -97,15 +124,6 @@ public LanguageModel getLanguageModel() throws Exception { .waitForModel(true) .build(); logger.info("using Hugging Face " + HUGGING_FACE_LANGUAGE_MODEL_ID + " language model"); - } else if (usingGithub()) { - throw new Exception("LangChain4J Github APIs do not support language model"); - } else if (usingOllama()) { - languageModel = OllamaLanguageModel.builder() - .baseUrl(OLLAMA_BASE_URL) - .modelName("tinydolphin") - .temperature(1.0) - .build(); - logger.info("using Ollama tinydolphin language model"); } else { throw new Exception("No available platform to access model"); } @@ -115,15 +133,7 @@ public LanguageModel getLanguageModel() throws Exception { public EmbeddingModel getEmbeddingModel() throws Exception { if (embeddingModel == null) { - if (usingHuggingFace()) { - embeddingModel = HuggingFaceEmbeddingModel.builder() - .accessToken(HUGGING_FACE_API_KEY) - .modelId(SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2) - .timeout(ofSeconds(120)) - .waitForModel(true) - .build(); - logger.info("using Hugging Face " + SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2 + " embedding model"); - } else if (usingGithub()) { + if (usingGithub()) { embeddingModel = GitHubModelsEmbeddingModel.builder() .gitHubToken(GITHUB_API_KEY) .modelName(TEXT_EMBEDDING_3_SMALL) @@ -131,12 +141,27 @@ public EmbeddingModel getEmbeddingModel() throws Exception { .build(); logger.info("using Github " + TEXT_EMBEDDING_3_SMALL + " embedding model"); } else if (usingOllama()) { - embeddingModel = OllamaEmbeddingModel.builder() - .baseUrl(OLLAMA_BASE_URL) - .modelName("all-minilm") - .timeout(ofSeconds(120)) - .build(); + embeddingModel = OllamaEmbeddingModel.builder() + .baseUrl(OLLAMA_BASE_URL) + .modelName("all-minilm") + .timeout(ofSeconds(120)) + .build(); logger.info("using Ollama all-minilm embedding model"); + } else if (usingMistralAi()) { + embeddingModel = MistralAiEmbeddingModel.builder() + .apiKey(MISTRAL_AI_API_KEY) + .modelName(MISTRAL_EMBED) + .timeout(ofSeconds(120)) + .build(); + logger.info("using Mistral AI " + MISTRAL_EMBED + " embedding model"); + } else if (usingHuggingFace()) { + embeddingModel = HuggingFaceEmbeddingModel.builder() + .accessToken(HUGGING_FACE_API_KEY) + .modelId(SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2) + .timeout(ofSeconds(120)) + .waitForModel(true) + .build(); + logger.info("using Hugging Face " + SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2 + " embedding model"); } else { throw new Exception("No available platform to access model"); } @@ -146,17 +171,7 @@ public EmbeddingModel getEmbeddingModel() throws Exception { public ChatModel getChatModelForResource() throws Exception { if (chatModelForResource == null) { - if (usingHuggingFace()) { - chatModelForResource = HuggingFaceChatModel.builder() - .accessToken(HUGGING_FACE_API_KEY) - .modelId(HUGGING_FACE_LANGUAGE_MODEL_ID) - .timeout(ofSeconds(120)) - .temperature(1.0) - .maxNewTokens(200) - .waitForModel(true) - .build(); - logger.info("using Hugging Face " + HUGGING_FACE_LANGUAGE_MODEL_ID + " chat model"); - } else if (usingGithub()) { + if (usingGithub()) { chatModelForResource = GitHubModelsChatModel.builder() .gitHubToken(GITHUB_API_KEY) .modelName(PHI_3_MINI_INSTRUCT_4K) @@ -166,13 +181,32 @@ public ChatModel getChatModelForResource() throws Exception { .build(); logger.info("using Github " + PHI_3_MINI_INSTRUCT_4K + " chat model"); } else if (usingOllama()) { - chatModelForResource = OllamaChatModel.builder() + chatModelForResource = OllamaChatModel.builder() .baseUrl(OLLAMA_BASE_URL) .modelName(OLLAMA_CHAT_MODEL_ID) .timeout(ofSeconds(TIMEOUT)) .temperature(TEMPERATURE) .build(); logger.info("using Ollama " + OLLAMA_CHAT_MODEL_ID + " chat model"); + } else if (usingMistralAi()) { + chatModelForResource = MistralAiChatModel.builder() + .apiKey(MISTRAL_AI_API_KEY) + .modelName(MISTRAL_SMALL_LATEST) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .maxTokens(MAX_NEW_TOKEN) + .build(); + logger.info("using Mistral AI " + MISTRAL_SMALL_LATEST + " chat model"); + } else if (usingHuggingFace()) { + chatModelForResource = HuggingFaceChatModel.builder() + .accessToken(HUGGING_FACE_API_KEY) + .modelId(HUGGING_FACE_LANGUAGE_MODEL_ID) + .timeout(ofSeconds(120)) + .temperature(1.0) + .maxNewTokens(200) + .waitForModel(true) + .build(); + logger.info("using Hugging Face " + HUGGING_FACE_LANGUAGE_MODEL_ID + " chat model"); } else { throw new Exception("No available platform to access model"); } @@ -182,17 +216,7 @@ public ChatModel getChatModelForResource() throws Exception { public ChatModel getChatModelForWeb() throws Exception { if (chatModelForWeb == null) { - if (usingHuggingFace()) { - chatModelForWeb = HuggingFaceChatModel.builder() - .accessToken(HUGGING_FACE_API_KEY) - .modelId(HUGGING_FACE_CHAT_MODEL_ID) - .timeout(ofSeconds(TIMEOUT)) - .temperature(TEMPERATURE) - .maxNewTokens(MAX_NEW_TOKEN) - .waitForModel(true) - .build(); - logger.info("using Hugging Face " + HUGGING_FACE_CHAT_MODEL_ID + " chat model for the web"); - } else if (usingGithub()) { + if (usingGithub()) { chatModelForWeb = GitHubModelsChatModel.builder() .gitHubToken(GITHUB_API_KEY) .modelName(GITHUB_CHAT_MODEL_ID) @@ -209,6 +233,26 @@ public ChatModel getChatModelForWeb() throws Exception { .temperature(TEMPERATURE) .build(); logger.info("using Ollama " + OLLAMA_CHAT_MODEL_ID + " chat model for the web"); + } else if (usingMistralAi()) { + chatModelForWeb = MistralAiChatModel.builder() + .apiKey(MISTRAL_AI_API_KEY) + .modelName(MISTRAL_AI_MISTRAL_CHAT_MODEL_ID) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .maxTokens(MAX_NEW_TOKEN) + .build(); + logger.info("using Mistral AI " + MISTRAL_AI_MISTRAL_CHAT_MODEL_ID + " chat model for the web"); + } else if (usingHuggingFace()) { + chatModelForWeb = HuggingFaceChatModel.builder() + .accessToken(HUGGING_FACE_API_KEY) + .modelId(HUGGING_FACE_CHAT_MODEL_ID) + .timeout(ofSeconds(TIMEOUT)) + .temperature(TEMPERATURE) + .maxNewTokens(MAX_NEW_TOKEN) + .waitForModel(true) + .build(); + logger.info("using Hugging Face " + HUGGING_FACE_CHAT_MODEL_ID + " chat model for the web"); + } else { throw new Exception("No available platform to access model"); } diff --git a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties index 94d8f733..264d4bed 100644 --- a/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties +++ b/jakartaee-microprofile-example/src/main/resources/META-INF/microprofile-config.properties @@ -1,13 +1,16 @@ -hugging.face.api.key=set it by env variable -hugging.face.chat.model.id=HuggingFaceH4/zephyr-7b-beta -hugging.face.language.model.id=microsoft/Phi-3-mini-4k-instruct - github.api.key=set it by env variable github.chat.model.id=gpt-4o-mini ollama.base.url=set it by env variable ollama.chat.model.id=llama3.2 +mistral.ai.api.key=set it by env variable +mistral.ai.chat.model.id=mistral-small-latest + +hugging.face.api.key=set it by env variable +hugging.face.chat.model.id=HuggingFaceH4/zephyr-7b-beta +hugging.face.language.model.id=microsoft/Phi-3-mini-4k-instruct + chat.model.timeout=120 chat.model.max.token=200 chat.model.temperature=1.0 diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java index 54a22f96..23ae43b0 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/ModelResourceIT.java @@ -29,7 +29,7 @@ public void teardown() { @Test public void testLanguageMode() { - if (Util.usingGithub()) { + if (Util.usingGithub() || Util.usingMistralAi()) { return; } String url = baseUrl + "language?question=When was Hugging Face launched?"; @@ -57,10 +57,10 @@ public void testEmbeddingMode() { JsonObject json = response.readEntity(JsonObject.class); double score = json.getJsonNumber("relevance-score").doubleValue(); - assertTrue(score > 0.63 && score < 0.70, "actual score: " + score); + assertTrue(score > 0.63 && score < 0.89, "actual score: " + score); double similarity = json.getJsonNumber("similarity").doubleValue(); - assertTrue(similarity > 0.27 && similarity < 0.39, + assertTrue(similarity > 0.27 && similarity < 0.79, "actual similarity: " + similarity); } diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java index 4323dd2f..8e4f32f7 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java @@ -5,6 +5,7 @@ public class Util { private static String hfApiKey = System.getenv("HUGGING_FACE_API_KEY"); private static String githubApiKey = System.getenv("GITHUB_API_KEY"); private static String ollamaBaseUrl = System.getenv("OLLAMA_BASE_URL"); + private static String mistralAiApiKey = System.getenv("MISTRAL_AI_API_KEY"); public static boolean usingHuggingFace() { return hfApiKey != null && hfApiKey.startsWith("hf_"); @@ -18,4 +19,8 @@ public static boolean usingOllama() { return ollamaBaseUrl != null && ollamaBaseUrl.startsWith("http"); } + public static boolean usingMistralAi() { + return mistralAiApiKey != null && mistralAiApiKey.length() > 30; + } + } From b5e11b6fb68d2d592071ddf9909a595742d74783 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Tue, 12 Aug 2025 18:17:19 -0400 Subject: [PATCH 18/21] update dependencies and support another github api key Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/pom.xml | 10 +++++----- .../langchain4j/example/chat/util/ModelBuilder.java | 3 ++- .../src/test/java/it/dev/langchan4j/example/Util.java | 4 +++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/jakartaee-microprofile-example/pom.xml b/jakartaee-microprofile-example/pom.xml index dd4552ff..693f064d 100644 --- a/jakartaee-microprofile-example/pom.xml +++ b/jakartaee-microprofile-example/pom.xml @@ -42,17 +42,17 @@ dev.langchain4j langchain4j-github-models - 1.0.1-beta6 + 1.3.0-beta9 dev.langchain4j langchain4j-ollama - 1.0.1-beta6 + 1.3.0 dev.langchain4j langchain4j-mistral-ai - 1.0.1-beta6 + 1.3.0 org.slf4j @@ -68,7 +68,7 @@ org.junit.jupiter junit-jupiter - 5.13.0 + 5.13.4 test @@ -109,7 +109,7 @@ io.openliberty.tools liberty-maven-plugin - 3.11.3 + 3.11.4 diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java index 0b2338ad..981611fa 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java @@ -86,7 +86,8 @@ public class ModelBuilder { private ChatModel chatModelForWeb = null; public boolean usingGithub() { - return GITHUB_API_KEY.startsWith("ghp_"); + return GITHUB_API_KEY.startsWith("ghp_") || + GITHUB_API_KEY.startsWith("github_pat_"); } public boolean usingOllama() { diff --git a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java index 8e4f32f7..434e9fa1 100644 --- a/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java +++ b/jakartaee-microprofile-example/src/test/java/it/dev/langchan4j/example/Util.java @@ -12,7 +12,9 @@ public static boolean usingHuggingFace() { } public static boolean usingGithub() { - return githubApiKey != null && githubApiKey.startsWith("ghp_"); + return githubApiKey != null && + (githubApiKey.startsWith("ghp_") || + githubApiKey.startsWith("github_pat_")); } public static boolean usingOllama() { From 28f115efc16e08ffaee92ee6c7a741298bcbbead Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Fri, 5 Sep 2025 16:51:47 -0400 Subject: [PATCH 19/21] update dependencies Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jakartaee-microprofile-example/pom.xml b/jakartaee-microprofile-example/pom.xml index 5b45d394..a18854e0 100644 --- a/jakartaee-microprofile-example/pom.xml +++ b/jakartaee-microprofile-example/pom.xml @@ -92,7 +92,7 @@ org.eclipse.jetty.websocket websocket-jakarta-client - 11.0.25 + 11.0.26 test @@ -109,7 +109,7 @@ io.openliberty.tools liberty-maven-plugin - 3.11.4 + 3.11.5 From a9fd0da5c34c412becd067f99e846656ed5a7643 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Wed, 24 Sep 2025 13:53:08 -0400 Subject: [PATCH 20/21] fix github model Signed-off-by: Gilbert Kwan --- .../java/dev/langchain4j/example/chat/util/ModelBuilder.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java index 981611fa..311e1edd 100644 --- a/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java +++ b/jakartaee-microprofile-example/src/main/java/dev/langchain4j/example/chat/util/ModelBuilder.java @@ -1,6 +1,5 @@ package dev.langchain4j.example.chat.util; -import static dev.langchain4j.model.github.GitHubModelsChatModelName.PHI_3_MINI_INSTRUCT_4K; import static dev.langchain4j.model.github.GitHubModelsEmbeddingModelName.TEXT_EMBEDDING_3_SMALL; import static dev.langchain4j.model.huggingface.HuggingFaceModelName.SENTENCE_TRANSFORMERS_ALL_MINI_LM_L6_V2; import static dev.langchain4j.model.mistralai.MistralAiChatModelName.MISTRAL_SMALL_LATEST; @@ -175,12 +174,12 @@ public ChatModel getChatModelForResource() throws Exception { if (usingGithub()) { chatModelForResource = GitHubModelsChatModel.builder() .gitHubToken(GITHUB_API_KEY) - .modelName(PHI_3_MINI_INSTRUCT_4K) + .modelName("Phi-4-mini-instruct") .timeout(ofSeconds(120)) .temperature(1.0) .maxTokens(200) .build(); - logger.info("using Github " + PHI_3_MINI_INSTRUCT_4K + " chat model"); + logger.info("using Github Phi-4-mini-instruct chat model"); } else if (usingOllama()) { chatModelForResource = OllamaChatModel.builder() .baseUrl(OLLAMA_BASE_URL) From a8f71cb8144ab9e3479704357bdf7ea075b167a6 Mon Sep 17 00:00:00 2001 From: Gilbert Kwan Date: Wed, 24 Sep 2025 14:00:29 -0400 Subject: [PATCH 21/21] update dependencies Signed-off-by: Gilbert Kwan --- jakartaee-microprofile-example/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jakartaee-microprofile-example/pom.xml b/jakartaee-microprofile-example/pom.xml index 74d7ba63..99eae23a 100644 --- a/jakartaee-microprofile-example/pom.xml +++ b/jakartaee-microprofile-example/pom.xml @@ -42,17 +42,17 @@ dev.langchain4j langchain4j-github-models - 1.3.0-beta9 + 1.5.0-beta11 dev.langchain4j langchain4j-ollama - 1.3.0 + 1.5.0 dev.langchain4j langchain4j-mistral-ai - 1.3.0 + 1.5.0 org.slf4j