Java: Apply ADR 008 (#3366)

Closed #2417 in favour of this PR which also includes @relango s
commits.

This PR updates for full support for ADR 008
(https://github.com/microsoft/semantic-kernel/blob/main/docs/decisions/0008-support-generic-llm-request-settings.md),
which is the ADR in this area.

This PR does the following:
- Updates the code to support ADR 008.
- Apply code formatting needed on these
- If you dont want do do this PR via your branch I can PR it directly
and close this PR.

Now you can add serviceId and model to invocation, i.e:
``
Mono<SKContext> result = function.invokeAsync("time travel to dinosaur
age",
        SKBuilders
            .completionRequestSettings()
            .serviceId("text-davinci-003")
            .build());
``
function config, i.e:

```
    var function = kernel.
        getSemanticFunctionBuilder()
        .withPromptTemplate("tell a joke about {{$input}}")
        .withRequestSettings(
            SKBuilders.completionRequestSettings()
                .temperature(0.4)
                .topP(1)
                .maxTokens(100)
                .serviceId("text-davinci-003")
                .build())
        .build();
```

Or config file

```
{
  "schema": 1,
  "description": "Sample plugin with a model and service id",
  "type": "completion",
  "completion": {
    "max_tokens": 150,
    "temperature": 0.9,
    "top_p": 0.0,
    "presence_penalty": 0.6,
    "frequency_penalty": 0.0,
    "service_id": "text-davinci-003",
    "model_id": "text-davinci-003"
  }
}
```

---------

Co-authored-by: Rajasekar Elango <[email protected]>
This commit is contained in:
John Oliver
2023-11-28 14:16:45 +00:00
committed by GitHub
co-authored by Rajasekar Elango
parent 299bde90bd
commit aff5552977
46 changed files with 1232 additions and 734 deletions
@@ -4,7 +4,6 @@ import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import java.io.IOException;
@@ -106,8 +105,14 @@ public class InlineFunctionExample {
kernel.getSemanticFunctionBuilder()
.withPromptTemplate(prompt)
.withFunctionName("summarize")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0.2, 0.5, 0, 0, 2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.maxTokens(2000)
.presencePenalty(0)
.frequencyPenalty(0)
.build())
.build();
if (summarize == null) {
@@ -4,7 +4,6 @@ import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import java.io.IOException;
@@ -17,6 +16,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InlineFunctionWithPreBuiltSkillExample {
public static final String AZURE_CONF_PROPERTIES = "conf.properties";
private static final Logger LOGGER =
LoggerFactory.getLogger(InlineFunctionWithPreBuiltSkillExample.class);
@@ -26,35 +26,35 @@ public class InlineFunctionWithPreBuiltSkillExample {
private static final String ENDPOINT;
private static final String TEXT_TO_SUMMARIZE =
"""
Demo (ancient Greek poet)
From Wikipedia, the free encyclopedia
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
Roman period, known for a single epigram, engraved upon the Colossus of
Memnon, which bears her name. She speaks of herself therein as a lyric
poetess dedicated to the Muses, but nothing is known of her life.[1]
Identity
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
signifies. The name was relatively common in the Hellenistic world, in
Egypt and elsewhere, and she cannot be further identified. The date of her
visit to the Colossus of Memnon cannot be established with certainty, but
internal evidence on the left leg suggests her poem was inscribed there at
some point in or after AD 196.[2]
Epigram
There are a number of graffiti inscriptions on the Colossus of Memnon.
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
couplets, entitled and presumably authored by "Demo" or "Damo" (the
Greek inscription is difficult to read), is a dedication to the Muses.[2]
The poem is traditionally published with the works of Balbilla, though the
internal evidence suggests a different author.[1]
In the poem, Demo explains that Memnon has shown her special respect. In
return, Demo offers the gift for poetry, as a gift to the hero. At the end
of this epigram, she addresses Memnon, highlighting his divine status by
recalling his strength and holiness.[2]
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
dialect. The language indicates she was knowledgeable in Homeric
poetry—'bearing a pleasant gift', for example, alludes to the use of that
phrase throughout the Iliad and Odyssey.[a][2];
""";
Demo (ancient Greek poet)
From Wikipedia, the free encyclopedia
Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the
Roman period, known for a single epigram, engraved upon the Colossus of
Memnon, which bears her name. She speaks of herself therein as a lyric
poetess dedicated to the Muses, but nothing is known of her life.[1]
Identity
Demo was evidently Greek, as her name, a traditional epithet of Demeter,
signifies. The name was relatively common in the Hellenistic world, in
Egypt and elsewhere, and she cannot be further identified. The date of her
visit to the Colossus of Memnon cannot be established with certainty, but
internal evidence on the left leg suggests her poem was inscribed there at
some point in or after AD 196.[2]
Epigram
There are a number of graffiti inscriptions on the Colossus of Memnon.
Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac
couplets, entitled and presumably authored by "Demo" or "Damo" (the
Greek inscription is difficult to read), is a dedication to the Muses.[2]
The poem is traditionally published with the works of Balbilla, though the
internal evidence suggests a different author.[1]
In the poem, Demo explains that Memnon has shown her special respect. In
return, Demo offers the gift for poetry, as a gift to the hero. At the end
of this epigram, she addresses Memnon, highlighting his divine status by
recalling his strength and holiness.[2]
Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic
dialect. The language indicates she was knowledgeable in Homeric
poetry—'bearing a pleasant gift', for example, alludes to the use of that
phrase throughout the Iliad and Odyssey.[a][2];
""";
static {
try {
@@ -108,8 +108,14 @@ public class InlineFunctionWithPreBuiltSkillExample {
.withKernel(kernel)
.withPromptTemplate(prompt)
.withFunctionName("summarize")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0.2, 0.5, 0, 0, 2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.maxTokens(2000)
.presencePenalty(0)
.frequencyPenalty(0)
.build())
.build();
if (summarize == null) {
@@ -5,7 +5,6 @@ import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -50,8 +49,14 @@ public class ContextVariableFunctionTest extends AbstractKernelTest {
kernel.getSemanticFunctionBuilder()
.withPromptTemplate(prompt)
.withFunctionName("ChatBot")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0.7, 0.5, 0, 0, 2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.7)
.topP(0.5)
.maxTokens(2000)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.build();
SKContext readOnlySkContext = SKBuilders.context().withKernel(kernel).build();
@@ -2,9 +2,9 @@
package com.microsoft.semantickernel.e2e;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIf;
@@ -26,8 +26,14 @@ public class InlineFunctionTest extends AbstractKernelTest {
kernel.getSemanticFunctionBuilder()
.withPromptTemplate(prompt)
.withFunctionName("summarize")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0.2, 0.5, 0, 0, 2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.maxTokens(2000)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.build();
String text =
@@ -7,7 +7,6 @@ import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import java.io.IOException;
@@ -18,6 +17,7 @@ import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
public class KernelTest extends AbstractKernelTest {
private static final Logger LOGGER = LoggerFactory.getLogger(KernelTest.class);
private static void executeCompletion(Kernel kernel) {
@@ -25,23 +25,31 @@ public class KernelTest extends AbstractKernelTest {
kernel.getSemanticFunctionBuilder()
.withPromptTemplate(
"""
{{$input}}
{{$input}}
One line TLDR with the fewest words.""")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0, 0, 0, 0, 256))
One line TLDR with the fewest words.""")
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0)
.topP(0)
.maxTokens(256)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.build();
String text1 =
"""
1st Law of Thermodynamics - Energy cannot be created or destroyed.
2nd Law of Thermodynamics - For a spontaneous process, the entropy of the universe increases.
3rd Law of Thermodynamics - A perfect crystal at zero Kelvin has zero entropy""";
1st Law of Thermodynamics - Energy cannot be created or destroyed.
2nd Law of Thermodynamics - For a spontaneous process, the entropy of the universe increases.
3rd Law of Thermodynamics - A perfect crystal at zero Kelvin has zero entropy""";
Mono<SKContext> mono = summarize.invokeAsync(text1);
SKContext result = mono.block();
if (result != null) LOGGER.info("Result: " + result.getResult());
if (result != null) {
LOGGER.info("Result: " + result.getResult());
}
}
public static Kernel buildKernel(OpenAIAsyncClient client, String model) {
@@ -179,6 +179,7 @@ public class SequentialPlanTest {
Kernel kernel = SKBuilders.kernel().build();
kernel.importSkill(new Skills(), "Skills");
return SequentialPlanParser.toPlanFromXml(planString.stripIndent(), "", kernel.getSkills());
return SequentialPlanParser.toPlanFromXml(
planString.stripIndent(), "", kernel.getSkills(), kernel::getService);
}
}
@@ -76,7 +76,7 @@ public class OpenAITextCompletion extends ClientBase implements TextCompletion {
private Flux<String> generateMessageStream(CompletionsOptions completionsOptions) {
return getClient()
.getCompletionsStream(getModelId(), completionsOptions)
.getCompletionsStream(getModelId(completionsOptions), completionsOptions)
.groupBy(Completions::getId)
.concatMap(
completionResult -> {
@@ -103,12 +103,28 @@ public class OpenAITextCompletion extends ClientBase implements TextCompletion {
CompletionsOptions completionsOptions = getCompletionsOptions(text, requestSettings);
return getClient()
.getCompletions(getModelId(), completionsOptions)
.getCompletions(getModelId(requestSettings), completionsOptions)
.flatMapIterable(Completions::getChoices)
.mapNotNull(Choice::getText)
.collectList();
}
private String getModelId(CompletionRequestSettings requestSettings) {
String model = requestSettings.getModelId();
if (model == null) {
model = getModelId();
}
return model;
}
private String getModelId(CompletionsOptions completionsOptions) {
String model = completionsOptions.getModel();
if (model == null) {
model = getModelId();
}
return model;
}
private CompletionsOptions getCompletionsOptions(
String text, CompletionRequestSettings requestSettings) {
if (requestSettings.getMaxTokens() < 1) {
@@ -122,7 +138,7 @@ public class OpenAITextCompletion extends ClientBase implements TextCompletion {
.setTopP(requestSettings.getTopP())
.setFrequencyPenalty(requestSettings.getFrequencyPenalty())
.setPresencePenalty(requestSettings.getPresencePenalty())
.setModel(getModelId())
.setModel(getModelId(requestSettings))
.setUser(requestSettings.getUser())
.setBestOf(requestSettings.getBestOf())
.setLogitBias(new HashMap<>());
@@ -8,7 +8,6 @@ import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.orchestration.WritableContextVariables;
import com.microsoft.semantickernel.planner.PlanningException;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction;
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
@@ -34,6 +33,7 @@ import reactor.core.publisher.Mono;
/// the Plan object in future.
/// </summary>
public class ActionPlanner {
private static final Logger LOGGER = LoggerFactory.getLogger(ActionPlanner.class);
// Extracts the json portion of a plan between the braces, stripping off any non-json content
@@ -71,8 +71,14 @@ public class ActionPlanner {
.withKernel(kernel)
.withPromptTemplate(promptTemplate)
.withSkillName(SkillName)
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0.0, 0.0, 0.0, 0.0, 1024))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.0)
.topP(0.0)
.maxTokens(1024)
.presencePenalty(0)
.frequencyPenalty(0)
.build())
.build();
kernel.importSkill(this, SkillName);
@@ -150,9 +156,9 @@ public class ActionPlanner {
if (function == null) {
// No function was found - return a plan with no steps.
return new Plan(goal, variables, () -> kernel.getSkills());
return new Plan(goal, variables, kernel::getSkills, kernel::getService);
} else {
return new Plan(goal, variables, () -> kernel.getSkills(), function);
return new Plan(goal, variables, kernel::getSkills, kernel::getService, function);
}
}
@@ -5,13 +5,14 @@ import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.Verify;
import com.microsoft.semantickernel.memory.SemanticTextMemory;
import com.microsoft.semantickernel.orchestration.AbstractSkFunction;
import com.microsoft.semantickernel.orchestration.AIFunction;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.orchestration.WritableContextVariables;
import com.microsoft.semantickernel.planner.PlanningException;
import com.microsoft.semantickernel.planner.PlanningException.ErrorCodes;
import com.microsoft.semantickernel.services.AIServiceSupplier;
import com.microsoft.semantickernel.skilldefinition.FunctionView;
import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
@@ -30,7 +31,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/** Standard Semantic Kernel callable plan. Plan is used to create trees of SKFunctions. */
public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
public class Plan extends AIFunction<CompletionRequestSettings> {
private static final Pattern s_variablesRegex = Pattern.compile("\\$(\\w+)", Pattern.MULTILINE);
@@ -53,33 +54,40 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
public Plan(
String goal,
ContextVariables state,
@Nullable KernelSkillsSupplier kernelSkillsSupplier) {
@Nullable KernelSkillsSupplier kernelSkillsSupplier,
@Nullable AIServiceSupplier aiServiceSupplier) {
super(
new ArrayList<>(),
Plan.class.getName(),
"",
goal,
Collections.emptyList(),
kernelSkillsSupplier);
kernelSkillsSupplier,
aiServiceSupplier);
this.state = state;
}
public Plan(String goal, @Nullable KernelSkillsSupplier kernelSkillsSupplier) {
this(goal, SKBuilders.variables().build(), kernelSkillsSupplier);
public Plan(
String goal,
@Nullable KernelSkillsSupplier kernelSkillsSupplier,
@Nullable AIServiceSupplier aiServiceSupplier) {
this(goal, SKBuilders.variables().build(), kernelSkillsSupplier, aiServiceSupplier);
}
public Plan(
SKFunction<?> function,
ContextVariables state,
List<String> functionOutputs,
KernelSkillsSupplier kernelSkillsSupplier) {
KernelSkillsSupplier kernelSkillsSupplier,
AIServiceSupplier aiServiceSupplier) {
super(
function.describe().getParameters(),
function.getSkillName(),
function.getName(),
function.getDescription(),
formReturnParameters(functionOutputs),
kernelSkillsSupplier);
kernelSkillsSupplier,
aiServiceSupplier);
this.parameters = null;
this.function = function;
@@ -92,14 +100,16 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
@Nullable ContextVariables parameters,
ContextVariables state,
List<String> functionOutputs,
KernelSkillsSupplier kernelSkillsSupplier) {
KernelSkillsSupplier kernelSkillsSupplier,
AIServiceSupplier aiServiceSupplier) {
super(
function.describe().getParameters(),
function.getSkillName(),
function.getName(),
function.getDescription(),
formReturnParameters(functionOutputs),
kernelSkillsSupplier);
kernelSkillsSupplier,
aiServiceSupplier);
this.parameters = parameters;
this.function = function;
this.outputs = new ArrayList<>(functionOutputs);
@@ -113,25 +123,44 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
public Plan(
SKFunction<?> function,
List<String> functionOutputs,
KernelSkillsSupplier kernelSkillsSupplier) {
this(function, SKBuilders.variables().build(), functionOutputs, kernelSkillsSupplier);
KernelSkillsSupplier kernelSkillsSupplier,
AIServiceSupplier aiServiceSupplier) {
this(
function,
SKBuilders.variables().build(),
functionOutputs,
kernelSkillsSupplier,
aiServiceSupplier);
}
public Plan(SKFunction<?> function, KernelSkillsSupplier kernelSkillsSupplier) {
this(function, SKBuilders.variables().build(), new ArrayList<>(), kernelSkillsSupplier);
public Plan(
SKFunction<?> function,
KernelSkillsSupplier kernelSkillsSupplier,
AIServiceSupplier aiServiceSupplier) {
this(
function,
SKBuilders.variables().build(),
new ArrayList<>(),
kernelSkillsSupplier,
aiServiceSupplier);
}
public Plan(
String goal,
ContextVariables parameters,
KernelSkillsSupplier kernelSkillsSupplier,
AIServiceSupplier aiServiceSupplier,
SKFunction<?>... steps) {
this(goal, parameters, kernelSkillsSupplier);
this(goal, parameters, kernelSkillsSupplier, aiServiceSupplier);
this.addSteps(steps);
}
public Plan(String goal, KernelSkillsSupplier kernelSkillsSupplier, SKFunction<?>... steps) {
this(goal, kernelSkillsSupplier);
public Plan(
String goal,
KernelSkillsSupplier kernelSkillsSupplier,
AIServiceSupplier aiServiceSupplier,
SKFunction<?>... steps) {
this(goal, kernelSkillsSupplier, aiServiceSupplier);
this.addSteps(steps);
}
@@ -179,7 +208,7 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
public void addSteps(SKFunction<?>... steps) {
List<Plan> plans =
Arrays.stream(steps)
.map(step -> new Plan(step, getSkillsSupplier()))
.map(step -> new Plan(step, getSkillsSupplier(), getAiServiceSupplier()))
.collect(Collectors.toList());
this.steps.addAll(plans);
}
@@ -6,6 +6,7 @@ import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.orchestration.WritableContextVariables;
import com.microsoft.semantickernel.planner.PlanningException;
import com.microsoft.semantickernel.planner.actionplanner.Plan;
import com.microsoft.semantickernel.services.AIServiceSupplier;
import com.microsoft.semantickernel.skilldefinition.FunctionView;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import java.io.ByteArrayInputStream;
@@ -27,6 +28,7 @@ import org.xml.sax.SAXException;
/** Parse sequential plan text into a plan. */
public class SequentialPlanParser {
private static final Logger LOGGER = LoggerFactory.getLogger(SequentialPlanParser.class);
// The tag name used in the plan xml for the user's goal/ask.
@@ -56,10 +58,14 @@ public class SequentialPlanParser {
* @return The plan
* @throws PlanningException If the plan xml is invalid
*/
public static Plan toPlanFromXml(String xmlString, String goal, ReadOnlySkillCollection skills)
public static Plan toPlanFromXml(
String xmlString,
String goal,
ReadOnlySkillCollection skills,
AIServiceSupplier aiServiceSupplier)
throws PlanningException {
// to maintain backward compatibility -- uses the preexisting signature and behavior
return toPlanFromXml(xmlString, goal, skills, true);
return toPlanFromXml(xmlString, goal, skills, aiServiceSupplier, true);
}
/**
@@ -76,6 +82,7 @@ public class SequentialPlanParser {
String xmlString,
String goal,
ReadOnlySkillCollection skills,
AIServiceSupplier aiServiceSupplier,
boolean allowMissingFunctions)
throws PlanningException {
@@ -90,7 +97,7 @@ public class SequentialPlanParser {
NodeList solution = doc.getElementsByTagName(SolutionTag);
Plan plan = new Plan(goal, () -> skills);
Plan plan = new Plan(goal, () -> skills, aiServiceSupplier);
for (int i = 0; i < solution.getLength(); i++) {
Node solutionNode = solution.item(i);
@@ -101,7 +108,11 @@ public class SequentialPlanParser {
if (childNode.getNodeName().equals("#text")) {
if (childNode.getNodeValue() != null
&& !childNode.getNodeValue().trim().isEmpty()) {
plan.addSteps(new Plan(childNode.getNodeValue().trim(), () -> skills));
plan.addSteps(
new Plan(
childNode.getNodeValue().trim(),
() -> skills,
aiServiceSupplier));
}
continue;
}
@@ -136,7 +147,8 @@ public class SequentialPlanParser {
functionVariables,
SKBuilders.variables().build(),
functionOutputs,
() -> skills);
() -> skills,
aiServiceSupplier);
plan.addOutputs(functionResults);
plan.addSteps(planStep);
@@ -145,9 +157,12 @@ public class SequentialPlanParser {
"{}: appending function node {}",
parentNodeName,
skillFunctionName);
if (allowMissingFunctions) {
plan.addSteps(new Plan(childNode.getTextContent(), () -> skills));
plan.addSteps(
new Plan(
childNode.getTextContent(),
() -> skills,
aiServiceSupplier));
} else {
String errorMessage =
String.format(
@@ -161,7 +176,8 @@ public class SequentialPlanParser {
continue;
}
plan.addSteps(new Plan(childNode.getTextContent(), () -> skills));
plan.addSteps(
new Plan(childNode.getTextContent(), () -> skills, aiServiceSupplier));
}
}
return plan;
@@ -6,7 +6,6 @@ import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.planner.PlanningException;
import com.microsoft.semantickernel.planner.actionplanner.Plan;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import javax.annotation.Nullable;
import org.slf4j.Logger;
@@ -68,9 +67,14 @@ public class SequentialPlanner {
"Given a request or command or goal generate a step by step plan to"
+ " fulfill the request using functions. This ability is also"
+ " known as decision making and function flow")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(
0.0, 0.0, 0.0, 0.0, this.config.getMaxTokens()))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.0)
.topP(0.0)
.maxTokens(this.config.getMaxTokens())
.presencePenalty(0)
.frequencyPenalty(0)
.build())
.build();
this.kernel = kernel;
@@ -123,6 +127,7 @@ public class SequentialPlanner {
planResultString,
goal,
context.getSkills(),
kernel::getService,
config.getAllowMissingFunctions());
});
} catch (Exception e) {
@@ -104,13 +104,9 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
* @param kernel The semantic kernel instance.
* @param config Optional configuration object
* @param prompt Optional prompt override
* @param promptUserConfig Optional prompt config override
*/
public DefaultStepwisePlanner(
Kernel kernel,
@Nullable StepwisePlannerConfig config,
@Nullable String prompt,
@Nullable PromptTemplateConfig promptUserConfig) {
Kernel kernel, @Nullable StepwisePlannerConfig config, @Nullable String prompt) {
Verify.notNull(kernel);
this.kernel = kernel;
@@ -121,28 +117,9 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
this.config = config;
this.config.addExcludedSkills(RESTRICTED_SKILL_NAME);
PromptTemplateConfig promptConfig;
if (promptUserConfig == null) {
String promptConfigString = null;
try {
promptConfigString =
EmbeddedResourceLoader.readFile(
"config.json", DefaultStepwisePlanner.class);
if (!Verify.isNullOrEmpty(promptConfigString)) {
promptConfig =
new ObjectMapper()
.readValue(promptConfigString, PromptTemplateConfig.class);
} else {
promptConfig = new PromptTemplateConfig();
}
} catch (FileNotFoundException | JsonProcessingException e) {
throw new PlanningException(
PlanningException.ErrorCodes.INVALID_CONFIGURATION,
"Could not find or parse config.json",
e);
}
} else {
promptConfig = promptUserConfig;
PromptTemplateConfig promptConfig = config.promptTemplateConfig;
if (promptConfig == null) {
promptConfig = loadPromptConfig();
}
if (prompt == null) {
@@ -163,8 +140,8 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
promptConfig.getSchema(),
promptConfig.getDescription(),
promptConfig.getType(),
new PromptTemplateConfig.CompletionConfigBuilder(
promptConfig.getCompletionConfig())
new CompletionRequestSettings.Builder(
promptConfig.getCompletionRequestSettings())
.maxTokens(this.config.getMaxTokens())
.build(),
promptConfig.getInput());
@@ -176,6 +153,26 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
this.context = SKBuilders.context().withKernel(kernel).build();
}
private static PromptTemplateConfig loadPromptConfig() {
PromptTemplateConfig promptConfig;
String promptConfigString = null;
try {
promptConfigString =
EmbeddedResourceLoader.readFile("config.json", DefaultStepwisePlanner.class);
if (!Verify.isNullOrEmpty(promptConfigString)) {
promptConfig =
new ObjectMapper()
.readValue(promptConfigString, PromptTemplateConfig.class);
} else {
promptConfig = new PromptTemplateConfig();
}
} catch (FileNotFoundException | JsonProcessingException e) {
throw new PlanningException(
ErrorCodes.INVALID_CONFIGURATION, "Could not find or parse config.json", e);
}
return promptConfig;
}
/**
* Create a plan for the specified goal.
*
@@ -199,7 +196,7 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
/*
planStep.addOutputs(Arrays.asList("agentScratchPad", "stepCount", "skillCount", "stepsTaken"));
*/
return new Plan(goal, parameters, kernel::getSkills, planStep);
return new Plan(goal, parameters, kernel::getSkills, kernel::getService, planStep);
}
/**
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.planner.stepwiseplanner;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Nullable;
/// <summary>
/// Configuration for Stepwise planner instances.
@@ -61,6 +63,11 @@ public class StepwisePlannerConfig {
/// </summary>
private int minIterationTimeMs = 0;
/// <summary>
/// The configuration to use for the prompt template.
/// </summary>
@Nullable public PromptTemplateConfig promptTemplateConfig;
public void addExcludedSkills(String restrictedSkillName) {
excludedSkills.add(restrictedSkillName);
}
@@ -39,8 +39,8 @@ public class ConversationSummarySkill {
.withDescription(
"Given a section of a conversation transcript, summarize the part"
+ " of the conversation.")
.withCompletionConfig(
SKBuilders.completionConfig()
.withRequestSettings(
SKBuilders.completionRequestSettings()
.maxTokens(MaxTokens)
.temperature(0.1)
.topP(0.5)
@@ -57,8 +57,8 @@ public class ConversationSummarySkill {
.withDescription(
"Given a section of a conversation transcript, identify action"
+ " items.")
.withCompletionConfig(
SKBuilders.completionConfig()
.withRequestSettings(
SKBuilders.completionRequestSettings()
.maxTokens(MaxTokens)
.temperature(0.1)
.topP(0.5)
@@ -75,8 +75,8 @@ public class ConversationSummarySkill {
.withDescription(
"Analyze a conversation transcript and extract key topics worth"
+ " remembering.")
.withCompletionConfig(
SKBuilders.completionConfig()
.withRequestSettings(
SKBuilders.completionRequestSettings()
.maxTokens(MaxTokens)
.temperature(0.1)
.topP(0.5)
+1
View File
@@ -27,6 +27,7 @@
<artifactId>semantickernel-core</artifactId>
<!-- TODO: scope should be runtime, but VolatileMemoryStore is an issue -->
<!-- <scope>runtime</scope> -->
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
@@ -8,6 +8,7 @@ package com.microsoft.semantickernel.samples;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.connectors.ai.openai.util.OpenAIClientProvider;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.SKContext;
@@ -38,13 +39,14 @@ public class Example03_SemanticFunctionInline {
.getSemanticFunctionBuilder()
.withPromptTemplate(prompt)
.withFunctionName(functionName)
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(
0.2,
0.5,
0,
0,
2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.maxTokens(2000)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.build();
Mono<SKContext> result = summarize.invokeAsync(text);
@@ -12,7 +12,6 @@ import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.connectors.ai.openai.util.OpenAIClientProvider;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -46,13 +45,14 @@ public class Example04_ContextVariablesChat {
.getSemanticFunctionBuilder()
.withPromptTemplate(prompt)
.withFunctionName("ChatBot")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(
0.7,
0.5,
0,
0,
2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.7)
.topP(0.5)
.maxTokens(2000)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.build();
SKContext readOnlySkContext = SKBuilders.context().withKernel(kernel).build();
@@ -0,0 +1,140 @@
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.microsoft.semantic-kernel:semantickernel-core:0.2.6-alpha
//DEPS com.microsoft.semantic-kernel:semantickernel-core-skills:0.2.6-alpha
//DEPS com.microsoft.semantic-kernel.connectors:semantickernel-connectors:0.2.6-alpha
//DEPS org.slf4j:slf4j-jdk14:2.0.7
//SOURCES syntaxexamples/SampleSkillsUtil.java,Config.java
package com.microsoft.semantickernel.samples;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
import com.microsoft.semantickernel.connectors.ai.openai.util.OpenAIClientProvider;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.samples.syntaxexamples.SampleSkillsUtil;
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import java.io.IOException;
import reactor.core.publisher.Mono;
/**
* Getting started
* <p>
* Create a conf.properties file based on the examples files at the root of this module.
* <p>
* <a href= "https://learn.microsoft.com/en-us/azure/cognitive-services/openai/quickstart">Get
* started with Azure OpenAI</a>
* <a href="https://openai.com/product">Get started with OpenAI</a>
*/
public class Example11_UseMultipleModels {
/**
* Returns a Semantic Kernel with Text Completion.
*
* @param client Client that will handle requests to AzureOpenAI or OpenAI.
* @return Kernel.
*/
public static Kernel getKernel(OpenAIAsyncClient client) {
OpenAITextCompletion davinciTextCompletion = new OpenAITextCompletion(client,
"text-davinci-003");
OpenAITextCompletion adaTextCompletion = new OpenAITextCompletion(client, "text-ada-001");
Kernel kernel = SKBuilders.kernel()
// Add one of this serviceId to config.json in FunSkill to test difference models
.withAIService("text-davinci-003", davinciTextCompletion, false, OpenAITextCompletion.class)
.withAIService("text-ada-001", adaTextCompletion, false, OpenAITextCompletion.class)
.build();
return kernel;
}
/**
* Imports 'FunSkill' from directory examples and runs the 'Joke' function within it.
*
* @param kernel Kernel with Text Completion.
*/
public static void runWithServiceDefinedAtInvocation(Kernel kernel) {
ReadOnlyFunctionCollection skill = kernel
.importSkillFromDirectory("FunSkill", SampleSkillsUtil.detectSkillDirLocation(),
"FunSkill");
CompletionSKFunction function = skill.getFunction("Joke",
CompletionSKFunction.class);
Mono<SKContext> result = function.invokeAsync("time travel to dinosaur age",
SKBuilders
.completionRequestSettings()
.serviceId("text-davinci-003")
.build());
String davinci = result.block().getResult();
result = function.invokeAsync("time travel to dinosaur age",
SKBuilders
.completionRequestSettings()
.serviceId("text-ada-001")
.build());
String ada = result.block().getResult();
System.out.println("=== RESULT FROM text-davinci-003 ===");
System.out.println(davinci);
System.out.println("====================================");
System.out.println("===== RESULT FROM text-ada-001 =====");
System.out.println(ada);
System.out.println("====================================");
}
public static void runWithServiceDefinedByInlineFunction(Kernel kernel) {
// Create function via kernel
var function = kernel.
getSemanticFunctionBuilder()
.withPromptTemplate("tell a joke about {{$input}}")
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.4)
.topP(1)
.maxTokens(100)
.serviceId("text-davinci-003")
.build())
.build();
String davinci = function.invokeAsync("time travel to dinosaur age").block().getResult();
System.out.println("=== RESULT FROM text-davinci-003 ===");
System.out.println(davinci);
System.out.println("====================================");
}
public static void runWithServiceDefinedInFile(Kernel kernel) {
ReadOnlyFunctionCollection skills = kernel.importSkillFromResources(
"Plugins",
"ExamplePlugins",
"ExampleFunctionWithService"
);
SKFunction<?> function = skills.getFunction("ExampleFunctionWithService");
System.out.println("=== RESULT FROM text-davinci-003 ===");
System.out.println(function.invokeAsync().block().getResult());
System.out.println("====================================");
}
public static void run(OpenAIAsyncClient client) {
Kernel kernel = getKernel(client);
runWithServiceDefinedInFile(kernel);
runWithServiceDefinedAtInvocation(kernel);
runWithServiceDefinedByInlineFunction(kernel);
}
public static void main(String args[]) throws ConfigurationException, IOException {
run(OpenAIClientProvider.getClient());
}
}
@@ -7,7 +7,6 @@ import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.SamplesConfig;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -52,11 +51,11 @@ public class Example05_InlineFunctionDefinition {
.completionFunctions()
.withKernel(kernel)
.withPromptTemplate(functionDefinition)
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfigBuilder()
.maxTokens(100)
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.4)
.topP(1)
.maxTokens(100)
.build())
.build();
@@ -72,11 +71,11 @@ public class Example05_InlineFunctionDefinition {
getSemanticFunctionBuilder()
.withPromptTemplate("Translate this date " +
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(LocalDateTime.now()) + " to French format")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfigBuilder()
.maxTokens(100)
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.4)
.topP(1)
.maxTokens(100)
.build())
.build();
@@ -11,8 +11,8 @@ import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
/**
* Show how to invoke a Native Function written in Java
* from a Semantic Function written in natural language
* Show how to invoke a Native Function written in Java from a Semantic Function written in natural
* language
* <p>
* Refer to the <a href=
* "https://github.com/microsoft/semantic-kernel/blob/experimental-java/java/samples/sample-code/README.md">
@@ -20,84 +20,89 @@ import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
*/
public class Example06_TemplateLanguage {
public static void main(String[] args) throws ConfigurationException {
System.out.println("======== TemplateLanguage ========");
public static void main(String[] args) throws ConfigurationException {
System.out.println("======== TemplateLanguage ========");
OpenAIAsyncClient client = SamplesConfig.getClient();
OpenAIAsyncClient client = SamplesConfig.getClient();
Kernel kernel = SKBuilders.kernel()
.withDefaultAIService(SKBuilders.textCompletion()
.withModelId("text-davinci-003")
.withOpenAIClient(client)
.build())
.build();
Kernel kernel = SKBuilders.kernel()
.withDefaultAIService(SKBuilders.textCompletion()
.withModelId("text-davinci-003")
.withOpenAIClient(client)
.build())
.build();
// Load native skill into the kernel skill collection, sharing its functions
// with prompt templates
// Functions loaded here are available as "time.*"
kernel.importSkill(new TimeSkill(), "time");
// Load native skill into the kernel skill collection, sharing its functions
// with prompt templates
// Functions loaded here are available as "time.*"
kernel.importSkill(new TimeSkill(), "time");
// Semantic Function invoking time.Date and time.Time native functions
String functionDefinition = """
Today is: {{time.Date}}
Current time is: {{time.Time}}
// Semantic Function invoking time.Date and time.Time native functions
String functionDefinition = """
Today is: {{time.Date}}
Current time is: {{time.Time}}
Answer to the following questions using JSON syntax, including the data used.
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
Is it weekend time (weekend/not weekend)?
""";
Answer to the following questions using JSON syntax, including the data used.
Is it morning, afternoon, evening, or night (morning/afternoon/evening/night)?
Is it weekend time (weekend/not weekend)?
""";
// This allows to see the prompt before it's sent to OpenAI
System.out.println("--- Rendered Prompt");
// This allows to see the prompt before it's sent to OpenAI
System.out.println("--- Rendered Prompt");
var promptRenderer = SKBuilders.promptTemplate()
.withPromptTemplateConfig(new PromptTemplateConfig())
.withPromptTemplate(functionDefinition)
.withPromptTemplateEngine(kernel.getPromptTemplateEngine())
.build();
var promptRenderer = SKBuilders.promptTemplate()
.withPromptTemplateConfig(new PromptTemplateConfig())
.withPromptTemplate(functionDefinition)
.withPromptTemplateEngine(kernel.getPromptTemplateEngine())
.build();
SKContext skContext = SKBuilders
.context()
.withSkills(kernel.getSkills())
.build();
SKContext skContext = SKBuilders
.context()
.withSkills(kernel.getSkills())
.build();
var renderedPrompt = promptRenderer.renderAsync(skContext);
System.out.println(renderedPrompt.block());
var renderedPrompt = promptRenderer.renderAsync(skContext);
System.out.println(renderedPrompt.block());
// Run the prompt / semantic function
var kindOfDay = kernel
.getSemanticFunctionBuilder()
.withPromptTemplate(functionDefinition)
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(
0, 0, 0, 0, 256))
.build();
// Run the prompt / semantic function
var kindOfDay = kernel
.getSemanticFunctionBuilder()
.withPromptTemplate(functionDefinition)
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0)
.topP(0)
.maxTokens(256)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.build();
// Show the result
System.out.println("--- Semantic Function result");
var result = kindOfDay.invokeAsync("").block().getResult();
System.out.println(result);
/*
* OUTPUT:
*
* --- Rendered Prompt
*
* Today is: Friday, April 28, 2023
* Current time is: 11:04:30 PM
*
* Answer to the following questions using JSON syntax, including the data used.
* Is it morning, afternoon, evening, or night
* (morning/afternoon/evening/night)?
* Is it weekend time (weekend/not weekend)?
*
* --- Semantic Function result
*
* {
* "date": "Friday, April 28, 2023",
* "time": "11:04:30 PM",
* "period": "night",
* "weekend": "weekend"
* }
*/
}
// Show the result
System.out.println("--- Semantic Function result");
var result = kindOfDay.invokeAsync("").block().getResult();
System.out.println(result);
/*
* OUTPUT:
*
* --- Rendered Prompt
*
* Today is: Friday, April 28, 2023
* Current time is: 11:04:30 PM
*
* Answer to the following questions using JSON syntax, including the data used.
* Is it morning, afternoon, evening, or night
* (morning/afternoon/evening/night)?
* Is it weekend time (weekend/not weekend)?
*
* --- Semantic Function result
*
* {
* "date": "Friday, April 28, 2023",
* "time": "11:04:30 PM",
* "period": "night",
* "weekend": "weekend"
* }
*/
}
}
@@ -13,7 +13,6 @@ import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.connectors.ai.openai.util.AzureOpenAISettings;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.settings.SettingsMap;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
@@ -90,9 +89,14 @@ public class Example08_RetryHandler {
.withKernel(kernel)
.withPromptTemplate(prompt)
.withFunctionName("summarize")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(
0.2, 0.5, 0, 0, 2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.maxTokens(2000)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.build();
kernel.registerSemanticFunction(summarizeFunc);
@@ -11,7 +11,7 @@ import com.microsoft.semantickernel.memory.MemoryStore;
import com.microsoft.semantickernel.memory.VolatileMemoryStore;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import java.util.List;
@@ -75,20 +75,20 @@ public class Example15_MemorySkill {
kernel.importSkill(memorySkill, "memory");
// Build a semantic function that saves info to memory
PromptTemplateConfig.CompletionConfig completionConfig = SKBuilders.completionConfig()
.temperature(0.2)
.topP(0.5)
.presencePenalty(0)
.frequencyPenalty(0)
.maxTokens(2000)
.build();
CompletionRequestSettings completionConfig = SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.presencePenalty(0)
.frequencyPenalty(0)
.maxTokens(2000)
.build();
CompletionSKFunction saveFunctionDefinition = SKBuilders.completionFunctions()
.withKernel(kernel)
.withPromptTemplate("{{memory.save $info}}")
.withFunctionName("save")
.withDescription("save information to memory")
.withCompletionConfig(completionConfig)
.withRequestSettings(completionConfig)
.build();
CompletionSKFunction memorySaver =
@@ -170,7 +170,7 @@ public class Example15_MemorySkill {
CompletionSKFunction recallFunctionDefinition = SKBuilders.completionFunctions()
.withKernel(kernel)
.withPromptTemplate(prompt)
.withCompletionConfig(completionConfig)
.withRequestSettings(completionConfig)
.build();
SKFunction<?> aboutMeOracle = kernel.registerSemanticFunction(recallFunctionDefinition);
@@ -101,7 +101,7 @@ public class Example51_StepwisePlanner {
System.out.println("*****************************************************");
System.out.println("Question: " + question);
StepwisePlanner planner = new DefaultStepwisePlanner(kernel, null, null, null);
StepwisePlanner planner = new DefaultStepwisePlanner(kernel, null, null);
var plan = planner.createPlan(question);
@@ -0,0 +1,14 @@
{
"schema": 1,
"description": "Sample plugin with a model and service id",
"type": "completion",
"completion": {
"max_tokens": 150,
"temperature": 0.9,
"top_p": 0.0,
"presence_penalty": 0.6,
"frequency_penalty": 0.0,
"service_id": "text-davinci-003",
"model_id": "text-davinci-003"
}
}
@@ -2,14 +2,14 @@
package com.microsoft.semantickernel.guice;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import jakarta.inject.Inject;
public interface CompletionFunctionFactory {
CompletionSKFunction createFunction(
String prompt, String name, PromptTemplateConfig.CompletionConfig completionConfig);
String prompt, String name, CompletionRequestSettings completionConfig);
class CompletionFunctionFactoryImpl implements CompletionFunctionFactory {
@Inject
@@ -19,11 +19,11 @@ public interface CompletionFunctionFactory {
public CompletionSKFunction createFunction(
String prompt,
String name,
PromptTemplateConfig.CompletionConfig completionConfig) {
CompletionRequestSettings completionConfig) {
return kernel.getSemanticFunctionBuilder()
.withPromptTemplate(prompt)
.withFunctionName(name)
.withCompletionConfig(completionConfig)
.withRequestSettings(completionConfig)
.build();
}
}
@@ -4,75 +4,81 @@ package com.microsoft.semantickernel.guice;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
public class CompletionFunctionExample {
private final CompletionFunctionFactory completionFunctionFactory;
private final CompletionFunctionFactory completionFunctionFactory;
public static void main(String[] args) {
Injector injector =
Guice.createInjector(
new SemanticKernelModule().withTextCompletionService("text-davinci-003"));
public static void main(String[] args) {
Injector injector =
Guice.createInjector(
new SemanticKernelModule().withTextCompletionService("text-davinci-003"));
CompletionFunctionExample example = injector.getInstance(CompletionFunctionExample.class);
example.run();
}
CompletionFunctionExample example = injector.getInstance(CompletionFunctionExample.class);
example.run();
}
@Inject
public CompletionFunctionExample(CompletionFunctionFactory completionFunctionFactory) {
this.completionFunctionFactory = completionFunctionFactory;
}
@Inject
public CompletionFunctionExample(CompletionFunctionFactory completionFunctionFactory) {
this.completionFunctionFactory = completionFunctionFactory;
}
public void run() {
String prompt = "{{$input}}\n" + "Summarize the content above.";
public void run() {
String prompt = "{{$input}}\n" + "Summarize the content above.";
String text =
"\n"
+ "Demo (ancient Greek poet)\n"
+ "From Wikipedia, the free encyclopedia\n"
+ "Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the\n"
+ "Roman period, known for a single epigram, engraved upon the Colossus of\n"
+ "Memnon, which bears her name. She speaks of herself therein as a lyric\n"
+ "poetess dedicated to the Muses, but nothing is known of her life.[1]\n"
+ "Identity\n"
+ "Demo was evidently Greek, as her name, a traditional epithet of Demeter,\n"
+ "signifies. The name was relatively common in the Hellenistic world, in\n"
+ "Egypt and elsewhere, and she cannot be further identified. The date of her\n"
+ "visit to the Colossus of Memnon cannot be established with certainty, but\n"
+ "internal evidence on the left leg suggests her poem was inscribed there at\n"
+ "some point in or after AD 196.[2]\n"
+ "Epigram\n"
+ "There are a number of graffiti inscriptions on the Colossus of Memnon.\n"
+ "Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac\n"
+ "couplets, entitled and presumably authored by \"Demo\" or \"Damo\" (the\n"
+ "Greek inscription is difficult to read), is a dedication to the Muses.[2]\n"
+ "The poem is traditionally published with the works of Balbilla, though the\n"
+ "internal evidence suggests a different author.[1]\n"
+ "In the poem, Demo explains that Memnon has shown her special respect. In\n"
+ "return, Demo offers the gift for poetry, as a gift to the hero. At the end\n"
+ "of this epigram, she addresses Memnon, highlighting his divine status by\n"
+ "recalling his strength and holiness.[2]\n"
+ "Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic\n"
+ "dialect. The language indicates she was knowledgeable in Homeric\n"
+ "poetry—'bearing a pleasant gift', for example, alludes to the use of that\n"
+ "phrase throughout the Iliad and Odyssey.[a][2];";
String text =
"\n"
+ "Demo (ancient Greek poet)\n"
+ "From Wikipedia, the free encyclopedia\n"
+ "Demo or Damo (Greek: Δεμώ, Δαμώ; fl. c. AD 200) was a Greek woman of the\n"
+ "Roman period, known for a single epigram, engraved upon the Colossus of\n"
+ "Memnon, which bears her name. She speaks of herself therein as a lyric\n"
+ "poetess dedicated to the Muses, but nothing is known of her life.[1]\n"
+ "Identity\n"
+ "Demo was evidently Greek, as her name, a traditional epithet of Demeter,\n"
+ "signifies. The name was relatively common in the Hellenistic world, in\n"
+ "Egypt and elsewhere, and she cannot be further identified. The date of her\n"
+ "visit to the Colossus of Memnon cannot be established with certainty, but\n"
+ "internal evidence on the left leg suggests her poem was inscribed there at\n"
+ "some point in or after AD 196.[2]\n"
+ "Epigram\n"
+ "There are a number of graffiti inscriptions on the Colossus of Memnon.\n"
+ "Following three epigrams by Julia Balbilla, a fourth epigram, in elegiac\n"
+ "couplets, entitled and presumably authored by \"Demo\" or \"Damo\" (the\n"
+ "Greek inscription is difficult to read), is a dedication to the Muses.[2]\n"
+ "The poem is traditionally published with the works of Balbilla, though the\n"
+ "internal evidence suggests a different author.[1]\n"
+ "In the poem, Demo explains that Memnon has shown her special respect. In\n"
+ "return, Demo offers the gift for poetry, as a gift to the hero. At the end\n"
+ "of this epigram, she addresses Memnon, highlighting his divine status by\n"
+ "recalling his strength and holiness.[2]\n"
+ "Demo, like Julia Balbilla, writes in the artificial and poetic Aeolic\n"
+ "dialect. The language indicates she was knowledgeable in Homeric\n"
+ "poetry—'bearing a pleasant gift', for example, alludes to the use of that\n"
+ "phrase throughout the Iliad and Odyssey.[a][2];";
SKContext summary =
completionFunctionFactory
.createFunction(
prompt,
"summarize",
new PromptTemplateConfig.CompletionConfig(
0.2, 0.5, 0, 0, 2000))
.invokeAsync(text)
.block();
SKContext summary =
completionFunctionFactory
.createFunction(
prompt,
"summarize",
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.maxTokens(2000)
.frequencyPenalty(0)
.presencePenalty(0)
.build())
.invokeAsync(text)
.block();
if (summary != null) {
System.out.println("Result: " + summary.getResult());
} else {
System.out.println("Null result");
}
if (summary != null) {
System.out.println("Result: " + summary.getResult());
} else {
System.out.println("Null result");
}
}
}
@@ -10,13 +10,14 @@ import com.microsoft.semantickernel.memory.SemanticTextMemory;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings.Builder;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
public class SKBuilders {
// Prevent creating object
private SKBuilders() {}
@@ -60,9 +61,9 @@ public class SKBuilders {
return BuildersSingleton.INST.getInstance(SKContext.Builder.class);
}
public static PromptTemplateConfig.CompletionConfigBuilder completionConfig() {
return BuildersSingleton.INST.getInstance(
PromptTemplateConfig.CompletionConfigBuilder.class);
public static Builder completionRequestSettings() {
// No need to look up as this is in the API
return new Builder();
}
@SuppressWarnings("unchecked")
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.ai;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nullable;
/** Request settings for an AI request. */
public class AIRequestSettings {
/**
* Service identifier. This identifies a service and is set when the AI service is registered.
*/
@JsonProperty("service_id")
@Nullable
private final String serviceId;
/// <summary>
/// Model identifier.
/// This identifies the AI model these settings are configured for e.g., gpt-4, gpt-3.5-turbo
/// </summary>
@JsonProperty("model_id")
@Nullable
private final String modelId;
@JsonCreator
public AIRequestSettings(
@JsonProperty("service_id") @Nullable String serviceId,
@JsonProperty("model_id") @Nullable String modelId) {
this.serviceId = serviceId;
this.modelId = modelId;
}
@Nullable
public String getServiceId() {
return serviceId;
}
@Nullable
public String getModelId() {
return modelId;
}
}
@@ -10,7 +10,6 @@ import com.microsoft.semantickernel.memory.SemanticTextMemory;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
@@ -31,8 +30,6 @@ public enum BuildersSingleton {
private static final String FALLBACK_CHAT_COMPLETION_BUILDER_CLASS =
"com.microsoft.semantickernel.connectors.ai.openai.chatcompletion.OpenAIChatCompletion$Builder";
private static final String FALLBACK_COMPLETION_CONFIG_BUILDER_CLASS =
"com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig$CompletionConfigBuilder";
private static final String FALLBACK_COMPLETION_FUNCTION_BUILDER_CLASS =
"com.microsoft.semantickernel.orchestration.DefaultCompletionSKFunction$Builder";
private static final String FALLBACK_CONTEXT_BUILDER_CLASS =
@@ -65,9 +62,6 @@ public enum BuildersSingleton {
try {
// Keep this list in alphabetical order by fallback variable name
registerBuilder(ChatCompletion.Builder.class, FALLBACK_CHAT_COMPLETION_BUILDER_CLASS);
registerBuilder(
PromptTemplateConfig.CompletionConfigBuilder.class,
FALLBACK_COMPLETION_CONFIG_BUILDER_CLASS);
registerBuilder(
CompletionSKFunction.Builder.class, FALLBACK_COMPLETION_FUNCTION_BUILDER_CLASS);
registerBuilder(SKContext.Builder.class, FALLBACK_CONTEXT_BUILDER_CLASS);
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.ai.AIRequestSettings;
import com.microsoft.semantickernel.services.AIServiceSupplier;
import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
import java.util.List;
import javax.annotation.Nullable;
public abstract class AIFunction<RequestConfiguration extends AIRequestSettings>
extends AbstractSkFunction<RequestConfiguration>
implements SKFunction<RequestConfiguration> {
@Nullable private AIServiceSupplier aiServiceSupplier;
/**
* Constructor.
*
* @param parameters The parameters of the function.
* @param skillName The name of the skill.
* @param functionName The name of the function.
* @param description The description of the function.
* @param returnParameters
* @param skillsSupplier The skill supplier.
*/
public AIFunction(
List<ParameterView> parameters,
String skillName,
String functionName,
String description,
List<ParameterView> returnParameters,
@Nullable KernelSkillsSupplier skillsSupplier,
@Nullable AIServiceSupplier aiServiceSupplier) {
super(parameters, skillName, functionName, description, returnParameters, skillsSupplier);
this.aiServiceSupplier = aiServiceSupplier;
}
protected void setServiceSupplier(@Nullable AIServiceSupplier aiServiceSupplier) {
this.aiServiceSupplier = aiServiceSupplier;
}
@Nullable
protected AIServiceSupplier getAiServiceSupplier() {
return aiServiceSupplier;
}
}
@@ -84,6 +84,12 @@ public abstract class AbstractSkFunction<RequestConfiguration>
return skillsSupplier;
}
@Override
public Mono<SKContext> invokeAsync(
@Nullable String input, @Nullable RequestConfiguration settings) {
return invokeAsync(input, null, settings);
}
@Override
public Mono<SKContext> invokeAsync(
@Nullable String input,
@@ -15,6 +15,7 @@ import reactor.core.publisher.Mono;
* the function is invoked
*/
public interface SKFunction<RequestConfiguration> {
/**
* Returns a description of the function, including parameters.
*
@@ -77,6 +78,16 @@ public interface SKFunction<RequestConfiguration> {
@CheckReturnValue
Mono<SKContext> invokeAsync(SKContext context, @Nullable RequestConfiguration settings);
/**
* Invokes the function with the given context and settings
*
* @param input input provided to the function
* @param settings Configuration of the request
* @return an updated context with the result of the request
*/
@CheckReturnValue
Mono<SKContext> invokeAsync(String input, @Nullable RequestConfiguration settings);
/**
* @return The name of the skill that this function is within
*/
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.semanticfunctions;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Collections;
import java.util.List;
/** Input configuration (list of all input parameters for a semantic function). */
public class InputConfig {
public final List<InputParameter> parameters;
@JsonCreator
public InputConfig(@JsonProperty("parameters") List<InputParameter> parameters) {
this.parameters = Collections.unmodifiableList(parameters);
}
public List<InputParameter> getParameters() {
return parameters;
}
}
@@ -0,0 +1,51 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.semanticfunctions;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
/** Input parameter for semantic functions */
public class InputParameter {
private final String name;
private final String description;
private final String defaultValue;
@JsonCreator
public InputParameter(
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("defaultValue") String defaultValue) {
this.name = name;
this.description = description;
this.defaultValue = defaultValue;
}
/**
* Name of the parameter to pass to the function. e.g. when using "{{$input}}" the name is
* "input", when using "{{$style}}" the name is "style", etc.
*
* @return name
*/
public String getName() {
return name;
}
/**
* Parameter description for UI apps and planner. Localization is not supported here.
*
* @return description
*/
public String getDescription() {
return description;
}
/**
* Default value when nothing is provided
*
* @return the default value
*/
public String getDefaultValue() {
return defaultValue;
}
}
@@ -4,366 +4,17 @@ package com.microsoft.semantickernel.semanticfunctions;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import reactor.util.annotation.Nullable;
import javax.annotation.Nullable;
/** Prompt template configuration */
@JsonIgnoreProperties(ignoreUnknown = true)
public class PromptTemplateConfig {
private final CompletionConfig completionConfig;
private final CompletionRequestSettings completionRequestSettings;
private final InputConfig input;
/**
* A returns the configuration for the text completion
*
* @return CompletionConfig
*/
public CompletionConfig getCompletionConfig() {
return completionConfig;
}
public int getSchema() {
return schema;
}
public String getType() {
return type;
}
/** Builder for CompletionConfig */
public static class CompletionConfigBuilder implements SemanticKernelBuilder<CompletionConfig> {
private CompletionConfig completionConfig;
public CompletionConfigBuilder() {
completionConfig = new CompletionConfig();
}
public CompletionConfigBuilder(CompletionConfig completionConfig) {
this.completionConfig = completionConfig;
}
public CompletionConfigBuilder temperature(double temperature) {
return new CompletionConfigBuilder(
new CompletionConfig(
temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder topP(double topP) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder presencePenalty(double presencePenalty) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder frequencyPenalty(double frequencyPenalty) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder maxTokens(int maxTokens) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences));
}
public CompletionConfigBuilder stopSequences(List<String> stopSequences) {
return new CompletionConfigBuilder(
new CompletionConfig(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
stopSequences));
}
public CompletionConfig build() {
return completionConfig;
}
}
public InputConfig getInput() {
return input;
}
/** Completion configuration parameters */
public static class CompletionConfig implements Buildable {
/*
/// <summary>
/// Sampling temperature to use, between 0 and 2. Higher values will make the output more random.
/// Lower values will make it more focused and deterministic.
/// </summary>
[JsonPropertyName("temperature")]
[JsonPropertyOrder(1)]
*/
private final double temperature;
/*
/// <summary>
/// Cut-off of top_p probability mass of tokens to consider.
/// For example, 0.1 means only the tokens comprising the top 10% probability mass are considered.
/// </summary>
[JsonPropertyName("top_p")]
[JsonPropertyOrder(2)]
*/
private final double topP;
/*
/// <summary>
/// Lowers the probability of a word appearing if it already appeared in the predicted text.
/// Unlike the frequency penalty, the presence penalty does not depend on the frequency at which words
/// appear in past predictions.
/// </summary>
[JsonPropertyName("presence_penalty")]
[JsonPropertyOrder(3)]
*/
private final double presencePenalty;
/*
/// <summary>
/// Controls the model’s tendency to repeat predictions. The frequency penalty reduces the probability
/// of words that have already been generated. The penalty depends on how many times a word has already
/// occurred in the prediction.
/// </summary>
[JsonPropertyName("frequency_penalty")]
[JsonPropertyOrder(4)]
*/
private final double frequencyPenalty;
/*
/// <summary>
/// Maximum number of tokens that can be generated.
/// </summary>
[JsonPropertyName("max_tokens")]
[JsonPropertyOrder(5)]*/
private final int maxTokens; // { get; set; } = 256;
/*
/// <summary>
/// Stop sequences are optional sequences that tells the AI model when to stop generating tokens.
/// </summary>
[JsonPropertyName("stop_sequences")]
[JsonPropertyOrder(6)]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
*/
public final List<String> stopSequences; // { get; set; } = new();
/**
* The maximum number of completions to generate for each prompt. This is used by the
* CompletionService to generate multiple completions for a single prompt.
*/
private final Integer bestOf;
/**
* A unique identifier representing your end-user, which can help OpenAI to monitor and
* detect abuse
*/
private final String user;
public CompletionConfig() {
this(0.0, 0.0, 0.0, 0.0, 256, 1, "", new ArrayList<>());
}
public CompletionConfig(
double temperature,
double topP,
double presencePenalty,
double frequencyPenalty,
int maxTokens) {
this(
temperature,
topP,
presencePenalty,
frequencyPenalty,
maxTokens,
1,
"",
new ArrayList<>());
}
@JsonCreator
public CompletionConfig(
@JsonProperty("temperature") double temperature,
@JsonProperty("top_p") double topP,
@JsonProperty("presence_penalty") double presencePenalty,
@JsonProperty("frequency_penalty") double frequencyPenalty,
@JsonProperty("max_tokens") int maxTokens,
@JsonProperty("best_of") int bestOf,
@JsonProperty("user") String user,
@JsonProperty(value = "stop_sequences") List<String> stopSequences) {
this.temperature = temperature;
this.topP = topP;
this.presencePenalty = presencePenalty;
this.frequencyPenalty = frequencyPenalty;
this.maxTokens = maxTokens;
// bestOf must be at least 1
this.bestOf = Math.max(1, bestOf);
if (user == null) {
user = "";
}
this.user = user;
if (stopSequences == null) {
stopSequences = new ArrayList<>();
}
this.stopSequences = stopSequences;
}
public double getTemperature() {
return temperature;
}
public double getTopP() {
return topP;
}
public double getPresencePenalty() {
return presencePenalty;
}
public double getFrequencyPenalty() {
return frequencyPenalty;
}
public int getMaxTokens() {
return maxTokens;
}
/**
* The maximum number of completions to generate for each prompt. This is used by the
* CompletionService to generate multiple completions for a single prompt.
*/
public int getBestOf() {
return bestOf;
}
/**
* A unique identifier representing your end-user, which can help OpenAI to monitor and
* detect abuse
*/
public String getUser() {
return user;
}
public SemanticKernelBuilder<CompletionConfig> builder() {
return BuildersSingleton.INST.getInstance(CompletionConfigBuilder.class);
}
public List<String> getStopSequences() {
return Collections.unmodifiableList(stopSequences);
}
}
/** Input parameter for semantic functions */
public static class InputParameter {
private final String name;
private final String description;
private final String defaultValue;
@JsonCreator
public InputParameter(
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("defaultValue") String defaultValue) {
this.name = name;
this.description = description;
this.defaultValue = defaultValue;
}
/**
* Name of the parameter to pass to the function. e.g. when using "{{$input}}" the name is
* "input", when using "{{$style}}" the name is "style", etc.
*
* @return name
*/
public String getName() {
return name;
}
/**
* Parameter description for UI apps and planner. Localization is not supported here.
*
* @return description
*/
public String getDescription() {
return description;
}
/**
* Default value when nothing is provided
*
* @return the default value
*/
public String getDefaultValue() {
return defaultValue;
}
}
/** Input configuration (list of all input parameters for a semantic function). */
public static class InputConfig {
public final List<InputParameter> parameters;
@JsonCreator
public InputConfig(@JsonProperty("parameters") List<InputParameter> parameters) {
this.parameters = Collections.unmodifiableList(parameters);
}
public List<InputParameter> getParameters() {
return parameters;
}
}
private final int schema;
private final String type; // { get; set; } = "completion";
private final String description;
@@ -371,13 +22,15 @@ public class PromptTemplateConfig {
this("", "", null);
}
public PromptTemplateConfig(CompletionConfig completionConfig) {
this(1, "", "", completionConfig, new InputConfig(new ArrayList<>()));
public PromptTemplateConfig(CompletionRequestSettings completionRequestSettings) {
this(1, "", "", completionRequestSettings, new InputConfig(new ArrayList<>()));
}
public PromptTemplateConfig(
String description, String type, @Nullable CompletionConfig completionConfig) {
this(1, description, type, completionConfig, new InputConfig(new ArrayList<>()));
String description,
String type,
@Nullable CompletionRequestSettings completionRequestSettings) {
this(1, description, type, completionRequestSettings, new InputConfig(new ArrayList<>()));
}
@JsonCreator
@@ -385,15 +38,16 @@ public class PromptTemplateConfig {
@JsonProperty("schema") int schema,
@JsonProperty("description") String description,
@JsonProperty("type") String type,
@Nullable @JsonProperty("completion") CompletionConfig completionConfig,
@Nullable @JsonProperty("completion")
CompletionRequestSettings completionRequestSettings,
@Nullable @JsonProperty("input") InputConfig input) {
if (completionConfig == null) {
completionConfig = new CompletionConfig();
if (completionRequestSettings == null) {
completionRequestSettings = new CompletionRequestSettings();
}
this.schema = schema;
this.description = description;
this.type = type;
this.completionConfig = completionConfig;
this.completionRequestSettings = completionRequestSettings;
if (input == null) {
input = new InputConfig(new ArrayList<>());
}
@@ -408,4 +62,25 @@ public class PromptTemplateConfig {
public String getDescription() {
return description;
}
/**
* A returns the configuration for the text completion
*
* @return CompletionRequestSettings
*/
public CompletionRequestSettings getCompletionRequestSettings() {
return completionRequestSettings;
}
public int getSchema() {
return schema;
}
public String getType() {
return type;
}
public InputConfig getInput() {
return input;
}
}
@@ -0,0 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.services;
public interface AIServiceSupplier {
<T extends AIService> T get(String serviceId, Class<T> clazz);
}
@@ -1,14 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.textcompletion;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.microsoft.semantickernel.ai.AIRequestSettings;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** Settings for a text completion request */
public class CompletionRequestSettings {
public class CompletionRequestSettings extends AIRequestSettings implements Buildable {
/**
* Temperature controls the randomness of the completion. The higher the temperature, the more
* random the completion
@@ -79,7 +84,9 @@ public class CompletionRequestSettings {
maxTokens,
1,
"",
Collections.emptyList());
Collections.emptyList(),
null,
null);
}
/**
@@ -101,27 +108,39 @@ public class CompletionRequestSettings {
* @param stopSequences Sequences where the completion will stop generating further tokens.
*/
public CompletionRequestSettings(
double temperature,
double topP,
double presencePenalty,
double frequencyPenalty,
int maxTokens,
int bestOf,
String user,
List<String> stopSequences) {
@JsonProperty("temperature") double temperature,
@JsonProperty("top_p") double topP,
@JsonProperty("presence_penalty") double presencePenalty,
@JsonProperty("frequency_penalty") double frequencyPenalty,
@JsonProperty("max_tokens") int maxTokens,
@JsonProperty("best_of") int bestOf,
@JsonProperty("user") String user,
@JsonProperty(value = "stop_sequences") List<String> stopSequences,
@JsonProperty(value = "service_id") @Nullable String serviceId,
@JsonProperty(value = "model_id") @Nullable String modelId) {
super(serviceId, modelId);
this.temperature = temperature;
this.topP = topP;
this.presencePenalty = presencePenalty;
this.frequencyPenalty = frequencyPenalty;
this.maxTokens = maxTokens;
this.bestOf = bestOf;
// bestOf must be at least 1
this.bestOf = Math.max(1, bestOf);
if (user == null) {
user = "";
}
this.user = user;
this.stopSequences = new ArrayList<>(stopSequences);
if (stopSequences == null) {
stopSequences = new ArrayList<>();
}
this.stopSequences = stopSequences;
}
/** Create a new settings object with default values. */
public CompletionRequestSettings() {
this(0, 0, 0, 0, 256, 1, "", new ArrayList<>());
this(0, 0, 0, 0, 256, 1, "", new ArrayList<>(), null, null);
}
public CompletionRequestSettings(@Nonnull CompletionRequestSettings requestSettings) {
@@ -133,25 +152,9 @@ public class CompletionRequestSettings {
requestSettings.getMaxTokens(),
requestSettings.getBestOf(),
requestSettings.getUser(),
requestSettings.getStopSequences());
}
/**
* Create a new settings object with the values from another settings object.
*
* @param config The config to copy values from
*/
public static CompletionRequestSettings fromCompletionConfig(
PromptTemplateConfig.CompletionConfig config) {
return new CompletionRequestSettings(
config.getTemperature(),
config.getTopP(),
config.getPresencePenalty(),
config.getFrequencyPenalty(),
config.getMaxTokens(),
config.getBestOf(),
config.getUser(),
config.getStopSequences());
requestSettings.getStopSequences(),
requestSettings.getServiceId(),
requestSettings.getModelId());
}
/**
@@ -212,4 +215,172 @@ public class CompletionRequestSettings {
public String getUser() {
return user;
}
/** Builder for CompletionRequestSettings */
public static class Builder implements SemanticKernelBuilder<CompletionRequestSettings> {
private final CompletionRequestSettings completionConfig;
public Builder() {
completionConfig = new CompletionRequestSettings();
}
public Builder(CompletionRequestSettings completionConfig) {
this.completionConfig = completionConfig;
}
public Builder temperature(double temperature) {
return new Builder(
new CompletionRequestSettings(
temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder topP(double topP) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder presencePenalty(double presencePenalty) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder frequencyPenalty(double frequencyPenalty) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder maxTokens(int maxTokens) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder bestOf(int bestOf) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
bestOf,
completionConfig.user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder user(String user) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder stopSequences(List<String> stopSequences) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
stopSequences,
completionConfig.getServiceId(),
completionConfig.getModelId()));
}
public Builder serviceId(String serviceId) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences,
serviceId,
completionConfig.getModelId()));
}
public Builder modelId(String modelId) {
return new Builder(
new CompletionRequestSettings(
completionConfig.temperature,
completionConfig.topP,
completionConfig.presencePenalty,
completionConfig.frequencyPenalty,
completionConfig.maxTokens,
completionConfig.bestOf,
completionConfig.user,
completionConfig.stopSequences,
completionConfig.getServiceId(),
modelId));
}
public CompletionRequestSettings build() {
return completionConfig;
}
}
}
@@ -39,7 +39,7 @@ public interface CompletionSKFunction extends SKFunction<CompletionRequestSettin
Builder withPromptTemplateConfig(PromptTemplateConfig config);
Builder withCompletionConfig(PromptTemplateConfig.CompletionConfig completionConfig);
Builder withRequestSettings(CompletionRequestSettings completionRequestSettings);
Builder withSemanticFunctionConfig(SemanticFunctionConfig functionConfig);
@@ -9,6 +9,7 @@ import com.microsoft.semantickernel.orchestration.FunctionNotRegisteredException
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
import com.microsoft.semantickernel.services.AIServiceSupplier;
import com.microsoft.semantickernel.skilldefinition.FunctionView;
import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
@@ -51,8 +52,15 @@ public class DefaultCompletionSKFunction
String description,
CompletionRequestSettings requestSettings,
SemanticFunctionConfig functionConfig,
@Nullable KernelSkillsSupplier kernelSkillsSupplier) {
super(parameters, skillName, functionName, description, kernelSkillsSupplier);
@Nullable KernelSkillsSupplier kernelSkillsSupplier,
@Nullable AIServiceSupplier aiServiceSupplier) {
super(
parameters,
skillName,
functionName,
description,
kernelSkillsSupplier,
aiServiceSupplier);
// TODO
// Verify.NotNull(delegateFunction, "The function delegate is empty");
// Verify.ValidSkillName(skillName);
@@ -163,13 +171,20 @@ public class DefaultCompletionSKFunction
settings = this.requestSettings;
}
if (this.aiService.get() == null) {
TextCompletion service;
if (settings.getServiceId() != null && getAiServiceSupplier() != null) {
service = getAiServiceSupplier().get(settings.getServiceId(), TextCompletion.class);
} else {
service = this.aiService.get();
}
if (service == null) {
throw new IllegalStateException("Failed to initialise aiService");
}
CompletionRequestSettings finalSettings = settings;
return function.run(this.aiService.get(), finalSettings, context)
return function.run(service, finalSettings, context)
.map(
result -> {
return context.update(result.getVariables());
@@ -230,7 +245,16 @@ public class DefaultCompletionSKFunction
};
this.setSkillsSupplier(kernel::getSkills);
this.aiService = () -> kernel.getService(null, TextCompletion.class);
this.setServiceSupplier(kernel::getService);
this.aiService =
() ->
kernel.getService(
this.functionConfig
.getConfig()
.getCompletionRequestSettings()
.getServiceId(),
TextCompletion.class);
}
private static Mono<SKContext> performCompletionRequest(
@@ -284,10 +308,9 @@ public class DefaultCompletionSKFunction
@Nullable private String functionName = null;
@Nullable private String skillName = null;
@Nullable private String description = null;
private PromptTemplateConfig.CompletionConfig completionConfig =
new PromptTemplateConfig.CompletionConfig();
@Nullable private SemanticFunctionConfig functionConfig = null;
@Nullable private PromptTemplateConfig promptTemplateConfig = null;
@Nullable private CompletionRequestSettings completionRequestSettings;
@Override
public CompletionSKFunction build() {
@@ -320,7 +343,8 @@ public class DefaultCompletionSKFunction
if (promptTemplateConfig == null) {
promptTemplateConfig =
new PromptTemplateConfig(description, "completion", completionConfig);
new PromptTemplateConfig(
description, "completion", completionRequestSettings);
}
PromptTemplate template =
@@ -335,8 +359,7 @@ public class DefaultCompletionSKFunction
}
CompletionRequestSettings requestSettings =
CompletionRequestSettings.fromCompletionConfig(
functionConfig.getConfig().getCompletionConfig());
functionConfig.getConfig().getCompletionRequestSettings();
PromptTemplate promptTemplate = functionConfig.getTemplate();
@@ -348,6 +371,7 @@ public class DefaultCompletionSKFunction
functionConfig.getConfig().getDescription(),
requestSettings,
functionConfig,
null,
null);
kernel.registerSemanticFunction(function);
@@ -374,9 +398,9 @@ public class DefaultCompletionSKFunction
}
@Override
public CompletionSKFunction.Builder withCompletionConfig(
PromptTemplateConfig.CompletionConfig completionConfig) {
this.completionConfig = completionConfig;
public CompletionSKFunction.Builder withRequestSettings(
CompletionRequestSettings completionRequestSettings) {
this.completionRequestSettings = completionRequestSettings;
return this;
}
@@ -2,7 +2,9 @@
package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.ai.AIRequestSettings;
import com.microsoft.semantickernel.memory.NullMemory;
import com.microsoft.semantickernel.services.AIServiceSupplier;
import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
import java.util.Collections;
@@ -16,23 +18,24 @@ import reactor.core.publisher.Mono;
// cref="Action"/>,
/// with additional methods required by the kernel.
/// </summary>
public abstract class DefaultSemanticSKFunction<RequestConfiguration>
extends AbstractSkFunction<RequestConfiguration>
implements SKFunction<RequestConfiguration> {
public abstract class DefaultSemanticSKFunction<RequestConfiguration extends AIRequestSettings>
extends AIFunction<RequestConfiguration> {
public DefaultSemanticSKFunction(
List<ParameterView> parameters,
String skillName,
String functionName,
String description,
@Nullable KernelSkillsSupplier kernelSkillsSupplier) {
@Nullable KernelSkillsSupplier kernelSkillsSupplier,
@Nullable AIServiceSupplier aiServiceSupplier) {
super(
parameters,
skillName,
functionName,
description,
Collections.emptyList(),
kernelSkillsSupplier);
kernelSkillsSupplier,
aiServiceSupplier);
}
@Override
@@ -11,7 +11,8 @@ import com.azure.ai.openai.models.Completions;
import com.azure.ai.openai.models.CompletionsOptions;
import com.microsoft.semantickernel.connectors.ai.openai.textcompletion.OpenAITextCompletion;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import java.util.Arrays;
@@ -50,8 +51,14 @@ public class DefaultKernelTest {
.withKernel(kernel)
.withPromptTemplate(prompt)
.withFunctionName("ChatBot")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0.7, 0.5, 0, 0, 2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.7)
.topP(0.5)
.presencePenalty(0)
.frequencyPenalty(0)
.maxTokens(2000)
.build())
.build();
SKContext readOnlySkContext =
@@ -261,14 +268,14 @@ public class DefaultKernelTest {
openAIAsyncClient.getCompletionsStream(
Mockito.any(String.class),
Mockito.argThat(
it ->
response.getT1()
.matches(
it.getPrompt()
.get(
it.getPrompt()
.size()
- 1)))))
it -> {
return response.getT1()
.matches(
it.getPrompt()
.get(
it.getPrompt().size()
- 1));
})))
.then(
(arg) -> {
response.getT3()
@@ -371,8 +378,14 @@ public class DefaultKernelTest {
.withKernel(kernel)
.withPromptTemplate(prompt)
.withFunctionName("summarize")
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0.2, 0.5, 0, 0, 2000))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.presencePenalty(0)
.frequencyPenalty(0)
.maxTokens(2000)
.build())
.build();
Mono<SKContext> mono = summarize.invokeAsync(text);
@@ -402,4 +415,134 @@ public class DefaultKernelTest {
.get(0)
.equals(expected)));
}
@Test
public void modelCanBeOverriddenInTheInvocationTest() {
String model = "a-model";
String expectedResponse = "foo";
OpenAIAsyncClient openAIAsyncClient =
mockCompletionOpenAIAsyncClient("block", expectedResponse);
Kernel kernel = buildKernel(model, openAIAsyncClient);
String text = "A block of text\n";
String prompt = "{{$input}}\n" + "Summarize the content above.";
String expectedPrompt = "A block of text\n\nSummarize the content above.";
CompletionSKFunction summarize =
SKBuilders.completionFunctions()
.withKernel(kernel)
.withPromptTemplate(prompt)
.withFunctionName("summarize")
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.presencePenalty(0)
.frequencyPenalty(0)
.maxTokens(2000)
.build())
.build();
Mono<SKContext> mono = summarize.invokeAsync(text);
SKContext result = mono.block();
assertCompletionsWasCalledWithModelAndText(openAIAsyncClient, model, expectedPrompt);
assertTheResultEquals(result, expectedResponse);
// Invoke again, this time overriding with a different model
mono =
summarize.invokeAsync(
text,
SKBuilders.completionRequestSettings().modelId("text-ada-001").build());
result = mono.block();
assertCompletionsWasCalledWithModelAndText(
openAIAsyncClient, "text-ada-001", expectedPrompt);
assertTheResultEquals(result, expectedResponse);
}
@Test
public void modelAndServiceCanBeOverriddenInTheConfigFileTest() {
String expectedResponse = "foo";
OpenAIAsyncClient openAIAsyncClient =
mockCompletionOpenAIAsyncClient("Tell me a joke.", expectedResponse);
TextCompletion textCompletion =
new OpenAITextCompletion(openAIAsyncClient, "model-that-should-not-be-used");
Kernel kernel =
SKBuilders.kernel()
.withAIService("a-service-id", textCompletion, false, TextCompletion.class)
.build();
ReadOnlyFunctionCollection skills =
kernel.importSkillFromResources(
"Plugins", "ExamplePlugins", "ExampleFunctionWithService");
SKFunction<?> function = skills.getFunction("ExampleFunctionWithService");
SKContext result = function.invokeAsync().block();
assertCompletionsWasCalledWithModelAndText(
openAIAsyncClient, "a-model-id", "Tell me a joke.");
assertTheResultEquals(result, expectedResponse);
}
@Test
public void serviceCanBeOverriddenInTheInvocationTest() {
String model = "a-model";
String expectedResponse = "foo";
OpenAIAsyncClient openAIAsyncClient =
mockCompletionOpenAIAsyncClient("block", expectedResponse);
TextCompletion textCompletion = new OpenAITextCompletion(openAIAsyncClient, model);
Kernel kernel =
SKBuilders.kernel()
.withAIService("a-service-id", textCompletion, false, TextCompletion.class)
.build();
String text = "A block of text\n";
String prompt = "{{$input}}\n" + "Summarize the content above.";
String expectedPrompt = "A block of text\n\nSummarize the content above.";
CompletionSKFunction summarize =
SKBuilders.completionFunctions()
.withKernel(kernel)
.withPromptTemplate(prompt)
.withFunctionName("summarize")
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0.2)
.topP(0.5)
.presencePenalty(0)
.frequencyPenalty(0)
.maxTokens(2000)
.build())
.build();
Mono<SKContext> mono = summarize.invokeAsync(text);
SKContext result = mono.block();
assertCompletionsWasCalledWithModelAndText(openAIAsyncClient, model, expectedPrompt);
assertTheResultEquals(result, expectedResponse);
// Invoke again, this time overriding with a different model
mono =
summarize.invokeAsync(
text,
SKBuilders.completionRequestSettings().modelId("text-ada-001").build());
result = mono.block();
assertCompletionsWasCalledWithModelAndText(
openAIAsyncClient, "text-ada-001", expectedPrompt);
assertTheResultEquals(result, expectedResponse);
}
}
@@ -85,7 +85,7 @@ public class StepwisePlannerTest {
System.out.println("*****************************************************");
System.out.println("Question: " + question);
StepwisePlanner planner = new DefaultStepwisePlanner(kernel, null, null, null);
StepwisePlanner planner = new DefaultStepwisePlanner(kernel, null, null);
Plan plan = planner.createPlan(question);
@@ -71,8 +71,14 @@ public class Example06TemplateLanguageTest {
kernel.getSemanticFunctionBuilder()
.withKernel(kernel)
.withPromptTemplate(functionDefinition)
.withCompletionConfig(
new PromptTemplateConfig.CompletionConfig(0, 0, 0, 0, 256))
.withRequestSettings(
SKBuilders.completionRequestSettings()
.temperature(0)
.topP(0)
.presencePenalty(0)
.frequencyPenalty(0)
.maxTokens(256)
.build())
.build();
Assertions.assertEquals("A-RESULT", kindOfDay.invokeAsync("").block().getResult());
@@ -0,0 +1,14 @@
{
"schema": 1,
"description": "Sample plugin with a model and service id",
"type": "completion",
"completion": {
"max_tokens": 150,
"temperature": 0.9,
"top_p": 0.0,
"presence_penalty": 0.6,
"frequency_penalty": 0.0,
"service_id": "a-service-id",
"model_id": "a-model-id"
}
}