-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Modular RAG - Query Analysis #1703
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modular RAG - Query Analysis #1703
Conversation
90f6791
to
69494ec
Compare
return new DefaultChatClient(this.defaultRequest); | ||
} | ||
|
||
public Builder clone() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the other APIs used by ChatClient have similar methods, but they are called mutate()
instead of clone()
. I wonder if it'd make sense to change them to clone()
? It would be aligned with the naming used in other Spring APIs (like RestClient) and also aligned with Java conventions in general.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We borrowed the mutate from RestClient : https://github.com/spring-projects/spring-framework/blob/b523f3caff8b57feca7b445a1a151cb9aa1f7fb3/spring-web/src/main/java/org/springframework/web/client/RestClient.java#L136
So mutate is the Spring API style
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, we figured the mystery :) The Builder has the "clone()" method and the Client APIs the "mutate()" method.
return AdvisedRequest.from(request).withUserText(augmentedQuery.text()).withAdviseContext(context).build(); | ||
} | ||
|
||
private AdvisedResponse after(AdvisedResponse advisedResponse) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could make protected, along with before
if someone wants to customize the algorithm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, the customisation approach will be based on implementing a custom Advisor and using the available RAG components to build a custom RAG flow, whereas all these out-of-the-box implementations will be "final" following the Spring Security approach.
Just some general thoughts, not necessary to resolve for this PR.
this way additional information that can be used by an implementing class can be taken into account. The document is the core part, but there could be additional information to influence how the query gets augmented. Perhaps that would be passed in the constrcutor to the QueryAugmentor impl. Just looking to move away from types that don't have extensibility in the interface.
|
// 3. Augment user query with the document contextual data. | ||
Query augmentedQuery = this.queryAugmentor.augment(transformedQuery, documents); | ||
|
||
return AdvisedRequest.from(request).withUserText(augmentedQuery.text()).withAdviseContext(context).build(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wondering about the multimodal/media aspects of this as it focused on text and any media for the request is lost.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The AdvisedRequest has a separate Media property for the media elements, so they are currently propagated correctly.
List<Document> documents = this.documentRetriever.retrieve(query); | ||
// 2. Retrieve similar documents for the original query. | ||
List<Document> documents = this.documentRetriever.retrieve(transformedQuery); | ||
context.put(DOCUMENT_CONTEXT, documents); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe a RAGContext that in turn contains the documents so that for the future when additional things are added to the context for RAG, it is all in a central spot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We agreed to talk more about this when we reconsider the design of ChatResponse and how to propagate back evidence from different intermediate steps in a ChatClient, such as retrieved documents and called functions.
this.queryTransformers = queryTransformers; | ||
this.documentRetriever = documentRetriever; | ||
this.queryAugmentor = queryAugmentor != null ? queryAugmentor : ContextualQueryAugmentor.builder().build(); | ||
this.protectFromBlocking = protectFromBlocking != null ? protectFromBlocking : false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think protectFromBlocking
being true by default is a more conservative option, this way it works out of the box in a reactive environment and for a non-reactive environment there isn't much of an impact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! It's now true by default.
* @author Thomas Vitale | ||
* @since 1.0.0 | ||
*/ | ||
public interface QueryExpander extends Function<Query, List<Query>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm wondering if this is something that should be used inside RetrievalAugmentationAdvisor
or it is used in code at higher level. Maybe this is part of the Query Optimization part that is to come
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't adopted that in RetrievalAugmentationAdvisor
yet, but I'll do so in a next PR where I introduce the Router and Fuser components that are needed to handle multiple queries/retrievals.
private List<Document> knowledgeBaseDocuments; | ||
|
||
@Autowired | ||
OpenAiChatModel openAiChatModel; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm getting a test failure
Caused by: java.lang.IllegalArgumentException: OpenAI API key must be set. Use the connection property: spring.ai.openai.api-key or spring.ai.openai.chat.api-key property.
at org.springframework.util.Assert.hasText(Assert.java:240) ~[spring-core-6.1.13.jar:6.1.13]
at org.springframework.ai.autoconfigure.openai.OpenAiAutoConfiguration.resolveConnectionProperties(OpenAiAutoConfiguration.java:100) ~[classes/:na]
I think some additional context config is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into that. I wonder if it's due to the new APIKey concept introduced after I opened this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah, it's actually the missing property you mentioned in #1703 (comment) I'll fix that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
I get test failures for tests |
Query Analysis * Introduce Query Analysis Module * Define QueryTransformer API and TranslationQueryTransformer implementation * Define QueryExpander API and MultiQueryExpander implementation * Support QueryTransformer in RetrievalAugmentationAdvisor (support for QueryExpander will be in the next PR together with the needed DocumentFuser API). Improvements * Refine Retrieval and Augmentation Modules for increased robustness * Expand test coverage for both modules * Define clone() method for ChatClient.Builder Tests * Introduce “spring-ai-integration-tests” for full-fledged integration tests * Add integration tests for RAG modules * Add integration tests for RAG advisor Relates to #spring-projectsgh-1603 Signed-off-by: Thomas Vitale <ThomasVitale@users.noreply.github.com>
Query Analysis * Introduce Query Analysis Module * Define QueryTransformer API and TranslationQueryTransformer implementation * Define QueryExpander API and MultiQueryExpander implementation * Support QueryTransformer in RetrievalAugmentationAdvisor (support for QueryExpander will be in the next PR together with the needed DocumentFuser API). Improvements * Refine Retrieval and Augmentation Modules for increased robustness * Expand test coverage for both modules * Define clone() method for ChatClient.Builder Tests * Introduce “spring-ai-integration-tests” for full-fledged integration tests * Add integration tests for RAG modules * Add integration tests for RAG advisor Relates to #spring-projectsgh-1603 Signed-off-by: Thomas Vitale <ThomasVitale@users.noreply.github.com>
69494ec
to
f902229
Compare
merged in 263fe2f |
Query Analysis
Improvements
Tests
Relates to #gh-1603