@@ -243,4 +243,163 @@ public void qaAdvisorTakesUserParameterizedUserMessagesIntoAccountForSimilarityS
243
243
Assertions .assertThat (this .vectorSearchCaptor .getValue ().getQuery ()).isEqualTo (expectedQuery );
244
244
}
245
245
246
+ @ Test
247
+ public void qaAdvisorWithMultipleFilterParameters () {
248
+ given (this .chatModel .call (this .promptCaptor .capture ()))
249
+ .willReturn (new ChatResponse (List .of (new Generation (new AssistantMessage ("Filtered response" ))),
250
+ ChatResponseMetadata .builder ().build ()));
251
+
252
+ given (this .vectorStore .similaritySearch (this .vectorSearchCaptor .capture ()))
253
+ .willReturn (List .of (new Document ("doc1" ), new Document ("doc2" )));
254
+
255
+ var qaAdvisor = QuestionAnswerAdvisor .builder (this .vectorStore )
256
+ .searchRequest (SearchRequest .builder ().topK (10 ).build ())
257
+ .build ();
258
+
259
+ var chatClient = ChatClient .builder (this .chatModel )
260
+ .defaultAdvisors (qaAdvisor )
261
+ .build ();
262
+
263
+ chatClient .prompt ()
264
+ .user ("Complex query" )
265
+ .advisors (a -> a .param (QuestionAnswerAdvisor .FILTER_EXPRESSION , "type == 'Documentation' AND status == 'Published'" ))
266
+ .call ()
267
+ .chatResponse ();
268
+
269
+ var capturedFilter = this .vectorSearchCaptor .getValue ().getFilterExpression ();
270
+ assertThat (capturedFilter ).isNotNull ();
271
+ // The filter should be properly constructed with AND operation
272
+ assertThat (capturedFilter .toString ()).contains ("type" );
273
+ assertThat (capturedFilter .toString ()).contains ("Documentation" );
274
+ }
275
+
276
+ @ Test
277
+ public void qaAdvisorWithDifferentSimilarityThresholds () {
278
+ given (this .chatModel .call (this .promptCaptor .capture ()))
279
+ .willReturn (new ChatResponse (List .of (new Generation (new AssistantMessage ("High threshold response" ))),
280
+ ChatResponseMetadata .builder ().build ()));
281
+
282
+ given (this .vectorStore .similaritySearch (this .vectorSearchCaptor .capture ()))
283
+ .willReturn (List .of (new Document ("relevant doc" )));
284
+
285
+ var qaAdvisor = QuestionAnswerAdvisor .builder (this .vectorStore )
286
+ .searchRequest (SearchRequest .builder ().similarityThreshold (0.95 ).topK (3 ).build ())
287
+ .build ();
288
+
289
+ var chatClient = ChatClient .builder (this .chatModel )
290
+ .defaultAdvisors (qaAdvisor )
291
+ .build ();
292
+
293
+ chatClient .prompt ()
294
+ .user ("Specific question requiring high similarity" )
295
+ .call ()
296
+ .chatResponse ();
297
+
298
+ assertThat (this .vectorSearchCaptor .getValue ().getSimilarityThreshold ()).isEqualTo (0.95 );
299
+ assertThat (this .vectorSearchCaptor .getValue ().getTopK ()).isEqualTo (3 );
300
+ }
301
+
302
+ @ Test
303
+ public void qaAdvisorWithComplexParameterizedTemplate () {
304
+ given (this .chatModel .call (this .promptCaptor .capture ()))
305
+ .willReturn (new ChatResponse (List .of (new Generation (new AssistantMessage ("Complex template response" ))),
306
+ ChatResponseMetadata .builder ().build ()));
307
+
308
+ given (this .vectorStore .similaritySearch (this .vectorSearchCaptor .capture ()))
309
+ .willReturn (List .of (new Document ("template doc" )));
310
+
311
+ var qaAdvisor = QuestionAnswerAdvisor .builder (this .vectorStore )
312
+ .searchRequest (SearchRequest .builder ().build ())
313
+ .build ();
314
+
315
+ var chatClient = ChatClient .builder (this .chatModel )
316
+ .defaultAdvisors (qaAdvisor )
317
+ .build ();
318
+
319
+ var complexTemplate = "Please analyze {topic} considering {aspect1} and {aspect2} for user {userId}" ;
320
+ chatClient .prompt ()
321
+ .user (u -> u .text (complexTemplate )
322
+ .param ("topic" , "machine learning" )
323
+ .param ("aspect1" , "performance" )
324
+ .param ("aspect2" , "scalability" )
325
+ .param ("userId" , "user1" ))
326
+ .call ()
327
+ .chatResponse ();
328
+
329
+ var expectedQuery = "Please analyze machine learning considering performance and scalability for user user1" ;
330
+ assertThat (this .vectorSearchCaptor .getValue ().getQuery ()).isEqualTo (expectedQuery );
331
+
332
+ Message userMessage = this .promptCaptor .getValue ().getInstructions ().get (0 );
333
+ assertThat (userMessage .getText ()).contains (expectedQuery );
334
+ assertThat (userMessage .getText ()).doesNotContain ("{topic}" );
335
+ assertThat (userMessage .getText ()).doesNotContain ("{aspect1}" );
336
+ assertThat (userMessage .getText ()).doesNotContain ("{aspect2}" );
337
+ assertThat (userMessage .getText ()).doesNotContain ("{userId}" );
338
+ }
339
+
340
+ @ Test
341
+ public void qaAdvisorWithDocumentsContainingMetadata () {
342
+ given (this .chatModel .call (this .promptCaptor .capture ()))
343
+ .willReturn (new ChatResponse (List .of (new Generation (new AssistantMessage ("Metadata response" ))),
344
+ ChatResponseMetadata .builder ().build ()));
345
+
346
+ var docWithMetadata1 = new Document ("First document content" , Map .of ("source" , "wiki" , "author" , "John" ));
347
+ var docWithMetadata2 = new Document ("Second document content" , Map .of ("source" , "manual" , "version" , "2.1" ));
348
+
349
+ given (this .vectorStore .similaritySearch (this .vectorSearchCaptor .capture ()))
350
+ .willReturn (List .of (docWithMetadata1 , docWithMetadata2 ));
351
+
352
+ var qaAdvisor = QuestionAnswerAdvisor .builder (this .vectorStore )
353
+ .searchRequest (SearchRequest .builder ().topK (2 ).build ())
354
+ .build ();
355
+
356
+ var chatClient = ChatClient .builder (this .chatModel )
357
+ .defaultAdvisors (qaAdvisor )
358
+ .build ();
359
+
360
+ chatClient .prompt ()
361
+ .user ("Question about documents with metadata" )
362
+ .call ()
363
+ .chatResponse ();
364
+
365
+ Message userMessage = this .promptCaptor .getValue ().getInstructions ().get (0 );
366
+ assertThat (userMessage .getText ()).contains ("First document content" );
367
+ assertThat (userMessage .getText ()).contains ("Second document content" );
368
+ }
369
+
370
+ @ Test
371
+ public void qaAdvisorBuilderValidation () {
372
+ // Test that builder validates required parameters
373
+ Assertions .assertThatThrownBy (() -> QuestionAnswerAdvisor .builder (null ))
374
+ .isInstanceOf (IllegalArgumentException .class );
375
+
376
+ // Test successful builder creation
377
+ var advisor = QuestionAnswerAdvisor .builder (this .vectorStore ).build ();
378
+ assertThat (advisor ).isNotNull ();
379
+ }
380
+
381
+ @ Test
382
+ public void qaAdvisorWithZeroTopK () {
383
+ given (this .chatModel .call (this .promptCaptor .capture ()))
384
+ .willReturn (new ChatResponse (List .of (new Generation (new AssistantMessage ("Zero docs response" ))),
385
+ ChatResponseMetadata .builder ().build ()));
386
+
387
+ given (this .vectorStore .similaritySearch (this .vectorSearchCaptor .capture ()))
388
+ .willReturn (List .of ());
389
+
390
+ var qaAdvisor = QuestionAnswerAdvisor .builder (this .vectorStore )
391
+ .searchRequest (SearchRequest .builder ().topK (0 ).build ())
392
+ .build ();
393
+
394
+ var chatClient = ChatClient .builder (this .chatModel )
395
+ .defaultAdvisors (qaAdvisor )
396
+ .build ();
397
+
398
+ chatClient .prompt ()
399
+ .user ("Question with zero topK" )
400
+ .call ()
401
+ .chatResponse ();
402
+
403
+ assertThat (this .vectorSearchCaptor .getValue ().getTopK ()).isEqualTo (0 );
404
+ }
246
405
}
0 commit comments