Skip to content

Commit 8fefe94

Browse files
authored
feat: Use prompt templates via Orchestration (#368)
* Enable orchestration referencing templates * add tests and adapt coverage * add documentation and release notes * add links to documentation * small fix * typo * merge response-files --------- Co-authored-by: Jonas Israel <[email protected]>
1 parent 3255daa commit 8fefe94

File tree

12 files changed

+299
-3
lines changed

12 files changed

+299
-3
lines changed

docs/guides/ORCHESTRATION_CHAT_COMPLETION.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,22 @@ var result = client.chatCompletion(prompt, configWithTemplate);
119119

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

122+
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.
123+
124+
```java
125+
var template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
126+
var configWithTemplate = config.withTemplateConfig(template);
127+
128+
var inputParams = Map.of("language", "Italian", "input", "cloud ERP systems");
129+
var prompt = new OrchestrationPrompt(inputParams);
130+
131+
var result = client.chatCompletion(prompt, configWithTemplate);
132+
```
133+
134+
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).
135+
136+
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.
137+
122138
## Message history
123139

124140
Include a message history to maintain context in the conversation:

docs/release-notes/release_notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
### ✨ New Functionality
1414

15-
-
15+
- [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)
1616

1717
### 📈 Improvements
1818

orchestration/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
</developers>
3232
<properties>
3333
<project.rootdir>${project.basedir}/../</project.rootdir>
34-
<coverage.complexity>82%</coverage.complexity>
35-
<coverage.line>93%</coverage.line>
34+
<coverage.complexity>83%</coverage.complexity>
35+
<coverage.line>94%</coverage.line>
3636
<coverage.instruction>94%</coverage.instruction>
3737
<coverage.branch>75%</coverage.branch>
3838
<coverage.method>93%</coverage.method>

orchestration/src/main/java/com/sap/ai/sdk/orchestration/ConfigToRequestTransformer.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.sap.ai.sdk.orchestration.model.ModuleConfigs;
66
import com.sap.ai.sdk.orchestration.model.OrchestrationConfig;
77
import com.sap.ai.sdk.orchestration.model.Template;
8+
import com.sap.ai.sdk.orchestration.model.TemplateRef;
89
import com.sap.ai.sdk.orchestration.model.TemplatingModuleConfig;
910
import io.vavr.control.Option;
1011
import java.util.ArrayList;
@@ -47,6 +48,9 @@ static TemplatingModuleConfig toTemplateModuleConfig(
4748
* In this case, the request will fail, since the templating module will try to resolve the parameter.
4849
* To be fixed with https://github.tools.sap/AI/llm-orchestration/issues/662
4950
*/
51+
if (config instanceof TemplateRef) {
52+
return config;
53+
}
5054
val template = config instanceof Template t ? t : Template.create().template();
5155
val messages = template.getTemplate();
5256
val responseFormat = template.getResponseFormat();

orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,4 +880,56 @@ void testResponseFormatText() throws IOException {
880880
verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request)));
881881
}
882882
}
883+
884+
@Test
885+
void testTemplateFromPromptRegistryById() throws IOException {
886+
{
887+
stubFor(
888+
post(anyUrl())
889+
.willReturn(
890+
aResponse()
891+
.withBodyFile("templateReferenceResponse.json")
892+
.withHeader("Content-Type", "application/json")));
893+
894+
var template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
895+
var configWithTemplate = config.withTemplateConfig(template);
896+
897+
var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems");
898+
var prompt = new OrchestrationPrompt(inputParams);
899+
900+
final var response = client.chatCompletion(prompt, configWithTemplate);
901+
assertThat(response.getContent()).startsWith("I sistemi ERP (Enterprise Resource Planning)");
902+
assertThat(response.getOriginalResponse().getModuleResults().getTemplating()).hasSize(2);
903+
904+
try (var requestInputStream = fileLoader.apply("templateReferenceByIdRequest.json")) {
905+
final String request = new String(requestInputStream.readAllBytes());
906+
verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request)));
907+
}
908+
}
909+
}
910+
911+
@Test
912+
void testTemplateFromPromptRegistryByScenario() throws IOException {
913+
stubFor(
914+
post(anyUrl())
915+
.willReturn(
916+
aResponse()
917+
.withBodyFile("templateReferenceResponse.json")
918+
.withHeader("Content-Type", "application/json")));
919+
920+
var template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1");
921+
var configWithTemplate = config.withTemplateConfig(template);
922+
923+
var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems");
924+
var prompt = new OrchestrationPrompt(inputParams);
925+
926+
final var response = client.chatCompletion(prompt, configWithTemplate);
927+
assertThat(response.getContent()).startsWith("I sistemi ERP (Enterprise Resource Planning)");
928+
assertThat(response.getOriginalResponse().getModuleResults().getTemplating()).hasSize(2);
929+
930+
try (var requestInputStream = fileLoader.apply("templateReferenceByScenarioRequest.json")) {
931+
final String request = new String(requestInputStream.readAllBytes());
932+
verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request)));
933+
}
934+
}
883935
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"request_id": "c02a6e4c-5552-4a72-a801-b6512d4f2f2a",
3+
"module_results": {
4+
"templating": [
5+
{
6+
"role": "system",
7+
"content": "Please answer in Italian"
8+
},
9+
{
10+
"role": "user",
11+
"content": "Give me a short introduction of Cloud ERP systems."
12+
}
13+
],
14+
"llm": {
15+
"id": "chatcmpl-B6zYkaS7gjo5Ye6U87iK0B2dp4hde",
16+
"object": "chat.completion",
17+
"created": 1741006302,
18+
"model": "gpt-4o-2024-08-06",
19+
"system_fingerprint": "fp_b705f0c291",
20+
"choices": [
21+
{
22+
"index": 0,
23+
"message": {
24+
"role": "assistant",
25+
"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"
26+
},
27+
"finish_reason": "length"
28+
}
29+
],
30+
"usage": {
31+
"completion_tokens": 50,
32+
"prompt_tokens": 25,
33+
"total_tokens": 75
34+
}
35+
}
36+
},
37+
"orchestration_result": {
38+
"id": "chatcmpl-B6zYkaS7gjo5Ye6U87iK0B2dp4hde",
39+
"object": "chat.completion",
40+
"created": 1741006302,
41+
"model": "gpt-4o-2024-08-06",
42+
"system_fingerprint": "fp_b705f0c291",
43+
"choices": [
44+
{
45+
"index": 0,
46+
"message": {
47+
"role": "assistant",
48+
"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"
49+
},
50+
"finish_reason": "length"
51+
}
52+
],
53+
"usage": {
54+
"completion_tokens": 50,
55+
"prompt_tokens": 25,
56+
"total_tokens": 75
57+
}
58+
}
59+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"orchestration_config" : {
3+
"module_configurations" : {
4+
"llm_module_config" : {
5+
"model_name" : "gpt-4o",
6+
"model_params" : {
7+
"max_tokens" : 50,
8+
"temperature" : 0.1,
9+
"frequency_penalty" : 0,
10+
"presence_penalty" : 0,
11+
"top_p" : 1,
12+
"n" : 1
13+
},
14+
"model_version" : "latest"
15+
},
16+
"templating_module_config" : {
17+
"template_ref" : {
18+
"id" : "21cb1358-0bf1-4f43-870b-00f14d0f9f16"
19+
}
20+
}
21+
},
22+
"stream" : false
23+
},
24+
"input_params" : {
25+
"input" : "Cloud ERP systems",
26+
"language" : "Italian"
27+
},
28+
"messages_history" : [ ]
29+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"orchestration_config" : {
3+
"module_configurations" : {
4+
"llm_module_config" : {
5+
"model_name" : "gpt-4o",
6+
"model_params" : {
7+
"max_tokens" : 50,
8+
"temperature" : 0.1,
9+
"frequency_penalty" : 0,
10+
"presence_penalty" : 0,
11+
"top_p" : 1,
12+
"n" : 1
13+
},
14+
"model_version" : "latest"
15+
},
16+
"templating_module_config" : {
17+
"template_ref" : {
18+
"scenario" : "test",
19+
"name" : "test",
20+
"version" : "0.0.1"
21+
}
22+
}
23+
},
24+
"stream" : false
25+
},
26+
"input_params" : {
27+
"input" : "Cloud ERP systems",
28+
"language" : "Italian"
29+
},
30+
"messages_history" : [ ]
31+
}

sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,26 @@ Object responseFormatJsonObject(
236236
}
237237
return response.getContent();
238238
}
239+
240+
@GetMapping("/templateFromPromptRegistryById")
241+
@Nonnull
242+
Object templateFromPromptRegistryById(
243+
@RequestParam(value = "format", required = false) final String format) {
244+
final var response = service.templateFromPromptRegistryById("cloud ERP systems");
245+
if ("json".equals(format)) {
246+
return response;
247+
}
248+
return response.getContent();
249+
}
250+
251+
@GetMapping("/templateFromPromptRegistryByScenario")
252+
@Nonnull
253+
Object templateFromPromptRegistryByScenario(
254+
@RequestParam(value = "format", required = false) final String format) {
255+
final var response = service.templateFromPromptRegistryByScenario("cloud ERP systems");
256+
if ("json".equals(format)) {
257+
return response;
258+
}
259+
return response.getContent();
260+
}
239261
}

sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,4 +435,49 @@ public OrchestrationChatResponse responseFormatText(@Nonnull final String word)
435435

436436
return client.chatCompletion(prompt, configWithTemplate);
437437
}
438+
439+
/**
440+
* Chat request to OpenAI through the Orchestration service using a template from the prompt
441+
* registry.
442+
*
443+
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/templating">SAP
444+
* AI Core: Orchestration - Templating</a>
445+
* @return the assistant response object
446+
*/
447+
@Nonnull
448+
public OrchestrationChatResponse templateFromPromptRegistryById(@Nonnull final String topic) {
449+
final var llmWithImageSupportConfig =
450+
new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI);
451+
452+
val template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
453+
val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template);
454+
455+
val inputParams = Map.of("language", "Italian", "input", topic);
456+
val prompt = new OrchestrationPrompt(inputParams);
457+
458+
return client.chatCompletion(prompt, configWithTemplate);
459+
}
460+
461+
/**
462+
* Chat request to OpenAI through the Orchestration service using a template from the prompt
463+
* registry.
464+
*
465+
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/templating">SAP
466+
* AI Core: Orchestration - Templating</a>
467+
* @return the assistant response object
468+
*/
469+
@Nonnull
470+
public OrchestrationChatResponse templateFromPromptRegistryByScenario(
471+
@Nonnull final String topic) {
472+
final var llmWithImageSupportConfig =
473+
new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI);
474+
475+
val template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1");
476+
val configWithTemplate = config.withTemplateConfig(template);
477+
478+
val inputParams = Map.of("language", "Italian", "input", topic);
479+
val prompt = new OrchestrationPrompt(inputParams);
480+
481+
return client.chatCompletion(prompt, configWithTemplate);
482+
}
438483
}

0 commit comments

Comments
 (0)