|
41 | 41 | import com.sap.ai.sdk.orchestration.model.CompletionPostRequest; |
42 | 42 | import com.sap.ai.sdk.orchestration.model.CompletionPostResponse; |
43 | 43 | import com.sap.ai.sdk.orchestration.model.DPIEntities; |
| 44 | +import com.sap.ai.sdk.orchestration.model.DataRepositoryType; |
| 45 | +import com.sap.ai.sdk.orchestration.model.DocumentGroundingFilter; |
44 | 46 | import com.sap.ai.sdk.orchestration.model.GenericModuleResult; |
| 47 | +import com.sap.ai.sdk.orchestration.model.GroundingFilterSearchConfiguration; |
| 48 | +import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig; |
| 49 | +import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfig; |
45 | 50 | import com.sap.ai.sdk.orchestration.model.ImageContent; |
46 | 51 | import com.sap.ai.sdk.orchestration.model.ImageContentImageUrl; |
| 52 | +import com.sap.ai.sdk.orchestration.model.KeyValueListPair; |
47 | 53 | import com.sap.ai.sdk.orchestration.model.LLMModuleConfig; |
48 | 54 | import com.sap.ai.sdk.orchestration.model.LLMModuleResult; |
49 | 55 | import com.sap.ai.sdk.orchestration.model.LLMModuleResultSynchronous; |
50 | 56 | import com.sap.ai.sdk.orchestration.model.ModuleConfigs; |
51 | 57 | import com.sap.ai.sdk.orchestration.model.MultiChatMessage; |
52 | 58 | import com.sap.ai.sdk.orchestration.model.OrchestrationConfig; |
| 59 | +import com.sap.ai.sdk.orchestration.model.SearchDocumentKeyValueListPair; |
| 60 | +import com.sap.ai.sdk.orchestration.model.SearchSelectOptionEnum; |
53 | 61 | import com.sap.ai.sdk.orchestration.model.Template; |
54 | 62 | import com.sap.ai.sdk.orchestration.model.TextContent; |
55 | 63 | import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5Accessor; |
@@ -129,34 +137,68 @@ void testCompletion() { |
129 | 137 | } |
130 | 138 |
|
131 | 139 | @Test |
132 | | - void testGrounding() { |
| 140 | + void testGrounding() throws IOException { |
133 | 141 | stubFor( |
134 | | - post(anyUrl()) |
| 142 | + post(urlPathEqualTo("/completion")) |
135 | 143 | .willReturn( |
136 | 144 | aResponse() |
137 | 145 | .withBodyFile("groundingResponse.json") |
138 | 146 | .withHeader("Content-Type", "application/json"))); |
139 | | - final var response = client.chatCompletion(prompt, config); |
140 | | - final var result = response.getOriginalResponse(); |
141 | | - var llmChoice = |
142 | | - ((LLMModuleResultSynchronous) result.getOrchestrationResult()).getChoices().get(0); |
143 | | - |
144 | | - final var groundingData = |
145 | | - (Map<String, Object>) result.getModuleResults().getGrounding().getData(); |
146 | | - assertThat(groundingData.get("grounding_query")).isEqualTo("grounding call"); |
147 | | - assertThat(groundingData.get("grounding_result").toString()) |
148 | | - .startsWith("Joule is the AI copilot that truly understands your business."); |
149 | | - assertThat(result.getModuleResults().getGrounding().getMessage()).isEqualTo("grounding result"); |
150 | | - assertThat(((ChatMessage) result.getModuleResults().getTemplating().get(0)).getContent()) |
151 | | - .startsWith( |
152 | | - "What does Joule do? Use the following information as additional context: Joule is the AI copilot that truly understands your business."); |
153 | | - assertThat(llmChoice.getMessage().getContent()) |
154 | | - .startsWith( |
155 | | - "Joule is an AI copilot that revolutionizes how users interact with their SAP business systems."); |
156 | | - assertThat(llmChoice.getFinishReason()).isEqualTo("stop"); |
157 | | - assertThat(llmChoice.getMessage().getContent()) |
158 | | - .startsWith( |
159 | | - "Joule is an AI copilot that revolutionizes how users interact with their SAP business systems."); |
| 147 | + |
| 148 | + final var documentMetadata = |
| 149 | + SearchDocumentKeyValueListPair.create() |
| 150 | + .key("document metadata") |
| 151 | + .value("2") |
| 152 | + .selectMode(List.of(SearchSelectOptionEnum.IGNORE_IF_KEY_ABSENT)); |
| 153 | + final var databaseFilter = |
| 154 | + DocumentGroundingFilter.create() |
| 155 | + .id("arbitrary-user-defined-id") |
| 156 | + .dataRepositoryType(DataRepositoryType.VECTOR) |
| 157 | + .searchConfig(GroundingFilterSearchConfiguration.create().maxChunkCount(3)) |
| 158 | + .documentMetadata(List.of(documentMetadata)) |
| 159 | + .chunkMetadata(List.of(KeyValueListPair.create().key("chunk metadata").value("1"))); |
| 160 | + final var groundingConfigConfig = |
| 161 | + GroundingModuleConfigConfig.create() |
| 162 | + .inputParams(List.of("query")) |
| 163 | + .outputParam("results") |
| 164 | + .addFiltersItem(databaseFilter); |
| 165 | + final var groundingConfig = |
| 166 | + GroundingModuleConfig.create() |
| 167 | + .type(GroundingModuleConfig.TypeEnum.DOCUMENT_GROUNDING_SERVICE) |
| 168 | + .config(groundingConfigConfig); |
| 169 | + final var configWithGrounding = config.withGroundingConfig(groundingConfig); |
| 170 | + |
| 171 | + final Map<String, String> inputParams = |
| 172 | + Map.of("query", "String used for similarity search in database"); |
| 173 | + final var prompt = |
| 174 | + new OrchestrationPrompt( |
| 175 | + inputParams, |
| 176 | + Message.system("Context message with embedded grounding results. {{?results}}")); |
| 177 | + |
| 178 | + final var response = client.chatCompletion(prompt, configWithGrounding); |
| 179 | + |
| 180 | + assertThat(response).isNotNull(); |
| 181 | + assertThat(response.getOriginalResponse().getRequestId()) |
| 182 | + .isEqualTo("e5d2add4-408c-4da5-84ca-1d8b0fe350c8"); |
| 183 | + |
| 184 | + var moduleResults = response.getOriginalResponse().getModuleResults(); |
| 185 | + assertThat(moduleResults).isNotNull(); |
| 186 | + |
| 187 | + var groundingModule = moduleResults.getGrounding(); |
| 188 | + assertThat(groundingModule).isNotNull(); |
| 189 | + assertThat(groundingModule.getMessage()).isEqualTo("grounding result"); |
| 190 | + assertThat(groundingModule.getData()).isNotNull(); |
| 191 | + var groundingData = |
| 192 | + Map.of( |
| 193 | + "grounding_query", |
| 194 | + "grounding call", |
| 195 | + "grounding_result", |
| 196 | + "First chunk```Second chunk```Last found chunk"); |
| 197 | + assertThat(groundingModule.getData()).isEqualTo(groundingData); |
| 198 | + |
| 199 | + final String requestBody = new String(fileLoader.apply("groundingRequest.json").readAllBytes()); |
| 200 | + verify( |
| 201 | + postRequestedFor(urlPathEqualTo("/completion")).withRequestBody(equalToJson(requestBody))); |
160 | 202 | } |
161 | 203 |
|
162 | 204 | @Test |
|
0 commit comments