diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000..963354f23
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,3 @@
+{
+ "printWidth": 120
+}
diff --git a/langchain4j-weaviate/pom.xml b/langchain4j-weaviate/pom.xml
new file mode 100644
index 000000000..e13b28c12
--- /dev/null
+++ b/langchain4j-weaviate/pom.xml
@@ -0,0 +1,48 @@
+
+
+ 4.0.0
+
+
+ dev.langchain4j
+ langchain4j-parent
+ 0.18.0
+ ../langchain4j-parent/pom.xml
+
+
+
+ langchain4j-weaviate
+ jar
+
+ LangChain4j integration with Weaviate
+ Uses io.weaviate.client library which has a BSD 3-Clause license:
+ https://github.com/weaviate/java-client/blob/main/LICENSE
+
+
+
+
+
+ dev.langchain4j
+ langchain4j-core
+ 0.18.0
+
+
+
+ io.weaviate
+ client
+ 4.2.0
+
+
+
+
+
+
+ Apache-2.0
+ https://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+ A business-friendly OSS license
+
+
+
+
\ No newline at end of file
diff --git a/langchain4j-weaviate/src/main/java/dev/langchain4j/store/embedding/WeaviateEmbeddingStoreImpl.java b/langchain4j-weaviate/src/main/java/dev/langchain4j/store/embedding/WeaviateEmbeddingStoreImpl.java
new file mode 100644
index 000000000..477b04bbc
--- /dev/null
+++ b/langchain4j-weaviate/src/main/java/dev/langchain4j/store/embedding/WeaviateEmbeddingStoreImpl.java
@@ -0,0 +1,215 @@
+package dev.langchain4j.store.embedding;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonList;
+import static java.util.stream.Collectors.joining;
+
+import dev.langchain4j.data.embedding.Embedding;
+import dev.langchain4j.data.segment.TextSegment;
+import io.weaviate.client.Config;
+import io.weaviate.client.WeaviateAuthClient;
+import io.weaviate.client.WeaviateClient;
+import io.weaviate.client.base.Result;
+import io.weaviate.client.base.WeaviateErrorMessage;
+import io.weaviate.client.v1.auth.exception.AuthException;
+import io.weaviate.client.v1.data.model.WeaviateObject;
+import io.weaviate.client.v1.data.replication.model.ConsistencyLevel;
+import io.weaviate.client.v1.graphql.model.GraphQLResponse;
+import io.weaviate.client.v1.graphql.query.argument.NearVectorArgument;
+import io.weaviate.client.v1.graphql.query.fields.Field;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.*;
+import java.util.stream.Collectors;
+import lombok.Builder;
+
+public class WeaviateEmbeddingStoreImpl implements EmbeddingStore {
+
+ private static final String DEFAULT_CLASS = "Default";
+ private static final Double DEFAULT_MIN_CERTAINTY = 0.0;
+ private static final String METADATA_TEXT_SEGMENT = "text";
+ private static final String ADDITIONALS = "_additional";
+
+ private final WeaviateClient client;
+ private final String objectClass;
+ private boolean avoidDups = true;
+ private String consistencyLevel = ConsistencyLevel.QUORUM;
+
+ @Builder
+ public WeaviateEmbeddingStoreImpl(
+ String apiKey,
+ String scheme,
+ String host,
+ String objectClass,
+ boolean avoidDups,
+ String consistencyLevel
+ ) {
+ try {
+ client = WeaviateAuthClient.apiKey(new Config(scheme, host), apiKey);
+ } catch (AuthException e) {
+ throw new IllegalArgumentException(e);
+ }
+ this.objectClass = objectClass != null ? objectClass : DEFAULT_CLASS;
+ this.avoidDups = avoidDups;
+ this.consistencyLevel = consistencyLevel;
+ }
+
+ @Override
+ public String add(Embedding embedding) {
+ String id = generateRandomId();
+ add(id, embedding);
+ return id;
+ }
+
+ @Override
+ public void add(String id, Embedding embedding) {
+ addAll(singletonList(id), singletonList(embedding), null);
+ }
+
+ @Override
+ public String add(Embedding embedding, TextSegment textSegment) {
+ return addAll(singletonList(embedding), singletonList(textSegment)).stream().findFirst().orElse(null);
+ }
+
+ @Override
+ public List addAll(List embeddings) {
+ return addAll(embeddings, null);
+ }
+
+ @Override
+ public List addAll(List embeddings, List embedded) {
+ return addAll(null, embeddings, embedded);
+ }
+
+ @Override
+ public List> findRelevant(Embedding referenceEmbedding, int maxResults) {
+ return findRelevant(referenceEmbedding, maxResults, DEFAULT_MIN_CERTAINTY);
+ }
+
+ @Override
+ public List> findRelevant(
+ Embedding referenceEmbedding,
+ int maxResults,
+ double minCertainty
+ ) {
+ Result result = client
+ .graphQL()
+ .get()
+ .withClassName(objectClass)
+ .withFields(
+ Field.builder().name(METADATA_TEXT_SEGMENT).build(),
+ Field
+ .builder()
+ .name(ADDITIONALS)
+ .fields(
+ Field.builder().name("id").build(),
+ Field.builder().name("certainty").build(),
+ Field.builder().name("vector").build()
+ )
+ .build()
+ )
+ .withNearVector(
+ NearVectorArgument
+ .builder()
+ .vector(referenceEmbedding.vectorAsList().toArray(new Float[0]))
+ .certainty((float) minCertainty)
+ .build()
+ )
+ .withLimit(maxResults)
+ .run();
+
+ if (result.hasErrors()) {
+ throw new IllegalArgumentException(
+ result.getError().getMessages().stream().map(WeaviateErrorMessage::getMessage).collect(joining("\n"))
+ );
+ }
+
+ Optional> resGetPart =
+ ((Map) result.getResult().getData()).entrySet().stream().findFirst();
+ if (!resGetPart.isPresent()) {
+ return emptyList();
+ }
+
+ Optional resItemsPart = resGetPart.get().getValue().entrySet().stream().findFirst();
+ if (!resItemsPart.isPresent()) {
+ return emptyList();
+ }
+
+ List