Skip to content
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

Improvements to HttpClient auto-configuration #115

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ThomasVitale
Copy link
Collaborator

Change

Introduce shared HttpClientAutoConfiguration to define a HttpClientBuilder prototype bean and related task executors, with support for virtual threads (when on Java 21+) and context propagation (when Micrometer is used).

General checklist

  • There are no breaking changes
  • I have added unit and/or integration tests for my change
  • The tests cover both positive and negative cases
  • I have manually run all the unit and integration tests in the module I have added/changed, and they are all green
  • I have added/updated the documentation
  • I have added an example in the examples repo (only for "big" features)

Introduce shared HttpClientAutoConfiguration to define a HttpClientBuilder prototype bean and related task executors, with support for virtual threads (when on Java 21+) and context propagation (when Micrometer is used).
@ThomasVitale
Copy link
Collaborator Author

@dliubarskyi This is a suggestion for a possible improvement of the HTTP Client configuration, based on the ideas we considered in the previous PR.

@Bean
@ConditionalOnMissingBean
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This annotation is important because it allows developers to define their own OllamaChatModel bean if they need additional customisations.

Same for the other model beans in this class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I guess ollamaStreamingLanguageModel should also be annotated with @ConditionalOnMissingBean?

ObjectProvider<HttpClientBuilderCustomizer> customizers
) {
HttpClientBuilder httpClientBuilder = new SpringRestClientBuilder()
.streamingRequestExecutor(asyncTaskExecutor)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there's always an AsyncTaskExecutor bean available, it can be configured directly, removing the need to operate the createDefaultStreamingRequestExecutor switch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it always available because of the bean definitions below (httpClientVirtualThreadsTaskExecutor, etc), right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if there is a way to avoid creating an executor in case it is not required? Or it is not a concern worth worrying about?

Copy link
Member

@dliubarskyi dliubarskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ThomasVitale thanks a lot, this looks great!
I like how it simplifies the code, but I am a bit worried that now there is no way to precisely configure client/executor per model type and/or provider. WDYT?

return SpringRestClient.builder()
.restClientBuilder(restClientBuilder.getIfAvailable(RestClient::builder))
// executor is not needed for no-streaming OllamaChatModel
.createDefaultStreamingRequestExecutor(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, with current configuration, task executor will always be created, even if it is not required (e.g., only non-streaming OllamaChatModel is used in the application)?

@Bean
@ConditionalOnMissingBean
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I guess ollamaStreamingLanguageModel should also be annotated with @ConditionalOnMissingBean?

@ConditionalOnProperty(PREFIX + ".chat-model.base-url")
OllamaChatModel ollamaChatModel(
@Qualifier(CHAT_MODEL_HTTP_CLIENT_BUILDER) HttpClientBuilder httpClientBuilder,
HttpClientBuilder httpClientBuilder,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly that there is currently no way to customize http client and/or executor per model type (e.g., use different configuration for non-streaming and streaming model) or provider (e.g., use different configuration for different LLM providers)?

@@ -31,6 +31,12 @@
</exclusions>
</dependency>

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-autoconfigure</artifactId>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(note for myself): need to do the same for OpenAI SB starter

ObjectProvider<HttpClientBuilderCustomizer> customizers
) {
HttpClientBuilder httpClientBuilder = new SpringRestClientBuilder()
.streamingRequestExecutor(asyncTaskExecutor)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it always available because of the bean definitions below (httpClientVirtualThreadsTaskExecutor, etc), right?

}

@Test
void httpClientBuilderWhenNoAutoConfiguredRestClient() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain when/why can this happen that there is no RestClientAutoConfiguration?

ObjectProvider<HttpClientBuilderCustomizer> customizers
) {
HttpClientBuilder httpClientBuilder = new SpringRestClientBuilder()
.streamingRequestExecutor(asyncTaskExecutor)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if there is a way to avoid creating an executor in case it is not required? Or it is not a concern worth worrying about?

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

Successfully merging this pull request may close these issues.

2 participants