Skip to content

Make ChatClient and Advisor APIs more robust, consistent, and flexible #2655

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

Open
ThomasVitale opened this issue Apr 6, 2025 · 2 comments
Open
Assignees

Comments

@ThomasVitale
Copy link
Contributor

ThomasVitale commented Apr 6, 2025

Advisor API

The Advisor API went through some changes over time. Initially, there was a concept of "advisor type", with separate interfaces for "before", "after", and "around" advisors. Currently, there is only one type of advisor (around). Still, the naming of many APIs and the observation context include the legacy "around" concept. We should probably get rid of that to avoid confusion.

AdvisedRequest

The AdvisedRequest API contains the same information of a Prompt, but in a de-structured format. Furthermore, for the same information, multiple ways exist to store it. This causes lots of troubles in all consumers of an AdvisedRequest object (e.g. advisors and observations), in particular:

Furthermore, an AdvisedRequest contains a mutable ChatModel instance which is very confusing. Consumers of an AdvisedRequest have the power to replace the ChatModel instance, but that operation would have no effect. Actually, it could lead to wrong information provided downstream. If a subsequent consumer relies on that field to know which model is used by the chain of advisors, it could receive wrong information. It should probably be removed.

Similarly, an AdvisedRequest contains a mutable List<Advisor> which includes the list of advisors in the chain. Consumers of an AdvisedRequest have the power to replace the manipulate the List<Advisor> instance, but that operation would have no effect. Actually, it could lead to wrong information provided downstream. If a subsequent consumer relies on that field to know which advisors are being executed in the chain, it could receive wrong information. It should probably be removed.

Finally, an AdvisedRequest contains both advisorParams and adviseContext fields. However, the first one is only used at the beginning of an advisor chain to populate the second field, and never used anymore. It should probably be removed to avoid confusion and unpredictable behaviour.

AdvisedResponse

The AdvisedResponse API carries both an optional ChatResponse object returned from a chat model call and the context used throughout the chat client execution, including the advisor chain. This context includes useful information. For example, when performing a RAG operation, it contains the contextual documents retrieved by the vector store and used by the model for answering the user question. This context is currently hidden within the advisor chain, causing issues to users that would like to use that contextual information for several reasons, including for evaluation and validation. There have been some suggestions for expanding the ChatResponse so to include this extra context, but that solution doesn't really scale and dirties the lower-level Chat Model API. Instead, a better solution would be to return the context to the caller in a clean way.

Some issues registered about this: #1747

Observation

The observation context for the ChatClient operations is affected by the problems mentioned above regarding the AdvisedRequest. In particular, the information included in the observation context might be wrong or incomplete. For example, user messages, system messages, and tools are likely to be incomplete since we only consider one of the possible locations in the AdvisedRequest where they could be stored.

Also, the ChatClientObservationContext is strictly dependent on the DefaultChatClientRequestSpec, meaning that it only works with the default implementation of the ChatClient API.

Prompt Templating

The ChatClient API supports passing userParams and systemParams, which can be used to render the templates passed as userText and systemText. At a minimum, the templates are rendered right before calling the chat model, using a default PromptTemplate object. When using advisors, the rendering might be needed earlier. For example, it had to be included in QuestionAnswerAdvisor and RetrievalAugmentationAdvisor. That's part of the issues mentioned earlier in the context of AdvisedRequest.

The templating strategy is based on StringTemplate and cannot be changed. This creates problems in two main cases:

  • When a user prompt doesn't contain templating, but includes curly braces, the call will fail.
  • When a user prompt needs a different templating strategy, it's not possible.

The ChatClient API should provide the possibility to customise the prompt template rendering strategy.

Some issues registered about this: #355, #1687, #2448, #2456, #1849, #1428, #2468, #2020

ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 6, 2025
- Introduce “ChatClientRequest” and “ChatClientResponse” for propagating requests/responses in a ChatClient advisor chain.
- Structure a Prompt at the beginning of the chain, to ensure a consistent view across execution chain and observations. Any template is rendered at the beginning so that every advisor doesn’t have to do it again.
- Improve observations to include the complete view of the prompt messages, instead of only considering userText and systemText.
- Remove legacy “around” advisor type concept.
- Keep backward compatibility for AdvisedRequest, AdvisedResponse, and legacy Advisor APIs.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
@SpiReCZ
Copy link

SpiReCZ commented Apr 11, 2025

The first issue with the current/old Advisor API I encountered was unavailable context information for the user (RAG document names), needed custom or extra advisor.
Then for chat UI it also didn't allow to dispatch events to the resulting stream before LLM inference.
Example:
SpiReCZ/spring-ai@main...SpiReCZ:spring-ai:ahead-stream-events

Users need more control and less encapsulation with advisors.

@SpiReCZ
Copy link

SpiReCZ commented Apr 14, 2025

@ThomasVitale @tzolov What do you guys think? Can we achieve full control over Flux<ChatResponse> in 1.0.0 ?
The idea in the ahead stream events is to allow Advisors to publish events ahead of time before LLM inference..

Use case for this could be giving UI/frontend hints about what AI chatbot/agent is doing..
example UI hints: thinking, searching...

