@@ -243,4 +243,163 @@ public void qaAdvisorTakesUserParameterizedUserMessagesIntoAccountForSimilarityS
243243 Assertions .assertThat (this .vectorSearchCaptor .getValue ().getQuery ()).isEqualTo (expectedQuery );
244244 }
245245
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" , "user123" ))
326+ .call ()
327+ .chatResponse ();
328+
329+ var expectedQuery = "Please analyze machine learning considering performance and scalability for user user123" ;
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+ }
246405}
0 commit comments