fix: 收紧 starter 自动装配并修复默认连接问题

- 为 llm 与 store 自动配置增加显式属性门槛

- 修复 ollama think 为空时的启动空指针

- 补充 starter 条件装配测试
This commit is contained in:
2026-03-25 15:26:42 +08:00
parent 735a840945
commit 2f20064ee1
12 changed files with 71 additions and 4 deletions

View File

@@ -51,6 +51,25 @@
<artifactId>easy-agents-bom</artifactId> <artifactId>easy-agents-bom</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -4,6 +4,7 @@ import com.easyagents.llm.deepseek.DeepseekConfig;
import com.easyagents.llm.deepseek.DeepseekChatModel; import com.easyagents.llm.deepseek.DeepseekChatModel;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -13,6 +14,7 @@ import org.springframework.context.annotation.Configuration;
* DeepSeek * DeepSeek
*/ */
@ConditionalOnClass(DeepseekChatModel.class) @ConditionalOnClass(DeepseekChatModel.class)
@ConditionalOnProperty(prefix = "easy-agents.llm.deepseek", name = "api-key")
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(DeepSeekProperties.class) @EnableConfigurationProperties(DeepSeekProperties.class)
public class DeepSeekAutoConfiguration { public class DeepSeekAutoConfiguration {

View File

@@ -4,6 +4,7 @@ import com.easyagents.llm.ollama.OllamaChatModel;
import com.easyagents.llm.ollama.OllamaChatConfig; import com.easyagents.llm.ollama.OllamaChatConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -15,6 +16,7 @@ import org.springframework.context.annotation.Configuration;
* @since 2025-02-11 * @since 2025-02-11
*/ */
@ConditionalOnClass(OllamaChatModel.class) @ConditionalOnClass(OllamaChatModel.class)
@ConditionalOnProperty(prefix = "easy-agents.llm.ollama", name = "model")
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OllamaProperties.class) @EnableConfigurationProperties(OllamaProperties.class)
public class OllamaAutoConfiguration { public class OllamaAutoConfiguration {
@@ -26,7 +28,7 @@ public class OllamaAutoConfiguration {
config.setApiKey(properties.getApiKey()); config.setApiKey(properties.getApiKey());
config.setEndpoint(properties.getEndpoint()); config.setEndpoint(properties.getEndpoint());
config.setModel(properties.getModel()); config.setModel(properties.getModel());
config.setThinkingEnabled(properties.getThink()); config.setThinkingEnabled(Boolean.TRUE.equals(properties.getThink()));
return new OllamaChatModel(config); return new OllamaChatModel(config);
} }

View File

@@ -12,7 +12,7 @@ public class OllamaProperties {
private String model; private String model;
private String endpoint = "http://localhost:11434"; private String endpoint = "http://localhost:11434";
private String apiKey; private String apiKey;
private Boolean think; private Boolean think = Boolean.FALSE;
public String getModel() { public String getModel() {
return model; return model;

View File

@@ -4,6 +4,7 @@ import com.easyagents.llm.openai.OpenAIChatModel;
import com.easyagents.llm.openai.OpenAIChatConfig; import com.easyagents.llm.openai.OpenAIChatConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -15,6 +16,7 @@ import org.springframework.context.annotation.Configuration;
* @since 2024-04-10 * @since 2024-04-10
*/ */
@ConditionalOnClass(OpenAIChatModel.class) @ConditionalOnClass(OpenAIChatModel.class)
@ConditionalOnProperty(prefix = "easy-agents.llm.openai", name = "api-key")
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OpenAIProperties.class) @EnableConfigurationProperties(OpenAIProperties.class)
public class OpenAIAutoConfiguration { public class OpenAIAutoConfiguration {

View File

@@ -4,6 +4,7 @@ import com.easyagents.llm.qwen.QwenChatModel;
import com.easyagents.llm.qwen.QwenChatConfig; import com.easyagents.llm.qwen.QwenChatConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -15,6 +16,7 @@ import org.springframework.context.annotation.Configuration;
* @since 2024-04-10 * @since 2024-04-10
*/ */
@ConditionalOnClass(QwenChatModel.class) @ConditionalOnClass(QwenChatModel.class)
@ConditionalOnProperty(prefix = "easy-agents.llm.qwen", name = "api-key")
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(QwenProperties.class) @EnableConfigurationProperties(QwenProperties.class)
public class QwenAutoConfiguration { public class QwenAutoConfiguration {

View File

@@ -4,6 +4,7 @@ import com.easyagents.store.aliyun.AliyunVectorStore;
import com.easyagents.store.aliyun.AliyunVectorStoreConfig; import com.easyagents.store.aliyun.AliyunVectorStoreConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -14,6 +15,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(AliyunVectorStore.class) @ConditionalOnClass(AliyunVectorStore.class)
@ConditionalOnProperty(prefix = "easy-agents.store.aliyun", name = "endpoint")
@EnableConfigurationProperties(AliyunProperties.class) @EnableConfigurationProperties(AliyunProperties.class)
public class AliyunAutoConfiguration { public class AliyunAutoConfiguration {

View File

@@ -17,9 +17,9 @@ package com.easyagents.spring.boot.store.chroma;
import com.easyagents.store.chroma.ChromaVectorStore; import com.easyagents.store.chroma.ChromaVectorStore;
import com.easyagents.store.chroma.ChromaVectorStoreConfig; import com.easyagents.store.chroma.ChromaVectorStoreConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -31,6 +31,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ChromaVectorStore.class) @ConditionalOnClass(ChromaVectorStore.class)
@ConditionalOnProperty(prefix = "easy-agents.store.chroma", name = "host")
@EnableConfigurationProperties(ChromaProperties.class) @EnableConfigurationProperties(ChromaProperties.class)
public class ChromaAutoConfiguration { public class ChromaAutoConfiguration {

View File

@@ -21,6 +21,7 @@ import com.easyagents.store.elasticsearch.ElasticSearchVectorStoreConfig;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -31,6 +32,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ElasticSearchVectorStore.class) @ConditionalOnClass(ElasticSearchVectorStore.class)
@ConditionalOnProperty(prefix = "easy-agents.store.elasticsearch", name = "server-url")
@EnableConfigurationProperties(ElasticSearchProperties.class) @EnableConfigurationProperties(ElasticSearchProperties.class)
public class ElasticSearchAutoConfiguration { public class ElasticSearchAutoConfiguration {

View File

@@ -21,6 +21,7 @@ import org.opensearch.client.opensearch.OpenSearchClient;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -31,6 +32,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OpenSearchVectorStore.class) @ConditionalOnClass(OpenSearchVectorStore.class)
@ConditionalOnProperty(prefix = "easy-agents.store.opensearch", name = "server-url")
@EnableConfigurationProperties(OpenSearchProperties.class) @EnableConfigurationProperties(OpenSearchProperties.class)
public class OpenSearchAutoConfiguration { public class OpenSearchAutoConfiguration {

View File

@@ -4,6 +4,7 @@ import com.easyagents.store.qcloud.QCloudVectorStore;
import com.easyagents.store.qcloud.QCloudVectorStoreConfig; import com.easyagents.store.qcloud.QCloudVectorStoreConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@@ -14,6 +15,7 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnClass(QCloudVectorStore.class) @ConditionalOnClass(QCloudVectorStore.class)
@ConditionalOnProperty(prefix = "easy-agents.store.qcloud", name = "host")
@EnableConfigurationProperties(QCloudProperties.class) @EnableConfigurationProperties(QCloudProperties.class)
public class QCloudStoreAutoConfiguration { public class QCloudStoreAutoConfiguration {

View File

@@ -0,0 +1,31 @@
package com.easyagents.spring.boot.autoconfigure;
import com.easyagents.llm.ollama.OllamaChatModel;
import com.easyagents.spring.boot.llm.ollama.OllamaAutoConfiguration;
import com.easyagents.spring.boot.rag.ingestion.RagIngestionAutoConfiguration;
import com.easyagents.spring.boot.store.opensearch.OpenSearchAutoConfiguration;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
public class StarterConditionalAutoConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(RagIngestionAutoConfiguration.class, OllamaAutoConfiguration.class, OpenSearchAutoConfiguration.class);
@Test
public void shouldNotCreateOptionalBeansWithoutExplicitProperties() {
contextRunner.run(context -> {
Assert.assertTrue(context.containsBean("ragIngestionService"));
Assert.assertFalse(context.containsBean("ollamaLlm"));
Assert.assertFalse(context.containsBean("openSearchVectorStore"));
});
}
@Test
public void shouldCreateOllamaBeanWhenModelConfigured() {
contextRunner
.withPropertyValues("easy-agents.llm.ollama.model=qwen3:8b")
.run(context -> Assert.assertNotNull(context.getBean(OllamaChatModel.class)));
}
}