
Langchain4j Spring Boot Integration
- 1.6k installs
- 311 repo stars
- Updated June 22, 2026
- giuseppe-trisciuoglio/developer-kit
How to integrate LangChain4j into Spring Boot applications using declarative AI Services, auto-configuration, and Spring dependency injection for production-ready AI microservices.
About
LangChain4j Spring Boot integration enables developers to embed AI capabilities into Spring applications through declarative AI Services, auto-configuration, and Spring dependency injection. Developers use this when building AI-powered microservices, configuring multiple AI providers (OpenAI, Azure, Ollama, Anthropic), and implementing RAG pipelines with Spring Data. Key workflows include defining AI services via @AiService interfaces, configuring models through application properties, setting up chat memory with Spring context, and integrating tools as Spring components. The skill handles bean registration, property-based configuration across providers, streaming responses via Project Reactor, and embedding store integration for knowledge augmentation.
- Declarative AI Services using @AiService interfaces with message templates and Spring dependency injection
- Auto-configuration and property-based setup for OpenAI, Azure, Ollama, and Anthropic models without manual bean wiring
- Chat memory with Spring context management via @MemoryId for multi-user conversational assistants
- RAG pipeline integration with embedding stores (PgVector), document splitting, and content retrieval
- Spring component tools using @Tool annotations and streaming responses with Project Reactor Flux
Langchain4j Spring Boot Integration by the numbers
- 1,640 all-time installs (skills.sh)
- +56 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #742 of 16,659 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
langchain4j-spring-boot-integration capabilities & compatibility
Pay-per-token to AI providers (OpenAI, Azure, Anthropic); infrastructure costs for embedding store (PostgreSQL optional)
- Capabilities
- auto configuration of ai model beans via spring · declarative ai services with @aiservice and mess · multi provider ai model switching with property · chat memory management with spring context and @ · rag pipeline with embedding stores and spring da · tool integration via spring components and @tool · streaming responses using project reactor flux · dependency injection for ai services into other
- Works with
- openai · azure · anthropic · postgres
- Use cases
- api development · orchestration · code review · memory
- Platforms
- macOS · Windows · Linux · WSL
- Runs
- Remote server
- Pricing
- Free
What langchain4j-spring-boot-integration says it does
Integrate LangChain4j with Spring Boot using declarative AI Services, auto-configuration, and Spring Boot starters.
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill langchain4j-spring-boot-integrationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.6k |
|---|---|
| repo stars | ★ 311 |
| Security audit | 3 / 3 scanners passed |
| Last updated | June 22, 2026 |
| Repository | giuseppe-trisciuoglio/developer-kit ↗ |
What it does
Integrate LangChain4j AI services into Spring Boot applications with declarative beans and auto-configuration.
Who is it for?
Java backend developers building Spring Boot microservices, enterprise AI integrations, multi-provider LLM deployments, conversational systems with memory, and RAG-augmented applications.
Skip if: Frontend frameworks, non-Spring Java applications, serverless functions, or use cases requiring non-declarative control over AI service lifecycle.
When should I use this skill?
Integrating LangChain4j into existing Spring Boot applications, configuring auto-configuration, defining AI Services with @AiService, setting up chat memory, implementing RAG with Spring Data, or building multi-provider
What you get
Developers can rapidly build AI-powered Spring Boot microservices with declarative AI Services, externalized configuration, memory management, tool integration, and RAG pipelines without managing low-level LangChain4j wi
- Configured Spring Boot application with LangChain4j starter dependencies
- Declarative @AiService interfaces with system and user message templates
- Property-based configuration in application.properties/yaml for AI models
By the numbers
- LangChain4j version 1.8.0 or later supports Spring Boot 3.0+ auto-configuration
- Supports 4+ AI providers: OpenAI, Azure OpenAI, Ollama, Anthropic
- Streaming via Project Reactor Flux for real-time responses
Files
LangChain4j Spring Boot Integration
Integrate LangChain4j with Spring Boot using declarative AI Services, auto-configuration, and Spring Boot starters. Configure AI model beans, set up chat memory, implement RAG pipelines with Spring Data, and build production-ready AI applications.
When to Use
Use this skill when:
- Integrating LangChain4j into existing Spring Boot applications
- Building AI-powered microservices with Spring Boot
- Configuring AI model beans with
@Beanannotations - Setting up auto-configuration for AI models and services
- Creating declarative AI Services with Spring dependency injection
- Implementing RAG systems with Spring Data integrations
- Setting up chat memory with Spring context management
- Configuring multiple AI providers (OpenAI, Azure, Ollama, Anthropic)
- Building production-ready AI applications with Spring Boot
Overview
LangChain4j Spring Boot integration provides declarative AI Services through Spring Boot starters, enabling automatic configuration of AI components based on properties. Combine Spring dependency injection with LangChain4j's AI capabilities using interface-based definitions with annotations.
Instructions
1. Add Dependencies
<!-- Core LangChain4j Spring Boot Starter -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.8.0</version>
</dependency>
<!-- OpenAI Spring Boot Starter -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>1.8.0</version>
</dependency>2. Configure Application Properties
# application.properties
langchain4j.open-ai.chat-model.api-key=${OPENAI_API_KEY}
langchain4j.open-ai.chat-model.model-name=gpt-4o-mini
langchain4j.open-ai.chat-model.temperature=0.7
langchain4j.open-ai.chat-model.timeout=PT60S
langchain4j.open-ai.chat-model.max-tokens=1000Or using YAML:
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY}
model-name: gpt-4o-mini
temperature: 0.7
timeout: 60s
max-tokens: 10003. Create Declarative AI Service
import dev.langchain4j.service.spring.AiService;
@AiService
public interface CustomerSupportAssistant {
@SystemMessage("You are a helpful customer support agent for TechCorp.")
String handleInquiry(String customerMessage);
@UserMessage("Translate to {{language}}: {{text}}")
String translate(String text, String language);
}4. Enable Component Scanning
@SpringBootApplication
@ComponentScan(basePackages = {
"com.yourcompany",
"dev.langchain4j.service.spring"
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}5. Inject and Use the AI Service
@Service
public class CustomerService {
private final CustomerSupportAssistant assistant;
public CustomerService(CustomerSupportAssistant assistant) {
this.assistant = assistant;
}
public String processCustomerQuery(String query) {
return assistant.handleInquiry(query);
}
}6. Verify the Integration
After setup, verify the configuration: 1. Start the application and check logs for LangChain4jSpringBootAutoConfiguration activation 2. Confirm AI service beans are registered: look for CustomerSupportAssistant in Spring context 3. Test the service: invoke assistant.handleInquiry("test") and verify a response is returned
Configuration
Property-Based Configuration: Configure AI models through application.properties for different providers.
Manual Bean Configuration: For advanced configurations, define beans manually:
@Configuration
public class AiConfig {
@Bean
public ChatModel chatModel(@Value("${OPENAI_API_KEY}") String apiKey) {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName("gpt-4o-mini")
.temperature(0.7)
.build();
}
}Multiple Providers: Use explicit wiring when configuring multiple AI providers:
@AiService(wiringMode = WiringMode.EXPLICIT)
interface MultiProviderAssistant {
@AiServiceAnnotation
ChatModel openAiModel;
@AiServiceAnnotation
ChatModel azureModel;
}Declarative AI Services
Basic AI Service: Create interfaces with @AiService annotation and define methods with message templates.
Streaming AI Service: Implement streaming responses using Project Reactor:
@AiService
public interface StreamingAssistant {
@SystemMessage("You are a helpful assistant.")
Flux<String> chatStream(String message);
}Chat Memory: Set up conversation memory with Spring context:
@AiService
public interface ConversationalAssistant {
@SystemMessage("You are a helpful assistant with memory.")
String chat(@MemoryId String userId, String message);
}RAG Implementation
Embedding Stores: Configure embedding stores for RAG pipelines with Spring Data:
@Configuration
public class RagConfig {
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return PgVectorEmbeddingStore.builder()
.host("localhost")
.port(5432)
.database("vectordb")
.table("embeddings")
.dimension(1536)
.build();
}
@Bean
public EmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.withApiKey(System.getenv("OPENAI_API_KEY"));
}
}
@AiService
public interface RagAssistant {
String answer(@UserMessage("Question: {{question}}") String question);
}Document Ingestion: Use ContentInjector and DocumentSplitter for processing documents. Content Retrieval: Configure EmbeddingStoreContentRetriever for knowledge augmentation.
Tool Integration
Spring Component Tools: Define tools as Spring components:
@Component
public class Calculator {
@Tool("Calculate the sum of two numbers")
public double add(double a, double b) {
return a + b;
}
}
@AiService
public interface MathAssistant {
String solve(String problem);
}Examples
Basic AI Service
@AiService
public interface ChatAssistant {
@SystemMessage("You are a helpful assistant.")
String chat(String message);
}AI Service with Memory
@AiService
public interface ConversationalAssistant {
@SystemMessage("You are a helpful assistant with memory of conversations.")
String chat(@MemoryId String userId, String message);
}AI Service with Tools
@Component
public class WeatherService {
@Tool("Get weather for a city")
public String getWeather(String city) {
return "Sunny, 22°C in " + city;
}
}
@AiService
public interface WeatherAssistant {
String getWeatherForCity(String city);
}For more examples (including RAG configurations, streaming assistants, and multi-provider setups), refer to references/examples.md.
Best Practices
- Use Property-Based Configuration: External configuration over hardcoded values
- Use Profiles: Separate configurations for development, testing, and production
- Add Proper Logging: Debug AI service calls and monitor performance
- Implement Retry Mechanisms: Handle transient failures with backoff strategies
- Monitor Token Usage: Track token consumption and implement limits
References
For detailed API references and advanced configurations:
- API Reference - Complete API documentation
- Examples - Comprehensive implementation examples
- Configuration Guide - Deep dive into configuration options
Constraints and Warnings
- Store API keys securely using environment variables or secret management systems
- AI model responses are non-deterministic; tests should account for variability
- Rate limits may apply to AI providers; implement proper retry and backoff strategies
- Memory providers store conversation history; implement cleanup for multi-user scenarios
- Token costs accumulate quickly; monitor usage and implement token limits
- Streaming responses require proper error handling for partial failures
- Check provider-specific documentation for supported features
- Use explicit wiring mode when multiple chat models are configured
- Validate AI-generated outputs before use in production systems
LangChain4j Spring Boot Integration - Configuration Guide
Detailed configuration options and advanced setup patterns for LangChain4j with Spring Boot.
Property-Based Configuration
Core Configuration Properties
application.yml
langchain4j:
# OpenAI Configuration
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY}
model-name: gpt-4o-mini
temperature: 0.7
max-tokens: 1000
log-requests: true
log-responses: true
timeout: PT60S
max-retries: 3
organization: ${OPENAI_ORGANIZATION:}
embedding-model:
api-key: ${OPENAI_API_KEY}
model-name: text-embedding-3-small
dimensions: 1536
timeout: PT60S
streaming-chat-model:
api-key: ${OPENAI_API_KEY}
model-name: gpt-4o-mini
temperature: 0.7
max-tokens: 2000
# Azure OpenAI Configuration
azure-open-ai:
chat-model:
endpoint: ${AZURE_OPENAI_ENDPOINT}
api-key: ${AZURE_OPENAI_KEY}
deployment-name: gpt-4o
service-version: 2024-02-15-preview
temperature: 0.7
max-tokens: 1000
log-requests-and-responses: true
embedding-model:
endpoint: ${AZURE_OPENAI_ENDPOINT}
api-key: ${AZURE_OPENAI_KEY}
deployment-name: text-embedding-3-small
dimensions: 1536
# Anthropic Configuration
anthropic:
chat-model:
api-key: ${ANTHROPIC_API_KEY}
model-name: claude-3-5-sonnet-20241022
max-tokens: 4000
temperature: 0.7
streaming-chat-model:
api-key: ${ANTHROPIC_API_KEY}
model-name: claude-3-5-sonnet-20241022
# Ollama Configuration
ollama:
chat-model:
base-url: http://localhost:11434
model-name: llama3.1
temperature: 0.8
timeout: PT60S
# Memory Configuration
memory:
store-type: in-memory # in-memory, postgresql, mysql, mongodb
max-messages: 20
window-size: 10
# Vector Store Configuration
vector-store:
type: in-memory # in-memory, pinecone, weaviate, qdrant, postgresql
pinecone:
api-key: ${PINECONE_API_KEY}
index-name: my-index
namespace: production
qdrant:
host: localhost
port: 6333
collection-name: documents
weaviate:
host: localhost
port: 8080
collection-name: Documents
postgresql:
table: document_embeddings
dimension: 1536Spring Profiles Configuration
application-dev.yml
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY_DEV}
model-name: gpt-4o-mini
temperature: 0.8 # Higher temperature for experimentation
log-requests: true
log-responses: true
vector-store:
type: in-memoryapplication-prod.yml
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY_PROD}
model-name: gpt-4o
temperature: 0.3 # Lower temperature for consistency
log-requests: false
log-responses: false
vector-store:
type: pinecone
pinecone:
api-key: ${PINECONE_API_KEY_PROD}
index-name: production-knowledge-baseManual Bean Configuration
Advanced Chat Model Configuration
@Configuration
@Profile("custom-openai")
public class CustomOpenAiConfiguration {
@Bean
@Primary
public ChatModel customOpenAiChatModel(
@Value("${custom.openai.api.key}") String apiKey,
@Value("${custom.openai.model}") String model,
@Value("${custom.openai.temperature}") Double temperature) {
OpenAiChatModelBuilder builder = OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName(model)
.temperature(temperature);
if (Boolean.TRUE.equals(env.getProperty("custom.openai.log-requests", Boolean.class))) {
builder.logRequests(true);
}
if (Boolean.TRUE.equals(env.getProperty("custom.openai.log-responses", Boolean.class))) {
builder.logResponses(true);
}
return builder.build();
}
@Bean
@ConditionalOnProperty(name = "custom.openai.proxy.enabled", havingValue = "true")
public ChatModel proxiedChatModel(ChatModel delegate) {
return new ProxiedChatModel(delegate,
env.getProperty("custom.openai.proxy.url"),
env.getProperty("custom.openai.proxy.username"),
env.getProperty("custom.openai.proxy.password"));
}
}
class ProxiedChatModel implements ChatModel {
private final ChatModel delegate;
private final String proxyUrl;
private final String username;
private final String password;
public ProxiedChatModel(ChatModel delegate, String proxyUrl, String username, String password) {
this.delegate = delegate;
this.proxyUrl = proxyUrl;
this.username = username;
this.password = password;
}
@Override
public Response<AiMessage> generate(ChatRequest request) {
// Apply proxy configuration
// Make request through proxy
return delegate.generate(request);
}
}Multiple Provider Configuration
@Configuration
public class MultiProviderConfiguration {
@Bean("openAiChatModel")
public ChatModel openAiChatModel(
@Value("${openai.api.key}") String apiKey,
@Value("${openai.model.name}") String modelName) {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.temperature(0.7)
.logRequests(env.acceptsProfiles("dev"))
.build();
}
@Bean("anthropicChatModel")
public ChatModel anthropicChatModel(
@Value("${anthropic.api.key}") String apiKey,
@Value("${anthropic.model.name}") String modelName) {
return AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.maxTokens(4000)
.build();
}
@Bean("ollamaChatModel")
@ConditionalOnProperty(name = "ollama.enabled", havingValue = "true")
public ChatModel ollamaChatModel(
@Value("${ollama.base-url}") String baseUrl,
@Value("${ollama.model.name}") String modelName) {
return OllamaChatModel.builder()
.baseUrl(baseUrl)
.modelName(modelName)
.temperature(0.8)
.build();
}
}Explicit Wiring Configuration
@AiService(wiringMode = EXPLICIT, chatModel = "productionChatModel")
interface ProductionAssistant {
@SystemMessage("You are a production-grade AI assistant providing high-quality, reliable responses.")
String chat(String message);
}
@AiService(wiringMode = EXPLICIT, chatModel = "developmentChatModel")
interface DevelopmentAssistant {
@SystemMessage("You are a development assistant helping with code and debugging. " +
"Be experimental and creative in your responses.")
String chat(String message);
}
@AiService(wiringMode = EXPLICIT,
chatModel = "specializedChatModel",
tools = "businessTools")
interface SpecializedAssistant {
@SystemMessage("You are a specialized assistant with access to business tools. " +
"Use the available tools to provide accurate information.")
String chat(String message);
}
@Component("businessTools")
public class BusinessLogicTools {
@Tool("Calculate discount based on customer status")
public BigDecimal calculateDiscount(
@P("Purchase amount") BigDecimal amount,
@P("Customer status") String customerStatus) {
return switch (customerStatus.toLowerCase()) {
case "vip" -> amount.multiply(new BigDecimal("0.15"));
case "premium" -> amount.multiply(new BigDecimal("0.10"));
case "standard" -> amount.multiply(new BigDecimal("0.05"));
default -> BigDecimal.ZERO;
};
}
}Embedding Store Configuration
PostgreSQL with pgvector
@Configuration
@RequiredArgsConstructor
public class PostgresEmbeddingStoreConfiguration {
@Bean
public EmbeddingStore<TextSegment> postgresEmbeddingStore(
DataSource dataSource,
@Value("${spring.datasource.schema}") String schema) {
return PgVectorEmbeddingStore.builder()
.dataSource(dataSource)
.table("document_embeddings")
.dimension(1536)
.initializeSchema(true)
.schema(schema)
.indexName("document_embeddings_idx")
.build();
}
@Bean
public ContentRetriever postgresContentRetriever(
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(5)
.minScore(0.7)
.build();
}
}Pinecone Configuration
@Configuration
@Profile("pinecone")
public class PineconeConfiguration {
@Bean
public EmbeddingStore<TextSegment> pineconeEmbeddingStore(
@Value("${pinecone.api.key}") String apiKey,
@Value("${pinecone.index.name}") String indexName,
@Value("${pinecone.namespace}") String namespace) {
PineconeEmbeddingStore store = PineconeEmbeddingStore.builder()
.apiKey(apiKey)
.indexName(indexName)
.namespace(namespace)
.build();
// Initialize if needed
if (!store.indexExists()) {
store.createIndex(1536);
}
return store;
}
}Custom Embedding Store
@Component
public class CustomEmbeddingStore implements EmbeddingStore<TextSegment> {
private final Map<UUID, TextSegment> embeddings = new ConcurrentHashMap<>();
private final Map<UUID, float[]> vectors = new ConcurrentHashMap<>();
@Override
public void add(Embedding embedding, TextSegment textSegment) {
UUID id = UUID.randomUUID();
embeddings.put(id, textSegment);
vectors.put(id, embedding.vector());
}
@Override
public void addAll(List<Embedding> embeddings, List<TextSegment> textSegments) {
for (int i = 0; i < embeddings.size(); i++) {
add(embeddings.get(i), textSegments.get(i));
}
}
@Override
public List<Embedding> findRelevant(Embedding embedding, int maxResults) {
return vectors.entrySet().stream()
.sorted(Comparator.comparingDouble(e -> cosineSimilarity(e.getValue(), embedding.vector())))
.limit(maxResults)
.map(e -> new EmbeddingImpl(e.getValue(), embeddings.get(e.getKey()).id()))
.collect(Collectors.toList());
}
private double cosineSimilarity(float[] vec1, float[] vec2) {
// Implementation of cosine similarity
return 0.0;
}
}Memory Configuration
Chat Memory Store Configuration
@Configuration
public class MemoryConfiguration {
@Bean
@Profile("in-memory")
public ChatMemoryStore inMemoryChatMemoryStore() {
return new InMemoryChatMemoryStore();
}
@Bean
@Profile("database")
public ChatMemoryStore databaseChatMemoryStore(ChatMessageRepository messageRepository) {
return new DatabaseChatMemoryStore(messageRepository);
}
@Bean
public ChatMemoryProvider chatMemoryProvider(ChatMemoryStore memoryStore) {
return memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(getMaxMessages())
.chatMemoryStore(memoryStore)
.build();
}
private int getMaxMessages() {
return env.getProperty("langchain4j.memory.max-messages", int.class, 20);
}
}Database Chat Memory Store
@Component
@RequiredArgsConstructor
public class DatabaseChatMemoryStore implements ChatMemoryStore {
private final ChatMessageRepository repository;
@Override
public List<ChatMessage> getMessages(Object memoryId) {
return repository.findByMemoryIdOrderByCreatedAtAsc(memoryId.toString())
.stream()
.map(this::toMessage)
.collect(Collectors.toList());
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages) {
String id = memoryId.toString();
repository.deleteByMemoryId(id);
List<ChatMessageEntity> entities = messages.stream()
.map(msg -> toEntity(id, msg))
.collect(Collectors.toList());
repository.saveAll(entities);
}
private ChatMessage toMessage(ChatMessageEntity entity) {
return switch (entity.getMessageType()) {
case USER -> UserMessage.from(entity.getContent());
case AI -> AiMessage.from(entity.getContent());
case SYSTEM -> SystemMessage.from(entity.getContent());
};
}
private ChatMessageEntity toEntity(String memoryId, ChatMessage message) {
ChatMessageEntity entity = new ChatMessageEntity();
entity.setMemoryId(memoryId);
entity.setContent(message.text());
entity.setCreatedAt(LocalDateTime.now());
entity.setMessageType(determineMessageType(message));
return entity;
}
private MessageType determineMessageType(ChatMessage message) {
if (message instanceof UserMessage) return MessageType.USER;
if (message instanceof AiMessage) return MessageType.AI;
if (message instanceof SystemMessage) return MessageType.SYSTEM;
throw new IllegalArgumentException("Unknown message type: " + message.getClass());
}
}Observability Configuration
Monitoring and Metrics
@Configuration
public class ObservabilityConfiguration {
@Bean
public ChatModelListener chatModelListener(MeterRegistry meterRegistry) {
return new MonitoringChatModelListener(meterRegistry);
}
@Bean
public HealthIndicator aiHealthIndicator(ChatModel chatModel) {
return new AiHealthIndicator(chatModel);
}
}
class MonitoringChatModelListener implements ChatModelListener {
private final MeterRegistry meterRegistry;
private final Counter requestCounter;
private final Timer responseTimer;
public MonitoringChatModelListener(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.requestCounter = Counter.builder("ai.requests.total")
.description("Total AI requests")
.register(meterRegistry);
this.responseTimer = Timer.builder("ai.response.duration")
.description("AI response time")
.register(meterRegistry);
}
@Override
public void onRequest(ChatModelRequestContext requestContext) {
requestCounter.increment();
logRequest(requestContext);
}
@Override
public void onResponse(ChatModelResponseContext responseContext) {
responseTimer.record(responseContext.duration());
logResponse(responseContext);
}
private void logRequest(ChatModelRequestContext requestContext) {
meterRegistry.gauge("ai.request.tokens",
requestContext.request().messages().size());
}
private void logResponse(ChatModelResponseContext responseContext) {
Response<AiMessage> response = responseContext.response();
meterRegistry.gauge("ai.response.tokens",
response.tokenUsage().totalTokenCount());
}
}Custom Health Check
@Component
@RequiredArgsConstructor
public class AiHealthIndicator implements HealthIndicator {
private final ChatModel chatModel;
private final EmbeddingModel embeddingModel;
@Override
public Health health() {
try {
// Test chat model
Health.Builder builder = Health.up();
String chatResponse = chatModel.chat("ping");
builder.withDetail("chat_model", "healthy");
if (chatResponse == null || chatResponse.trim().isEmpty()) {
return Health.down().withDetail("reason", "Empty response");
}
// Test embedding model
List<String> testTexts = List.of("test", "ping", "hello");
List<Embedding> embeddings = embeddingModel.embedAll(testTexts).content();
if (embeddings.isEmpty()) {
return Health.down().withDetail("reason", "No embeddings generated");
}
builder.withDetail("embedding_model", "healthy")
.withDetail("embedding_dimension", embeddings.get(0).vector().length);
return builder.build();
} catch (Exception e) {
return Health.down()
.withDetail("error", e.getMessage())
.withDetail("exception_class", e.getClass().getSimpleName());
}
}
}Security Configuration
API Key Security
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.requestMatchers("/api/ai/**").hasRole("AI_USER")
.requestMatchers("/actuator/ai/**").hasRole("AI_ADMIN")
.anyRequest().permitAll()
.and()
.httpBasic();
return http.build();
}
@Bean
public ApiKeyAuthenticationFilter apiKeyAuthenticationFilter() {
return new ApiKeyAuthenticationFilter("/api/ai/**");
}
}
class ApiKeyAuthenticationFilter extends OncePerRequestFilter {
private final String pathPrefix;
public ApiKeyAuthenticationFilter(String pathPrefix) {
this.pathPrefix = pathPrefix;
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if (request.getRequestURI().startsWith(pathPrefix)) {
String apiKey = request.getHeader("X-API-Key");
if (apiKey == null || !isValidApiKey(apiKey)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid API key");
return;
}
}
filterChain.doFilter(request, response);
}
private boolean isValidApiKey(String apiKey) {
// Validate API key against database or security service
return true;
}
}Configuration Validation
@Component
@RequiredArgsConstructor
@Slf4j
public class AiConfigurationValidator implements InitializingBean {
private final AiProperties properties;
@Override
public void afterPropertiesSet() {
validateConfiguration();
}
private void validateConfiguration() {
if (properties.getOpenai() != null) {
validateOpenAiConfiguration();
}
if (properties.getAzureOpenAi() != null) {
validateAzureConfiguration();
}
if (properties.getAnthropic() != null) {
validateAnthropicConfiguration();
}
log.info("AI configuration validation completed successfully");
}
private void validateOpenAiConfiguration() {
OpenAiProperties openAi = properties.getOpenai();
if (openAi.getChatModel() != null &&
(openAi.getChatModel().getApiKey() == null ||
openAi.getChatModel().getApiKey().isEmpty())) {
log.warn("OpenAI chat model API key is not configured");
}
if (openAi.getChatModel() != null &&
openAi.getChatModel().getMaxTokens() != null &&
openAi.getChatModel().getMaxTokens() > 8192) {
log.warn("OpenAI max tokens {} exceeds recommended limit of 8192",
openAi.getChatModel().getMaxTokens());
}
}
private void validateAzureConfiguration() {
AzureOpenAiProperties azure = properties.getAzureOpenAi();
if (azure.getChatModel() != null &&
(azure.getChatModel().getEndpoint() == null ||
azure.getChatModel().getApiKey() == null)) {
log.error("Azure OpenAI endpoint or API key is not configured");
}
}
private void validateAnthropicConfiguration() {
AnthropicProperties anthropic = properties.getAnthropic();
if (anthropic.getChatModel() != null &&
(anthropic.getChatModel().getApiKey() == null ||
anthropic.getChatModel().getApiKey().isEmpty())) {
log.warn("Anthropic chat model API key is not configured");
}
}
}
@Configuration
@ConfigurationProperties(prefix = "langchain4j")
@Validated
@Data
public class AiProperties {
private OpenAiProperties openai;
private AzureOpenAiProperties azureOpenAi;
private AnthropicProperties anthropic;
private MemoryProperties memory;
private VectorStoreProperties vectorStore;
// Validation annotations for properties
}
@Data
@Validated
public class OpenAiProperties {
private ChatModelProperties chatModel;
private EmbeddingModelProperties embeddingModel;
private StreamingChatModelProperties streamingChatModel;
@Valid
@NotNull
public ChatModelProperties getChatModel() {
return chatModel;
}
}Environment-Specific Configurations
Development Configuration
# application-dev.yml
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY_DEV}
model-name: gpt-4o-mini
temperature: 0.8
log-requests: true
log-responses: true
memory:
store-type: in-memory
max-messages: 10
vector-store:
type: in-memory
logging:
level:
dev.langchain4j: DEBUG
org.springframework.ai: DEBUGProduction Configuration
# application-prod.yml
langchain4j:
open-ai:
chat-model:
api-key: ${OPENAI_API_KEY_PROD}
model-name: gpt-4o
temperature: 0.3
log-requests: false
log-responses: false
max-tokens: 4000
memory:
store-type: postgresql
max-messages: 5
vector-store:
type: pinecone
pinecone:
index-name: production-knowledge-base
namespace: prod
logging:
level:
dev.langchain4j: WARN
org.springframework.ai: WARN
management:
endpoints:
web:
exposure:
include: health, metrics, info
endpoint:
health:
show-details: when-authorizedThis configuration guide provides comprehensive options for setting up LangChain4j with Spring Boot, covering various providers, storage backends, monitoring, and security considerations.
LangChain4j Spring Boot Integration - Examples
Comprehensive implementation examples for Spring Boot integration with LangChain4j.
Basic Setup Example
Complete Spring Boot Application
@SpringBootApplication
public class Langchain4jApplication {
public static void main(String[] args) {
SpringApplication.run(Langchain4jApplication.class, args);
}
}
@Configuration
public class AiConfiguration {
@Bean
@Profile("openai")
public ChatModel openAiChatModel(@Value("${langchain4j.open-ai.chat-model.api-key}") String apiKey) {
return OpenAiChatModel.builder()
.apiKey(apiKey)
.modelName("gpt-4o-mini")
.temperature(0.7)
.maxTokens(1000)
.logRequests(true)
.logResponses(true)
.build();
}
@Bean
public EmbeddingModel openAiEmbeddingModel(@Value("${langchain4j.open-ai.embedding-model.api-key}") String apiKey) {
return OpenAiEmbeddingModel.builder()
.apiKey(apiKey)
.modelName("text-embedding-3-small")
.dimensions(1536)
.build();
}
}
@AiService
interface CustomerSupportAssistant {
@SystemMessage("You are a helpful customer support agent for TechCorp. " +
"Be polite, professional, and try to resolve customer issues efficiently. " +
"If you cannot resolve an issue, escalate to a human agent.")
String handleInquiry(String customerMessage);
@UserMessage("Analyze this customer feedback and extract sentiment: {{feedback}}")
@SystemMessage("Return only: POSITIVE, NEGATIVE, or NEUTRAL")
String analyzeSentiment(String feedback);
@UserMessage("Extract key entities from this text: {{text}}")
@SystemMessage("Return a JSON object with entities as keys and their types as values")
String extractEntities(String text);
}
@RestController
@RequestMapping("/api/support")
@RequiredArgsConstructor
public class CustomerSupportController {
private final CustomerSupportAssistant assistant;
@PostMapping("/inquiry")
public ResponseEntity<SupportResponse> handleInquiry(@RequestBody @Valid SupportRequest request) {
String response = assistant.handleInquiry(request.getMessage());
return ResponseEntity.ok(new SupportResponse(response, Instant.now()));
}
@PostMapping("/sentiment")
public ResponseEntity<SentimentResponse> analyzeSentiment(@RequestBody @Valid SentimentRequest request) {
String sentiment = assistant.analyzeSentiment(request.getFeedback());
return ResponseEntity.ok(new SentimentResponse(sentiment, Instant.now()));
}
@PostMapping("/entities")
public ResponseEntity<EntitiesResponse> extractEntities(@RequestBody @Valid EntitiesRequest request) {
String entities = assistant.extractEntities(request.getText());
return ResponseEntity.ok(new EntitiesResponse(entities, Instant.now()));
}
}
// DTO Classes
record SupportRequest(String message) {}
record SupportResponse(String response, Instant timestamp) {}
record SentimentRequest(String feedback) {}
record SentimentResponse(String sentiment, Instant timestamp) {}
record EntitiesRequest(String text) {}
record EntitiesResponse(String entities, Instant timestamp) {}2. Custom AI Service Bean Configuration
Scenario: Configure AI services as Spring beans.
@Configuration
public class AiConfig {
@Bean
public ChatModel chatModel() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("gpt-4o-mini")
.temperature(0.7)
.build();
}
@Bean
public EmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
}
@Bean
public DocumentAssistant documentAssistant(ChatModel chatModel) {
return AiServices.builder(DocumentAssistant.class)
.chatModel(chatModel)
.chatMemory(MessageWindowChatMemory.withMaxMessages(10))
.build();
}
}
interface DocumentAssistant {
String chat(String message);
}3. REST API with AI Service
Scenario: Expose AI functionality via REST endpoints.
@RestController
@RequestMapping("/api/chat")
public class ChatController {
private final ChatAssistant assistant;
@Autowired
public ChatController(ChatAssistant assistant) {
this.assistant = assistant;
}
@PostMapping
public ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest request) {
try {
String response = assistant.chat(request.getMessage());
return ResponseEntity.ok(new ChatResponse(response));
} catch (Exception e) {
return ResponseEntity.internalServerError()
.body(new ChatResponse("Error: " + e.getMessage()));
}
}
@PostMapping("/stream")
public ResponseEntity<StreamingResponseBody> streamChat(@RequestBody ChatRequest request) {
return ResponseEntity.ok(outputStream -> {
var streamAssistant = streamingAssistant;
var stream = streamAssistant.streamChat(request.getMessage());
stream.onNext(token -> {
try {
outputStream.write(token.getBytes());
outputStream.flush();
} catch (IOException e) {
// Handle write error
}
}).start();
});
}
}
@Data
class ChatRequest {
private String message;
}
@Data
class ChatResponse {
private String response;
}4. Service with RAG Integration
Scenario: Service layer with document search and retrieval.
@Service
public class KnowledgeBaseService {
private final DocumentAssistant assistant;
private final EmbeddingStore<TextSegment> embeddingStore;
private final EmbeddingModel embeddingModel;
@Autowired
public KnowledgeBaseService(
DocumentAssistant assistant,
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
this.assistant = assistant;
this.embeddingStore = embeddingStore;
this.embeddingModel = embeddingModel;
}
public void ingestDocument(String content, Map<String, Object> metadata) {
var document = Document.from(content);
document.metadata().putAll(metadata);
var ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.documentSplitter(DocumentSplitters.recursive(500, 50))
.build();
ingestor.ingest(document);
}
public String answerQuestion(String question) {
return assistant.answerAbout(question);
}
}
interface DocumentAssistant {
String answerAbout(String question);
}5. Scheduled Task for Document Updates
Scenario: Periodically update knowledge base.
@Service
public class DocumentUpdateService {
private final EmbeddingStore<TextSegment> embeddingStore;
private final EmbeddingModel embeddingModel;
@Autowired
public DocumentUpdateService(
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
this.embeddingStore = embeddingStore;
this.embeddingModel = embeddingModel;
}
@Scheduled(fixedRate = 86400000) // Daily
public void updateDocuments() {
var documents = fetchLatestDocuments();
var ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
documents.forEach(ingestor::ingest);
logger.info("Documents updated successfully");
}
private List<Document> fetchLatestDocuments() {
// Fetch from database or external API
return Collections.emptyList();
}
}6. Controller with Tool Integration
Scenario: AI service with business logic tools.
@Service
public class BusinessLogicService {
@Tool("Get user by ID")
public User getUser(@P("user ID") String userId) {
// Implementation
return new User(userId);
}
@Tool("Calculate discount")
public double calculateDiscount(@P("purchase amount") double amount) {
if (amount > 1000) return 0.15;
if (amount > 500) return 0.10;
return 0.05;
}
}
@Service
public class ToolAssistant {
private final ChatModel chatModel;
private final BusinessLogicService businessLogic;
@Autowired
public ToolAssistant(ChatModel chatModel, BusinessLogicService businessLogic) {
this.chatModel = chatModel;
this.businessLogic = businessLogic;
}
public String processRequest(String request) {
return AiServices.builder(Assistant.class)
.chatModel(chatModel)
.tools(businessLogic)
.build()
.chat(request);
}
}
interface Assistant {
String chat(String message);
}7. Error Handling with Spring Exception Handler
Scenario: Centralized error handling for AI services.
@ControllerAdvice
public class AiExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleBadRequest(IllegalArgumentException e) {
return ResponseEntity.badRequest()
.body(new ErrorResponse("Invalid input: " + e.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleError(Exception e) {
logger.error("Error in AI service", e);
return ResponseEntity.internalServerError()
.body(new ErrorResponse("An error occurred: " + e.getMessage()));
}
}
@Data
class ErrorResponse {
private String message;
}8. Configuration Properties
Scenario: Externalize AI configuration.
@Configuration
@ConfigurationProperties(prefix = "app.ai")
@Data
public class AiProperties {
private String openaiApiKey;
private String openaiModel = "gpt-4o-mini";
private double temperature = 0.7;
private int maxTokens = 2000;
private String embeddingModel = "text-embedding-3-small";
private int memorySize = 10;
private String vectorStoreType = "in-memory";
}
// application.yml
app:
ai:
openai-api-key: ${OPENAI_API_KEY}
openai-model: gpt-4o-mini
temperature: 0.7
max-tokens: 2000
embedding-model: text-embedding-3-small
memory-size: 10
vector-store-type: pinecone9. Integration Testing
Scenario: Test AI services with Spring Boot Test.
@SpringBootTest
class ChatServiceTest {
@MockBean
private ChatModel chatModel;
@Autowired
private ChatService chatService;
@Test
void testChat() {
when(chatModel.chat("Hello"))
.thenReturn("Hi there!");
String response = chatService.chat("Hello");
assertEquals("Hi there!", response);
}
}10. Async Processing with CompletableFuture
Scenario: Non-blocking AI service calls.
@Service
@EnableAsync
public class AsyncChatService {
private final ChatModel chatModel;
@Autowired
public AsyncChatService(ChatModel chatModel) {
this.chatModel = chatModel;
}
@Async
public CompletableFuture<String> chatAsync(String message) {
try {
String response = chatModel.chat(message);
return CompletableFuture.completedFuture(response);
} catch (Exception e) {
return CompletableFuture.failedFuture(e);
}
}
}
// Usage in controller
@RestController
public class AsyncController {
@Autowired
private AsyncChatService asyncChatService;
@PostMapping("/chat/async")
public CompletableFuture<ResponseEntity<String>> chatAsync(@RequestBody ChatRequest request) {
return asyncChatService.chatAsync(request.getMessage())
.thenApply(ResponseEntity::ok)
.exceptionally(e -> ResponseEntity.internalServerError().build());
}
}Configuration Examples
Maven Dependency
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>0.27.0</version>
</dependency>Gradle
implementation 'dev.langchain4j:langchain4j-spring-boot-starter:0.27.0'LangChain4j Spring Boot Integration - API References
Complete API reference for Spring Boot integration with LangChain4j.
Spring Boot Starter Dependencies
Maven
<!-- Core Spring Boot LangChain4j integration -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>0.27.0</version>
</dependency>
<!-- OpenAI integration -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
<version>0.27.0</version>
</dependency>Gradle
implementation 'dev.langchain4j:langchain4j-spring-boot-starter:0.27.0'
implementation 'dev.langchain4j:langchain4j-open-ai-spring-boot-starter:0.27.0'Auto-Configuration Properties
OpenAI Configuration
langchain4j:
open-ai:
api-key: ${OPENAI_API_KEY}
model-name: gpt-4o-mini
temperature: 0.7
top-p: 1.0
max-tokens: 2000
timeout: 60s
log-requests: true
log-responses: true
openai-embedding:
api-key: ${OPENAI_API_KEY}
model-name: text-embedding-3-small
timeout: 60sVector Store Configuration
langchain4j:
vector-store:
type: in-memory # or pinecone, weaviate, qdrant, etc.
# Pinecone
pinecone:
api-key: ${PINECONE_API_KEY}
index-name: my-index
namespace: production
# Qdrant
qdrant:
host: localhost
port: 6333
collection-name: documents
# Weaviate
weaviate:
host: localhost
port: 8080
collection-name: DocumentsSpring Configuration Annotations
@Configuration
@Configuration
public class AiConfig {
@Bean
public ChatModel chatModel() {
// Bean definition
}
@Bean
@ConditionalOnMissingBean
public EmbeddingModel embeddingModel() {
// Fallback bean
}
}@ConditionalOnProperty
@Configuration
@ConditionalOnProperty(
prefix = "app.ai",
name = "enabled",
havingValue = "true"
)
public class AiFeatureConfig {
// Configuration only if enabled
}@EnableConfigurationProperties
@Configuration
@EnableConfigurationProperties(AiProperties.class)
public class AiConfig {
@Autowired
private AiProperties aiProperties;
}Dependency Injection
Constructor Injection (Recommended)
@Service
public class ChatService {
private final ChatModel chatModel;
private final EmbeddingModel embeddingModel;
public ChatService(ChatModel chatModel, EmbeddingModel embeddingModel) {
this.chatModel = chatModel;
this.embeddingModel = embeddingModel;
}
}Field Injection (Discouraged)
@Service
public class ChatService {
@Autowired
private ChatModel chatModel; // Not recommended
}Setter Injection
@Service
public class ChatService {
private ChatModel chatModel;
@Autowired
public void setChatModel(ChatModel chatModel) {
this.chatModel = chatModel;
}
}REST Annotations
@RestController with RequestMapping
@RestController
@RequestMapping("/api/chat")
public class ChatController {
@PostMapping
public ResponseEntity<Response> chat(@RequestBody ChatRequest request) {
// Implementation
}
@GetMapping("/{id}")
public ResponseEntity<Response> getChat(@PathVariable String id) {
// Implementation
}
}RequestBody Validation
@PostMapping
public ResponseEntity<Response> chat(@Valid @RequestBody ChatRequest request) {
// Validates request object
}
public class ChatRequest {
@NotBlank(message = "Message cannot be blank")
private String message;
@Min(0)
@Max(100)
private int maxTokens = 2000;
}Exception Handling
@ControllerAdvice
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ErrorResponse> handleBadRequest(IllegalArgumentException e) {
return ResponseEntity.badRequest()
.body(new ErrorResponse(400, e.getMessage()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(Exception e) {
return ResponseEntity.internalServerError()
.body(new ErrorResponse(500, "Internal server error"));
}
}ResponseStatusException
if (!authorized) {
throw new ResponseStatusException(
HttpStatus.FORBIDDEN,
"User not authorized"
);
}Async and Reactive
@Async
@Service
@EnableAsync
public class AsyncService {
@Async
public CompletableFuture<String> processAsync(String input) {
String result = processSync(input);
return CompletableFuture.completedFuture(result);
}
}@Scheduled
@Component
public class ScheduledTasks {
@Scheduled(fixedRate = 60000) // Every minute
public void performTask() {
// Task implementation
}
@Scheduled(cron = "0 0 * * * *") // Daily at midnight
public void dailyTask() {
// Daily task
}
}Testing
@SpringBootTest
@SpringBootTest
class ChatServiceTest {
@Autowired
private ChatService chatService;
@Test
void testChat() {
// Test implementation
}
}@WebMvcTest
@WebMvcTest(ChatController.class)
class ChatControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private ChatService chatService;
@Test
void testChatEndpoint() throws Exception {
mockMvc.perform(post("/api/chat")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"message\": \"Hello\"}"))
.andExpect(status().isOk());
}
}@DataJpaTest
@DataJpaTest
class DocumentRepositoryTest {
@Autowired
private DocumentRepository repository;
@Test
void testFindByUserId() {
// Test implementation
}
}Logging Configuration
application.yml
logging:
level:
root: INFO
dev.langchain4j: DEBUG
org.springframework: WARN
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file:
name: logs/app.logHealth Checks
Custom Health Indicator
@Component
public class AiHealthIndicator extends AbstractHealthIndicator {
@Override
protected void doHealthCheck(Health.Builder builder) {
try {
// Check AI service availability
chatModel.chat("ping");
builder.up();
} catch (Exception e) {
builder.down().withDetail("reason", e.getMessage());
}
}
}Actuator Integration
Maven Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>Configuration
management:
endpoints:
web:
exposure:
include: health, metrics, info
endpoint:
health:
show-details: alwaysSecurity Configuration
@EnableWebSecurity
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/private/**").authenticated()
.and()
.httpBasic();
return http.build();
}
}Bean Lifecycle
@PostConstruct and @PreDestroy
@Service
public class AiService {
@PostConstruct
public void init() {
// Initialize resources
embeddingStore = createEmbeddingStore();
}
@PreDestroy
public void cleanup() {
// Clean up resources
embeddingStore.close();
}
}Best Practices
1. Use Constructor Injection: Explicitly declare dependencies 2. Externalize Configuration: Use application.yml for settings 3. Handle Exceptions: Use @ControllerAdvice for consistent error handling 4. Implement Caching: Cache AI responses when appropriate 5. Use Async Processing: For long-running AI operations 6. Add Health Checks: Implement custom health indicators 7. Log Appropriately: Debug AI service calls in development 8. Test Thoroughly: Use @SpringBootTest and @WebMvcTest 9. Secure APIs: Implement authentication and authorization 10. Monitor Performance: Track AI service metrics
Related skills
Forks & variants (1)
Langchain4j Spring Boot Integration has 1 known copy in the catalog totaling 21 installs. They canonicalize to this original listing.
- giuseppe-trisciuoglio - 21 installs
How it compares
Choose langchain4j-spring-boot-integration over generic LLM skills when the stack is Java Spring Boot with LangChain4j property-based configuration.
FAQ
How do I configure multiple AI providers in one Spring Boot application?
Use explicit wiring mode (WiringMode.EXPLICIT) in @AiService annotation and define separate ChatModel beans for each provider (OpenAI, Azure, Ollama). Configure each via application.properties with provider-specific prefixes like langchain4j.open-ai and langchain4j.azure-open-ai.
How does Spring context handle chat memory for conversations?
Use @MemoryId annotation on parameters to scope conversation history per user or session. Spring manages memory lifecycle through ChatMemory beans configured in the AI service, automatically maintaining state across multiple calls.
What embedding store options are available for RAG?
LangChain4j Spring Boot supports PgVectorEmbeddingStore for PostgreSQL, with EmbeddingStore<TextSegment> interface for extensibility. Configure via bean definitions with host, port, database, table, and dimension parameters.
Is Langchain4j Spring Boot Integration safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.