{"id":4466,"date":"2024-02-06T17:42:18","date_gmt":"2024-02-06T17:42:18","guid":{"rendered":"https:\/\/kindgeek.com\/blog\/?p=4466"},"modified":"2025-02-21T08:11:33","modified_gmt":"2025-02-21T08:11:33","slug":"experiments-with-langchain4j-or-java-way-to-llm-powered-applications","status":"publish","type":"post","link":"https:\/\/www.kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications","title":{"rendered":"Experiments with Langchain4j or Java way to LLM-powered applications"},"content":{"rendered":"<div class=\"inhype-post\"><p class=\"post-date\">Recently updated on February 21, 2025<\/p><\/div>\n<p><em>In this article, we are discussing with Michael Kramarenko, Kindgeek CTO, how to incorporate LM\/LLM-based features into Java projects using Langchain4j. This framework streamlines the development of LLM-powered Java applications, drawing inspiration from Langchain, a popular Java Langchain<\/em> f<em>ramework that  is designed to simplify the process of building applications utilizing large language models.<\/em><\/p>\n\n\n\n<p><em>Join us with a cup of a great coffee, and enjoy our info-packed ten-minute read on&nbsp;Java way to building an LLM app with Langchain4j\u2615.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Brief intro or a quick reality check<\/h2>\n\n\n\n<p>Integrating LM\/LLM-based functionality in existing and new products is definitely proving to be more than a mere trend. Today, embracing AI innovation is more about keeping up with the curve.<\/p>\n\n\n\n<p>Indeed, as per <a href=\"https:\/\/www.gartner.com\/en\/articles\/what-s-new-in-artificial-intelligence-from-the-2023-gartner-hype-cycle\">Gartner<\/a> analysis, Generative AI, GPT, and LM\/LLM applications are becoming key driving forces in shaping IT products for the upcoming 5\u201310 years. And no wonder, artificial intelligence is the future.  Such solutions will use features like chat but will be integrated with a corporate knowledge base, internal and external data via API, and acquired from web crawling.&nbsp;This article provides insights on how to use LM\/LLM in Java applications effectively.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Content<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"#text1\">Setting the Scene or \u201cWhat problem are we solving?\u201d<\/a><\/li>\n\n\n\n<li><a href=\"#text2\">Starting from business needs, not from technological aspects<\/a><\/li>\n\n\n\n<li><a href=\"#text3\">Typical building blocks of LLM-powered application<\/a><\/li>\n\n\n\n<li><a href=\"#text4\">Starting our Langchain4j for llm journey&nbsp;<\/a><\/li>\n\n\n\n<li><a href=\"#text5\">User Experience aspect: delving into nuances<\/a><\/li>\n\n\n\n<li><a href=\"#text6\">Memory and state management<\/a><\/li>\n\n\n\n<li><a href=\"#text7\">Corporate data aspect or extending LLM&#8217;s knowledge<\/a><\/li>\n\n\n\n<li><a href=\"#text8\">LLM Functions and Langchain4j java @Tools<\/a><\/li>\n\n\n\n<li><a href=\"#text9\">Summing up<\/a><\/li>\n<\/ol>\n\n\n\n<a id=\"text1\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\">Setting the Scene or \u201cWhat problem are we solving?\u201d<\/h2>\n\n\n\n<p>At this point of the story let us meet our <strong>virtual character<\/strong> \u2013 <strong>John Geek<\/strong>.<\/p>\n\n\n\n<p>He&#8217;s a tech lead of a mission-critical Java Spring-based project that has been in development for years.&nbsp;<\/p>\n\n\n\n<p>Now, amidst AI advancements, the customer asks John to explore LLM integration into Java fully integrated with the essential corporate data (structured, semi-structured, and unstructured), internal and external data points accessible via REST API.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"900\" height=\"316\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ID-5.png\" alt=\"\" class=\"wp-image-4499\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ID-5.png 900w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ID-5-300x105.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ID-5-768x270.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ID-5-360x126.png 360w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/figure>\n\n\n\n<p>So what are the options for John?<\/p>\n\n\n\n<p>He perfectly knows that Python is the lingua franca of AI development, not Java.<\/p>\n\n\n\n<p>Theoretically, he could choose the \u201cPolyglot architecture\u201d way. However, such a way would increase the Learning Curve for John&#8217;s development team, maintenance complexity, complicate dependency management, CI\/CD pipeline, testing, and deployment strategies.&nbsp;<\/p>\n\n\n\n<p>It&#8217;s clear to him that the microservices architecture is technology-neutral. However, his current architecture is a modular monolith. Given this, transitioning to a microservices architecture presents significant implementation challenges. It\u2019s an additional complication compared to the \u201cPolyglot architecture\u201d way.<\/p>\n\n\n\n<p>On the other hand, John has heard about different pure Java options like<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>using Java library supporting OpenAI API like <a href=\"https:\/\/github.com\/sashirestela\/simple-openai\/tree\/main\">Simple OpenAI<\/a><\/li>\n\n\n\n<li>exploring <a href=\"https:\/\/github.com\/spring-projects\/spring-ai\">Spring AI<\/a>, however the project doesn&#8217;t have public releases yet<\/li>\n\n\n\n<li>leveraging Java framework like Langchain4j<\/li>\n<\/ul>\n\n\n\n<p class=\"has-text-align-center\"><em><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"289\" src=\"https:\/\/lh7-us.googleusercontent.com\/KIbO057i64-T_c4DCgHhLfgsP-tiQkV13GDWdCQDOAH_RHChfdF8SptVoIRT-sderNPBsXHETMvVWbtFohQZXNjhBwF9Y9-49oR_MTVBcv3ksrGES2WlE6x-txOvo9U2zYf4H1IoEPAQwIxEhQfrdyM\"><\/em><\/p>\n\n\n\n<a id=\"text2\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\">Starting from business needs, not from technological aspects<\/h2>\n\n\n\n<p>Enterprise-grade LLM-powered applications can be developed using various components tailored to specific business requirements. So the first step&nbsp;requires a <strong>deep understanding<\/strong> of the <strong>business case<\/strong> and <strong>supported use cases<\/strong>. This understanding, in turn, facilitates a seamless alignment of the LLM solution with the business needs, leading to the identification of critical success factors of the final deliverable. During this phase, it&#8217;s possible to refine aspects such as roles, regulations, communication strategies, and prompting procedures.<\/p>\n\n\n\n<p>Since LLM-driven applications are inherently data-centric,  you need to deeply understand your data:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>origin: <\/strong>external or internal data<\/li>\n\n\n\n<li><strong>data type: <\/strong>structured, semi-structured, or unstructured data<\/li>\n\n\n\n<li><strong>data source type: <\/strong>internal API, 3-d party API, web crawling, etc.&nbsp;<\/li>\n\n\n\n<li><strong>data formats:<\/strong> html, json, pdf, doc etc.&nbsp;&nbsp;<\/li>\n<\/ul>\n\n\n\n<p>To gain a profound understanding of use cases and corporate data, we\u2019d highly recommend utilizing methodologies like CPMAI, CRISP-DM.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"547\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/schema-1024x547.png\" alt=\"\" class=\"wp-image-4481\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/schema-1024x547.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/schema-300x160.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/schema-768x411.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/schema-1536x821.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/schema-2048x1095.png 2048w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/schema-360x192.png 360w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<a id=\"text3\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\">Typical building blocks of LLM-powered application<\/h2>\n\n\n\n<p>Understanding of your  use cases and data allows you to produce an AI solution that addresses the business problem. So you can use different building blocks for your app:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.32.18-1024x608.png\" alt=\"\" class=\"wp-image-4487\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.32.18-1024x608.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.32.18-300x178.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.32.18-768x456.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.32.18-1536x913.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.32.18-360x214.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.32.18.png 1646w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>LM\/LLM<\/strong>: lies at the heart of LM\/LLM-driven applications, exemplified by models like GPT-3, BERT, etc. These models, offered by different LLM providers, have been trained on vast amounts of text data and can perform a variety of NLP tasks, such as text generation, summarization, translation, and question-answering.<\/li>\n\n\n\n<li><strong>Prompts &amp; Templates<\/strong>: inputs given to the LLM to generate a response or perform a specific task. The design of these prompts is critical, as it significantly influences the output of the model.&nbsp;<\/li>\n\n\n\n<li><strong>Embeddings<\/strong>:&nbsp; numerical representations of words, phrases, or entire documents that convert text into a format that can be processed by LLMs to capture the semantics of the text, which aids in tasks like semantic search, text classification, and similarity comparisons.<\/li>\n\n\n\n<li><strong>Vector Database<\/strong>: is used to store and manage embeddings. It enables efficient storage, retrieval, and comparison of these high-dimensional vectors for semantic search, where the goal is to find the most relevant pieces of text based on their semantic similarity.<\/li>\n\n\n\n<li><strong>Memory and State Management<\/strong>: for context retention over multiple interactions<\/li>\n\n\n\n<li><strong>Data Preprocessing and Normalization<\/strong>: involves tasks such as cleaning the data, removing irrelevant information, standardizing formats, and ensuring that the data is in a suitable form for the model to process.<\/li>\n\n\n\n<li><strong>APIs and Integration Tools<\/strong>:&nbsp; for integration of LLM capabilities into applications, whether it\u2019s for a chatbot, content creation tool, or data analysis platform.<\/li>\n<\/ul>\n\n\n\n<a id=\"text4\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\">Starting our Langchain4j journey&nbsp;<\/h2>\n\n\n\n<p>Before we commence our project journey, make sure to complete the following preparation steps:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a Spring Boot 3.2.1 Maven project using, for example, <a href=\"https:\/\/start.spring.io\/\">Spring Initializr<\/a>. We can start with <a href=\"https:\/\/mvnrepository.com\/artifact\/org.springframework.boot\/spring-boot-starter-web\/3.2.1\">spring-boot-starter-web<\/a>&nbsp;<\/li>\n\n\n\n<li>Add <a href=\"https:\/\/mvnrepository.com\/artifact\/dev.langchain4j\/langchain4j\/0.25.0\">Langchain4j 0.25.0<\/a> Maven dependencies. We can start our journey with \u200b\u200b<a href=\"https:\/\/mvnrepository.com\/artifact\/dev.langchain4j\/langchain4j\/0.25.0\">langchain4j<\/a>&nbsp; and <a href=\"https:\/\/mvnrepository.com\/artifact\/dev.langchain4j\/langchain4j-open-ai\">langchain4j-open-ai<\/a>&nbsp;<\/li>\n\n\n\n<li>Feel free to add other dependencies like <a href=\"https:\/\/mvnrepository.com\/artifact\/org.projectlombok\/lombok\/1.18.30\">lombok<\/a>, <a href=\"https:\/\/mvnrepository.com\/artifact\/org.slf4j\/slf4j-api\/2.0.10\">org.slf4j<\/a>, <a href=\"https:\/\/mvnrepository.com\/artifact\/commons-io\/commons-io\/2.15.1\">commons-io<\/a>, <a href=\"https:\/\/mvnrepository.com\/artifact\/org.springdoc\/springdoc-openapi-starter-webmvc-ui\/2.2.0\">Springdoc openapi<\/a>, etc.&nbsp;<\/li>\n<\/ul>\n\n\n\n<p>To <strong>use LLM in Java with Langchain4j<\/strong>, developers can take advantage of its predefined components and easy setup.<\/p>\n\n\n\n<p>Within this experiment, we&#8217;ll proceed with OpenAI LLMs, so the last preparation step would involve acquiring the OpenAI API key using the <a href=\"https:\/\/platform.openai.com\/api-keys\">api-keys<\/a> page&nbsp;to finalize the necessary setup. This setup ensures a seamless integration of Langchain Java capabilities into your application.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Configuring your LLM-powered application<\/h3>\n\n\n\n<p>Langchain4j 0.25.0 offers numerous integrations with the following AI platforms:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td><strong>AI Platform&nbsp;<\/strong><\/td><td><strong>Deployment model<\/strong><\/td><td><strong>Business model<\/strong><\/td><td><strong>Opensource&nbsp;<\/strong><\/td><td>                          <strong>Comments<\/strong><\/td><\/tr><tr><td><a href=\"https:\/\/openai.com\/\">OpenAI<\/a>&nbsp;<\/td><td>AIaaS<\/td><td>usage-based pricing model&nbsp;<\/td><td>      \u274c<\/td><td>One of the most advanced AI platforms, a vendor of multimodal LLMs like GPT-4, DALL\u00b7E, and Whisper, a versatile speech recognition model<\/td><\/tr><tr><td><a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/ai-services\/openai\/overview\">Azure OpenAI<\/a>&nbsp;<\/td><td>AIaaS<\/td><td>usage-based pricing model&nbsp;<\/td><td>     \u274c<\/td><td>Deployment of OpenAI models into Microsoft&#8217;s Azure cloud for seamless integration with other native cloud services<\/td><\/tr><tr><td><a href=\"https:\/\/cloud.google.com\/vertex-ai\/docs\/generative-ai\/learn\/overview\">Google Vertex AI<\/a>, <a href=\"https:\/\/cloud.google.com\/vertex-ai\/docs\/generative-ai\/multimodal\/overview\">Vertex AI Gemini<\/a>&nbsp;&nbsp;<\/td><td>AIaaS<\/td><td>usage-based pricing model&nbsp;<\/td><td>    \u274c<\/td><td>Comprehensive, scalable platform for AI development and deployment, with access to cutting-edge Google AI technology and its integration with the broader ecosystem of Google Cloud services<\/td><\/tr><tr><td><a href=\"https:\/\/docs.aws.amazon.com\/bedrock\/latest\/userguide\/what-is-bedrock.html\">Amazon Bedrock<\/a>&nbsp;<\/td><td>AIaaS<\/td><td>usage-based pricing mode&nbsp;<\/td><td>    \u274c<\/td><td>Serverless AI platform  that allows building agents using top-foundation models integrated with enterprise systems and data sources<\/td><\/tr><tr><td><a href=\"https:\/\/huggingface.co\/\">Huggingface<\/a>&nbsp;<\/td><td>primary AIaaS<\/td><td>core-free, subscription-based<\/td><td>    \u2705<\/td><td>Open-source project with a strong community focus, encouraging collaboration and sharing among AI researchers.&nbsp;<\/td><\/tr><tr><td><a href=\"https:\/\/github.com\/QwenLM\/Qwen\">QwenLM<\/a>&nbsp;<\/td><td>primaryAIaaS<\/td><td><br>primary usage-based pricing model<\/td><td>    \u2705<\/td><td>The most simple way to use Qwen through DashScope API service of Alibaba Cloud &#8211;&nbsp; multimodal LLMs platform, including <a href=\"https:\/\/huggingface.co\/Qwen\/Qwen-Audio?spm=a2c65.11461447.0.0.642d3d8dhcnl6p\">Qwen Audio<\/a>&nbsp; and <a href=\"https:\/\/huggingface.co\/Qwen\/Qwen-Audio-Chat?spm=a2c65.11461447.0.0.642d3d8dhcnl6p\">Qwen Audio Chat<\/a>&nbsp;<\/td><\/tr><tr><td><a href=\"https:\/\/localai.io\/\">LocalAI<\/a>&nbsp;<\/td><td>on-premise&nbsp;<\/td><td>free&nbsp;<\/td><td>   \u2705<\/td><td>Open-source alternative to OpenAI, designed as a drop-in replacement REST API for local inferencing<\/td><\/tr><tr><td><a href=\"https:\/\/github.com\/jmorganca\/ollama\/tree\/main\">Ollama<\/a>&nbsp;<\/td><td>on-premise<\/td><td>free<\/td><td>   \u2705<\/td><td>Allows to run open-source large language models, such as LLaMA2, locally<\/td><\/tr><tr><td><a href=\"https:\/\/github.com\/THUDM\/ChatGLM-6B\/blob\/main\/README_en.md\">ChatGLM-6B<\/a><\/td><td>on-premise<\/td><td>free<\/td><td>  \u2705<\/td><td>Employs technology similar to ChatGPT, optimized specifically for Chinese question-answering and dialogue scenarios<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>To further enhance the flexibility of our application, we will extensively employ the @Value annotation. This approach enables the efficient configuration of LLM settings and other building blocks in external files such as <em>application.properties<\/em> or <em>application.yml.&nbsp;<\/em><\/p>\n\n\n\n<p>&nbsp;Here&#8217;s a brief overview of OpenAI parameters supported by Langchain4j 0.25.0&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td><strong>OpenAI parameter&nbsp;<\/strong><\/td><td><strong>Description<\/strong><\/td><\/tr><tr><td>API key&nbsp;<\/td><td>Enables OpenAI to authenticate users and ensure that only authorized users can access the API<\/td><\/tr><tr><td>Model Version\/Name<\/td><td>Different versions or types of models (e.g., GPT-3, GPT-3.5, GPT-4) have different capabilities, with newer versions generally offering more advanced features or larger parameter counts<\/td><\/tr><tr><td>Temperature<\/td><td>Controls the randomness (or \u201ccreativity\u201d) of the model&#8217;s responses. A higher temperature results in more creative and less predictable responses, while a lower temperature produces more deterministic and potentially more accurate responses. A higher temperature increases the \u201challucination\u201d probability<\/td><\/tr><tr><td>Frequency Penalty<\/td><td>Reduces the model&#8217;s tendency to repeat the same word or phrase. Increasing the frequency penalty helps in generating a more diverse response<\/td><\/tr><tr><td>Presence Penalty<\/td><td>Being similar to the frequency penalty, this setting discourages the model from mentioning topics or entities that it has already talked about. This can be useful for keeping the conversation or content generation diverse<\/td><\/tr><tr><td>Top-P (Nucleus Sampling)<\/td><td>Instead of sampling only from the most likely K words, Top-p sampling chooses from the smallest possible set of words whose cumulative probability exceeds the probability <em>p<\/em>&nbsp;<\/td><\/tr><tr><td>Logit Bias<\/td><td>Employed to adjust the likelihood of certain words or phrases appearing in the model&#8217;s output. By applying a bias to the logits (the raw output scores from the model before they are converted into probabilities), you can make certain words more or less likely to be selected<\/td><\/tr><tr><td>Seed<\/td><td>If specified, the platform will make the best effort to sample deterministically, ensuring that repeated requests with the same seed and parameters should return the same result<\/td><\/tr><tr><td>User<\/td><td>Sending end-user IDs in your requests can be a useful tool to help OpenAI detect abuse, and generate more relevant and coherent responses.The IDs should be a string that uniquely identifies each user<\/td><\/tr><tr><td>Response Format<\/td><td>Format &#8220;json_object&#8221; guarantees a model respond as a valid JSON<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Indeed, mind that LangChain4j offers up its own specific settings, which prove to be very useful for our further experiments:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td><strong>API Timeout<\/strong><\/td><td><strong>Log API request<\/strong><\/td><td><strong>Log API response<\/strong><\/td><\/tr><tr><td>Regulate the time limit for API requests to ensure prompt responsiveness<\/td><td>Choose to log details of LLM API requests to facilitate debugging processes.<\/td><td>Opt to log API response details, aiding in the analysis of model outputs and troubleshooting potential issues.<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>It is worth noting that Langchain4j primarily utilizes the <strong>Builder pattern<\/strong> with numerous parameters.&nbsp;<\/p>\n\n\n\n<p>As a result, our application could contain <strong>several externally configurable Builders<\/strong> inherited from <em><span class=\"has-inline-color has-black-color\">abstract cla<\/span>ss<\/em> <span class=\"has-inline-color has-black-color\">lik<\/span>e <em><span class=\"has-inline-color has-vivid-green-cyan-color\">ChatModelBuilderParameters<\/span><\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n<span class=\"has-inline-color has-luminous-vivid-amber-color\">@Slf4j<\/span>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public abstract class<\/span> ChatModelBuilderParameters {\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"${OPENAI_API_KEY}\"<\/span>)\n   String OPENAI_API_KEY;\n  <span class=\"has-inline-color has-luminous-vivid-amber-color\"> @Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"${GPT.modelName}\"<\/span>)\n   String <span class=\"has-inline-color has-vivid-purple-color\">gptModelName<\/span>;\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"#{new Boolean('${openai.log.requests}')}\"<\/span>)\n   Boolean <span class=\"has-inline-color has-vivid-purple-color\">logRequests<\/span>;\n <span class=\"has-inline-color has-luminous-vivid-amber-color\">  @Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"#{new Boolean('${openai.log.responses}')}\"<\/span>)\n   Boolean <span class=\"has-inline-color has-vivid-purple-color\">logResponses<\/span>;\n  <span class=\"has-inline-color has-luminous-vivid-amber-color\"> @Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"#{new Long ('${openai.timeout.sec}')}\"<\/span>)\n   Long <span class=\"has-inline-color has-vivid-purple-color\">timeoutSec<\/span>;\n  <span class=\"has-inline-color has-luminous-vivid-amber-color\"> @Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"#{new Double ('${openai.temperature}')}\"<\/span>)\n   Double <span class=\"has-inline-color has-vivid-purple-color\">temperature<\/span>;\n\n\n}\n<\/code><\/pre>\n\n\n\n<p>In such a case, a corresponding <em><span class=\"has-inline-color has-light-green-cyan-color\">ChatModelBuilder<\/span><\/em> could look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-amber-color\">@Service\n@Slf4j<\/span>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public class<\/span> ChatLanguageModelBuilder <span class=\"has-inline-color has-luminous-vivid-orange-color\">extends<\/span> ChatModelBuilderParameters \n<span class=\"has-inline-color has-luminous-vivid-orange-color\">implements<\/span> ChatModelBuilder {\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"#{new Integer ('${openai.maxRetries}')}\"<\/span>)\n   Integer <span class=\"has-inline-color has-vivid-purple-color\">maxRetries<\/span>;\n\n\n <span class=\"has-inline-color has-luminous-vivid-amber-color\">  @Override<\/span>\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> ChatLanguageModel <span class=\"has-inline-color has-luminous-vivid-amber-color\">build<\/span>() {\n       ChatLanguageModel chatLanguageModel = OpenAiChatModel.builder()\n               .apiKey(OPENAI_API_KEY)\n               .modelName(gptModelName)\n               .timeout(ofSeconds(timeoutSec.longValue()))\n               .logRequests(logRequests.booleanValue())\n               .logResponses(logResponses.booleanValue())\n               .maxRetries(maxRetries)\n               .temperature(temperature)\n               .build();\n       <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> chatLanguageModel;\n   }\n}\n<\/code><\/pre>\n\n\n\n<a id=\"text5\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>User Experience aspect: delving into nuances<\/strong><\/h2>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"413\" src=\"https:\/\/lh7-us.googleusercontent.com\/ln6aH5XiHXV5DjOuvCCHyheRwg-jUxtwF1YKvjlAKBr9pIH6fHsz4yWIWa9NCCkxq1lo7jAJEcy4Naa8x5Ke5_uKAM1s5hiQfdoAAky06vjHI5f496L1R_0FyRMT2nO-pTSOjWrvdpRMdy6FOwKxUMQ\"><\/p>\n\n\n\n<p>Indeed, the traditional approach involves standard Spring MVC, characterized by a blocking model of &#8220;request-response.&#8221;&nbsp;<\/p>\n\n\n\n<p>However, Spring Boot also embraces a <strong>non-blocking, asynchronous model<\/strong>. <\/p>\n\n\n\n<p>Particularly, <a href=\"https:\/\/docs.spring.io\/spring-framework\/reference\/web\/webflux.html\">Spring WebFlux<\/a> is a reactive web framework built on reactive streams. And it&#8217;s exactly what we are looking for.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"480\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.31.12-1024x480.png\" alt=\"\" class=\"wp-image-4485\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.31.12-1024x480.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.31.12-300x140.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.31.12-768x360.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.31.12-1536x719.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.31.12-360x169.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-17.31.12.png 1670w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>In WebFlux, a <strong>stream<\/strong> (sequence of data sent from one system to another) is processed in a <strong>non-blocking reactive manner,<\/strong> meaning that the system can respond to changes and events <strong>in real-time<\/strong>, ensuring it can handle data as it arrives without the need for blocking or sequential processing.<\/p>\n\n\n\n<p>This approach enables a <strong>more dynamic<\/strong> and <strong>responsive system<\/strong>, allowing for <strong>concurrent processing<\/strong> of incoming data streams:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"536\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.00-1024x536.png\" alt=\"\" class=\"wp-image-4486\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.00-1024x536.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.00-300x157.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.00-768x402.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.00-1536x805.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.00-360x189.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.00.png 1676w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"552\" src=\"https:\/\/lh7-us.googleusercontent.com\/MORxvzgJcnakgKTShl5qFJ7bUX4hD6cQ0pj2OPOp77u5L1Pola4YsplNloSdPGvplWxi3rRSLQrAjYcO32Djsu7qIUCeq7Z1XqYO8A7gPeX2Kn9J93yBTyDimkaTrSOAPnCnNjnr35HQlCT5wvj_RBY\"><\/p>\n\n\n\n<p>Here is an example of what the code for an image generation might look like:&nbsp;&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the first step \u2013 build<em> <\/em><span class=\"has-inline-color has-light-green-cyan-color\"><em>ImageModel<\/em> <\/span>using Builder like<em> <span class=\"has-inline-color has-pale-cyan-blue-color\">ImageModelBuilder<\/span><\/em><\/li>\n\n\n\n<li>the next step \u2013 generate an image based on the scene description<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-amber-color\">@Slf4j<\/span>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public class<\/span> ImageModelBuilderImpl <span class=\"has-inline-color has-luminous-vivid-orange-color\">extends<\/span> ChatModelBuilderParameters <span class=\"has-inline-color has-luminous-vivid-orange-color\">implements<\/span> ImageModelBuilder {\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"${openai.imageModelName}\"<\/span>)\n   String <span class=\"has-inline-color has-vivid-purple-color\">imageModelName<\/span>;\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Value<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"${openai.image.quality}\"<\/span>)\n   String <span class=\"has-inline-color has-vivid-purple-color\">imageQuality<\/span>;\n\n\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Override<\/span>\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> ImageModel <span class=\"has-inline-color has-luminous-vivid-amber-color\">build<\/span>() {\n       ImageModel model = OpenAiImageModel.builder()\n               .apiKey(OPENAI_API_KEY)\n               .modelName(imageModelName)\n               .quality(imageQuality)\n               .timeout(ofSeconds(timeoutSec.longValue()))\n               .logRequests(logRequests.booleanValue())\n               .logResponses(logResponses.booleanValue())\n               .build();\n       <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> model;\n   }\n}\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-amber-color\">@Override<\/span>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> URI <span class=\"has-inline-color has-luminous-vivid-amber-color\">generateImageUrl<\/span>(String description) {\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Generating image for : {} \"<\/span>, description);\n   Response&lt;Image&gt; response = <span class=\"has-inline-color has-vivid-purple-color\">model<\/span>.generate(description);\n   URI uri = response.content().url();\n  <span class=\"has-inline-color has-vivid-purple-color\"> log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Generated image  URI : {} \"<\/span>, uri);\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> uri;\n}\n\n<\/code><\/pre>\n\n\n\n<a id=\"text6\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\">Memory and state management<\/h2>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"269\" src=\"https:\/\/lh7-us.googleusercontent.com\/Q14zkDDHGgIL61hP056wNopii2UlrSTonQ2opc5btSr8cQ5JmCfJANBVyGSpxxlS7gKOSoeA5YcoIOmiJfFWG_fuGMR0ayT8Zr1J2iUfV8T_5ooMIEbVRtbxiJMsuBf43lzJH43JJACKzkwrzcCe4ys\"><\/p>\n\n\n\n<p>For a simple scenario, you have two options: <span class=\"has-inline-color has-pale-cyan-blue-color\">TokenWindowChatMemory<\/span>, and <span class=\"has-inline-color has-pale-cyan-blue-color\">MessageWindowChatMemory<\/span>.<\/p>\n\n\n\n<p><span class=\"has-inline-color has-pale-cyan-blue-color\">TokenWindowChatMemory <\/span>operates as a sliding window of <span class=\"has-inline-color has-cyan-bluish-gray-color\">maxTokens<\/span> tokens. It retains as many of the most recent messages as can fit into the window. If there isn&#8217;t enough space for a new message, the oldest one (or multiple) is discarded.<\/p>\n\n\n\n<p><span class=\"has-inline-color has-pale-cyan-blue-color\">MessageWindowChatMemory<\/span> operates as a sliding window of <span class=\"has-inline-color has-cyan-bluish-gray-color\">maxMessages<\/span> messages. It retains as many of the most recent messages as can fit into the window. If there isn&#8217;t enough space for a new message, the oldest one is discarded.<\/p>\n\n\n\n<p>For more complex scenarios, you can decide how chat memory is stored, and use your implementation of <span class=\"has-inline-color has-pale-cyan-blue-color\">ChatMemoryStore <\/span>interface.&nbsp;<\/p>\n\n\n\n<p>You can also use<span class=\"has-inline-color has-luminous-vivid-amber-color\"> @MemoryId<\/span> annotation to find the memory tied to a given user\/conversation.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"605\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.51-1-1024x605.png\" alt=\"\" class=\"wp-image-4488\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.51-1-1024x605.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.51-1-300x177.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.51-1-768x454.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.51-1-1536x908.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.51-1-360x213.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.22.51-1.png 1672w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<a id=\"text7\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\">Corporate data aspect or extending LLM&#8217;s knowledge<\/h2>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"352\" src=\"https:\/\/lh7-us.googleusercontent.com\/d6V0Bc3bMScyJgWIJuLZV_o8arv_mmt0b93HKDOvpoLXaXgzzZclb1uWkqaUhjO-2lLx7OYbUqbiE6MhKYQJu1ElsZch7slpnVDRcEL3GeCKYYkkbPxb9JT5jZOgszEAhqRb53TY0TB4xsaNMoKeaPo\"><\/p>\n\n\n\n<p>To extend LLM&#8217;s &#8220;knowledge&#8221;, you can use Retrieval-Augmented Generation (RAG), or leverage LLM API functions.<\/p>\n\n\n\n<p><strong>RAG<\/strong> is designed to enhance the ability of LLMs to provide more accurate and relevant responses by supplementing its pre-trained knowledge with information retrieved from a large corpus of documents (rather unstructured data), like corporate knowledge base or external data achievable via Web crawling.&nbsp;<\/p>\n\n\n\n<p>Another option for answering factual questions when detailed, specific knowledge is required is using <strong>LLM API functions<\/strong>. Indeed, certain LLMs have been fine-tuned to detect when a function should be called and respond with the inputs that should be passed to the function. In such a way, an application can be integrated with external APIs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">RAG approach<\/h3>\n\n\n\n<p>Similar to <a href=\"https:\/\/python.langchain.com\/docs\/get_started\/introduction\">Langchain<\/a>, Langchain4j provides all the building blocks for RAG applications:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"352\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/image-1024x352.png\" alt=\"\" class=\"wp-image-4475\" style=\"width:875px;height:300px\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/image-1024x352.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/image-300x103.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/image-768x264.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/image-360x124.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/image.png 1235w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\"> [ <a href=\"https:\/\/python.langchain.com\/docs\/get_started\/introduction\">source<\/a> ]<\/figcaption><\/figure>\n\n\n\n<p>The first step of the RAG chain is document loading. Langchain4j provides <span class=\"has-inline-color has-pale-cyan-blue-color\">DocumentLoader<\/span> for loading documents (using <span class=\"has-inline-color has-pale-cyan-blue-color\">Document<\/span> representation) from many sources (private S3 buckets, public websites, filesystem) in different formats (text, HTML, PDF, Microsoft documents).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"201\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.24.50-1024x201.png\" alt=\"\" class=\"wp-image-4489\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.24.50-1024x201.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.24.50-300x59.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.24.50-768x151.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.24.50-1536x302.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.24.50-360x71.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.24.50.png 1670w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>It is important to note that in HTML case, we need to clear markup using <span class=\"has-inline-color has-cyan-bluish-gray-color\">HtmlTextExtractor <\/span>,so our code could look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> <span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> Document <span class=\"has-inline-color has-luminous-vivid-amber-color\">extractHtmL<\/span>(String urlString) {\n  URL url = formUrl(urlString);\n  Document htmlDocument = UrlDocumentLoader.load(url, newTextDocumentParser());\n  HtmlTextExtractor transformer = new HtmlTextExtractor(null, null, true);\n  Document transformedDocument = transformer.transform(htmlDocument);\n  <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> transformedDocument;\n}\n<\/code><\/pre>\n\n\n\n<p>Also, you can use&nbsp; <span class=\"has-inline-color has-cyan-bluish-gray-color\">HtmlTextExtractor<\/span> as an HTML markup filter via specific CSS selectors.&nbsp;&nbsp;<\/p>\n\n\n\n<p>A key part of retrieval is fetching only the relevant parts of documents. The next step is splitting (or chunking) a&nbsp; <span class=\"has-inline-color has-pale-cyan-blue-color\">Document <\/span>into smaller chunks using <span class=\"has-inline-color has-pale-cyan-blue-color\">DocumentSplitter <\/span><span class=\"has-inline-color has-luminous-vivid-amber-color\">recursive<\/span><span class=\"has-inline-color has-pale-cyan-blue-color\">(<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">int<\/span><span class=\"has-inline-color has-pale-cyan-blue-color\"> maxSegmentSizeInTokens,<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\"> int<\/span><span class=\"has-inline-color has-pale-cyan-blue-color\"> maxOverlapSizeInTokens, Tokenizer tokenizer)<\/span><\/p>\n\n\n\n<p>The last step of document loading is the ingestion of documents into an embedding store. It manages the entire pipeline process, from splitting the documents into text segments, generating embeddings for them using a provided embedding model, and finally storing them in a vector database.&nbsp;<\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"269\" src=\"https:\/\/lh7-us.googleusercontent.com\/uX0U1itoUQr_O3mQDXvH5aJdoqTfh9V2Mpd95C2YBD4K4tBp5QTnJdrohlBRE4C6tf6-UTIulCq0oMWAes1YPdOBRL9uNeOhU7dDf4olRg2fvRYN9gnRliLCiX00eHPQBjjmWK1cU4CMn8MXDeLoZtY\"><\/p>\n\n\n\n<p><strong>Embeddings<\/strong> are condensed <strong>numerical representations<\/strong> of words, phrases, and entire documents <strong>that capture<\/strong> their <strong>semantic meaning and context<\/strong> and are expressed as vectors in a high-dimensional space.&nbsp;<\/p>\n\n\n\n<p>These vectors of floating point numbers are what LLMs normally process to grasp semantic and syntactic relationships between words. <strong>Small distances<\/strong> between vectors <strong>suggest high semantic relevance<\/strong>, while large distances imply low semantic relevance. By assessing the distance between these embedding vectors <strong>(cosine similarity)<\/strong>, we can learn what is semantically \u201cthe closest\u201d to other content.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Embedding models in LangChain4j<\/strong><\/h3>\n\n\n\n<p>In Langchain4j, embedding models corresponding to specific LLM are represented by specific classes (like <span class=\"has-inline-color has-pale-cyan-blue-color\">OpenAiEmbeddingModel<\/span>, Hugging Faces&nbsp; <span class=\"has-inline-color has-pale-cyan-blue-color\">AllMiniLmL6V2EmbeddingModel<\/span>, <span class=\"has-inline-color has-pale-cyan-blue-color\">LocalAiEmbeddingModeletc<\/span>.). For example, Hugging Faces <a href=\"https:\/\/huggingface.co\/sentence-transformers\/all-MiniLM-L6-v2\"><strong>all-MiniLM-L6-v2 model<\/strong><\/a> maps sentences &amp; paragraphs to a 384-dimensional dense vector space and can be used for tasks like clustering or semantic search.&nbsp;&nbsp;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Vector Database<\/strong>s<strong>&nbsp;in LangChain4j<\/strong><\/h3>\n\n\n\n<p>Langchain4j supports a broad selection of Vector databases for efficient storage of&nbsp; embeddings:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td>Vector DB Type&nbsp;<\/td><td>Vector DB<\/td><\/tr><tr><td>Pure vector databases<\/td><td><a href=\"https:\/\/www.trychroma.com\/\">Chroma<\/a> , <a href=\"https:\/\/milvus.io\/\">Milvus<\/a> , <a href=\"https:\/\/www.pinecone.io\/\">Pinecone<\/a> , <a href=\"https:\/\/vespa.ai\/\">Vespa<\/a> , &nbsp; <a href=\"https:\/\/weaviate.io\/\">Weaviate<\/a>&nbsp;<\/td><\/tr><tr><td>Full text search datastor<\/td><td><a href=\"https:\/\/www.elastic.co\/\">Elastic Search<\/a> , <a href=\"https:\/\/opensearch.org\/\">Open Search<\/a>&nbsp;<\/td><\/tr><tr><td>Vector-capable NoSQL databases<\/td><td><a href=\"https:\/\/docs.llamaindex.ai\/en\/stable\/examples\/vector_stores\/CassandraIndexDemo.html\">Cassandra<\/a>, <a href=\"https:\/\/www.datastax.com\/products\/datastax-astra\">Astra DB<\/a>, <a href=\"https:\/\/redis.io\/\">Redis<\/a>, <a href=\"https:\/\/neo4j.com\/\">Neo4j<\/a>,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/td><\/tr><tr><td>Vector-capable SQL databases<\/td><td><a href=\"https:\/\/github.com\/pgvector\/pgvector\">Pgvector<\/a> extension for <a href=\"https:\/\/www.postgresql.org\/\">Postgresql <\/a>(ver.11+)&nbsp;&nbsp;&nbsp;<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-us.googleusercontent.com\/a9pPZdinpj7P87ReteExNXSVrrTNC9N2PW7-76irsxTIknKotOhHzr02KgvRqYbykVCGQlUDyFcC-PAe0Hqo-U3KxFz3uVtIaXObVy5cDrlTMz7dhSrOdA2a7RQSIKajcFeBlS6oRT4tBJXvlcZREq4\" alt=\"\"\/><\/figure><\/div>\n\n\n<p>After <a href=\"https:\/\/github.com\/pgvector\/pgvector\">Pgvector extension installation <\/a>(via <span class=\"has-inline-color has-cyan-bluish-gray-color\">CREATE EXTENSION vector<\/span>), you will be able to use <span class=\"has-inline-color has-cyan-bluish-gray-color\">vector<\/span> type and <span class=\"has-inline-color has-cyan-bluish-gray-color\">vectors <\/span>table: &nbsp;&nbsp;<\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"602\" height=\"395\" src=\"https:\/\/lh7-us.googleusercontent.com\/qZ3jNYt06dgJkV3iOWM1qZief4F-IKKcpgvN58Gtpf6-L8slM1STEvtUuVgNih5wHmx1GirMKytppEHCCzd38sDZ1cew4UVUSAd19-Bm4_fdUrTHCVuzmIb-izVjK2EuVadQxgwK9VF-bV0kpG8I1j0\"><\/p>\n\n\n\n<p>As a result, HTML document loading and ingesting process can be implemented in the following way:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n<span class=\"has-inline-color has-luminous-vivid-amber-color\">@Override<\/span>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> LoadHtmlDocumentDto <span class=\"has-inline-color has-luminous-vivid-amber-color\">loadHtmlDocument<\/span>(String urlString, Integer maxSegmentSize, Integer maxOverlapSize) {\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Loading document from: {} maxSegmentSize {} maxOverlapSize  {}\"<\/span>, urlString, maxSegmentSize, maxOverlapSize);\n   EmbeddingStore&lt;TextSegment&gt; pgVectorEmbeddingStore = <span class=\"has-inline-color has-vivid-purple-color\">embeddingStoreServiceBuilder.<\/span>build();\n   HtmlLoader loader = <span class=\"has-inline-color has-luminous-vivid-orange-color\">new<\/span> HtmlTextLoader();\n   Document document = loader.extractHtmL(urlString);\n   EmbeddingModel embeddingModel = <span class=\"has-inline-color has-luminous-vivid-orange-color\">new<\/span> AllMiniLmL6V2EmbeddingModel();\n   EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()\n           .documentSplitter(DocumentSplitters.recursive(maxSegmentSize, maxOverlapSize))\n           .embeddingModel(embeddingModel)\n           .embeddingStore(pgVectorEmbeddingStore)\n           .build();\n   ingestor.ingest(document);\n   LoadHtmlDocumentDto documentDto = <span class=\"has-inline-color has-luminous-vivid-orange-color\">new<\/span> LoadHtmlDocumentDto(urlString, maxSegmentSize, maxOverlapSize);\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Ingested document: {}\"<\/span>, documentDto);\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> documentDto;\n}\n<\/code><\/pre>\n\n\n\n<p>Retrieval chain can be implemented the following way:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-amber-color\">@Override<\/span>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> ConversationalRetrievalChain <span class=\"has-inline-color has-luminous-vivid-amber-color\">build<\/span>() {\n   EmbeddingStore&lt;TextSegment&gt; pgVectorEmbeddingStore = <span class=\"has-inline-color has-vivid-purple-color\">embeddingStoreServiceBuilder<\/span>.build();\n   EmbeddingModel embeddingModel =<span class=\"has-inline-color has-luminous-vivid-orange-color\"> new<\/span> AllMiniLmL6V2EmbeddingModel();\n   ChatLanguageModel chatLanguageModel = <span class=\"has-inline-color has-vivid-purple-color\">chatLanguageModelBuilder<\/span>.build();\n   TokenWindowChatMemory selfExplainMemory = <span class=\"has-inline-color has-vivid-purple-color\">chatMemoryBuilder<\/span>.build();\n   ConversationalRetrievalChain chain = ConversationalRetrievalChain.builder()\n           .chatLanguageModel(chatLanguageModel)\n           .retriever(EmbeddingStoreRetriever.from(pgVectorEmbeddingStore, embeddingModel))\n           .chatMemory(selfExplainMemory)\n           .build();\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> chain;\n}\n<\/code><\/pre>\n\n\n\n<p>Besides, mind adding <a href=\"https:\/\/mvnrepository.com\/artifact\/dev.langchain4j\/langchain4j-pgvector\/0.25.0\">Langchain4j Pgvector<\/a> and <a href=\"https:\/\/mvnrepository.com\/artifact\/dev.langchain4j\/langchain4j-embeddings-all-minilm-l6-v2\/0.25.0\">Langchain4j Embeddings-all-minilm-l6-v2<\/a> dependencies in your Maven build.&nbsp;<\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"289\" src=\"https:\/\/lh7-us.googleusercontent.com\/aBdfAsP1lwDruD5f2du_Tprl1L3iQYjkHB-0OdejJ8Hrmn1bavdDZhukT0JnILxkI2O00EVoUudgbuQAtkX6CNna2PBcH3S6ByfabJxxXecuTfmZwRSyxM9o8PkCTEHfEbzDnKv0-oAkjlHeAnfL4TU\"><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"601\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.28.16-1024x601.png\" alt=\"\" class=\"wp-image-4478\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.28.16-1024x601.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.28.16-300x176.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.28.16-768x451.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.28.16-1536x901.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.28.16-360x211.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.28.16.png 1680w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>But essentially, a significant point here is the evaluation of translation quality.<\/p>\n\n\n\n<p>For that, we could use the following approach:&nbsp;<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Mark an original web-crawled content as an original document written in some original language&nbsp;<\/li>\n\n\n\n<li>Mark translated content as a translated document in a corresponding translation language&nbsp;<\/li>\n\n\n\n<li>Introduce some threshold semantic distance between original and translated content. <\/li>\n<\/ol>\n\n\n\n<p>Here, we might also use direct and reverse translation, and calculate a semantic distance between the original and the reverse-translated documents.<\/p>\n\n\n\n<p>By employing such a threshold, we would be able to highlight the documents for further manual correction of translation.&nbsp;&nbsp;<\/p>\n\n\n\n<p>As a result, our code can look as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Prompt-template base Translator interface&nbsp;<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> interface Translator {\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@UserMessage<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Translate the following text: {{text}} from {{from_language}} to {{to_language}}\"<\/span>)\n   String <span class=\"has-inline-color has-luminous-vivid-amber-color\">translate<\/span>(<span class=\"has-inline-color has-luminous-vivid-amber-color\">@V<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"text\"<\/span>) String text, <span class=\"has-inline-color has-luminous-vivid-amber-color\">@V<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"from_language\"<\/span>) String from_language, <span class=\"has-inline-color has-luminous-vivid-amber-color\">@V<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"to_language\"<\/span>) String to_language);\n}\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Declarative <span class=\"has-inline-color has-pale-cyan-blue-color\">Translator <\/span>implementation<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>Translator <span class=\"has-inline-color has-vivid-purple-color\">translator<\/span> = AiServices.builder(Translator.<span class=\"has-inline-color has-luminous-vivid-orange-color\">class<\/span>)\n       .chatLanguageModel(<span class=\"has-inline-color has-vivid-purple-color\">chatLanguageModel<\/span>)\n       .chatMemory(<span class=\"has-inline-color has-vivid-purple-color\">memory<\/span>)\n       .build();\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Direct and reverse translation with cosine similarity calculation <\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-amber-color\">@Override<\/span>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> TranslationDto <span class=\"has-inline-color has-luminous-vivid-amber-color\">translate<\/span>(String text, String from_language, String to_language) {\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">\\n<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">Translating text : {} from {} to  {} \"<\/span>, text, from_language, to_language);\n   String translatedText = <span class=\"has-inline-color has-vivid-purple-color\">translator<\/span>.translate(text, from_language, to_language);\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">\\n<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">Translation result:  {} \"<\/span>, translatedText);\n   String reverseTranslatedText = <span class=\"has-inline-color has-vivid-purple-color\">translator<\/span>.translate(translatedText, to_language, from_language);\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">\\n<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">Reverse Translation text : {} from {} to  {} \"<\/span>, reverseTranslatedText, to_language, from_language);\n   EmbeddingModel embeddingModel = <span class=\"has-inline-color has-luminous-vivid-orange-color\">new<\/span> AllMiniLmL6V2EmbeddingModel();\n   Embedding embeddingInput = embeddingModel.embed(text).content();\n   Embedding embeddingReverseTranslation = embeddingModel.embed(reverseTranslatedText).content();\n   Double cosineSimilarity = CosineSimilarity.between(embeddingInput, embeddingReverseTranslation);\n   TranslationDto translationDto = <span class=\"has-inline-color has-luminous-vivid-orange-color\">new<\/span> TranslationDto(from_language, text, to_language, translatedText, reverseTranslatedText, cosineSimilarity);\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> translationDto;\n}\n<\/code><\/pre>\n\n\n\n<p>It is worth to note, that we can ingest original and translated documents as well their summarization using declarative <span class=\"has-inline-color has-pale-cyan-blue-color\">Summariser<\/span> implementation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-orange-color\">public interface<\/span> Summariser {\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@UserMessage<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Summarise the following text in {{length}} {{units}}: {{text}} \"<\/span>)\n   String <span class=\"has-inline-color has-luminous-vivid-amber-color\">summarise<\/span>(<span class=\"has-inline-color has-luminous-vivid-amber-color\">@V<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"text\"<\/span>) String text, <span class=\"has-inline-color has-luminous-vivid-amber-color\">@V<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"units\"<\/span>) String unitsOfText, <span class=\"has-inline-color has-luminous-vivid-amber-color\">@V<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"length\"<\/span>) Integer length);\n}\n\n\u200b\u200b    Summariser summariser = AiServices.builder(Summariser.class)\n       .chatLanguageModel(<span class=\"has-inline-color has-vivid-purple-color\">chatLanguageModel<\/span>)\n       .build()\n<\/code><\/pre>\n\n\n\n<a id=\"text8\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>LLM Functions and Langchain4j <em>@Tools<\/em><\/strong><\/h2>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"329\" src=\"https:\/\/lh7-us.googleusercontent.com\/wYRAQM4wrVmmOF7Ds-4w7pLNIx5QgHzZrKLrgn94rmSYLU45YP2Lzysu-r-x-0LIo485QxRaGXFwZu-8dBp-1WWabZdnfKzaOoG4xFz1AMaFLqpSlL2thvTWBzT0fv6OCLi49tFzBmxxP7vx1zjyeyY\"><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"603\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.29.37-1-1024x603.png\" alt=\"\" class=\"wp-image-4492\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.29.37-1-1024x603.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.29.37-1-300x177.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.29.37-1-768x452.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.29.37-1-1536x904.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.29.37-1-360x212.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.29.37-1.png 1678w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Langchain4j utilizes a declarative approach via <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool <\/span>annotation, providing an easier and more efficient &#8220;function&#8221; integration way.&nbsp;<\/p>\n\n\n\n<p>Langchain4j <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool<\/span> concept is very similar to <a href=\"https:\/\/python.langchain.com\/docs\/modules\/agents\/\">Langchain Agent<\/a> which can be thought of as an intermediary that is responsible for orchestrating the flow of information and maintaining the efficiency and effectiveness of the language model within the application context. So, we can wrap a third-party REST API as a Langchain4j <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool<\/span>.&nbsp;&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"547\" src=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.30.41-1-1024x547.png\" alt=\"\" class=\"wp-image-4493\" srcset=\"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.30.41-1-1024x547.png 1024w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.30.41-1-300x160.png 300w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.30.41-1-768x410.png 768w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.30.41-1-1536x820.png 1536w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.30.41-1-360x192.png 360w, https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/\u0417\u043d\u0456\u043c\u043e\u043a-\u0435\u043a\u0440\u0430\u043d\u0430-2024-02-06-\u043e-16.30.41-1.png 1674w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Historical Stock Data via REST API<\/strong><\/h3>\n\n\n\n<p>Let\u2019s illustrate this approach step-by-step with an example of &nbsp;<a href=\"https:\/\/polygon.io\/docs\/stocks\/get_vx_reference_financials\">Polygon.io<\/a> REST API, assuming that our application should provide historical <strong>stock<\/strong> <strong>data<\/strong> for a given <strong>stock ticker<\/strong>. We will use API-endpoint, which provides <strong>financial XBRL-data<\/strong> from company <strong>SEC<\/strong> filings including equity, audited financial statements, and other relevant information.&nbsp;&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The first step is obtaining JSON using the following <span class=\"has-inline-color has-pale-cyan-blue-color\">PolygonRestClient<\/span>, parsing it, and converting it to an object that will be used in a function execution context (<span class=\"has-inline-color has-pale-cyan-blue-color\">List&lt;String&gt;<\/span> in our example):<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> List&lt;String&gt; <span class=\"has-inline-color has-luminous-vivid-amber-color\">getFinancials<\/span>(String ticker) <span class=\"has-inline-color has-luminous-vivid-orange-color\">throws<\/span> Exception {\n   RestTemplate restTemplate = <span class=\"has-inline-color has-luminous-vivid-orange-color\">new<\/span> RestTemplate();\n   ResponseEntity&lt;String&gt; response\n           = restTemplate.getForEntity(formUrl(ticker), String.<span class=\"has-inline-color has-luminous-vivid-orange-color\">class<\/span>);\n\n\n   String financialJson = response.getBody();\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.trace(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Json: {}\"<\/span>, financialJson);\n   ObjectMapper mapper = new ObjectMapper();\n   JsonFactory factory = mapper.getFactory();\n   <span class=\"has-inline-color has-cyan-bluish-gray-color\">\/\/ to prevent exception when encountering unknown property:<\/span>\n   mapper.disable(DeserializationFeature.<span class=\"has-inline-color has-vivid-purple-color\">FAIL_ON_UNKNOWN_PROPERTIES<\/span>);\n   <span class=\"has-inline-color has-cyan-bluish-gray-color\">\/\/ to allow coercion of JSON empty String (\"\") to null Object value:<\/span>\n   mapper.enable(DeserializationFeature.<span class=\"has-inline-color has-vivid-purple-color\">ACCEPT_EMPTY_STRING_AS_NULL_OBJECT)<\/span>;\n   JsonParser parser = factory.createParser(financialJson);\n   JsonNode root = mapper.readTree(parser);\n   Map&lt;String, Object&gt; map = mapper.treeToValue(root, Map.<span class=\"has-inline-color has-luminous-vivid-orange-color\">class<\/span>);\n   List&lt;String&gt; resultList = convert(map);\n  <span class=\"has-inline-color has-luminous-vivid-orange-color\"> return<\/span> resultList;\n}\n<\/code><\/pre>\n\n\n\n<p>The next step is a wrapping of low-level <span class=\"has-inline-color has-pale-cyan-blue-color\">PolygonRestClient<\/span> by <span class=\"has-inline-color has-pale-cyan-blue-color\">PolygonService<\/span> implementation like code below:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-orange-color\">public <\/span>List&lt;String&gt; <span class=\"has-inline-color has-luminous-vivid-amber-color\">getFinancials<\/span>(String ticker) {\n   List&lt;String&gt; resultList;\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">try<\/span> {\n       resultList = <span class=\"has-inline-color has-vivid-purple-color\">polygonRestClient<\/span>.getFinancials(ticker);\n       <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> resultList;\n   } <span class=\"has-inline-color has-luminous-vivid-orange-color\">catch<\/span> (Exception e) {\n       <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.error(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"API error\"<\/span>, e);\n   }\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">return null<\/span>;\n}\n<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The last step is an adding <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool <\/span>annotation to&nbsp;<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public class<\/span> ToolProvider {\n\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">private final<\/span> PolygonService <span class=\"has-inline-color has-vivid-purple-color\">polygonService<\/span>;\n\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Provides historical financial data for a stock ticker. The financials data is extracted from XBRL from company SEC filings. Provides the following information: Balance sheet, Income statement, Statement of comprehensive Income, Cash flow statement,  \"<\/span>)\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> List&lt;String&gt; <span class=\"has-inline-color has-luminous-vivid-amber-color\">getFinancial<\/span>(String ticker) {\n       log.info(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Getting financial info for: {}\"<\/span>, ticker);\n       List&lt;String&gt; financialResults = polygonService.getFinancials(ticker);\n       <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> financialResults;\n   }\n\n<\/code><\/pre>\n\n\n\n<p>As a result, the following function definition will be used for answering a user query like <span class=\"has-inline-color has-vivid-green-cyan-color\">\u201c<em>provide financial analysis for a ticker IBM<\/em>\u201d<\/span>:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\n<span class=\"has-inline-color has-vivid-purple-color\">\"tools\"<\/span>: &#91;\n     <span class=\"has-inline-color has-vivid-purple-color\">\"type\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"function\"<\/span>,\n     <span class=\"has-inline-color has-vivid-purple-color\">\"function\"<\/span>: {\n      <span class=\"has-inline-color has-vivid-purple-color\"> \"name\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"getFinancial\"<\/span>,\n       <span class=\"has-inline-color has-vivid-purple-color\">\"description\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"Provides historical financial data for a stock ticker. The financials data is extracted from XBRL from company SEC filings. Provides the following information: Balance sheet, Income statement, Statement of comprehensive Income, Cash flow statement,  \"<\/span>,\n       <span class=\"has-inline-color has-vivid-purple-color\">\"parameters\"<\/span>: {\n         <span class=\"has-inline-color has-vivid-purple-color\">\"type\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"object\"<\/span>,\n        <span class=\"has-inline-color has-vivid-purple-color\"> \"properties\"<\/span>: {\n          <span class=\"has-inline-color has-vivid-purple-color\"> \"ticker\"<\/span>: {\n             <span class=\"has-inline-color has-vivid-purple-color\">\"type\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"string\"<\/span>\n           }\n         },\n         <span class=\"has-inline-color has-vivid-purple-color\">\"required\"<\/span>: &#91;\n           <span class=\"has-inline-color has-vivid-green-cyan-color\">\"ticker\"<\/span>\n         ]\n       }\n     }\n   }\n]<\/code><\/pre>\n\n\n\n<p>In such a case, LLM answer in a log file will be similar for the next one:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"212\" src=\"https:\/\/lh7-us.googleusercontent.com\/eINbC2HV9asioG30O1ydFHgWMVNNLiDqNJV1Bh0IlHj4zjB1-h4LGfoHvCrMCFjtbYfqaMJe8dE2J0Y7wODtobzGUDkEL7PEf8YjJVs55IvvfxmPAjwXo4lSL8rPcTJWs5CR0wXl6CPIJNEWowcfrpw\"><\/p>\n\n\n\n<p>Finally, let\u2019s get back to the aforementioned point about \u201c<strong>Polyglot architecture<\/strong>\u201d. The recent Langchain4j integration with <a href=\"https:\/\/mvnrepository.com\/artifact\/dev.langchain4j\/langchain4j-code-execution-engine-graalvm-polyglot\">Graalvm Polyglot<\/a> supports code execution written in Python and JavaScript code execution. <\/p>\n\n\n\n<p>As a result, we can wrap a <strong>Python<\/strong> code as a <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool<\/span> as follows:&nbsp;&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool<\/span>(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Execute external Python code from file and return result\"<\/span>)\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> String <span class=\"has-inline-color has-luminous-vivid-amber-color\">executeCode<\/span> (String path) {\n    log.info(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Executing Python code from : {}\"<\/span>, path);\n   String result= pythonCodeExecutor.executeCode(path);\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> result;\n}\n<\/code><\/pre>\n\n\n\n<p>A <span class=\"has-inline-color has-pale-cyan-blue-color\">PythonCodeExecutor<\/span> can look like:&nbsp;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-orange-color\">public class<\/span> PythonCodeExecutor <span class=\"has-inline-color has-luminous-vivid-orange-color\">implements<\/span> CodeExecutor{\n\n   <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Override<\/span>\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> String <span class=\"has-inline-color has-luminous-vivid-amber-color\">executeCode<\/span>(String path) {\n       <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\" Loading code from file {}\"<\/span> , path );\n       String pyCode= PythonCodeLoader.fromResourceFile(path);\n       <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">\\n<\/span> <span class=\"has-inline-color has-vivid-green-cyan-color\">Code: {}\"<\/span>, pyCode);\n       CodeExecutionEngine engine = new GraalVmPythonExecutionEngine();\n       String result = engine.execute(pyCode);\n       <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">\\n<\/span> <span class=\"has-inline-color has-vivid-green-cyan-color\">Code execution result : {}\"<\/span>, result);\n       <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> result;\n   }\n  }\n<\/code><\/pre>\n\n\n\n<p>Let\u2019s assume that we have some Python code stored on the external file code\/python\/fibonacci.py:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-orange-color\">def <\/span><span class=\"has-inline-color has-luminous-vivid-amber-color\">fibonacci<\/span>(n):\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">if<\/span> n &lt;= 1:\n       <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> n\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">else<\/span>:\n       <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> fibonacci(n-1) + fibonacci(n-2)\n\n\nfibonacci(10)\n<\/code><\/pre>\n\n\n\n<p>In such a case, a user query like <span class=\"has-inline-color has-cyan-bluish-gray-color\">\u201cexecute a code in code\/python\/fibonacci.py\u201d<\/span>&nbsp; will be answered like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-vivid-purple-color\">\"model\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"gpt-4-1106-preview\"<\/span>,\n<span class=\"has-inline-color has-vivid-purple-color\">\"choices\"<\/span>: &#91;\n  {\n     <span class=\"has-inline-color has-vivid-purple-color\">\"index\"<\/span>: 0,\n     <span class=\"has-inline-color has-vivid-purple-color\">\"message\"<\/span>: {\n        <span class=\"has-inline-color has-vivid-purple-color\">\"role\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"assistant\"<\/span>,\n        <span class=\"has-inline-color has-vivid-purple-color\">\"content\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"The code in the file `code\/python\/fibonacci.py` has been executed successfully, and the result is `55`. This likely means that the code was designed to calculate a specific Fibonacci number, and the result of the calculation is 55.\"<\/span>\n     },\n     <span class=\"has-inline-color has-vivid-purple-color\">\"logprobs\"<\/span>: <span class=\"has-inline-color has-luminous-vivid-orange-color\">null<\/span>,\n     <span class=\"has-inline-color has-vivid-purple-color\">\"finish_reason\"<\/span>: <span class=\"has-inline-color has-vivid-green-cyan-color\">\"stop\"<\/span>\n  }\n],\n<\/code><\/pre>\n\n\n\n<p>Just for fun &#8211; we can also wrap our &nbsp;<span class=\"has-inline-color has-cyan-bluish-gray-color\">ImageModel <\/span>as <span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool <\/span>in the following way:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-luminous-vivid-amber-color\">@Tool<\/span>( <span class=\"has-inline-color has-vivid-green-cyan-color\">\"Draw the picture base on following description\"<\/span>)\n<span class=\"has-inline-color has-luminous-vivid-orange-color\">public<\/span> URI <span class=\"has-inline-color has-luminous-vivid-amber-color\">generateImageUrl<\/span>(String description) {\n  <span class=\"has-inline-color has-vivid-purple-color\"> log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Generating image for : {} \"<\/span>, description);\n   Response&lt;Image&gt; response = <span class=\"has-inline-color has-vivid-purple-color\">model<\/span>.generate(description);\n   URI uri = response.content().url();\n   <span class=\"has-inline-color has-vivid-purple-color\">log<\/span>.debug(<span class=\"has-inline-color has-vivid-green-cyan-color\">\"Generated image  URI : {} \"<\/span>, uri);\n   <span class=\"has-inline-color has-luminous-vivid-orange-color\">return<\/span> uri;\n}\n<\/code><\/pre>\n\n\n\n<p>In such a case, a user query like <span class=\"has-inline-color has-cyan-bluish-gray-color\">\u201c<em>draw a picture about fibonacci<\/em>\u201d<\/span> will be answered like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><span class=\"has-inline-color has-vivid-green-cyan-color\">\"message\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">: <\/span><span class=\"has-inline-color has-black-color\">{<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">\n \"role\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">:<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\"> \"assistant\",\n \"content\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">:<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\"> \"A picture representing the Fibonacci sequence with spirals and numbers has been created. You can view the image by clicking on the link below:<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">\\n\\n<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">!&#91;Fibonacci Sequence Visual Representation](https:\/\/\u2026.blob.core.windows.net\/img-ArKUI0wtgDcTw1zHLi29y3ZK.png\"\n <\/span><span class=\"has-inline-color has-black-color\">}<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">,\n \"logprobs\": <\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">null<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">,\n \"finish_reason\"<\/span><span class=\"has-inline-color has-luminous-vivid-orange-color\">:<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\"> \"stop\"\n<\/span><span class=\"has-inline-color has-black-color\">}<\/span><span class=\"has-inline-color has-vivid-green-cyan-color\">\n<\/span><\/code><\/pre>\n\n\n\n<p>By clicking the provided link within code, you can see a generated picture. Enjoy \ud83d\ude42<\/p>\n\n\n\n<p class=\"has-text-align-center\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh7-us.googleusercontent.com\/tFBWYqGh6XIKbJ14cMZZ8aeCRukve4JtQRkav1yv2svZTF5nadTR_VepQg4qeGJFr_vZHOXuHOlrN5mvd1zU2fv1B0YV0clpK8Yg-yjajGFCn3bunZ93bKYL9Om2u11uWcaoRoCIIjX912M2daeMorw\" width=\"354\" height=\"354\"><\/p>\n\n\n\n<a id=\"text9\"><\/a>\n\n\n\n<h2 class=\"wp-block-heading\">Summing up<\/h2>\n\n\n\n<p>LangChain4j stands out as a still young but promising&nbsp; framework &nbsp;tailored for LLM-driven application development in Java.<\/p>\n\n\n\n<p>It connects various ready-to-use building blocks: LLMs themselves, document loaders, parsers, vector stores, tools, conversational chains, and prompt templates.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/lh7-us.googleusercontent.com\/d4eOKBWiJsIc21oIbPuLfw5ck2DbbJEhd-JAVkFqAg1tDlTTlyoGZNjLY-8ZEVLGHELTNPITvfW8ZhS8Sdp-_A6CAD0USRPvJ8-JuyFuaQsTMYukhI7MOsxm-DtFh20L4vEI8HT9tloSyi4VQwb1S-A\" alt=\"\"\/><\/figure><\/div>\n\n\n<p>Here is what we would like to highlight about Langchain4j framework:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Higher abstraction level compared with LLMs API level<\/li>\n\n\n\n<li>No LM\/LLM vendor\/platform lock-in. As a result, Enabling AIaaS as&nbsp; on-premise LLMs usage<\/li>\n\n\n\n<li>No Vector databases vendor lock-in&nbsp;<\/li>\n\n\n\n<li>Supporting different deployment scenarios&nbsp;<\/li>\n\n\n\n<li>In-built document transformation pipeline that supports the most popular document formats and data storages<\/li>\n\n\n\n<li>Declarative application development approach: interface-based and annotation-based implementation<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-1 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/kindgeek.com\/ai_transformation_services\" style=\"border-radius:26px\" target=\"_blank\" rel=\"noreferrer noopener\">Check out Kindgeek AI Transformation Services<\/a><\/div>\n<\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently updated on February 21, 2025 In this article, we are discussing with Michael Kramarenko, Kindgeek CTO, how to incorporate LM\/LLM-based features&#8230;<\/p>\n","protected":false},"author":10,"featured_media":4502,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[256],"tags":[],"class_list":{"0":"post-4466","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","7":"category-ai"},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.4 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to incorporate LM\/LLM features into Java using Langchain4j<\/title>\n<meta name=\"description\" content=\"In this article, we are discussing with Michael Kramarenko, Kindgeek CTO, how to integrate LM\/LLM-based features into Java using Langchain4j\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to incorporate LM\/LLM features into Java using Langchain4j\" \/>\n<meta property=\"og:description\" content=\"In this article, we are discussing with Michael Kramarenko, Kindgeek CTO, how to integrate LM\/LLM-based features into Java using Langchain4j\" \/>\n<meta property=\"og:url\" content=\"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications\" \/>\n<meta property=\"og:site_name\" content=\"Kindgeek\" \/>\n<meta property=\"article:published_time\" content=\"2024-02-06T17:42:18+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-21T08:11:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ImportedPhoto_1707293058690.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1554\" \/>\n\t<meta property=\"og:image:height\" content=\"816\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Iryna Hvozdyk\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Iryna Hvozdyk\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"19 minutes\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to incorporate LM\/LLM features into Java using Langchain4j","description":"In this article, we are discussing with Michael Kramarenko, Kindgeek CTO, how to integrate LM\/LLM-based features into Java using Langchain4j","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications","og_locale":"en_US","og_type":"article","og_title":"How to incorporate LM\/LLM features into Java using Langchain4j","og_description":"In this article, we are discussing with Michael Kramarenko, Kindgeek CTO, how to integrate LM\/LLM-based features into Java using Langchain4j","og_url":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications","og_site_name":"Kindgeek","article_published_time":"2024-02-06T17:42:18+00:00","article_modified_time":"2025-02-21T08:11:33+00:00","og_image":[{"width":1554,"height":816,"url":"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ImportedPhoto_1707293058690.jpg","type":"image\/jpeg"}],"author":"Iryna Hvozdyk","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Iryna Hvozdyk","Est. reading time":"19 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications#article","isPartOf":{"@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications"},"author":{"name":"Iryna Hvozdyk","@id":"https:\/\/kindgeek.com\/blog\/#\/schema\/person\/0d130691f3d1533fee31614b16f42367"},"headline":"Experiments with Langchain4j or Java way to LLM-powered applications","datePublished":"2024-02-06T17:42:18+00:00","dateModified":"2025-02-21T08:11:33+00:00","mainEntityOfPage":{"@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications"},"wordCount":3239,"commentCount":0,"publisher":{"@id":"https:\/\/kindgeek.com\/blog\/#organization"},"image":{"@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications#primaryimage"},"thumbnailUrl":"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ImportedPhoto_1707293058690.jpg","articleSection":["AI"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications","url":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications","name":"How to incorporate LM\/LLM features into Java using Langchain4j","isPartOf":{"@id":"https:\/\/kindgeek.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications#primaryimage"},"image":{"@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications#primaryimage"},"thumbnailUrl":"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ImportedPhoto_1707293058690.jpg","datePublished":"2024-02-06T17:42:18+00:00","dateModified":"2025-02-21T08:11:33+00:00","description":"In this article, we are discussing with Michael Kramarenko, Kindgeek CTO, how to integrate LM\/LLM-based features into Java using Langchain4j","breadcrumb":{"@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications#primaryimage","url":"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ImportedPhoto_1707293058690.jpg","contentUrl":"https:\/\/www.kindgeek.com\/blog\/wp-content\/uploads\/2024\/02\/ImportedPhoto_1707293058690.jpg","width":1554,"height":816,"caption":"Developing applications powered by LM\/LLM models"},{"@type":"BreadcrumbList","@id":"https:\/\/kindgeek.com\/blog\/post\/experiments-with-langchain4j-or-java-way-to-llm-powered-applications#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/kindgeek.com\/blog"},{"@type":"ListItem","position":2,"name":"Experiments with Langchain4j or Java way to LLM-powered applications"}]},{"@type":"WebSite","@id":"https:\/\/kindgeek.com\/blog\/#website","url":"https:\/\/kindgeek.com\/blog\/","name":"Kindgeek","description":"Blog | Kindgeek","publisher":{"@id":"https:\/\/kindgeek.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/kindgeek.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/kindgeek.com\/blog\/#organization","name":"Kindgeek","url":"https:\/\/kindgeek.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/kindgeek.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2026\/02\/kg-logo-updated.png","contentUrl":"https:\/\/kindgeek.com\/blog\/wp-content\/uploads\/2026\/02\/kg-logo-updated.png","width":300,"height":60,"caption":"Kindgeek"},"image":{"@id":"https:\/\/kindgeek.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/kindgeek.com\/blog\/#\/schema\/person\/0d130691f3d1533fee31614b16f42367","name":"Iryna Hvozdyk","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/kindgeek.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/4f48bb5f5cac28a18a66c604ffa0954a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/4f48bb5f5cac28a18a66c604ffa0954a?s=96&d=mm&r=g","caption":"Iryna Hvozdyk"},"url":"https:\/\/www.kindgeek.com\/blog\/post\/author\/iryna-hvozdykkindgeek-com"}]}},"_links":{"self":[{"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/posts\/4466","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/users\/10"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/comments?post=4466"}],"version-history":[{"count":42,"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/posts\/4466\/revisions"}],"predecessor-version":[{"id":5293,"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/posts\/4466\/revisions\/5293"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/media\/4502"}],"wp:attachment":[{"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/media?parent=4466"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/categories?post=4466"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kindgeek.com\/blog\/wp-json\/wp\/v2\/tags?post=4466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}