Skip to content

Commit 192db45

Browse files
Merge branch 'main' into orchestration-streaming
# Conflicts: # docs/guides/ORCHESTRATION_CHAT_COMPLETION.md
2 parents 39642e5 + a174ba8 commit 192db45

File tree

8 files changed

+180
-2
lines changed

8 files changed

+180
-2
lines changed

docs/guides/ORCHESTRATION_CHAT_COMPLETION.md

Lines changed: 31 additions & 1 deletion
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
### Stream chat completion
190221

191222
It's possible to pass a stream of chat completion delta elements, e.g. from the application backend to the frontend in real-time.
@@ -212,7 +243,6 @@ try (Stream<String> stream = client.streamChatCompletion(prompt, config)) {
212243
Please find [an example in our Spring Boot application](../../sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java).
213244
It shows the usage of Spring Boot's `ResponseBodyEmitter` to stream the chat completion delta messages to the frontend in real-time.
214245

215-
216246
### Set model parameters
217247

218248
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
@@ -109,6 +109,37 @@ void testCompletion() {
109109
assertThat(result.getContent()).isNotEmpty();
110110
}
111111

112+
@Test
113+
void testGrounding() {
114+
stubFor(
115+
post(anyUrl())
116+
.willReturn(
117+
aResponse()
118+
.withBodyFile("groundingResponse.json")
119+
.withHeader("Content-Type", "application/json")));
120+
final var response = client.chatCompletion(prompt, config);
121+
final var result = response.getOriginalResponse();
122+
var llmChoice =
123+
((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices().get(0);
124+
125+
final var groundingData =
126+
(Map<String, Object>) result.getModuleResults().getGrounding().getData();
127+
assertThat(groundingData.get("grounding_query")).isEqualTo("grounding call");
128+
assertThat(groundingData.get("grounding_result").toString())
129+
.startsWith("Joule is the AI copilot that truly understands your business.");
130+
assertThat(result.getModuleResults().getGrounding().getMessage()).isEqualTo("grounding result");
131+
assertThat(result.getModuleResults().getTemplating().get(0).getContent())
132+
.startsWith(
133+
"What does Joule do? Use the following information as additional context: Joule is the AI copilot that truly understands your business.");
134+
assertThat(llmChoice.getMessage().getContent())
135+
.startsWith(
136+
"Joule is an AI copilot that revolutionizes how users interact with their SAP business systems.");
137+
assertThat(llmChoice.getFinishReason()).isEqualTo("stop");
138+
assertThat(llmChoice.getMessage().getContent())
139+
.startsWith(
140+
"Joule is an AI copilot that revolutionizes how users interact with their SAP business systems.");
141+
}
142+
112143
@Test
113144
void testTemplating() throws IOException {
114145
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
@@ -14,6 +14,10 @@
1414
import com.sap.ai.sdk.orchestration.OrchestrationModuleConfig;
1515
import com.sap.ai.sdk.orchestration.OrchestrationPrompt;
1616
import com.sap.ai.sdk.orchestration.model.DPIEntities;
17+
import com.sap.ai.sdk.orchestration.model.DataRepositoryType;
18+
import com.sap.ai.sdk.orchestration.model.DocumentGroundingFilter;
19+
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig;
20+
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfig;
1721
import com.sap.ai.sdk.orchestration.model.Template;
1822
import com.sap.cloud.sdk.cloudplatform.thread.ThreadContextExecutors;
1923
import java.util.List;
@@ -246,4 +250,35 @@ OrchestrationChatResponse maskingPseudonymization() {
246250

247251
return client.chatCompletion(prompt, configWithMasking);
248252
}
253+
254+
/**
255+
* Using grounding to provide additional context to the AI model.
256+
*
257+
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/grounding">SAP
258+
* AI Core: Orchestration - Grounding</a>
259+
*/
260+
@GetMapping("/grounding")
261+
@Nonnull
262+
OrchestrationChatResponse grounding() {
263+
final var message =
264+
Message.user(
265+
"{{?groundingInput}} Use the following information as additional context: {{?groundingOutput}}");
266+
final var prompt =
267+
new OrchestrationPrompt(Map.of("groundingInput", "What does Joule do?"), message);
268+
269+
final var filterInner =
270+
DocumentGroundingFilter.create().id("someID").dataRepositoryType(DataRepositoryType.VECTOR);
271+
final var groundingConfigConfig =
272+
GroundingModuleConfigConfig.create()
273+
.inputParams(List.of("groundingInput"))
274+
.outputParam("groundingOutput")
275+
.addFiltersItem(filterInner);
276+
final var groundingConfig =
277+
GroundingModuleConfig.create()
278+
.type(GroundingModuleConfig.TypeEnum.DOCUMENT_GROUNDING_SERVICE)
279+
.config(groundingConfigConfig);
280+
final var configWithGrounding = config.withGroundingConfig(groundingConfig);
281+
282+
return client.chatCompletion(prompt, configWithGrounding);
283+
}
249284
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ <h2>Endpoints</h2>
7474
<li><a href="/orchestration/filter/NUMBER_0">/orchestration/filter/NUMBER_0</a> Strict filter (fails)</li>
7575
<li><a href="/orchestration/maskingAnonymization">/orchestration/maskingAnonymization</a></li>
7676
<li><a href="/orchestration/maskingPseudonymization">/orchestration/maskingPseudonymization</a></li>
77+
<li><a href="/orchestration/grounding">/orchestration/grounding</a></li>
7778
</ul>
7879
</li>
7980
<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
@@ -178,8 +178,16 @@ void testMaskingPseudonymization() {
178178
@Test
179179
@DisabledIfSystemProperty(named = "aicore.landscape", matches = "production")
180180
void testGrounding() {
181-
// Placeholder for grounding test
182181
assertThat(System.getProperty("aicore.landscape")).isNotEqualTo("production");
182+
var response = controller.grounding();
183+
var result = response.getOriginalResponse();
184+
var llmChoice =
185+
((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices().get(0);
186+
assertThat(response).isNotNull();
187+
assertThat(llmChoice.getFinishReason()).isEqualTo("stop");
188+
assertThat(result.getModuleResults().getGrounding()).isNotNull();
189+
assertThat(result.getModuleResults().getGrounding().getData()).isNotNull();
190+
assertThat(result.getModuleResults().getGrounding().getMessage()).isEqualTo("grounding result");
183191
}
184192

185193
@Test

0 commit comments

Comments
 (0)