Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Provides Qdrant vector database integration patterns with LangChain4j. Handles embedding storage, similarity search, and vector management for Java applications. Use when implementing vector-based retrieval for RAG systems, semantic search, or recommendation engines.
.claude/skills/giuseppe-trisciuoglio-qdrant/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 37% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 163% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 83% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 68% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 110% | 0% |
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.
bashdocker run -p 6333:6333 -p 6334:6334 \ -v "$(pwd)/qdrant_storage:/qdrant/storage:z" \ qdrant/qdrant
Access: REST API at http://localhost:6333, gRPC at http://localhost:6334.
Maven:
xml<dependency> <groupId>io.qdrant</groupId> <artifactId>client</artifactId> <version>1.15.0</version> </dependency>
Gradle:
gradleimplementation 'io.qdrant:client:1.15.0'
javaQdrantClient client = new QdrantClient( QdrantGrpcClient.newBuilder("localhost").build());
For production with API key:
javaQdrantClient client = new QdrantClient( QdrantGrpcClient.newBuilder("localhost", 6334, false) .withApiKey("YOUR_API_KEY") .build());
javaclient.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().
javaList<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.
javaList<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:
javaList<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();
For RAG pipelines, use LangChain4j's high-level abstractions:
javaEmbeddingStore<TextSegment> embeddingStore = QdrantEmbeddingStore.builder() .collectionName("rag-collection") .host("localhost") .port(6334) .apiKey("YOUR_API_KEY") .build();
Spring Boot configuration with LangChain4j:
java@Bean public EmbeddingStore<TextSegment> embeddingStore() { return QdrantEmbeddingStore.builder() .collectionName("rag-collection") .host(host) .port(port) .build(); } @Bean public EmbeddingModel embeddingModel() { return new AllMiniLmL6V2EmbeddingModel(); }
Inject the client via configuration:
java@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()); } }
java@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); } }
javapublic void upsertForTenant(String tenantId, List<PointStruct> points) { String collectionName = "tenant_" + tenantId + "_documents"; client.upsertAsync(collectionName, points).get(); }
yamlservices: qdrant: image: qdrant/qdrant:v1.7.0 ports: - "6333:6333" - "6334:6334" volumes: - qdrant_storage:/qdrant/storage
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 18,238 | 17,462 | -4% | 1 | 1 | 0% | 3,869 | 5,304 | +37% | 0 | 0 | — |
case-02 | pass→pass | 9,855 | 7,482 | -24% | 1 | 1 | 0% | 2,001 | 3,121 | +56% | 0 | 0 | — |
case-03 | pass→pass | 16,086 | 16,395 | +2% | 1 | 1 | 0% | 3,001 | 5,003 | +67% | 0 | 0 | — |
case-04 | pass→pass | 16,966 | 13,606 | -20% | 1 | 1 | 0% | 3,294 | 4,498 | +37% | 0 | 0 | — |
case-05 | fail→pass | 4,766 | 2,548 | -47% | 1 | 1 | 0% | 784 | 2,059 | +163% | 0 | 0 | — |
case-06 | fail→pass | 5,585 | 1,552 | -72% | 1 | 1 | 0% | 1,041 | 1,910 | +83% | 0 | 0 | — |
case-07 | pass→pass | 6,199 | 5,401 | -13% | 1 | 1 | 0% | 1,138 | 2,604 | +129% | 0 | 0 | — |
case-08 | pass→pass | 9,761 | 5,777 | -41% | 1 | 1 | 0% | 1,790 | 2,912 | +63% | 0 | 0 | — |
case-09 | fail→pass | 9,192 | 9,710 | +6% | 1 | 1 | 0% | 1,560 | 2,623 | +68% | 0 | 0 | — |
case-10 | fail→fail | 8,659 | 5,786 | -33% | 1 | 1 | 0% | 1,533 | 2,733 | +78% | 0 | 0 | — |
case-11 | fail→pass | 8,024 | 6,094 | -24% | 1 | 1 | 0% | 1,255 | 2,634 | +110% | 0 | 0 | — |
case-12 | pass→pass | 13,698 | 11,395 | -17% | 1 | 1 | 0% | 2,917 | 4,080 | +40% | 0 | 0 | — |
case-13 | pass→pass | 10,997 | 7,153 | -35% | 1 | 1 | 0% | 2,082 | 3,091 | +48% | 0 | 0 | — |
case-14 | pass→pass | 9,904 | 8,334 | -16% | 1 | 1 | 0% | 1,612 | 3,040 | +89% | 0 | 0 | — |
case-15 | pass→pass | 16,699 | 16,134 | -3% | 1 | 1 | 0% | 2,820 | 4,701 | +67% | 0 | 0 | — |
case-16 | pass→pass | 8,101 | 3,893 | -52% | 1 | 1 | 0% | 1,216 | 2,232 | +84% | 0 | 0 | — |
case-17 | pass→pass | 10,282 | 4,501 | -56% | 1 | 1 | 0% | 1,542 | 2,368 | +54% | 0 | 0 | — |
case-18 | pass→pass | 4,568 | 1,955 | -57% | 1 | 1 | 0% | 729 | 2,058 | +182% | 0 | 0 | — |
case-19 | fail→fail | 9,858 | 4,687 | -52% | 1 | 1 | 0% | 1,806 | 2,513 | +39% | 0 | 0 | — |
case-20 | pass→pass | 8,959 | 6,292 | -30% | 1 | 1 | 0% | 1,633 | 2,779 | +70% | 0 | 0 | — |
case-21 | fail→pass | 15,890 | 8,917 | -44% | 1 | 1 | 0% | 1,578 | 3,549 | +125% | 0 | 0 | — |
case-22 | pass→pass | 12,921 | 9,439 | -27% | 1 | 1 | 0% | 2,299 | 3,465 | +51% | 0 | 0 | — |
case-23 | pass→pass | 9,564 | 3,090 | -68% | 1 | 1 | 0% | 1,596 | 2,192 | +37% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +26 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.