Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions docs/guides/ORCHESTRATION_CHAT_COMPLETION.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,22 @@ var result = client.chatCompletion(prompt, configWithTemplate);

In this case the template is defined with the placeholder `{{?language}}` which is replaced by the value `German` in the input parameters.

Alternatively, you can use already prepared templates from the [Prompt Registry](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/prompt-registry) of SAP AI Core instead of passing a template in the request yourself.

```java
var template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
var configWithTemplate = config.withTemplateConfig(template);

var inputParams = Map.of("language", "Italian", "input", "cloud ERP systems");
var prompt = new OrchestrationPrompt(inputParams);

var result = client.chatCompletion(prompt, configWithTemplate);
```

A prompt template can be referenced either by ID as above, or by using a combination of name, scenario, and version. For details on storing a template in the Prompt Registry, refer to [this guide](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-prompt-template-imperative).

You can find [some examples](https://github.com/SAP/ai-sdk-java/tree/main/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java) in our Spring Boot application demonstrating using templates from Prompt Registry.

## Message history

Include a message history to maintain context in the conversation:
Expand Down
2 changes: 1 addition & 1 deletion docs/release-notes/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

### ✨ New Functionality

-
- [Orchestration] [Prompt templates can be consumed from registry.](https://github.com/SAP/ai-sdk-java/tree/main/docs/guides/ORCHESTRATION_CHAT_COMPLETION.md#Chat-completion-with-Templates)

### 📈 Improvements

Expand Down
4 changes: 2 additions & 2 deletions orchestration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
</developers>
<properties>
<project.rootdir>${project.basedir}/../</project.rootdir>
<coverage.complexity>82%</coverage.complexity>
<coverage.line>93%</coverage.line>
<coverage.complexity>83%</coverage.complexity>
<coverage.line>94%</coverage.line>
<coverage.instruction>94%</coverage.instruction>
<coverage.branch>76%</coverage.branch>
<coverage.method>93%</coverage.method>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.sap.ai.sdk.orchestration.model.ModuleConfigs;
import com.sap.ai.sdk.orchestration.model.OrchestrationConfig;
import com.sap.ai.sdk.orchestration.model.Template;
import com.sap.ai.sdk.orchestration.model.TemplateRef;
import com.sap.ai.sdk.orchestration.model.TemplatingModuleConfig;
import io.vavr.control.Option;
import java.util.ArrayList;
Expand Down Expand Up @@ -47,6 +48,9 @@ static TemplatingModuleConfig toTemplateModuleConfig(
* In this case, the request will fail, since the templating module will try to resolve the parameter.
* To be fixed with https://github.tools.sap/AI/llm-orchestration/issues/662
*/
if (config instanceof TemplateRef) {
return config;
}
val template = config instanceof Template t ? t : Template.create().template();
val messages = template.getTemplate();
val responseFormat = template.getResponseFormat();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -864,4 +864,56 @@ void testResponseFormatText() throws IOException {
verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request)));
}
}

@Test
void testTemplateFromPromptRegistryById() throws IOException {
{
stubFor(
post(anyUrl())
.willReturn(
aResponse()
.withBodyFile("templateReferenceResponse.json")
.withHeader("Content-Type", "application/json")));

var template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
var configWithTemplate = config.withTemplateConfig(template);

var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems");
var prompt = new OrchestrationPrompt(inputParams);

final var response = client.chatCompletion(prompt, configWithTemplate);
assertThat(response.getContent()).startsWith("I sistemi ERP (Enterprise Resource Planning)");
assertThat(response.getOriginalResponse().getModuleResults().getTemplating()).hasSize(2);

try (var requestInputStream = fileLoader.apply("templateReferenceByIdRequest.json")) {
final String request = new String(requestInputStream.readAllBytes());
verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request)));
}
}
}

@Test
void testTemplateFromPromptRegistryByScenario() throws IOException {
stubFor(
post(anyUrl())
.willReturn(
aResponse()
.withBodyFile("templateReferenceResponse.json")
.withHeader("Content-Type", "application/json")));

var template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1");
var configWithTemplate = config.withTemplateConfig(template);

var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems");
var prompt = new OrchestrationPrompt(inputParams);

final var response = client.chatCompletion(prompt, configWithTemplate);
assertThat(response.getContent()).startsWith("I sistemi ERP (Enterprise Resource Planning)");
assertThat(response.getOriginalResponse().getModuleResults().getTemplating()).hasSize(2);

try (var requestInputStream = fileLoader.apply("templateReferenceByScenarioRequest.json")) {
final String request = new String(requestInputStream.readAllBytes());
verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request)));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"request_id": "c02a6e4c-5552-4a72-a801-b6512d4f2f2a",
"module_results": {
"templating": [
{
"role": "system",
"content": "Please answer in Italian"
},
{
"role": "user",
"content": "Give me a short introduction of Cloud ERP systems."
}
],
"llm": {
"id": "chatcmpl-B6zYkaS7gjo5Ye6U87iK0B2dp4hde",
"object": "chat.completion",
"created": 1741006302,
"model": "gpt-4o-2024-08-06",
"system_fingerprint": "fp_b705f0c291",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "I sistemi ERP (Enterprise Resource Planning) basati su cloud sono soluzioni software che consentono alle aziende di gestire e integrare le loro operazioni aziendali principali attraverso una piattaforma centralizzata accessibile via internet. A differenza dei"
},
"finish_reason": "length"
}
],
"usage": {
"completion_tokens": 50,
"prompt_tokens": 25,
"total_tokens": 75
}
}
},
"orchestration_result": {
"id": "chatcmpl-B6zYkaS7gjo5Ye6U87iK0B2dp4hde",
"object": "chat.completion",
"created": 1741006302,
"model": "gpt-4o-2024-08-06",
"system_fingerprint": "fp_b705f0c291",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "I sistemi ERP (Enterprise Resource Planning) basati su cloud sono soluzioni software che consentono alle aziende di gestire e integrare le loro operazioni aziendali principali attraverso una piattaforma centralizzata accessibile via internet. A differenza dei"
},
"finish_reason": "length"
}
],
"usage": {
"completion_tokens": 50,
"prompt_tokens": 25,
"total_tokens": 75
}
}
}
29 changes: 29 additions & 0 deletions orchestration/src/test/resources/templateReferenceByIdRequest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"orchestration_config" : {
"module_configurations" : {
"llm_module_config" : {
"model_name" : "gpt-4o",
"model_params" : {
"max_tokens" : 50,
"temperature" : 0.1,
"frequency_penalty" : 0,
"presence_penalty" : 0,
"top_p" : 1,
"n" : 1
},
"model_version" : "latest"
},
"templating_module_config" : {
"template_ref" : {
"id" : "21cb1358-0bf1-4f43-870b-00f14d0f9f16"
}
}
},
"stream" : false
},
"input_params" : {
"input" : "Cloud ERP systems",
"language" : "Italian"
},
"messages_history" : [ ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"orchestration_config" : {
"module_configurations" : {
"llm_module_config" : {
"model_name" : "gpt-4o",
"model_params" : {
"max_tokens" : 50,
"temperature" : 0.1,
"frequency_penalty" : 0,
"presence_penalty" : 0,
"top_p" : 1,
"n" : 1
},
"model_version" : "latest"
},
"templating_module_config" : {
"template_ref" : {
"scenario" : "test",
"name" : "test",
"version" : "0.0.1"
}
}
},
"stream" : false
},
"input_params" : {
"input" : "Cloud ERP systems",
"language" : "Italian"
},
"messages_history" : [ ]
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,26 @@ Object responseFormatJsonObject(
}
return response.getContent();
}

@GetMapping("/templateFromPromptRegistryById")
@Nonnull
Object templateFromPromptRegistryById(
@RequestParam(value = "format", required = false) final String format) {
final var response = service.templateFromPromptRegistryById("cloud ERP systems");
if ("json".equals(format)) {
return response;
}
return response.getContent();
}

@GetMapping("/templateFromPromptRegistryByScenario")
@Nonnull
Object templateFromPromptRegistryByScenario(
@RequestParam(value = "format", required = false) final String format) {
final var response = service.templateFromPromptRegistryByScenario("cloud ERP systems");
if ("json".equals(format)) {
return response;
}
return response.getContent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -435,4 +435,49 @@ public OrchestrationChatResponse responseFormatText(@Nonnull final String word)

return client.chatCompletion(prompt, configWithTemplate);
}

/**
* Chat request to OpenAI through the Orchestration service using a template from the prompt
* registry.
*
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/templating">SAP
* AI Core: Orchestration - Templating</a>
* @return the assistant response object
*/
@Nonnull
public OrchestrationChatResponse templateFromPromptRegistryById(@Nonnull final String topic) {
final var llmWithImageSupportConfig =
new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI);

val template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template);

val inputParams = Map.of("language", "Italian", "input", topic);
val prompt = new OrchestrationPrompt(inputParams);

return client.chatCompletion(prompt, configWithTemplate);
}

/**
* Chat request to OpenAI through the Orchestration service using a template from the prompt
* registry.
*
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/templating">SAP
* AI Core: Orchestration - Templating</a>
* @return the assistant response object
*/
@Nonnull
public OrchestrationChatResponse templateFromPromptRegistryByScenario(
@Nonnull final String topic) {
final var llmWithImageSupportConfig =
new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI);

val template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1");
val configWithTemplate = config.withTemplateConfig(template);

val inputParams = Map.of("language", "Italian", "input", topic);
val prompt = new OrchestrationPrompt(inputParams);

return client.chatCompletion(prompt, configWithTemplate);
}
}
22 changes: 22 additions & 0 deletions sample-code/spring-app/src/main/resources/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,28 @@ <h2>Orchestration</h2>
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit" formaction="/orchestration/templateFromPromptRegistryById"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/orchestration/templateFromPromptRegistryById</code>
</button>
<div class="tooltip-content">
Chat request to an LLM through the Orchestration service using a template from the prompt registry identified by ID.
</div>
</div>
</li>
<li class="list-group-item">
<div class="info-tooltip">
<button type="submit" formaction="/orchestration/templateFromPromptRegistryByScenario"
class="link-offset-2-hover link-underline link-underline-opacity-0 link-underline-opacity-75-hover endpoint">
<code>/orchestration/templateFromPromptRegistryByScenario</code>
</button>
<div class="tooltip-content">
Chat request to an LLM through the Orchestration service using a template from the prompt registry identified by Scenario, name, and version.
</div>
</div>
</li>
</ul>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,20 @@ void testResponseFormatText() {
final var choices = ((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices();
assertThat(choices.get(0).getMessage().getContent()).isNotEmpty();
}

@Test
void testTemplateFromPromptRegistryById() {
final var result =
service.templateFromPromptRegistryById("Cloud ERP systems").getOriginalResponse();
final var choices = ((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices();
assertThat(choices.get(0).getMessage().getContent()).isNotEmpty();
}

@Test
void testTemplateFromPromptRegistryByScenario() {
final var result =
service.templateFromPromptRegistryByScenario("Cloud ERP systems").getOriginalResponse();
final var choices = ((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices();
assertThat(choices.get(0).getMessage().getContent()).isNotEmpty();
}
}
Loading