Skip to content

QuestionAnswerAdvisor: Augmentation of the user prompt with document context fails with structured output #2973

@timosalm

Description

@timosalm

Bug description
The template rendering changes in M8 for the QuestionAnswerAdvisor are not working for structured output.

8:14: '"https://json-schema.org/draft/2020-12/schema"' came as a complete surprise to me

The template string is not valid.

java.lang.IllegalArgumentException: The template string is not valid.
	at org.springframework.ai.template.st.StTemplateRenderer.createST(StTemplateRenderer.java:100)
	at org.springframework.ai.template.st.StTemplateRenderer.apply(StTemplateRenderer.java:85)
	at org.springframework.ai.chat.prompt.PromptTemplate.render(PromptTemplate.java:155)
	at org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor.before(QuestionAnswerAdvisor.java:251)
	...

Probably, because the template rendering will be applied to the entire context, and fails on the JSON schema information for the structured output.

Environment
Spring AI version 1.0.0 M8

Steps to reproduce

var qaAdvisor = new QuestionAnswerAdvisor(this.vectorStore, SearchRequest.builder().build());
chatClient.prompt()
		.user(u -> u.text(userTextTemplate).param("question", "XYZ"))
		.advisors(qaAdvisor)
		.call()
		.entity(Sample.class);

Expected behavior
QuestionAnswerAdvisor works with structured output and the default system prompts provided by Spring AI

Minimal Complete Reproducible example

@ExtendWith(MockitoExtension.class)
public class QuestionAnswerAdvisorTests {

	@Mock
	ChatModel chatModel;

	@Captor
	ArgumentCaptor<Prompt> promptCaptor;

	@Captor
	ArgumentCaptor<SearchRequest> vectorSearchCaptor;

	@Mock
	VectorStore vectorStore;

	record Answer(String text) {}

	@Test
	public void qaAdvisorTakesUserTextParametersIntoAccountForSimilaritySearch() {

		given(this.chatModel.call(this.promptCaptor.capture()))
				.willReturn(new ChatResponse(List.of(new Generation(new AssistantMessage("""
				{"text":"Your answer is ZXY"}
				"""))), ChatResponseMetadata.builder().build()));

		given(this.vectorStore.similaritySearch(this.vectorSearchCaptor.capture()))
				.willReturn(List.of(new Document("doc1"), new Document("doc2")));

		var chatClient = ChatClient.builder(this.chatModel).build();
		var qaAdvisor = new QuestionAnswerAdvisor(this.vectorStore, SearchRequest.builder().build());

		var userTextTemplate = "Please answer my question {question}";
		// @formatter:off
		var answer = chatClient.prompt()
				.user(u -> u.text(userTextTemplate).param("question", "XYZ"))
				.advisors(qaAdvisor)
				.call()
				.entity(Answer.class);
		//formatter:on

		assertThat(answer).isNotNull();
		assertThat(answer.text()).isEqualTo("Your answer is ZXY");
	}

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions