Skip to content

Commit a174ba8

Browse files
Jonas-Isrbot-sdk-jsMatKuhr
authored
Test: Using Orchestration Grounding module (#228)
* Add grounding e2e test. * Update OrchestrationController * Formatting * Update index.html * Work in progress. * Add unit test. * Add documentation * Formatting * Update docs/guides/ORCHESTRATION_CHAT_COMPLETION.md Co-authored-by: Matthias Kuhr <[email protected]> * Apply requested changes. --------- Co-authored-by: Jonas Israel <[email protected]> Co-authored-by: SAP Cloud SDK Bot <[email protected]> Co-authored-by: Matthias Kuhr <[email protected]>
1 parent 92ccef4 commit a174ba8

File tree

8 files changed

+180
-1
lines changed

8 files changed

+180
-1
lines changed

docs/guides/ORCHESTRATION_CHAT_COMPLETION.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,37 @@ var result =
186186

187187
In this example, the input will be masked before the call to the LLM and will remain masked in the output.
188188

189+
### Grounding
190+
191+
Use the grounding module to provide additional context to the AI model.
192+
193+
```java
194+
var message =
195+
Message.user(
196+
"{{?groundingInput}} Use the following information as additional context: {{?groundingOutput}}");
197+
var prompt =
198+
new OrchestrationPrompt(Map.of("groundingInput", "What does Joule do?"), message);
199+
200+
var filterInner =
201+
DocumentGroundingFilter.create().id("someID").dataRepositoryType(DataRepositoryType.VECTOR);
202+
var groundingConfigConfig =
203+
GroundingModuleConfigConfig.create()
204+
.inputParams(List.of("groundingInput"))
205+
.outputParam("groundingOutput")
206+
.addFiltersItem(filterInner);
207+
208+
var groundingConfig =
209+
GroundingModuleConfig.create()
210+
.type(GroundingModuleConfig.TypeEnum.DOCUMENT_GROUNDING_SERVICE)
211+
.config(groundingConfigConfig);
212+
var configWithGrounding = config.withGroundingConfig(groundingConfig);
213+
214+
var result =
215+
new OrchestrationClient().chatCompletion(prompt, configWithGrounding);
216+
```
217+
218+
In this example, the AI model is provided with additional context in the form of grounding information. Note, that it is necessary to provide the grounding input via one or more input variables.
219+
189220
### Set model parameters
190221

191222
Change your LLM configuration to add model parameters:

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ static ModuleConfigs toModuleConfigs(@Nonnull final OrchestrationModuleConfig co
7070

7171
Option.of(config.getFilteringConfig()).forEach(moduleConfig::filteringModuleConfig);
7272
Option.of(config.getMaskingConfig()).forEach(moduleConfig::maskingModuleConfig);
73+
Option.of(config.getGroundingConfig()).forEach(moduleConfig::groundingModuleConfig);
7374

7475
return moduleConfig;
7576
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.sap.ai.sdk.orchestration;
22

33
import com.sap.ai.sdk.orchestration.model.FilteringModuleConfig;
4+
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig;
45
import com.sap.ai.sdk.orchestration.model.InputFilteringConfig;
56
import com.sap.ai.sdk.orchestration.model.LLMModuleConfig;
67
import com.sap.ai.sdk.orchestration.model.MaskingModuleConfig;
@@ -83,6 +84,15 @@ public class OrchestrationModuleConfig {
8384
*/
8485
@Nullable FilteringModuleConfig filteringConfig;
8586

87+
/**
88+
* A grounding configuration to provide additional context to the AI model.
89+
*
90+
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/grounding">SAP
91+
* AI Core: Orchestration - </a>
92+
* @since 1.1.0
93+
*/
94+
@Nullable GroundingModuleConfig groundingConfig;
95+
8696
/**
8797
* Creates a new configuration with the given LLM configuration.
8898
*

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,37 @@ void testCompletion() {
8585
assertThat(result.getContent()).isNotEmpty();
8686
}
8787

88+
@Test
89+
void testGrounding() {
90+
stubFor(
91+
post(anyUrl())
92+
.willReturn(
93+
aResponse()
94+
.withBodyFile("groundingResponse.json")
95+
.withHeader("Content-Type", "application/json")));
96+
final var response = client.chatCompletion(prompt, config);
97+
final var result = response.getOriginalResponse();
98+
var llmChoice =
99+
((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices().get(0);
100+
101+
final var groundingData =
102+
(Map<String, Object>) result.getModuleResults().getGrounding().getData();
103+
assertThat(groundingData.get("grounding_query")).isEqualTo("grounding call");
104+
assertThat(groundingData.get("grounding_result").toString())
105+
.startsWith("Joule is the AI copilot that truly understands your business.");
106+
assertThat(result.getModuleResults().getGrounding().getMessage()).isEqualTo("grounding result");
107+
assertThat(result.getModuleResults().getTemplating().get(0).getContent())
108+
.startsWith(
109+
"What does Joule do? Use the following information as additional context: Joule is the AI copilot that truly understands your business.");
110+
assertThat(llmChoice.getMessage().getContent())
111+
.startsWith(
112+
"Joule is an AI copilot that revolutionizes how users interact with their SAP business systems.");
113+
assertThat(llmChoice.getFinishReason()).isEqualTo("stop");
114+
assertThat(llmChoice.getMessage().getContent())
115+
.startsWith(
116+
"Joule is an AI copilot that revolutionizes how users interact with their SAP business systems.");
117+
}
118+
88119
@Test
89120
void testTemplating() throws IOException {
90121
stubFor(
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"request_id": "0d9d7ce3-9ded-481f-80c6-977e78e2e905",
3+
"module_results": {
4+
"grounding": {
5+
"message": "grounding result",
6+
"data": {
7+
"grounding_query": "grounding call",
8+
"grounding_result": "Joule is the AI copilot that truly understands your business. Joule revolutionizes how you interact with your SAP business systems, making every touchpoint count and every task simpler.```It enables the companion of the Intelligent Enterprise, guiding you through content discovery within SAP Ecosystem, and giving a transparent role-based access to the relevant processes from everywhere. This is the one assistant experience, a unified and delightful user experience across SAP’s \u01ee solution portfolio."
9+
}
10+
},
11+
"templating": [
12+
{
13+
"role": "user",
14+
"content": "What does Joule do? Use the following information as additional context: Joule is the AI copilot that truly understands your business. Joule revolutionizes how you interact with your SAP business systems, making every touchpoint count and every task simpler.```It enables the companion of the Intelligent Enterprise, guiding you through content discovery within SAP Ecosystem, and giving a transparent role-based access to the relevant processes from everywhere. This is the one assistant experience, a unified and delightful user experience across SAP’s \u01ee solution portfolio."
15+
}
16+
],
17+
"llm": {
18+
"id": "chatcmpl-AbRlNdsyQJfvBINnw3MOTP77WSE4X",
19+
"object": "chat.completion",
20+
"created": 1733488221,
21+
"model": "gpt-35-turbo",
22+
"system_fingerprint": "fp_808245b034",
23+
"choices": [
24+
{
25+
"index": 0,
26+
"message": {
27+
"role": "assistant",
28+
"content": "Joule is an AI copilot that revolutionizes how users interact with their SAP business systems. It enables the companion of the Intelligent Enterprise, guiding users through content discovery within the SAP Ecosystem and providing transparent role-based access to relevant processes from anywhere. Joule aims to provide a unified and delightful user experience across SAP's solution portfolio."
29+
},
30+
"finish_reason": "stop"
31+
}
32+
],
33+
"usage": {
34+
"completion_tokens": 68,
35+
"prompt_tokens": 113,
36+
"total_tokens": 181
37+
}
38+
}
39+
},
40+
"orchestration_result": {
41+
"id": "chatcmpl-AbRlNdsyQJfvBINnw3MOTP77WSE4X",
42+
"object": "chat.completion",
43+
"created": 1733488221,
44+
"model": "gpt-35-turbo",
45+
"system_fingerprint": "fp_808245b034",
46+
"choices": [
47+
{
48+
"index": 0,
49+
"message": {
50+
"role": "assistant",
51+
"content": "Joule is an AI copilot that revolutionizes how users interact with their SAP business systems. It enables the companion of the Intelligent Enterprise, guiding users through content discovery within the SAP Ecosystem and providing transparent role-based access to relevant processes from anywhere. Joule aims to provide a unified and delightful user experience across SAP's solution portfolio."
52+
},
53+
"finish_reason": "stop"
54+
}
55+
],
56+
"usage": {
57+
"completion_tokens": 68,
58+
"prompt_tokens": 113,
59+
"total_tokens": 181
60+
}
61+
}
62+
}

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
import com.sap.ai.sdk.orchestration.OrchestrationModuleConfig;
1414
import com.sap.ai.sdk.orchestration.OrchestrationPrompt;
1515
import com.sap.ai.sdk.orchestration.model.DPIEntities;
16+
import com.sap.ai.sdk.orchestration.model.DataRepositoryType;
17+
import com.sap.ai.sdk.orchestration.model.DocumentGroundingFilter;
18+
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig;
19+
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfig;
1620
import com.sap.ai.sdk.orchestration.model.Template;
1721
import java.util.List;
1822
import java.util.Map;
@@ -207,4 +211,35 @@ OrchestrationChatResponse maskingPseudonymization() {
207211

208212
return client.chatCompletion(prompt, configWithMasking);
209213
}
214+
215+
/**
216+
* Using grounding to provide additional context to the AI model.
217+
*
218+
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/grounding">SAP
219+
* AI Core: Orchestration - Grounding</a>
220+
*/
221+
@GetMapping("/grounding")
222+
@Nonnull
223+
OrchestrationChatResponse grounding() {
224+
final var message =
225+
Message.user(
226+
"{{?groundingInput}} Use the following information as additional context: {{?groundingOutput}}");
227+
final var prompt =
228+
new OrchestrationPrompt(Map.of("groundingInput", "What does Joule do?"), message);
229+
230+
final var filterInner =
231+
DocumentGroundingFilter.create().id("someID").dataRepositoryType(DataRepositoryType.VECTOR);
232+
final var groundingConfigConfig =
233+
GroundingModuleConfigConfig.create()
234+
.inputParams(List.of("groundingInput"))
235+
.outputParam("groundingOutput")
236+
.addFiltersItem(filterInner);
237+
final var groundingConfig =
238+
GroundingModuleConfig.create()
239+
.type(GroundingModuleConfig.TypeEnum.DOCUMENT_GROUNDING_SERVICE)
240+
.config(groundingConfigConfig);
241+
final var configWithGrounding = config.withGroundingConfig(groundingConfig);
242+
243+
return client.chatCompletion(prompt, configWithGrounding);
244+
}
210245
}

sample-code/spring-app/src/main/resources/static/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ <h2>Endpoints</h2>
7373
<li><a href="/orchestration/filter/NUMBER_0">/orchestration/filter/NUMBER_0</a> Strict filter (fails)</li>
7474
<li><a href="/orchestration/maskingAnonymization">/orchestration/maskingAnonymization</a></li>
7575
<li><a href="/orchestration/maskingPseudonymization">/orchestration/maskingPseudonymization</a></li>
76+
<li><a href="/orchestration/grounding">/orchestration/grounding</a></li>
7677
</ul>
7778
</li>
7879
<li><h3>Foundation Models</h3>

sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,16 @@ void testMaskingPseudonymization() {
154154
@Test
155155
@DisabledIfSystemProperty(named = "aicore.landscape", matches = "production")
156156
void testGrounding() {
157-
// Placeholder for grounding test
158157
assertThat(System.getProperty("aicore.landscape")).isNotEqualTo("production");
158+
var response = controller.grounding();
159+
var result = response.getOriginalResponse();
160+
var llmChoice =
161+
((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices().get(0);
162+
assertThat(response).isNotNull();
163+
assertThat(llmChoice.getFinishReason()).isEqualTo("stop");
164+
assertThat(result.getModuleResults().getGrounding()).isNotNull();
165+
assertThat(result.getModuleResults().getGrounding().getData()).isNotNull();
166+
assertThat(result.getModuleResults().getGrounding().getMessage()).isEqualTo("grounding result");
159167
}
160168

161169
@Test

0 commit comments

Comments
 (0)