Then another use case is to sent out filenames of documents from retrieved RAG chunks.
If I could choose, I would publish all events/metadata ahead for LLM inference if available.

ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 15, 2025
- Introduce “ChatClientRequest” and “ChatClientResponse” for propagating requests/responses in a ChatClient advisor chain.
- Structure a Prompt at the beginning of the chain, to ensure a consistent view across execution chain and observations. Any template is rendered at the beginning so that every advisor doesn’t have to do it again.
- Improve observations to include the complete view of the prompt messages, instead of only considering userText and systemText.
- Remove legacy “around” advisor type concept.
- Keep backward compatibility for AdvisedRequest, AdvisedResponse, and legacy Advisor APIs.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 15, 2025
- Introduce “ChatClientRequest” and “ChatClientResponse” for propagating requests/responses in a ChatClient advisor chain.
- Structure a Prompt at the beginning of the chain, to ensure a consistent view across execution chain and observations. Any template is rendered at the beginning so that every advisor doesn’t have to do it again.
- Improve observations to include the complete view of the prompt messages, instead of only considering userText and systemText.
- Remove legacy “around” advisor type concept.
- Keep backward compatibility for AdvisedRequest, AdvisedResponse, and legacy Advisor APIs.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
@tzolov tzolov added this to the 1.0.0-RC1 milestone Apr 15, 2025
@tzolov tzolov self-assigned this Apr 15, 2025
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 15, 2025
- Introduce “ChatClientRequest” and “ChatClientResponse” for propagating requests/responses in a ChatClient advisor chain.
- Structure a Prompt at the beginning of the chain, to ensure a consistent view across execution chain and observations. Any template is rendered at the beginning so that every advisor doesn’t have to do it again.
- Improve observations to include the complete view of the prompt messages, instead of only considering userText and systemText.
- Remove legacy “around” advisor type concept.
- Keep backward compatibility for AdvisedRequest, AdvisedResponse, and legacy Advisor APIs.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 15, 2025
- Introduce “ChatClientRequest” and “ChatClientResponse” for propagating requests/responses in a ChatClient advisor chain.
- Structure a Prompt at the beginning of the chain, to ensure a consistent view across execution chain and observations. Any template is rendered at the beginning so that every advisor doesn’t have to do it again.
- Improve observations to include the complete view of the prompt messages, instead of only considering userText and systemText.
- Remove legacy “around” advisor type concept.
- Keep backward compatibility for AdvisedRequest, AdvisedResponse, and legacy Advisor APIs.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 15, 2025
- Introduce “ChatClientRequest” and “ChatClientResponse” for propagating requests/responses in a ChatClient advisor chain.
- Structure a Prompt at the beginning of the chain, to ensure a consistent view across execution chain and observations. Any template is rendered at the beginning so that every advisor doesn’t have to do it again.
- Improve observations to include the complete view of the prompt messages, instead of only considering userText and systemText.
- Remove legacy “around” advisor type concept.
- Keep backward compatibility for AdvisedRequest, AdvisedResponse, and legacy Advisor APIs.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 16, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate.
- Extend ChatClient API to support passing a custom TemplateRenderer.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 16, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate.
- Extend ChatClient API to support passing a custom TemplateRenderer.

- Add integration tests showing how to customize prompts in QuestionAnswerAdvisor and RetrievalAugmentationAdvisor.
- Support PromptTemplate instead of String in QuestionAnswerAdvisor.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 16, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate.
- Extend ChatClient API to support passing a custom TemplateRenderer.

- Add integration tests showing how to customize prompts in QuestionAnswerAdvisor and RetrievalAugmentationAdvisor.
- Support PromptTemplate instead of String in QuestionAnswerAdvisor.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 17, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate. Additionally, make start and end delimiter character configurable.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 17, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate. Additionally, make start and end delimiter character configurable.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
tzolov pushed a commit that referenced this issue Apr 17, 2025
- Introduce “ChatClientRequest” and “ChatClientResponse” for propagating requests/responses in a ChatClient advisor chain.
- Structure a Prompt at the beginning of the chain, to ensure a consistent view across execution chain and observations. Any template is rendered at the beginning so that every advisor doesn’t have to do it again.
- Improve observations to include the complete view of the prompt messages, instead of only considering userText and systemText.
- Remove legacy “around” advisor type concept.
- Keep backward compatibility for AdvisedRequest, AdvisedResponse, and legacy Advisor APIs.

Relates to gh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 24, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate. Additionally, make start and end delimiter character configurable.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 24, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate. Additionally, make start and end delimiter character configurable.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
ThomasVitale added a commit to ThomasVitale/spring-ai that referenced this issue Apr 24, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate. Additionally, make start and end delimiter character configurable.

Relates to spring-projectsgh-2655

Signed-off-by: Thomas Vitale <[email protected]>
markpollack pushed a commit that referenced this issue Apr 24, 2025
- Introduce new TemplateRenderer API providing the logic for rendering an input template.
- Update the PromptTemplate API to accept a TemplateRenderer object at construction time.
- Move ST logic to StTemplateRenderer implementation, used by default in PromptTemplate. Additionally, make start and end delimiter character configurable.

Relates to gh-2655

Signed-off-by: Thomas Vitale <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants