Skip to content

Commit

Permalink
Test: Using Orchestration Grounding module (#228)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
4 people authored Dec 10, 2024
1 parent 92ccef4 commit a174ba8
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 1 deletion.
31 changes: 31 additions & 0 deletions docs/guides/ORCHESTRATION_CHAT_COMPLETION.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,37 @@ var result =

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

### Grounding

Use the grounding module to provide additional context to the AI model.

```java
var message =
Message.user(
"{{?groundingInput}} Use the following information as additional context: {{?groundingOutput}}");
var prompt =
new OrchestrationPrompt(Map.of("groundingInput", "What does Joule do?"), message);

var filterInner =
DocumentGroundingFilter.create().id("someID").dataRepositoryType(DataRepositoryType.VECTOR);
var groundingConfigConfig =
GroundingModuleConfigConfig.create()
.inputParams(List.of("groundingInput"))
.outputParam("groundingOutput")
.addFiltersItem(filterInner);

var groundingConfig =
GroundingModuleConfig.create()
.type(GroundingModuleConfig.TypeEnum.DOCUMENT_GROUNDING_SERVICE)
.config(groundingConfigConfig);
var configWithGrounding = config.withGroundingConfig(groundingConfig);

var result =
new OrchestrationClient().chatCompletion(prompt, configWithGrounding);
```

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.

### Set model parameters

Change your LLM configuration to add model parameters:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static ModuleConfigs toModuleConfigs(@Nonnull final OrchestrationModuleConfig co

Option.of(config.getFilteringConfig()).forEach(moduleConfig::filteringModuleConfig);
Option.of(config.getMaskingConfig()).forEach(moduleConfig::maskingModuleConfig);
Option.of(config.getGroundingConfig()).forEach(moduleConfig::groundingModuleConfig);

return moduleConfig;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.sap.ai.sdk.orchestration;

import com.sap.ai.sdk.orchestration.model.FilteringModuleConfig;
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig;
import com.sap.ai.sdk.orchestration.model.InputFilteringConfig;
import com.sap.ai.sdk.orchestration.model.LLMModuleConfig;
import com.sap.ai.sdk.orchestration.model.MaskingModuleConfig;
Expand Down Expand Up @@ -83,6 +84,15 @@ public class OrchestrationModuleConfig {
*/
@Nullable FilteringModuleConfig filteringConfig;

/**
* A grounding configuration to provide additional context to the AI model.
*
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/grounding">SAP
* AI Core: Orchestration - </a>
* @since 1.1.0
*/
@Nullable GroundingModuleConfig groundingConfig;

/**
* Creates a new configuration with the given LLM configuration.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,37 @@ void testCompletion() {
assertThat(result.getContent()).isNotEmpty();
}

@Test
void testGrounding() {
stubFor(
post(anyUrl())
.willReturn(
aResponse()
.withBodyFile("groundingResponse.json")
.withHeader("Content-Type", "application/json")));
final var response = client.chatCompletion(prompt, config);
final var result = response.getOriginalResponse();
var llmChoice =
((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices().get(0);

final var groundingData =
(Map<String, Object>) result.getModuleResults().getGrounding().getData();
assertThat(groundingData.get("grounding_query")).isEqualTo("grounding call");
assertThat(groundingData.get("grounding_result").toString())
.startsWith("Joule is the AI copilot that truly understands your business.");
assertThat(result.getModuleResults().getGrounding().getMessage()).isEqualTo("grounding result");
assertThat(result.getModuleResults().getTemplating().get(0).getContent())
.startsWith(
"What does Joule do? Use the following information as additional context: Joule is the AI copilot that truly understands your business.");
assertThat(llmChoice.getMessage().getContent())
.startsWith(
"Joule is an AI copilot that revolutionizes how users interact with their SAP business systems.");
assertThat(llmChoice.getFinishReason()).isEqualTo("stop");
assertThat(llmChoice.getMessage().getContent())
.startsWith(
"Joule is an AI copilot that revolutionizes how users interact with their SAP business systems.");
}

@Test
void testTemplating() throws IOException {
stubFor(
Expand Down
62 changes: 62 additions & 0 deletions orchestration/src/test/resources/__files/groundingResponse.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"request_id": "0d9d7ce3-9ded-481f-80c6-977e78e2e905",
"module_results": {
"grounding": {
"message": "grounding result",
"data": {
"grounding_query": "grounding call",
"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."
}
},
"templating": [
{
"role": "user",
"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."
}
],
"llm": {
"id": "chatcmpl-AbRlNdsyQJfvBINnw3MOTP77WSE4X",
"object": "chat.completion",
"created": 1733488221,
"model": "gpt-35-turbo",
"system_fingerprint": "fp_808245b034",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"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."
},
"finish_reason": "stop"
}
],
"usage": {
"completion_tokens": 68,
"prompt_tokens": 113,
"total_tokens": 181
}
}
},
"orchestration_result": {
"id": "chatcmpl-AbRlNdsyQJfvBINnw3MOTP77WSE4X",
"object": "chat.completion",
"created": 1733488221,
"model": "gpt-35-turbo",
"system_fingerprint": "fp_808245b034",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"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."
},
"finish_reason": "stop"
}
],
"usage": {
"completion_tokens": 68,
"prompt_tokens": 113,
"total_tokens": 181
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
import com.sap.ai.sdk.orchestration.OrchestrationModuleConfig;
import com.sap.ai.sdk.orchestration.OrchestrationPrompt;
import com.sap.ai.sdk.orchestration.model.DPIEntities;
import com.sap.ai.sdk.orchestration.model.DataRepositoryType;
import com.sap.ai.sdk.orchestration.model.DocumentGroundingFilter;
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig;
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfig;
import com.sap.ai.sdk.orchestration.model.Template;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -207,4 +211,35 @@ OrchestrationChatResponse maskingPseudonymization() {

return client.chatCompletion(prompt, configWithMasking);
}

/**
* Using grounding to provide additional context to the AI model.
*
* @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/grounding">SAP
* AI Core: Orchestration - Grounding</a>
*/
@GetMapping("/grounding")
@Nonnull
OrchestrationChatResponse grounding() {
final var message =
Message.user(
"{{?groundingInput}} Use the following information as additional context: {{?groundingOutput}}");
final var prompt =
new OrchestrationPrompt(Map.of("groundingInput", "What does Joule do?"), message);

final var filterInner =
DocumentGroundingFilter.create().id("someID").dataRepositoryType(DataRepositoryType.VECTOR);
final var groundingConfigConfig =
GroundingModuleConfigConfig.create()
.inputParams(List.of("groundingInput"))
.outputParam("groundingOutput")
.addFiltersItem(filterInner);
final var groundingConfig =
GroundingModuleConfig.create()
.type(GroundingModuleConfig.TypeEnum.DOCUMENT_GROUNDING_SERVICE)
.config(groundingConfigConfig);
final var configWithGrounding = config.withGroundingConfig(groundingConfig);

return client.chatCompletion(prompt, configWithGrounding);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ <h2>Endpoints</h2>
<li><a href="/orchestration/filter/NUMBER_0">/orchestration/filter/NUMBER_0</a> Strict filter (fails)</li>
<li><a href="/orchestration/maskingAnonymization">/orchestration/maskingAnonymization</a></li>
<li><a href="/orchestration/maskingPseudonymization">/orchestration/maskingPseudonymization</a></li>
<li><a href="/orchestration/grounding">/orchestration/grounding</a></li>
</ul>
</li>
<li><h3>Foundation Models</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,16 @@ void testMaskingPseudonymization() {
@Test
@DisabledIfSystemProperty(named = "aicore.landscape", matches = "production")
void testGrounding() {
// Placeholder for grounding test
assertThat(System.getProperty("aicore.landscape")).isNotEqualTo("production");
var response = controller.grounding();
var result = response.getOriginalResponse();
var llmChoice =
((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices().get(0);
assertThat(response).isNotNull();
assertThat(llmChoice.getFinishReason()).isEqualTo("stop");
assertThat(result.getModuleResults().getGrounding()).isNotNull();
assertThat(result.getModuleResults().getGrounding().getData()).isNotNull();
assertThat(result.getModuleResults().getGrounding().getMessage()).isEqualTo("grounding result");
}

@Test
Expand Down

0 comments on commit a174ba8

Please sign in to comment.