Skip to content

Commit

Permalink
Merge pull request #99 from johnoliver/chat-history
Browse files Browse the repository at this point in the history
Update to semantic kernel 1.2.2
  • Loading branch information
dantelmomsft authored Aug 26, 2024
2 parents 4e596c3 + e537ef0 commit d56f1f3
Show file tree
Hide file tree
Showing 14 changed files with 475 additions and 452 deletions.
2 changes: 1 addition & 1 deletion app/backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<spring-cloud-azure.version>5.14.0</spring-cloud-azure.version>
<azure-search.version>11.6.0-beta.8</azure-search.version>
<semantic-kernel.version>1.2.0</semantic-kernel.version>
<semantic-kernel.version>1.2.2</semantic-kernel.version>
<mockito-inline.version>4.5.1</mockito-inline.version>
<maven.compiler-plugin.version>3.11.0</maven.compiler-plugin.version>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,28 @@
package com.microsoft.openai.samples.rag.ask.approaches.semantickernel;

import com.azure.ai.openai.OpenAIAsyncClient;
import com.microsoft.openai.samples.rag.approaches.ContentSource;
import com.microsoft.openai.samples.rag.approaches.RAGApproach;
import com.microsoft.openai.samples.rag.approaches.RAGOptions;
import com.microsoft.openai.samples.rag.approaches.RAGResponse;
import com.microsoft.openai.samples.rag.chat.approaches.semantickernel.JavaSemanticKernelChainsChatApproach;
import com.microsoft.openai.samples.rag.proxy.AzureAISearchProxy;
import com.microsoft.openai.samples.rag.proxy.OpenAIProxy;
import com.microsoft.openai.samples.rag.retrieval.semantickernel.AzureAISearchPlugin;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
import com.microsoft.semantickernel.implementation.EmbeddedResourceLoader;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionYaml;
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* Use Java Semantic Kernel framework with semantic and native functions chaining. It uses an
Expand All @@ -36,12 +34,6 @@
@Component
public class JavaSemanticKernelChainsApproach implements RAGApproach<String, RAGResponse> {

private static final Logger LOGGER =
LoggerFactory.getLogger(JavaSemanticKernelChainsApproach.class);
private static final String PLAN_PROMPT =
"""
Take the input as a question and answer it finding any information needed
""";
private final AzureAISearchProxy azureAISearchProxy;

private final OpenAIProxy openAIProxy;
Expand All @@ -60,20 +52,15 @@ public JavaSemanticKernelChainsApproach(
this.openAIProxy = openAIProxy;
}

/**
* @param question
* @param options
* @return
*/
@Override
public RAGResponse run(String question, RAGOptions options) {

// Build semantic kernel context
Kernel semanticKernel = buildSemanticKernel(options);

// STEP 1: Retrieve relevant documents using user question. It reuses the
// AzureAISearchRetriever appraoch through the AzureAISearchPlugin native function.
FunctionResult<String> searchContext = semanticKernel
// AzureAISearchRetriever approach through the AzureAISearchPlugin native function.
FunctionResult<List> sources = semanticKernel
.getPlugin("InformationFinder")
.get("SearchFromQuestion")
.invokeAsync(semanticKernel)
Expand All @@ -82,20 +69,18 @@ public RAGResponse run(String question, RAGOptions options) {
.withInput(question)
.build()
)
.withResultType(String.class)
.withResultType(List.class)
.block();

var sources = formSourcesList(searchContext.getResult());

// STEP 2: Build a SK context with the sources retrieved from the memory store and the user
// question.
var answerVariables =
KernelFunctionArguments.builder()
.withVariable("sources", searchContext.getResult())
.withVariable("sources", sources.getResult())
.withVariable("input", question)
.build();

/**
/*
* STEP 3: Get a reference of the semantic function [AnswerQuestion] of the [RAG] plugin
* (a.k.a. skill) from the SK skills registry and provide it with the pre-built context.
* Triggering Open AI to get an answerVariables.
Expand All @@ -109,8 +94,8 @@ public RAGResponse run(String question, RAGOptions options) {
return new RAGResponse.Builder()
.prompt("Prompt is managed by Semantic Kernel")
.answer(answerExecutionContext.getResult())
.sources(sources)
.sourcesAsText(searchContext.getResult())
.sources(sources.getResult())
.sourcesAsText(sources.getResult().get(0).toString())
.question(question)
.build();
}
Expand All @@ -121,58 +106,46 @@ public void runStreaming(
throw new IllegalStateException("Streaming not supported for this approach");
}

private List<ContentSource> formSourcesList(String result) {
if (result == null) {
return Collections.emptyList();
}
return Arrays.stream(result.split("\n"))
.map(
source -> {
String[] split = source.split(":", 2);
if (split.length >= 2) {
var sourceName = split[0].trim();
var sourceContent = split[1].trim();
return new ContentSource(sourceName, sourceContent);
} else {
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

/**
* Build semantic kernel context with AnswerQuestion semantic function and
* InformationFinder.SearchFromQuestion native function. AnswerQuestion is imported from
* src/main/resources/semantickernel/Plugins. InformationFinder.SearchFromQuestion is implemented in a
* traditional Java class method: AzureAISearchPlugin.searchFromConversation
*
* @param options
* @return
*/
private Kernel buildSemanticKernel(RAGOptions options) {
return Kernel.builder()
.withAIService(
ChatCompletionService.class,
OpenAIChatCompletion.builder()
.withModelId(gptChatDeploymentModelId)
.withOpenAIAsyncClient(this.openAIAsyncClient)
.build()
)
.withPlugin(
KernelPluginFactory.createFromObject(
new AzureAISearchPlugin(this.azureAISearchProxy, this.openAIProxy, options),
"InformationFinder")
)
.withPlugin(
KernelPluginFactory.importPluginFromResourcesDirectory(
"semantickernel/Plugins",
"RAG",
"AnswerQuestion",
null,
String.class
)
)
.build();
try {
return Kernel.builder()
.withAIService(
ChatCompletionService.class,
OpenAIChatCompletion.builder()
.withModelId(gptChatDeploymentModelId)
.withOpenAIAsyncClient(this.openAIAsyncClient)
.build()
)
.withPlugin(
KernelPluginFactory.createFromObject(
new AzureAISearchPlugin(this.azureAISearchProxy, this.openAIProxy, options),
"InformationFinder")
)
.withPlugin(
KernelPluginFactory.createFromFunctions(
"RAG",
"AnswerQuestion",
List.of(
KernelFunctionYaml.fromPromptYaml(
EmbeddedResourceLoader.readFile(
"semantickernel/Plugins/RAG/AnswerQuestion/answerQuestion.prompt.yaml",
JavaSemanticKernelChainsChatApproach.class,
EmbeddedResourceLoader.ResourceLocation.CLASSPATH_ROOT
),
new HandlebarsPromptTemplateFactory())
)
)
)
.build();
} catch (IOException e) {
// Failed to read plugin yaml, should not happen
throw new RuntimeException(e);
}
}
}
Loading

0 comments on commit d56f1f3

Please sign in to comment.