
Qdrant
- 21 installs
- 318 repo stars
- Updated June 22, 2026
- giuseppe-trisciuoglio/developer-kit-claude-code
This is a copy of qdrant by giuseppe-trisciuoglio - installs and ranking accrue to the original listing.
Helps with ai & agent building tasks.
About
qdrant is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- qdrant
- AI & Agent Building
- AI-coding skill
Qdrant by the numbers
- 21 all-time installs (skills.sh)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit-claude-code --skill qdrantAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 21 |
|---|---|
| repo stars | ★ 318 |
| Last updated | June 22, 2026 |
| Repository | giuseppe-trisciuoglio/developer-kit-claude-code ↗ |
What it does
Helps with ai & agent building tasks.
Files
Qdrant Vector Database Integration
Overview
Qdrant is an AI-native vector database for semantic search and similarity retrieval. This skill provides patterns for integrating Qdrant with Java applications, focusing on Spring Boot and LangChain4j integration.
When to Use
- Semantic search or recommendation systems in Spring Boot applications
- RAG pipelines with Java and LangChain4j
- Vector database integration for AI/ML applications
- High-performance similarity search with filtered queries
Instructions
1. Deploy Qdrant with Docker
docker run -p 6333:6333 -p 6334:6334 \
-v "$(pwd)/qdrant_storage:/qdrant/storage:z" \
qdrant/qdrantAccess: REST API at http://localhost:6333, gRPC at http://localhost:6334.
2. Add Dependencies
Maven:
<dependency>
<groupId>io.qdrant</groupId>
<artifactId>client</artifactId>
<version>1.15.0</version>
</dependency>Gradle:
implementation 'io.qdrant:client:1.15.0'3. Initialize Client
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost").build());For production with API key:
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false)
.withApiKey("YOUR_API_KEY")
.build());4. Create Collection
client.createCollectionAsync("search-collection",
VectorParams.newBuilder()
.setDistance(Distance.Cosine)
.setSize(384)
.build()
).get();Validation: Verify the collection was created by checking client.getCollectionAsync("search-collection").get().
5. Upsert Vectors
List<PointStruct> points = List.of(
PointStruct.newBuilder()
.setId(id(1))
.setVectors(vectors(0.05f, 0.61f, 0.76f, 0.74f))
.putAllPayload(Map.of("title", value("Spring Boot Documentation")))
.build()
);
client.upsertAsync("search-collection", points).get();Validation: Check that client.upsertAsync(...).get() completes without throwing.
6. Search Vectors
List<ScoredPoint> results = client.queryAsync(
QueryPoints.newBuilder()
.setCollectionName("search-collection")
.setLimit(5)
.setQuery(nearest(0.2f, 0.1f, 0.9f, 0.7f))
.build()
).get();Filtered search:
List<ScoredPoint> results = client.searchAsync(
SearchPoints.newBuilder()
.setCollectionName("search-collection")
.addAllVector(List.of(0.62f, 0.12f, 0.53f, 0.12f))
.setFilter(Filter.newBuilder()
.addMust(range("category", Range.newBuilder().setEq("docs").build()))
.build())
.setLimit(5)
.build()).get();LangChain4j Integration
For RAG pipelines, use LangChain4j's high-level abstractions:
EmbeddingStore<TextSegment> embeddingStore = QdrantEmbeddingStore.builder()
.collectionName("rag-collection")
.host("localhost")
.port(6334)
.apiKey("YOUR_API_KEY")
.build();Spring Boot configuration with LangChain4j:
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return QdrantEmbeddingStore.builder()
.collectionName("rag-collection")
.host(host)
.port(port)
.build();
}
@Bean
public EmbeddingModel embeddingModel() {
return new AllMiniLmL6V2EmbeddingModel();
}Spring Boot Integration
Inject the client via configuration:
@Configuration
public class QdrantConfig {
@Value("${qdrant.host:localhost}")
private String host;
@Value("${qdrant.port:6334}")
private int port;
@Bean
public QdrantClient qdrantClient() {
return new QdrantClient(
QdrantGrpcClient.newBuilder(host, port, false).build());
}
}Examples
REST Search Endpoint
@RestController
@RequestMapping("/api/search")
public class SearchController {
private final VectorSearchService searchService;
public SearchController(VectorSearchService searchService) {
this.searchService = searchService;
}
@GetMapping
public List<ScoredPoint> search(@RequestParam String query) {
List<Float> queryVector = embeddingModel.embed(query).content().vectorAsList();
return searchService.search("documents", queryVector);
}
}Best Practices
- Distance metric: Cosine for normalized text embeddings, Euclidean for non-normalized.
- Batch upserts: Use batch operations over individual point insertions.
- Connection pooling: Configure connection pooling for high-throughput production workloads.
- Error handling: Wrap async operations in try/catch for ExecutionException/InterruptedException.
- API keys: Store in environment variables or Spring config, never hardcode.
Advanced Patterns
Multi-tenant Storage
public void upsertForTenant(String tenantId, List<PointStruct> points) {
String collectionName = "tenant_" + tenantId + "_documents";
client.upsertAsync(collectionName, points).get();
}Docker Compose for Production
services:
qdrant:
image: qdrant/qdrant:v1.7.0
ports:
- "6333:6333"
- "6334:6334"
volumes:
- qdrant_storage:/qdrant/storageReferences
- Qdrant API Reference — Complete client API documentation
- Complete Spring Boot Examples — Full application implementations
- Qdrant Documentation
- LangChain4j Documentation
Constraints and Warnings
- Vector dimensions must match the embedding model exactly; mismatched dimensions cause upsert errors.
- Input validation: Sanitize all document content before ingestion; untrusted payloads may contain prompt injection attacks.
- Content filtering: Apply content filtering on retrieved documents before passing them to the LLM.
- Large collections require proper indexing for acceptable search performance.
- Use gRPC API (port 6334) for production; REST API (port 6333) for debugging only.
- Collection recreation deletes all data; implement backup strategies for production environments.
Qdrant for Java: Complete Examples
This file provides comprehensive code examples for integrating Qdrant with Java and Spring Boot applications.
1. Complete Spring Boot Application with Qdrant
This example demonstrates a full Spring Boot application with Qdrant integration for vector search.
Project Structure
/src/main/java/com/example/qdrantdemo/
├── QdrantDemoApplication.java
├── config/
│ ├── QdrantConfig.java
│ └── Langchain4jConfig.java
├── controller/
│ ├── SearchController.java
│ └── RagController.java
├── service/
│ ├── VectorSearchService.java
│ └── RagService.java
└── Application.propertiesDependencies (pom.xml)
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Qdrant Java Client -->
<dependency>
<groupId>io.qdrant</groupId>
<artifactId>client</artifactId>
<version>1.15.0</version>
</dependency>
<!-- LangChain4j -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-qdrant</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-all-minilm-l6-v2</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>Application Configuration (application.properties)
# Qdrant Configuration
qdrant.host=localhost
qdrant.port=6334
qdrant.api-key=
# OpenAI Configuration (for RAG)
openai.api-key=YOUR_OPENAI_API_KEYQdrant Configuration
package com.example.qdrantdemo.config;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QdrantConfig {
@Value("${qdrant.host:localhost}")
private String host;
@Value("${qdrant.port:6334}")
private int port;
@Value("${qdrant.api-key:}")
private String apiKey;
@Bean
public QdrantClient qdrantClient() {
QdrantGrpcClient grpcClient = QdrantGrpcClient.newBuilder(host, port, false)
.withApiKey(apiKey)
.build();
return new QdrantClient(grpcClient);
}
}Vector Search Service
package com.example.qdrantdemo.service;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Points.PointStruct;
import io.qdrant.client.grpc.Points.QueryPoints;
import io.qdrant.client.grpc.Points.ScoredPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;
import static io.qdrant.client.QueryFactory.nearest;
@Service
public class VectorSearchService {
private final QdrantClient client;
@Autowired
private EmbeddingService embeddingService; // Helper service for embeddings
public static final String COLLECTION_NAME = "document-search";
public static final int VECTOR_SIZE = 384; // For AllMiniLM-L6-v2
public VectorSearchService(QdrantClient client) {
this.client = client;
}
@PostConstruct
public void initializeCollection() throws ExecutionException, InterruptedException {
// Create collection if it doesn't exist
client.createCollectionAsync(COLLECTION_NAME,
VectorParams.newBuilder()
.setDistance(Distance.Cosine)
.setSize(VECTOR_SIZE)
.build()
).get();
}
public List<ScoredPoint> search(String query, int limit) {
try {
List<Float> queryVector = embeddingService.embedQuery(query);
return client.queryAsync(
QueryPoints.newBuilder()
.setCollectionName(COLLECTION_NAME)
.setLimit(limit)
.setQuery(nearest(queryVector))
.setWithPayload(true)
.build()
).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Qdrant search failed", e);
}
}
public void addDocument(String documentId, String title, String content) {
try {
List<Float> contentVector = embeddingService.embedText(content);
PointStruct point = PointStruct.newBuilder()
.setId(id(documentId))
.setVectors(vectors(contentVector))
.putAllPayload(Map.of(
"title", value(title),
"content", value(content),
"created_at", value(System.currentTimeMillis())
))
.build();
client.upsertAsync(COLLECTION_NAME, List.of(point)).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Qdrant document insertion failed", e);
}
}
}Search Controller
package com.example.qdrantdemo.controller;
import com.example.qdrantdemo.service.VectorSearchService;
import io.qdrant.client.grpc.Points.ScoredPoint;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/search")
public class SearchController {
private final VectorSearchService searchService;
public SearchController(VectorSearchService searchService) {
this.searchService = searchService;
}
@GetMapping
public List<ScoredPoint> search(@RequestParam String query,
@RequestParam(defaultValue = "5") int limit) {
return searchService.search(query, limit);
}
@PostMapping("/document")
public String addDocument(@RequestBody AddDocumentRequest request) {
searchService.addDocument(request.getDocumentId(), request.getTitle(), request.getContent());
return "Document added successfully";
}
public static class AddDocumentRequest {
private String documentId;
private String title;
private String content;
// Getters and setters
public String getDocumentId() { return documentId; }
public void setDocumentId(String documentId) { this.documentId = documentId; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getContent() { return content; }
public void setContent(String content) { this.content = content; }
}
}2. Advanced RAG with LangChain4j
This example demonstrates a complete RAG system with Qdrant and LLM integration.
LangChain4j Configuration
package com.example.qdrantdemo.config;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.embedding.EmbeddingModel;
import dev.langchain4j.embedding.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Langchain4jConfig {
@Value("${qdrant.host:localhost}")
private String host;
@Value("${qdrant.port:6334}")
private int port;
@Value("${qdrant.api-key:}")
private String apiKey;
@Value("${openai.api-key}")
private String openaiApiKey;
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return QdrantEmbeddingStore.builder()
.collectionName("rag-collection")
.host(host)
.port(port)
.apiKey(apiKey)
.build();
}
@Bean
public EmbeddingModel embeddingModel() {
return new AllMiniLmL6V2EmbeddingModel();
}
@Bean
public ChatLanguageModel chatLanguageModel() {
return OpenAiChatModel.builder()
.apiKey(openaiApiKey)
.modelName("gpt-3.5-turbo")
.build();
}
@Bean
public EmbeddingStoreIngestor embeddingStoreIngestor(
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
return EmbeddingStoreIngestor.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.build();
}
}RAG Service with Assistant
package com.example.qdrantdemo.service;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingStoreIngestor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RagService {
// Define the AI assistant interface
interface Assistant {
String chat(String userMessage);
}
private final EmbeddingStoreIngestor ingestor;
private final Assistant assistant;
public RagService(EmbeddingStore<TextSegment> embeddingStore,
EmbeddingStoreIngestor ingestor,
ChatLanguageModel chatModel) {
this.ingestor = ingestor;
// Create content retriever for RAG
ContentRetriever contentRetriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.maxResults(3)
.minScore(0.7)
.build();
// Build the AI assistant with RAG capabilities
this.assistant = AiServices.builder(Assistant.class)
.chatLanguageModel(chatModel)
.contentRetriever(contentRetriever)
.build();
}
public void ingestDocument(String text) {
TextSegment segment = TextSegment.from(text);
ingestor.ingest(segment);
}
public String query(String userQuery) {
return assistant.chat(userQuery);
}
public List<TextSegment> findRelevantDocuments(String query, int maxResults) {
EmbeddingStore<TextSegment> embeddingStore = ingestor.getEmbeddingStore();
return embeddingStore.findRelevant(
ingestor.getEmbeddingModel().embed(query).content(),
maxResults,
0.7
).stream()
.map(match -> match.embedded())
.toList();
}
}RAG Controller
package com.example.qdrantdemo.controller;
import com.example.qdrantdemo.service.RagService;
import dev.langchain4j.data.segment.TextSegment;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/rag")
public class RagController {
private final RagService ragService;
public RagController(RagService ragService) {
this.ragService = ragService;
}
@PostMapping("/ingest")
public String ingestDocument(@RequestBody String document) {
ragService.ingestDocument(document);
return "Document ingested successfully.";
}
@PostMapping("/query")
public String query(@RequestBody QueryRequest request) {
return ragService.query(request.getQuery());
}
@GetMapping("/documents")
public List<TextSegment> findDocuments(@RequestParam String query,
@RequestParam(defaultValue = "3") int maxResults) {
return ragService.findRelevantDocuments(query, maxResults);
}
public static class QueryRequest {
private String query;
public String getQuery() { return query; }
public void setQuery(String query) { this.query = query; }
}
}3. Multi-tenant Vector Search Application
This example demonstrates advanced patterns for multi-tenant applications.
Multi-Tenant Vector Service
package com.example.qdrantdemo.service;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.grpc.Points.PointStruct;
import io.qdrant.client.grpc.Points.QueryPoints;
import io.qdrant.client.grpc.Points.ScoredPoint;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.ExecutionException;
@Service
public class MultiTenantVectorService {
private final QdrantClient client;
public MultiTenantVectorService(QdrantClient client) {
this.client = client;
}
// Collection-based multi-tenancy
public List<ScoredPoint> searchByTenant(String tenantId, List<Float> queryVector, int limit) {
try {
String collectionName = "tenant_" + tenantId + "_documents";
return client.queryAsync(
QueryPoints.newBuilder()
.setCollectionName(collectionName)
.setLimit(limit)
.addAllVector(queryVector)
.setWithPayload(true)
.build()
).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Multi-tenant search failed", e);
}
}
public void upsertForTenant(String tenantId, List<PointStruct> points) {
try {
String collectionName = "tenant_" + tenantId + "_documents";
client.upsertAsync(collectionName, points).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Multi-tenant upsert failed", e);
}
}
// Hybrid search with tenant-specific filters
public List<ScoredPoint> hybridSearch(String tenantId, List<Float> queryVector,
String category, int limit) {
try {
String collectionName = "tenant_" + tenantId + "_documents";
QueryPoints.Builder queryBuilder = QueryPoints.newBuilder()
.setCollectionName(collectionName)
.setLimit(limit)
.addAllVector(queryVector);
// Add category filter if provided
if (category != null && !category.isEmpty()) {
queryBuilder.setFilter(Filter.newBuilder()
.addMust(exactMatch("category", category))
.build());
}
return client.queryAsync(queryBuilder.build()).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Hybrid search failed", e);
}
}
}Deployment and Configuration
Docker Compose Setup
version: '3.8'
services:
qdrant:
image: qdrant/qdrant:v1.7.0
ports:
- "6333:6333"
- "6334:6334"
volumes:
- qdrant_storage:/qdrant/storage
environment:
- QDRANT__SERVICE__HTTP_PORT=6333
- QDRANT__SERVICE__GRPC_PORT=6334
volumes:
qdrant_storage:Production Configuration
# application-prod.properties
qdrant.host=qdrant-service
qdrant.port=6334
qdrant.api-key=${QDRANT_API_KEY}
# Enable HTTPS for production
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=${SSL_KEYSTORE_PASSWORD}
# OpenAI Configuration
openai.api-key=${OPENAI_API_KEY}
# Logging
logging.level.com.example.qdrantdemo=INFO
logging.level.io.qdrant=INFOTesting Strategy
Unit Tests for Vector Service
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class VectorSearchServiceTest {
@Autowired
private VectorSearchService vectorSearchService;
@Test
public void testCollectionInitialization() {
// Test that collection is created properly
// This could involve checking collection metadata
}
@Test
public void testDocumentUpsert() {
// Test document insertion and retrieval
}
@Test
public void testSearchFunctionality() {
// Test vector search functionality
}
}This comprehensive example provides a complete foundation for building Qdrant-powered applications with Spring Boot and LangChain4j.
Qdrant for Java: References
This file contains key technical details and code patterns for integrating Qdrant with Java applications.
Qdrant Java Client API Reference
Core Setup
Maven:
<dependency>
<groupId>io.qdrant</groupId>
<artifactId>client</artifactId>
<version>1.15.0</version>
</dependency>Gradle:
implementation 'io.qdrant:client:1.15.0'Client Initialization
// Basic client
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost").build());
// Advanced client with TLS and API key
ManagedChannel channel = Grpc.newChannelBuilder(
"localhost:6334",
TlsChannelCredentials.newBuilder()
.trustManager(new File("ssl/ca.crt"))
.build()).build();
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder(channel)
.withApiKey("<apikey>")
.build());Collection Management
// Create collection
client.createCollectionAsync("my_collection",
VectorParams.newBuilder()
.setDistance(Distance.Cosine)
.setSize(4)
.build()).get();
// Create collection with configuration
client.createCollectionAsync("my_collection",
VectorParams.newBuilder()
.setDistance(Distance.Cosine)
.setSize(384)
.build())
.get();Point Operations
// Insert points
List<PointStruct> points = List.of(
PointStruct.newBuilder()
.setId(id(1))
.setVectors(vectors(0.32f, 0.52f, 0.21f, 0.52f))
.putAllPayload(Map.of("color", value("red")))
.build()
);
UpdateResult result = client.upsertAsync("my_collection", points).get();Search Operations
// Simple search
List<ScoredPoint> results = client.searchAsync(
SearchPoints.newBuilder()
.setCollectionName("my_collection")
.addAllVector(List.of(0.6235f, 0.123f, 0.532f, 0.123f))
.setLimit(5)
.build()).get();
// Filtered search
List<ScoredPoint> filteredResults = client.searchAsync(
SearchPoints.newBuilder()
.setCollectionName("my_collection")
.addAllVector(List.of(0.6235f, 0.123f, 0.532f, 0.123f))
.setFilter(Filter.newBuilder()
.addMust(range("rand_number",
Range.newBuilder().setGte(3).build()))
.build())
.setLimit(5)
.build()).get();LangChain4j Integration Patterns
QdrantEmbeddingStore Setup
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-qdrant</artifactId>
<version>1.7.0</version>
</dependency>Configuration
EmbeddingStore<TextSegment> embeddingStore = QdrantEmbeddingStore.builder()
.collectionName("YOUR_COLLECTION_NAME")
.host("YOUR_HOST_URL")
.port(6334)
.apiKey("YOUR_API_KEY")
.build();
// Or with HTTPS
EmbeddingStore<TextSegment> embeddingStore = QdrantEmbeddingStore.builder()
.collectionName("YOUR_COLLECTION_NAME")
.host("YOUR_HOST_URL")
.port(443)
.useHttps(true)
.apiKey("YOUR_API_KEY")
.build();Official Documentation Resources
- [Qdrant Documentation](https://qdrant.tech/documentation/): Main documentation portal
- [Qdrant Java Client GitHub](https://github.com/qdrant/java-client): Source code and issues
- [Java Client Javadoc](https://qdrant.github.io/java-client/): Complete API documentation
- [API & SDKs](https://qdrant.tech/documentation/interfaces/): All supported clients
- [Quickstart Guide](https://qdrant.tech/documentation/quickstart/): Local setup guide
- [LangChain4j Official Site](https://langchain4j.dev/): Framework documentation
- [LangChain4j Examples](https://github.com/langchain4j/langchain4j-examples): Comprehensive examples