mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
Java: Update to Service registry pattern (#1923)
Resolves #1628 Also setKernelConfig -> withKernelConfig, to be in keeping with other builder functions
This commit is contained in:
@@ -107,7 +107,7 @@ public class InlineFunctionExample {
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
CompletionSKFunction summarize =
|
||||
kernel.getSemanticFunctionBuilder()
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public class InlineFunctionWithPreBuiltSkillExample {
|
||||
.addTextCompletionService(MODEL, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
CompletionSKFunction summarize =
|
||||
SKBuilders.completionFunctions(kernel)
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ public class AbstractKernelTest {
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel()
|
||||
.setKernelConfig(kernelConfig)
|
||||
.withKernelConfig(kernelConfig)
|
||||
.withMemoryStore(new VolatileMemoryStore())
|
||||
.build();
|
||||
}
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ public class KernelTest extends AbstractKernelTest {
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
return SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ public class Example00_GettingStarted {
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(config)
|
||||
.withKernelConfig(config)
|
||||
.build();
|
||||
|
||||
return kernel;
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ public class Example06_MemoryAndEmbeddings {
|
||||
// TODO: Add Volatile memory
|
||||
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(config)
|
||||
.withKernelConfig(config)
|
||||
.build();
|
||||
|
||||
return kernel;
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import reactor.core.publisher.Mono;
|
||||
public class Example02_Pipeline {
|
||||
public static void main(String[] args) {
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig().build();
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection text = kernel.importSkill(new TextSkill(), null);
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public class Example03_Variables {
|
||||
|
||||
public static void main(String[] args) {
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig().build();
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
// Load native skill
|
||||
ReadOnlyFunctionCollection functionCollection =
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ public class Example04_CombineLLMPromptsAndNativeCode {
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
kernel.importSkill(new SearchEngineSkill(), null);
|
||||
kernel.importSkillFromDirectory("SummarizeSkill", "./samples/skills", "SummarizeSkill");
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class Example05_InlineFunctionDefinition {
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
System.out.println("======== Inline Function Definition ========");
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ public class Example06_TemplateLanguage {
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(kernelConfig)
|
||||
.withKernelConfig(kernelConfig)
|
||||
.build();
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions
|
||||
|
||||
+1
-2
@@ -77,7 +77,7 @@ public class Example08_RetryHandler {
|
||||
|
||||
Kernel kernel = SKBuilders
|
||||
.kernel()
|
||||
.setKernelConfig(kernelConfig)
|
||||
.withKernelConfig(kernelConfig)
|
||||
.build();
|
||||
|
||||
CompletionSKFunction summarizeFunc = SKBuilders.completionFunctions(kernel)
|
||||
@@ -89,7 +89,6 @@ public class Example08_RetryHandler {
|
||||
new PromptTemplateConfig.CompletionConfig(
|
||||
0.2, 0.5, 0, 0, 2000));
|
||||
|
||||
|
||||
kernel.registerSemanticFunction(summarizeFunc);
|
||||
|
||||
SKContext context = summarizeFunc.invokeAsync(text).block();
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public class Example09_FunctionTypes {
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
System.out.println("======== Native function types ========");
|
||||
|
||||
|
||||
+1
-1
@@ -175,7 +175,7 @@ public class Example12_SequentialPlanner {
|
||||
private static Kernel initializeKernel() throws IOException {
|
||||
OpenAIAsyncClient client = Config.getClient();
|
||||
var kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(SKBuilders
|
||||
.withKernelConfig(SKBuilders
|
||||
.kernelConfig()
|
||||
.addTextCompletionService("text-davinci-003", kernel1 -> SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-003"))
|
||||
|
||||
+3
-2
@@ -186,9 +186,10 @@ public class Example13_ConversationSummarySkill {
|
||||
|
||||
KernelConfig kernelConfig =
|
||||
new KernelConfig.Builder()
|
||||
.addTextCompletionService("text-davinci-003", kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
return SKBuilders.kernel()
|
||||
.withKernelConfig(kernelConfig)
|
||||
.withAIService("text-davinci-003", textCompletion, true, TextCompletion.class).build();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -5,7 +5,6 @@ import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.connectors.memory.azurecognitivesearch.AzureCognitiveSearchMemory;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -42,7 +41,7 @@ public class Example14_SemanticMemory
|
||||
var kernelConfig = SKBuilders.kernelConfig().build();
|
||||
|
||||
var kernelWithACS = SKBuilders.kernel()
|
||||
.setKernelConfig(kernelConfig)
|
||||
.withKernelConfig(kernelConfig)
|
||||
.withMemory(new AzureCognitiveSearchMemory(System.getenv("ACS_ENDPOINT"), System.getenv("ACS_API_KEY")))
|
||||
.build();
|
||||
|
||||
@@ -69,7 +68,7 @@ public class Example14_SemanticMemory
|
||||
.build();
|
||||
|
||||
var kernelWithCustomDb = SKBuilders.kernel()
|
||||
.setKernelConfig(kernelConfigWithTextEmbedding)
|
||||
.withKernelConfig(kernelConfigWithTextEmbedding)
|
||||
.withMemoryStore(SKBuilders.memoryStore().build())
|
||||
.build();
|
||||
|
||||
|
||||
+8
-6
@@ -4,7 +4,6 @@ package com.microsoft.semantickernel.syntaxexamples;
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.Config;
|
||||
import com.microsoft.semantickernel.Kernel;
|
||||
import com.microsoft.semantickernel.KernelConfig;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.chatcompletion.ChatCompletion;
|
||||
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
|
||||
@@ -21,14 +20,17 @@ public class Example17_ChatGPT {
|
||||
public static void main(String[] args) throws IOException {
|
||||
OpenAIAsyncClient client = Config.ClientType.AZURE_OPEN_AI.getClient();
|
||||
|
||||
KernelConfig kernelConfig = SKBuilders.kernelConfig()
|
||||
.addChatCompletionService(
|
||||
Kernel kernel = SKBuilders.kernel()
|
||||
.withKernelConfig(SKBuilders.kernelConfig()
|
||||
.build())
|
||||
.withAIService(
|
||||
"chat-test",
|
||||
kernel -> SKBuilders.chatCompletion().build(client, "chat-test"))
|
||||
SKBuilders.chatCompletion().build(client, "chat-test"),
|
||||
true,
|
||||
ChatCompletion.class
|
||||
)
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
|
||||
ChatCompletion<OpenAIChatHistory> chatGPT = kernel.getService(null, ChatCompletion.class);
|
||||
|
||||
OpenAIChatHistory chatHistory = chatGPT.createNewChat("You are a librarian, expert about books");
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ public class Example28_ActionPlanner {
|
||||
System.out.println("======== Action Planner ========");
|
||||
|
||||
var kernel = SKBuilders.kernel()
|
||||
.setKernelConfig(SKBuilders
|
||||
.withKernelConfig(SKBuilders
|
||||
.kernelConfig()
|
||||
.addTextCompletionService("text-davinci-002", kernel1 -> SKBuilders.textCompletionService()
|
||||
.build(client, "text-davinci-002"))
|
||||
|
||||
@@ -7,11 +7,17 @@ import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.orchestration.ContextVariables;
|
||||
import com.microsoft.semantickernel.orchestration.SKContext;
|
||||
import com.microsoft.semantickernel.orchestration.SKFunction;
|
||||
import com.microsoft.semantickernel.services.AIService;
|
||||
import com.microsoft.semantickernel.services.AIServiceCollection;
|
||||
import com.microsoft.semantickernel.services.AIServiceProvider;
|
||||
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Interface for the semantic kernel. */
|
||||
@@ -66,7 +72,8 @@ public interface Kernel extends SkillExecutor {
|
||||
CompletionSKFunction.Builder getSemanticFunctionBuilder();
|
||||
|
||||
/** Obtains the service with the given name and type */
|
||||
<T> T getService(@Nullable String name, Class<T> clazz) throws KernelException;
|
||||
<T extends AIService> T getService(@Nullable String name, Class<T> clazz)
|
||||
throws KernelException;
|
||||
|
||||
/** Registers a semantic functon on this kernel */
|
||||
<RequestConfiguration, FunctionType extends SKFunction<RequestConfiguration>>
|
||||
@@ -80,14 +87,15 @@ public interface Kernel extends SkillExecutor {
|
||||
@Nullable private KernelConfig kernelConfig = null;
|
||||
@Nullable private PromptTemplateEngine promptTemplateEngine = null;
|
||||
@Nullable private MemoryStore memoryStore = null;
|
||||
@Nullable private AIServiceCollection aiServices = new AIServiceCollection();
|
||||
@Nullable private SemanticTextMemory memory = null;
|
||||
|
||||
public Builder setKernelConfig(KernelConfig kernelConfig) {
|
||||
public Builder withKernelConfig(KernelConfig kernelConfig) {
|
||||
this.kernelConfig = kernelConfig;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPromptTemplateEngine(PromptTemplateEngine promptTemplateEngine) {
|
||||
public Builder withPromptTemplateEngine(PromptTemplateEngine promptTemplateEngine) {
|
||||
this.promptTemplateEngine = promptTemplateEngine;
|
||||
return this;
|
||||
}
|
||||
@@ -97,6 +105,65 @@ public interface Kernel extends SkillExecutor {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an instance to the services collection
|
||||
*
|
||||
* @param instance The instance.
|
||||
* @param clazz The class of the instance.
|
||||
* @return The builder.
|
||||
*/
|
||||
public <T extends AIService> Builder withDefaultAIService(T instance, Class<T> clazz) {
|
||||
this.aiServices.setService(instance, clazz);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an instance to the services collection
|
||||
*
|
||||
* @param serviceId The service ID
|
||||
* @param instance The instance.
|
||||
* @param setAsDefault Optional: set as the default AI service for type T
|
||||
* @param clazz The class of the instance.
|
||||
*/
|
||||
public <T extends AIService> Builder withAIService(
|
||||
@Nullable String serviceId, T instance, boolean setAsDefault, Class<T> clazz) {
|
||||
this.aiServices.setService(serviceId, instance, setAsDefault, clazz);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a factory method to the services collection
|
||||
*
|
||||
* @param factory The factory method that creates the AI service instances of type T.
|
||||
* @param clazz The class of the instance.
|
||||
*/
|
||||
public <T extends AIService> Builder withDefaultAIService(
|
||||
Supplier<T> factory, Class<T> clazz) {
|
||||
this.aiServices.setService(factory, clazz);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a factory method to the services collection
|
||||
*
|
||||
* @param serviceId The service ID
|
||||
* @param factory The factory method that creates the AI service instances of type T.
|
||||
* @param setAsDefault Optional: set as the default AI service for type T
|
||||
* @param clazz The class of the instance.
|
||||
*/
|
||||
public <T extends AIService> Builder withAIService(
|
||||
@Nullable String serviceId,
|
||||
Function<KernelConfig, T> factory,
|
||||
boolean setAsDefault,
|
||||
Class<T> clazz) {
|
||||
this.aiServices.setService(
|
||||
serviceId,
|
||||
(Supplier<T>) () -> factory.apply(this.kernelConfig),
|
||||
setAsDefault,
|
||||
clazz);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withMemory(SemanticTextMemory memory) {
|
||||
this.memory = memory;
|
||||
return this;
|
||||
@@ -109,7 +176,12 @@ public interface Kernel extends SkillExecutor {
|
||||
|
||||
return BuildersSingleton.INST
|
||||
.getKernelBuilder()
|
||||
.build(kernelConfig, promptTemplateEngine, memory, memoryStore);
|
||||
.build(
|
||||
kernelConfig,
|
||||
promptTemplateEngine,
|
||||
memory,
|
||||
memoryStore,
|
||||
aiServices.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +190,7 @@ public interface Kernel extends SkillExecutor {
|
||||
KernelConfig kernelConfig,
|
||||
@Nullable PromptTemplateEngine promptTemplateEngine,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable MemoryStore memoryStore);
|
||||
@Nullable MemoryStore memoryStore,
|
||||
@Nullable AIServiceProvider aiServiceProvider);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -2,13 +2,14 @@
|
||||
package com.microsoft.semantickernel.ai.embeddings;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.services.AIService;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for text embedding generation services */
|
||||
public interface EmbeddingGeneration<TValue, TEmbedding extends Number> {
|
||||
public interface EmbeddingGeneration<TValue, TEmbedding extends Number> extends AIService {
|
||||
/**
|
||||
* Generates a list of embeddings associated to the data
|
||||
*
|
||||
|
||||
+2
-1
@@ -2,12 +2,13 @@
|
||||
package com.microsoft.semantickernel.chatcompletion;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.services.AIService;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface ChatCompletion<ChatHistoryType extends ChatHistory> {
|
||||
public interface ChatCompletion<ChatHistoryType extends ChatHistory> extends AIService {
|
||||
/**
|
||||
* Generate a new chat message
|
||||
*
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.services;
|
||||
|
||||
/** Marker interface for AI services */
|
||||
public interface AIService {}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.services;
|
||||
|
||||
import com.microsoft.semantickernel.Verify;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** A collection that can hold AI services */
|
||||
public class AIServiceCollection {
|
||||
// A constant key for the default service
|
||||
private static final String DefaultKey = "__DEFAULT__";
|
||||
|
||||
// A dictionary that maps a service type to a nested dictionary of names and service instances
|
||||
// or factories
|
||||
// private readonly Dictionary<Type, Dictionary<string, object>> _services = new();
|
||||
private final Map<Class<? extends AIService>, Map<String, Supplier<? extends AIService>>>
|
||||
services = new HashMap<>();
|
||||
|
||||
// A dictionary that maps a service type to the name of the default service
|
||||
private final Map<Class<? extends AIService>, String> defaultIds = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Registers a singleton service instance with the default name.
|
||||
*
|
||||
* @param service The service instance.
|
||||
* @param serviceType The type of the service.
|
||||
*/
|
||||
public <T extends AIService> void setService(T service, Class<T> serviceType) {
|
||||
setService(DefaultKey, (Supplier<T>) () -> service, true, serviceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a singleton service instance with an optional name and default flag.
|
||||
*
|
||||
* @param name The name of the service, or null for the default service.
|
||||
* @param service The service instance.
|
||||
* @param setAsDefault Whether the service should be the default for its type.
|
||||
* @param serviceType The type of the service.
|
||||
*/
|
||||
public <T extends AIService> void setService(
|
||||
String name, T service, boolean setAsDefault, Class<T> serviceType) {
|
||||
setService(name, (Supplier<T>) () -> service, setAsDefault, serviceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a transient service factory with the default name.
|
||||
*
|
||||
* @param factory The factory function to create the service instance.
|
||||
* @param serviceType The type of the service.
|
||||
*/
|
||||
public <T extends AIService> void setService(Supplier<T> factory, Class<T> serviceType) {
|
||||
setService(DefaultKey, factory, true, serviceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a transient service factory with an optional name and default flag.
|
||||
*
|
||||
* @param name The name of the service, or null for the default service.
|
||||
* @param factory The factory function to create the service instance.
|
||||
* @param setAsDefault Whether the service should be the default for its type.
|
||||
* @param serviceType The type of the service.
|
||||
*/
|
||||
public <T extends AIService> void setService(
|
||||
@Nullable String name,
|
||||
Supplier<T> factory,
|
||||
boolean setAsDefault,
|
||||
Class<T> serviceType) {
|
||||
// Validate the factory function
|
||||
if (factory == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Get or create the nested dictionary for the service type
|
||||
Map<String, Supplier<? extends AIService>> namedServices = this.services.get(serviceType);
|
||||
if (namedServices == null) {
|
||||
namedServices = new HashMap<>();
|
||||
services.put(serviceType, namedServices);
|
||||
}
|
||||
|
||||
// Set as the default if the name is empty, or the default flag is true,
|
||||
// or there is no default name for the service type.
|
||||
if (name == null || setAsDefault || !this.hasDefault(serviceType)) {
|
||||
// Update the default name for the service type
|
||||
this.defaultIds.put(serviceType, name == null ? DefaultKey : name);
|
||||
}
|
||||
|
||||
// Register the factory with the given name
|
||||
namedServices.put(name == null ? DefaultKey : name, factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an AIServiceProvider from the registered services and default names.
|
||||
*
|
||||
* @return The AIServiceProvider.
|
||||
*/
|
||||
public AIServiceProvider build() {
|
||||
// Create a clone of the services and defaults Dictionaries to prevent further changes
|
||||
// by the services provider.
|
||||
Map<Class<? extends AIService>, Map<String, Supplier<? extends AIService>>> servicesClone =
|
||||
cloneServices(services);
|
||||
|
||||
Map defaultsClone = new HashMap<>(defaultIds);
|
||||
|
||||
return new DefaultAIServiceProvider(servicesClone, defaultsClone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a clone of the services as a Map.
|
||||
*
|
||||
* @param services The services Map.
|
||||
* @return The clone.
|
||||
*/
|
||||
static <T> Map<Class<? extends T>, Map<String, Supplier<? extends T>>> cloneServices(
|
||||
Map<Class<? extends T>, Map<String, Supplier<? extends T>>> services) {
|
||||
return Collections.unmodifiableMap(
|
||||
services.entrySet().stream()
|
||||
.reduce(
|
||||
new HashMap<>(),
|
||||
(a, b) -> {
|
||||
a.put(b.getKey(), Collections.unmodifiableMap(b.getValue()));
|
||||
return a;
|
||||
},
|
||||
(a, b) -> {
|
||||
a.putAll(b);
|
||||
return a;
|
||||
}));
|
||||
}
|
||||
|
||||
private <T extends AIService> boolean hasDefault(Class<T> type) {
|
||||
String defaultName = defaultIds.get(type);
|
||||
return !Verify.isNullOrEmpty(defaultName);
|
||||
}
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.services;
|
||||
|
||||
public interface AIServiceProvider extends NamedServiceProvider<AIService> {}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.services;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/** Default implementation of {@link AIServiceProvider} */
|
||||
public class DefaultAIServiceProvider extends DefaultNamedServiceProvider<AIService>
|
||||
implements AIServiceProvider {
|
||||
public DefaultAIServiceProvider(
|
||||
Map<Class<? extends AIService>, Map<String, Supplier<? extends AIService>>> services,
|
||||
Map<Class<? extends AIService>, String> defaultIds) {
|
||||
super(services, defaultIds);
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.services;
|
||||
|
||||
import com.microsoft.semantickernel.Verify;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Default implementation of {@link NamedServiceProvider} */
|
||||
public class DefaultNamedServiceProvider<T> implements NamedServiceProvider<T> {
|
||||
|
||||
// A dictionary that maps a service type to a nested dictionary of names and service instances
|
||||
// or factories
|
||||
// private readonly Dictionary<Type, Dictionary<string, object>> _services = new();
|
||||
private final Map<Class<? extends T>, Map<String, Supplier<? extends T>>> services;
|
||||
|
||||
// A dictionary that maps a service type to the name of the default service
|
||||
private final Map<Class<? extends T>, String> defaultIds;
|
||||
|
||||
public DefaultNamedServiceProvider(
|
||||
Map<Class<? extends T>, Map<String, Supplier<? extends T>>> services,
|
||||
Map<Class<? extends T>, String> defaultIds) {
|
||||
this.services = AIServiceCollection.cloneServices(services);
|
||||
this.defaultIds = new HashMap<>(defaultIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the service of the specified type and name, or null if not found.
|
||||
*
|
||||
* @param name The name of the service, or null for the default service.
|
||||
* @param clazz The type of the service.
|
||||
* @return The service instance, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public <U extends T> U getService(@Nullable String name, Class<U> clazz) {
|
||||
// Return the service, casting or invoking the factory if needed
|
||||
Supplier<U> factory = this.getServiceFactory(name, clazz);
|
||||
if (factory != null) {
|
||||
return factory.get();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default service instance.
|
||||
*
|
||||
* @param clazz The type of the service.
|
||||
* @return The service instance, or null if none.
|
||||
*/
|
||||
@Nullable
|
||||
private <U extends T> String getDefaultServiceName(Class<U> clazz) {
|
||||
// Returns the name of the default service for the given type, or null if none
|
||||
String name = this.defaultIds.get(clazz);
|
||||
if (!Verify.isNullOrEmpty(name)) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <U extends T> Supplier<U> getServiceFactory(@Nullable String name, Class<U> clazz) {
|
||||
// Get the nested dictionary for the service type
|
||||
Map<String, Supplier<? extends T>> namedServices = services.get(clazz);
|
||||
|
||||
if (namedServices != null) {
|
||||
Supplier<U> serviceFactory = null;
|
||||
|
||||
// If the name is not specified, try to load the default factory
|
||||
name = name == null ? this.getDefaultServiceName(clazz) : name;
|
||||
if (name != null) {
|
||||
// Check if there is a service registered with the given name
|
||||
serviceFactory = (Supplier<U>) namedServices.get(name);
|
||||
}
|
||||
|
||||
return serviceFactory;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel.services;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface NamedServiceProvider<T> {
|
||||
/**
|
||||
* Gets the service of the specified type and name, or null if not found.
|
||||
*
|
||||
* @param name The name of the service, or null for the default service.
|
||||
* @param clazz The type of the service.
|
||||
* @return The service instance, or null if not found.
|
||||
*/
|
||||
@Nullable
|
||||
public <U extends T> U getService(@Nullable String name, Class<U> clazz);
|
||||
}
|
||||
+2
-1
@@ -2,13 +2,14 @@
|
||||
package com.microsoft.semantickernel.textcompletion;
|
||||
|
||||
import com.azure.ai.openai.OpenAIAsyncClient;
|
||||
import com.microsoft.semantickernel.services.AIService;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for text completion services */
|
||||
public interface TextCompletion {
|
||||
public interface TextCompletion extends AIService {
|
||||
// TODO: Support Cancellation Token
|
||||
|
||||
/**
|
||||
|
||||
+36
-8
@@ -7,7 +7,6 @@ import com.microsoft.semantickernel.builders.FunctionBuilders;
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.chatcompletion.ChatCompletion;
|
||||
import com.microsoft.semantickernel.coreskills.SkillImporter;
|
||||
import com.microsoft.semantickernel.exceptions.NotSupportedException;
|
||||
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException;
|
||||
import com.microsoft.semantickernel.extensions.KernelExtensions;
|
||||
import com.microsoft.semantickernel.memory.MemoryConfiguration;
|
||||
@@ -16,6 +15,8 @@ import com.microsoft.semantickernel.memory.NullMemory;
|
||||
import com.microsoft.semantickernel.memory.SemanticTextMemory;
|
||||
import com.microsoft.semantickernel.orchestration.*;
|
||||
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
|
||||
import com.microsoft.semantickernel.services.AIService;
|
||||
import com.microsoft.semantickernel.services.AIServiceProvider;
|
||||
import com.microsoft.semantickernel.skilldefinition.DefaultSkillCollection;
|
||||
import com.microsoft.semantickernel.skilldefinition.FunctionNotFound;
|
||||
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
|
||||
@@ -41,18 +42,21 @@ public class DefaultKernel implements Kernel {
|
||||
private final KernelConfig kernelConfig;
|
||||
private final DefaultSkillCollection defaultSkillCollection;
|
||||
private final PromptTemplateEngine promptTemplateEngine;
|
||||
private final AIServiceProvider aiServiceProvider;
|
||||
private SemanticTextMemory memory;
|
||||
|
||||
@Inject
|
||||
public DefaultKernel(
|
||||
KernelConfig kernelConfig,
|
||||
PromptTemplateEngine promptTemplateEngine,
|
||||
@Nullable SemanticTextMemory memoryStore) {
|
||||
@Nullable SemanticTextMemory memoryStore,
|
||||
AIServiceProvider aiServiceProvider) {
|
||||
if (kernelConfig == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
this.kernelConfig = kernelConfig;
|
||||
this.aiServiceProvider = aiServiceProvider;
|
||||
this.promptTemplateEngine = promptTemplateEngine;
|
||||
this.defaultSkillCollection = new DefaultSkillCollection();
|
||||
|
||||
@@ -64,7 +68,14 @@ public class DefaultKernel implements Kernel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getService(@Nullable String serviceId, Class<T> clazz) {
|
||||
public <T extends AIService> T getService(String serviceId, Class<T> clazz) {
|
||||
|
||||
T service = aiServiceProvider.getService(serviceId, clazz);
|
||||
|
||||
if (service != null) {
|
||||
return service;
|
||||
}
|
||||
|
||||
if (TextCompletion.class.isAssignableFrom(clazz)) {
|
||||
Function<Kernel, TextCompletion> factory =
|
||||
kernelConfig.getTextCompletionServiceOrDefault(serviceId);
|
||||
@@ -94,11 +105,25 @@ public class DefaultKernel implements Kernel {
|
||||
"No chat completion service available");
|
||||
}
|
||||
|
||||
return (T) factory.apply(this);
|
||||
} else if (EmbeddingGeneration.class.isAssignableFrom(clazz)) {
|
||||
Function<Kernel, EmbeddingGeneration<String, Float>> factory =
|
||||
kernelConfig.getTextEmbeddingGenerationServiceOrDefault(serviceId);
|
||||
if (factory == null) {
|
||||
throw new KernelException(
|
||||
KernelException.ErrorCodes.ServiceNotFound,
|
||||
"No chat completion service available");
|
||||
}
|
||||
|
||||
return (T) factory.apply(this);
|
||||
} else {
|
||||
// TODO correct exception
|
||||
throw new NotSupportedException(
|
||||
"The kernel service collection doesn't support the type " + clazz.getName());
|
||||
throw new KernelException(
|
||||
KernelException.ErrorCodes.ServiceNotFound,
|
||||
"Service of type "
|
||||
+ clazz.getName()
|
||||
+ " and name "
|
||||
+ serviceId
|
||||
+ " not registered");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +336,8 @@ public class DefaultKernel implements Kernel {
|
||||
KernelConfig kernelConfig,
|
||||
@Nullable PromptTemplateEngine promptTemplateEngine,
|
||||
@Nullable SemanticTextMemory memory,
|
||||
@Nullable MemoryStore memoryStore) {
|
||||
@Nullable MemoryStore memoryStore,
|
||||
@Nullable AIServiceProvider aiServiceProvider) {
|
||||
if (promptTemplateEngine == null) {
|
||||
promptTemplateEngine = new DefaultPromptTemplateEngine();
|
||||
}
|
||||
@@ -322,7 +348,9 @@ public class DefaultKernel implements Kernel {
|
||||
"It is required to set a kernelConfig to build a kernel");
|
||||
}
|
||||
|
||||
DefaultKernel kernel = new DefaultKernel(kernelConfig, promptTemplateEngine, memory);
|
||||
DefaultKernel kernel =
|
||||
new DefaultKernel(
|
||||
kernelConfig, promptTemplateEngine, memory, aiServiceProvider);
|
||||
|
||||
if (memoryStore != null) {
|
||||
MemoryConfiguration.useMemory(kernel, memoryStore, null);
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ public class DefaultSkillCollection implements ReadOnlySkillCollection {
|
||||
return addSemanticFunction(functionInstance);
|
||||
}
|
||||
|
||||
public DefaultSkillCollection merge(DefaultSkillCollection in) {
|
||||
public DefaultSkillCollection merge(ReadOnlySkillCollection in) {
|
||||
in.asMap()
|
||||
.entrySet()
|
||||
.forEach(
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
package com.microsoft.semantickernel;
|
||||
|
||||
import com.microsoft.semantickernel.builders.SKBuilders;
|
||||
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
|
||||
import com.microsoft.semantickernel.textcompletion.TextCompletion;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class AiServiceRegistryTest {
|
||||
|
||||
@Test
|
||||
public void registeredServicesAreAvailableInTheKernel() {
|
||||
runFunctionWithAiService(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleServiceIsRegisteredAsDefault() {
|
||||
runFunctionWithAiService(false);
|
||||
}
|
||||
|
||||
private static void runFunctionWithAiService(boolean setAsDefault) {
|
||||
KernelConfig config = SKBuilders.kernelConfig().build();
|
||||
TextCompletion service = Mockito.mock(TextCompletion.class);
|
||||
Mockito.when(service.completeAsync(Mockito.any(), Mockito.any()))
|
||||
.thenReturn(Mono.just(Collections.singletonList("foo")));
|
||||
|
||||
Kernel kernel =
|
||||
SKBuilders.kernel()
|
||||
.withAIService("a-service", service, setAsDefault, TextCompletion.class)
|
||||
.withKernelConfig(config)
|
||||
.build();
|
||||
|
||||
Assertions.assertSame(kernel.getService("a-service", TextCompletion.class), service);
|
||||
|
||||
CompletionSKFunction function =
|
||||
kernel.importSkillFromDirectory("FunSkill", "../../samples/skills")
|
||||
.getFunction("joke", CompletionSKFunction.class);
|
||||
|
||||
function.invokeAsync("time travel to dinosaur age").block();
|
||||
|
||||
Mockito.verify(service, Mockito.times(1)).completeAsync(Mockito.any(), Mockito.any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noServiceThrowsAnError() {
|
||||
KernelConfig config = SKBuilders.kernelConfig().build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(config).build();
|
||||
|
||||
Assertions.assertThrows(
|
||||
KernelException.class, () -> kernel.getService("a-service", TextCompletion.class));
|
||||
|
||||
Assertions.assertThrows(
|
||||
KernelException.class,
|
||||
() -> {
|
||||
CompletionSKFunction function =
|
||||
kernel.importSkillFromDirectory("FunSkill", "../../samples/skills")
|
||||
.getFunction("joke", CompletionSKFunction.class);
|
||||
|
||||
function.invokeAsync("time travel to dinosaur age").block();
|
||||
});
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -119,7 +119,7 @@ public class DefaultKernelTest {
|
||||
.addTextCompletionService(model, kernel -> textCompletion)
|
||||
.build();
|
||||
|
||||
return SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
return SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
}
|
||||
|
||||
private static OpenAIAsyncClient mockCompletionOpenAIAsyncClient(String arg, String response) {
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class OpenAIChatCompletionTest {
|
||||
.build(client, "gpt-3.5-turbo-0301"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
ChatCompletion<OpenAIChatHistory> chatGPT = kernel.getService(null, ChatCompletion.class);
|
||||
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ class AzureCognitiveSearchMemoryTests {
|
||||
|
||||
kernel =
|
||||
SKBuilders.kernel()
|
||||
.setKernelConfig(SKBuilders.kernelConfig().build())
|
||||
.withKernelConfig(SKBuilders.kernelConfig().build())
|
||||
.withMemory(new AzureCognitiveSearchMemory(searchIndexAsyncClient))
|
||||
.build();
|
||||
}
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public class Example04CombineLLMPromptsAndNativeCodeTest {
|
||||
.setDefaultTextCompletionService("text-davinci-003")
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
kernel.importSkill(new SearchEngineSkill(), null);
|
||||
kernel.importSkillFromDirectory("SummarizeSkill", "../../samples/skills", "SummarizeSkill");
|
||||
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class Example05UsingThePlannerTest {
|
||||
.build(client, "text-davinci-003"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(config).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(config).build();
|
||||
|
||||
SequentialPlanner planner = getPlanner(kernel);
|
||||
System.out.println(
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ public class Example06TemplateLanguageTest {
|
||||
.build(client, "text-davinci-003"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
// Load native skill into the kernel skill collection, sharing its functions
|
||||
// with prompt
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class Example12SequentialPlannerTest {
|
||||
private static Kernel getKernel(OpenAIAsyncClient client) {
|
||||
Kernel kernel =
|
||||
SKBuilders.kernel()
|
||||
.setKernelConfig(
|
||||
.withKernelConfig(
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"text-davinci-002",
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class Example17ChatGPTTest {
|
||||
.build(client, "gpt-3.5-turbo-0301"))
|
||||
.build();
|
||||
|
||||
Kernel kernel = SKBuilders.kernel().setKernelConfig(kernelConfig).build();
|
||||
Kernel kernel = SKBuilders.kernel().withKernelConfig(kernelConfig).build();
|
||||
|
||||
ChatCompletion<OpenAIChatHistory> chatGPT = kernel.getService(null, ChatCompletion.class);
|
||||
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@ public class Example28ActionPlanner {
|
||||
private static ActionPlanner createPlanner(OpenAIAsyncClient client) {
|
||||
Kernel kernel =
|
||||
SKBuilders.kernel()
|
||||
.setKernelConfig(
|
||||
.withKernelConfig(
|
||||
SKBuilders.kernelConfig()
|
||||
.addTextCompletionService(
|
||||
"text-davinci-002",
|
||||
|
||||
Reference in New Issue
Block a user