{"id":1004,"date":"2023-08-10T07:29:41","date_gmt":"2023-08-10T14:29:41","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/semantic-kernel\/?p=1004"},"modified":"2023-08-10T07:29:41","modified_gmt":"2023-08-10T14:29:41","slug":"ai-tooling-for-java-developers-with-sk","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/agent-framework\/ai-tooling-for-java-developers-with-sk\/","title":{"rendered":"AI tooling for Java developers with SK"},"content":{"rendered":"<p>Every system needs to be able to add AI to its workflow to empower the users to complete their task much faster.\u00a0 The Semantic Kernel team and community have been working hard to create a Java based kernel to support Java developers to unleash AI into their apps.\u00a0 I will walk you through this journey below.<\/p>\n<p>We will review the following concepts with examples:<\/p>\n<ol>\n<li>Kernel and use of Inline Function.<\/li>\n<li>Plugins and Functions loaded from directory.<\/li>\n<li>Plugins and Functions as pipeline.<\/li>\n<li>Giving memory to LLM, using local volatile memory and Azure Cognitive Search.<\/li>\n<\/ol>\n<p>All the examples are on GitHub: <a href=\"https:\/\/github.com\/sohamda\/SemanticKernel-Basics\">https:\/\/github.com\/sohamda\/SemanticKernel-Basics<\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>Step #1: Create a Kernel<\/h2>\n<p>The <a href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/create-chains\/kernel\">kernel<\/a>\u00a0orchestrates a user&#8217;s ask. To do so, the kernel runs a\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/semantic-kernel\/create-chains\/\">pipeline \/ chain<\/a> that is defined by a developer. While the chain is run, a common context is provided by the kernel so data can be shared between functions.<\/p>\n<p>First create a Kernel object:<\/p>\n<pre>client.azureopenai.key=XXYY1232\r\nclient.azureopenai.endpoint=https:\/\/abc.openai.azure.com\/\r\nclient.azureopenai.deploymentname=XXYYZZ<\/pre>\n<p>You can get these details from the Azure portal (endpoint and key) and Azure OpenAI (AOAI) studio (deployment name).<\/p>\n<p>This article uses deployment \u201cgpt-35-turbo\u201d language model.<\/p>\n<p>How to create such resource in Azure, follow this &gt; <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/ai-services\/openai\/how-to\/create-resource?pivots=web-portal\">How-to &#8211; Create a resource and deploy a model using Azure OpenAI Service &#8211; Azure OpenAI | Microsoft Learn<\/a><\/p>\n<p>Then add:<\/p>\n<pre>AzureOpenAISettings settings = new AzureOpenAISettings(SettingsMap.\r\n<em>getWithAdditional<\/em>(List.<em>of<\/em>(\r\nnew File(\"src\/main\/resources\/conf.properties\"))));\r\n\r\nOpenAIAsyncClient client = new OpenAIClientBuilder().endpoint(settings.getEndpoint()).credential(new AzureKeyCredential(settings.getKey())).buildAsyncClient();\r\nTextCompletion textCompletion = SKBuilders.<em>chatCompletion<\/em>().build(client, <em>settings<\/em>().getDeploymentName());\r\nKernelConfig config = SKBuilders.<em>kernelConfig<\/em>().addTextCompletionService(\"text-completion\", kernel -&gt; textCompletion).build();\r\nKernel kernel = SKBuilders.<em>kernel<\/em>().withKernelConfig(config).build();<\/pre>\n<p>&nbsp;<\/p>\n<h2>Step #2: Add a Function<\/h2>\n<p>Function? Yes \ud83d\ude0a<\/p>\n<p>Think of this as a prompt you provide to ChatGPT to direct it to do something. The below example, shows, how you create a \u201creusable\u201d prompt, aka function, to instruct the LLM to summarize a given input.<\/p>\n<pre>String semanticFunctionInline = \"\"\"\r\n{{$input}}\r\n\r\nSummarize the content above in less than 140 characters.\r\n\"\"\";<\/pre>\n<p>&nbsp;<\/p>\n<h2>Step#3: Instruct LLM to use this Function + Additional Settings<\/h2>\n<p>Now before you invoke AOAI API, you need to add this prompt\/function to the call and some additional settings, such as maxTokens, temperature, top etc.<\/p>\n<p><strong>FYI<\/strong>: LLMs are non-deterministic, meaning, the output for the same input might be different every time you invoke them. The \u201ctemperature\u201d parameter controls that, so higher temperature is higher level of non-deterministic behavior and lower temperature is lower that behavior.<\/p>\n<pre>CompletionSKFunction summarizeFunction = SKBuilders\r\n.<em>completionFunctions<\/em>(kernel)\r\n.createFunction(\r\nsemanticFunctionInline,\r\nnew PromptTemplateConfig.CompletionConfigBuilder()\r\n.maxTokens(100)\r\n.temperature(0.4)\r\n.topP(1)\r\n.build());\r\n\r\n<em>log<\/em>.debug(\"== Run the Kernel ==\");\r\nMono&lt;SKContext&gt; result = summarizeFunction.invokeAsync(<em>TextToSummarize<\/em>);\r\n\r\n<em>log<\/em>.debug(\"== Result ==\");\r\n<em>log<\/em>.debug(result.block().getResult());<\/pre>\n<p>\u201cTextToSummarize\u201d is the user input, a String which we want to summarize using the \u201csemanticFunctionInline\u201d function and LLM.<\/p>\n<p>Here is an example &#8211;&gt; <a href=\"https:\/\/github.com\/sohamda\/SemanticKernel-Basics\/blob\/main\/src\/main\/java\/soham\/sksamples\/Example01_InlineFunction.java\">InlineFunction.java<\/a><\/p>\n<p><span style=\"text-decoration: underline;\"><strong>CONGRATULATIONS<\/strong><\/span>!! \ud83d\ude0a You created your first <strong>JAVA<\/strong> program to interact with LLM using Semantic Kernel.<\/p>\n<p>&nbsp;<\/p>\n<h2>Step #4: Plugins and Functions<\/h2>\n<p>Functions are reusable prompts with AOAI API settings which can be used when invoking LLMs. A collection of functions is called a Plugin.<\/p>\n<p>A Function is represented by a \u201cskprompt.txt\u201d and optionally a \u201cconfig.json\u201d.<\/p>\n<p>Functions and Plugins are organized in a directory structure and ideally placed in the classpath. In this article examples, the Plugins and Function are placed inside \u201c\/resources\u201d folder, but you can think of separating them into their own repo and releasing them into JARs and using them into your application code as a dependency, making them easy to use and also make them part of the DevOps workflow and reusable by multiple applications.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Folder_Structure_Pic.png\"><img decoding=\"async\" class=\"alignleft size-full wp-image-1017\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Folder_Structure_Pic.png\" alt=\"Image Java Folder Structure Pic\" width=\"511\" height=\"484\" srcset=\"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Folder_Structure_Pic.png 511w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Folder_Structure_Pic-300x284.png 300w, https:\/\/devblogs.microsoft.com\/agent-framework\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Folder_Structure_Pic-24x24.png 24w\" sizes=\"(max-width: 511px) 100vw, 511px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Considering SummarizeSkill in resources folder, with multiple functions in it:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Folder_Structure_Pic_2.png\"><img decoding=\"async\" class=\"alignleft wp-image-1018\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Folder_Structure_Pic_2.png\" alt=\"Image Java Folder Structure Pic 2\" width=\"376\" height=\"304\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>To use, Summarize function from above with Semantic Kernel.<\/p>\n<pre>ReadOnlyFunctionCollection skill = kernel.importSkillFromDirectory(\"SummarizeSkill\", \"src\/main\/resources\/Skills\", \"SummarizeSkill\");\r\n\r\nCompletionSKFunction summarizeFunction = skill.getFunction(\"Summarize\", CompletionSKFunction.class);\r\n\r\n<em>log<\/em>.debug(\"== Set Summarize Skill ==\");\r\nSKContext summarizeContext = SKBuilders.<em>context<\/em>().build();\r\nsummarizeContext.setVariable(\"input\", <em>TextToSummarize<\/em>);\r\n\r\n<em>log<\/em>.debug(\"== Run the Kernel ==\");\r\nMono&lt;SKContext&gt; result = summarizeFunction.invokeAsync(summarizeContext);<\/pre>\n<p>The code above does the following:<\/p>\n<ol>\n<li>Loads a Plugins (Summarize) from a directory in classpath.<\/li>\n<li>Define the function (Summarize) which needs to be used.<\/li>\n<li>Add the input to the function and set it in the context<\/li>\n<li>Invoke AOAI API with the function.<\/li>\n<\/ol>\n<p>Here is a starter example &#8211;&gt; <a href=\"https:\/\/github.com\/sohamda\/SemanticKernel-Basics\/blob\/main\/src\/main\/java\/soham\/sksamples\/Example02_SummarizerAsPrompt.java\">SummarizerAsPrompt.java<\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>Step #5: Plugin&amp; Function as code<\/h2>\n<p>Well, we all love the fact that we can represent Plugins and functions as a Java class. Then we can instantiate and use it in OOB way and reduce String manipulation while using them.<\/p>\n<p>Say No More \ud83d\ude0a<\/p>\n<p>Still not in main branch, but this submodule defines a few you can use &#8211;&gt; <a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/tree\/experimental-java\/java\/plugins\/semantickernel-plugin-core\">semantickernel-plugin-core<\/a><\/p>\n<p>You can also implement your own, using annotations @DefineSKFunction, @SKFunctionInputAttribute, @SKFunctionParameters<\/p>\n<p>In the below example, we use an existing Plugin, Summarize and its function Summarize, so basically the same example as in Step #4 but this time with object references.<\/p>\n<pre>import com.microsoft.semantickernel.coreskills.ConversationSummarySkill;\r\n\r\n\r\n<em>log<\/em>.debug(\"== Load Conversation Summarizer Skill from plugins ==\");\r\nReadOnlyFunctionCollection conversationSummarySkill =\r\nkernel.importSkill(new ConversationSummarySkill(kernel), null);\r\n\r\n<em>log<\/em>.debug(\"== Run the Kernel ==\");\r\nMono&lt;SKContext&gt; summary = conversationSummarySkill\r\n.getFunction(\"SummarizeConversation\", SKFunction.class)\r\n.invokeAsync(<em>ChatTranscript<\/em>);<\/pre>\n<p>The above code does the following:<\/p>\n<ol>\n<li>Instantiate ConversationSummarySkill object.<\/li>\n<li>Define the function (SummarizeConversation) which needs to be used.<\/li>\n<li>Add the input to the function and set it in the context<\/li>\n<li>Invoke AOAI API with the function.<\/li>\n<\/ol>\n<p>You can also use Plugins and Function for all sorts of tasks within an AI pipeline. Think of transformation, translation, executing business logic and others. So don\u2019t see Plugins and functions as only to invoke LLM, but also do some other tasks which are needed for next step in the pipeline or transformation of output from previous step.<\/p>\n<p>Example code samples\u00a0 &#8211;&gt; <a href=\"https:\/\/github.com\/sohamda\/SemanticKernel-Basics\/blob\/main\/src\/main\/java\/soham\/sksamples\/Example03_SummarizerAsPlugin.java\">SummarizerAsPlugin.java<\/a> and <a href=\"https:\/\/github.com\/sohamda\/SemanticKernel-Basics\/blob\/main\/src\/main\/java\/soham\/sksamples\/Example04_SkillsPipeline.java\">SkillPipeline.java<\/a><\/p>\n<p>&nbsp;<\/p>\n<h2>Step #6: Giving LLM some memory<\/h2>\n<p>What\u2019s memory? Think of giving LLM information to support it when executing a (or a set) of Plugins. For example, you want to get a summary of your dental insurance details from a 100-page insurance document, here you might choose to send the whole document along with your query to the LLM, but every model in LLM has a limit on tokens what it can process with per request. To manage that token limitation, it is helpful if you can search the document first, get the relevant pages or texts out of it and then query the LLM with those selected pages\/texts. That way LLM can efficiently summarize the content and not run out of tokens per request. The \u201dselected pages\/texts\u201d in this example are Memories.<\/p>\n<p>For this example, we will be using 2 Kernels, one with AI Services type Embedding and another one with TextCompletion.<\/p>\n<p>In Azure AI Studio, you will also need 2 deployments.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Step6_1.png\"><img decoding=\"async\" class=\" wp-image-1016 alignleft\" src=\"https:\/\/devblogs.microsoft.com\/semantic-kernel\/wp-content\/uploads\/sites\/78\/2023\/08\/Java_Step6_1.png\" alt=\"Image Java Step6 1\" width=\"429\" height=\"266\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Kernel with Embedding is instantiated as follows:<\/p>\n<pre>OpenAIAsyncClient openAIAsyncClient = <em>openAIAsyncClient<\/em>();\r\n\r\nEmbeddingGeneration&lt;String&gt; textEmbeddingGenerationService =\r\nSKBuilders.<em>textEmbeddingGenerationService<\/em>()\r\n.build(openAIAsyncClient, \"embedding\");\r\n\r\nKernel kernel = SKBuilders.<em>kernel<\/em>()\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0.withDefaultAIService(textEmbeddingGenerationService)\r\n.withMemoryStorage(SKBuilders.<em>memoryStore<\/em>().build())\r\n.build();<\/pre>\n<p>The above example uses a volatile memory, a local simulation of a vector DB.<\/p>\n<p>Another way is to use Azure Cognitive Search, then the kernel would be instantiated as follows:<\/p>\n<pre>Kernel kernel = SKBuilders.<em>kernel<\/em>()\r\n.withDefaultAIService(textEmbeddingGenerationService)\r\n.withMemory(new AzureCognitiveSearchMemory(\"&lt;ACS_ENDPOINT&gt;\", \"&lt;ACS_KEY&gt;\"))\r\n.build();<\/pre>\n<p>&nbsp;<\/p>\n<p>After you store your data in the memory, you can search on it, which gives you back the relevant sections of the memory.<\/p>\n<pre>kernel.getMemory()\r\n.searchAsync(\u201c&lt;COLLECTION_NAME&gt;\u201d,\r\n\u201c&lt;QUERY&gt;\u201d, 2, 0.7, true);<\/pre>\n<p>&nbsp;<\/p>\n<p>Then use this search results, extract the memory as text and then run, for example, a Summarizer Plugin using another Kernel object which uses TextCompletion as AI Service.<\/p>\n<pre>List&lt;MemoryQueryResult&gt; relevantMems = relevantMemory.block();\r\n\r\nStringBuilder memory = new StringBuilder();\r\nrelevantMems.forEach(relevantMem -&gt; memory.append(\"URL: \").append(relevantMem.getMetadata().getId())\r\n.append(\"Title: \").append(relevantMem.getMetadata().getDescription()));\r\n\r\nKernel kernel = <em>kernel<\/em>();\r\nReadOnlyFunctionCollection conversationSummarySkill =\r\nkernel.importSkill(new ConversationSummarySkill(kernel), null);\r\n\r\nMono&lt;SKContext&gt; summary = conversationSummarySkill\r\n.getFunction(\"SummarizeConversation\", SKFunction.class)\r\n.invokeAsync(relevantMemory);\r\n\r\n<em>log<\/em>.debug(summary.block().getResult());<\/pre>\n<p>&nbsp;<\/p>\n<p>The results will be a summary of the query you initially executed on the Embedding kernel.<\/p>\n<p>Example Code &#8211;&gt; <a href=\"https:\/\/github.com\/sohamda\/SemanticKernel-Basics\/blob\/main\/src\/main\/java\/soham\/sksamples\/Example05_SKwithMemory.java\">SKWithMemory.java<\/a> and <a href=\"https:\/\/github.com\/sohamda\/SemanticKernel-Basics\/blob\/main\/src\/main\/java\/soham\/sksamples\/Example06_SKwithCognitiveSearch.java\">SKWithCognitiveSearch.java<\/a><\/p>\n<p>&nbsp;<\/p>\n<h3>Next Steps<\/h3>\n<p>Get involved with the Java Kernel development by <a href=\"https:\/\/github.com\/microsoft\/semantic-kernel\/blob\/main\/CONTRIBUTING.md\">contributing<\/a> and following the public <a href=\"https:\/\/github.com\/orgs\/microsoft\/projects\/868\">Java board<\/a> to see what you might want to pick up.<\/p>\n<p>Join the Semantic Kernel <a href=\"https:\/\/aka.ms\/sk-community\" target=\"_blank\" rel=\"noopener\">community<\/a>\u00a0and let us know what you think.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Every system needs to be able to add AI to its workflow to empower the users to complete their task much faster.\u00a0 The Semantic Kernel team and community have been working hard to create a Java based kernel to support Java developers to unleash AI into their apps.\u00a0 I will walk you through this journey [&hellip;]<\/p>\n","protected":false},"author":125575,"featured_media":1026,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[24,1,19],"tags":[],"class_list":["post-1004","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","category-semantic-kernel","category-vector-database"],"acf":[],"blog_post_summary":"<p>Every system needs to be able to add AI to its workflow to empower the users to complete their task much faster.\u00a0 The Semantic Kernel team and community have been working hard to create a Java based kernel to support Java developers to unleash AI into their apps.\u00a0 I will walk you through this journey [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/1004","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/users\/125575"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/comments?post=1004"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/posts\/1004\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media\/1026"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/media?parent=1004"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/categories?post=1004"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/agent-framework\/wp-json\/wp\/v2\/tags?post=1004"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}