Core classes and interfaces of LangChain4j providing foundational abstractions for LLM interaction, RAG, embeddings, agents, and observability
Package: dev.langchain4j.store.embedding, dev.langchain4j.data.embedding
Thread-Safety: Implementation-dependent (check provider documentation)
Use Case: Semantic search, RAG systems, similarity matching
Embedding stores provide persistent vector storage with semantic search capabilities, forming the foundation of RAG (Retrieval Augmented Generation) systems.
package dev.langchain4j.store.embedding;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
/**
* Storage and retrieval of embeddings with associated content
* Thread-Safety: Implementation-dependent
* @param <Embedded> Type of content stored with embeddings (usually TextSegment)
*/
public interface EmbeddingStore<Embedded> {
/**
* Add embedding with content, returns generated ID
* @param embedding Vector embedding (non-null)
* @param embedded Associated content (non-null)
* @return Generated ID
*/
String add(Embedding embedding, Embedded embedded);
/**
* Add embedding with specific ID
* @param id Custom ID (non-null)
* @param embedding Vector embedding (non-null)
* @return The provided ID
*/
String add(String id, Embedding embedding);
/**
* Add embedding with content and specific ID
* @param id Custom ID (non-null)
* @param embedding Vector embedding (non-null)
* @param embedded Associated content (non-null)
* @return The provided ID
*/
String add(String id, Embedding embedding, Embedded embedded);
/**
* Batch add embeddings
* @param embeddings List of embeddings (non-null)
* @return List of generated IDs
*/
List<String> addAll(List<Embedding> embeddings);
/**
* Batch add embeddings with content
* @param embeddings List of embeddings (non-null)
* @param embedded List of associated content (non-null, same size)
* @return List of generated IDs
*/
List<String> addAll(List<Embedding> embeddings, List<Embedded> embedded);
/**
* Search for similar embeddings
* @param request Search parameters (non-null)
* @return Search results with matches
*/
EmbeddingSearchResult<Embedded> search(EmbeddingSearchRequest request);
/**
* Remove embedding by ID
* @param id ID to remove (non-null)
*/
void remove(String id);
/**
* Remove all embeddings matching IDs
* @param ids IDs to remove (non-null)
*/
void removeAll(Collection<String> ids);
/**
* Remove all embeddings matching filter
* @param filter Metadata filter (non-null)
*/
void removeAll(Filter filter);
}package dev.langchain4j.store.embedding;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.store.embedding.filter.Filter;
/**
* Parameters for semantic search
* Immutability: Immutable, thread-safe
*/
public class EmbeddingSearchRequest {
private final Embedding queryEmbedding;
private final int maxResults;
private final double minScore;
private final Filter filter;
public static Builder builder() { /* ... */ }
public static class Builder {
public Builder queryEmbedding(Embedding queryEmbedding) { /* ... */ }
public Builder maxResults(int maxResults) { /* ... */ }
public Builder minScore(double minScore) { /* ... */ } // 0.0-1.0
public Builder filter(Filter filter) { /* ... */ }
public EmbeddingSearchRequest build() { /* ... */ }
}
}package dev.langchain4j.store.embedding;
/**
* Results of semantic search
* Immutability: Immutable, thread-safe
* @param <Embedded> Type of embedded content
*/
public class EmbeddingSearchResult<Embedded> {
private final List<EmbeddingMatch<Embedded>> matches;
public List<EmbeddingMatch<Embedded>> matches() { return matches; }
}package dev.langchain4j.store.embedding;
import dev.langchain4j.data.embedding.Embedding;
/**
* Single search result with score and content
* Immutability: Immutable, thread-safe
* @param <Embedded> Type of embedded content
*/
public class EmbeddingMatch<Embedded> {
private final double score; // Similarity score 0.0-1.0
private final String embeddingId; // ID of the embedding
private final Embedding embedding; // The embedding vector
private final Embedded embedded; // Associated content
public double score() { return score; }
public String embeddingId() { return embeddingId; }
public Embedding embedding() { return embedding; }
public Embedded embedded() { return embedded; }
}package dev.langchain4j.store.embedding.filter;
/**
* Metadata filters for search
* Immutability: Immutable, thread-safe
*/
public interface Filter {
// Static factory methods
static Filter metadataKey(String key) { /* ... */ }
static Filter and(Filter... filters) { /* ... */ }
static Filter or(Filter... filters) { /* ... */ }
static Filter not(Filter filter) { /* ... */ }
}
// Comparison filters
public interface ComparisonFilter extends Filter {
Filter isEqualTo(Object value);
Filter isNotEqualTo(Object value);
Filter isGreaterThan(Comparable<?> value);
Filter isGreaterThanOrEqualTo(Comparable<?> value);
Filter isLessThan(Comparable<?> value);
Filter isLessThanOrEqualTo(Comparable<?> value);
Filter isIn(Collection<?> values);
Filter isNotIn(Collection<?> values);
}import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingSearchResult;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.data.embedding.Embedding;
// Initialize store (from provider-specific module)
EmbeddingStore<TextSegment> store = /* InMemoryEmbeddingStore, etc. */;
// Add embeddings
List<TextSegment> segments = List.of(
TextSegment.from("Machine learning is a subset of AI"),
TextSegment.from("Deep learning uses neural networks"),
TextSegment.from("I love pizza and pasta")
);
// Generate embeddings
Response<List<Embedding>> response = embeddingModel.embedAll(segments);
List<Embedding> embeddings = response.content();
// Store with auto-generated IDs
List<String> ids = store.addAll(embeddings, segments);
System.out.println("Stored " + ids.size() + " embeddings");
// Search
String query = "What is machine learning?";
Embedding queryEmbedding = embeddingModel.embed(query).content();
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(5)
.minScore(0.7)
.build();
EmbeddingSearchResult<TextSegment> result = store.search(request);
// Process results
for (EmbeddingMatch<TextSegment> match : result.matches()) {
System.out.println("Score: " + match.score());
System.out.println("Text: " + match.embedded().text());
System.out.println("ID: " + match.embeddingId());
System.out.println("---");
}import dev.langchain4j.store.embedding.filter.Filter;
import dev.langchain4j.data.document.Metadata;
// Add segments with metadata
List<TextSegment> segments = List.of(
TextSegment.from("Technical doc 1", Metadata.from(Map.of(
"category", "technical",
"language", "en",
"version", "2.0"
))),
TextSegment.from("User guide 1", Metadata.from(Map.of(
"category", "user-guide",
"language", "en",
"version", "2.0"
))),
TextSegment.from("Technical doc 2", Metadata.from(Map.of(
"category", "technical",
"language", "fr",
"version", "1.0"
)))
);
// Generate and store embeddings
Response<List<Embedding>> response = embeddingModel.embedAll(segments);
store.addAll(response.content(), segments);
// Search with filter
Filter filter = Filter.metadataKey("category").isEqualTo("technical");
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(5)
.minScore(0.7)
.filter(filter) // Only technical docs
.build();
EmbeddingSearchResult<TextSegment> result = store.search(request);import dev.langchain4j.store.embedding.filter.Filter;
// AND filter
Filter andFilter = Filter.and(
Filter.metadataKey("category").isEqualTo("technical"),
Filter.metadataKey("language").isEqualTo("en")
);
// OR filter
Filter orFilter = Filter.or(
Filter.metadataKey("category").isEqualTo("technical"),
Filter.metadataKey("category").isEqualTo("tutorial")
);
// NOT filter
Filter notFilter = Filter.not(
Filter.metadataKey("deprecated").isEqualTo(true)
);
// Complex combination
Filter complexFilter = Filter.and(
Filter.or(
Filter.metadataKey("category").isEqualTo("technical"),
Filter.metadataKey("category").isEqualTo("api-reference")
),
Filter.metadataKey("language").isEqualTo("en"),
Filter.metadataKey("version").isGreaterThanOrEqualTo("2.0"),
Filter.not(Filter.metadataKey("archived").isEqualTo(true))
);
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(10)
.filter(complexFilter)
.build();// Add with specific IDs
String id1 = "doc-123-chunk-0";
String id2 = "doc-123-chunk-1";
store.add(id1, embedding1, segment1);
store.add(id2, embedding2, segment2);
// Later, remove by ID
store.remove(id1);
// Or remove multiple
store.removeAll(List.of(id1, id2));// ✅ GOOD: Batch operations (much faster)
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
List<String> ids = store.addAll(embeddings, segments);
// ❌ BAD: Individual operations in loop
for (int i = 0; i < embeddings.size(); i++) {
store.add(embeddings.get(i), segments.get(i)); // SLOW!
}import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
// Simple in-memory store (good for testing, development)
EmbeddingStore<TextSegment> store = new InMemoryEmbeddingStore<>();
// Thread-safety: Uses ConcurrentHashMap, thread-safe
// Persistence: None - data lost on restart
// Performance: Very fast, but limited by RAM
// Best for: Testing, prototypes, small datasets// Examples (from provider-specific modules):
// Pinecone
EmbeddingStore<TextSegment> pinecone = PineconeEmbeddingStore.builder()
.apiKey(apiKey)
.index("my-index")
.namespace("my-namespace")
.build();
// Chroma
EmbeddingStore<TextSegment> chroma = ChromaEmbeddingStore.builder()
.baseUrl("http://localhost:8000")
.collectionName("my-collection")
.build();
// Weaviate
EmbeddingStore<TextSegment> weaviate = WeaviateEmbeddingStore.builder()
.apiKey(apiKey)
.scheme("https")
.host("my-instance.weaviate.network")
.build();
// Qdrant
EmbeddingStore<TextSegment> qdrant = QdrantEmbeddingStore.builder()
.host("localhost")
.port(6334)
.collectionName("my-collection")
.build();import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.model.embedding.EmbeddingModel;
public class RAGSystem {
private final DocumentSplitter splitter;
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
private final ChatModel chatModel;
/**
* Ingest documents into vector store
*/
public void ingest(List<Document> documents) {
// 1. Split documents
List<TextSegment> segments = splitter.splitAll(documents);
// 2. Generate embeddings
Response<List<Embedding>> response = embeddingModel.embedAll(segments);
List<Embedding> embeddings = response.content();
// 3. Store in vector database
embeddingStore.addAll(embeddings, segments);
System.out.println("Ingested " + segments.size() + " segments");
}
/**
* Query with RAG
*/
public String query(String userQuery, String category) {
// 1. Embed query
Embedding queryEmbedding = embeddingModel.embed(userQuery).content();
// 2. Retrieve relevant segments
Filter filter = Filter.metadataKey("category").isEqualTo(category);
EmbeddingSearchRequest searchRequest = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(5)
.minScore(0.7)
.filter(filter)
.build();
EmbeddingSearchResult<TextSegment> searchResult = embeddingStore.search(searchRequest);
// 3. Build context from retrieved segments
String context = searchResult.matches().stream()
.map(match -> match.embedded().text())
.collect(Collectors.joining("\n\n"));
// 4. Generate response with context
String prompt = String.format("""
Answer the question based on the following context:
Context:
%s
Question: %s
Answer:
""", context, userQuery);
return chatModel.chat(prompt);
}
}// Score ranges (cosine similarity):
// 0.9-1.0: Nearly identical
// 0.7-0.9: Highly similar (RECOMMENDED threshold)
// 0.5-0.7: Moderately similar
// 0.0-0.5: Weakly similar or unrelated
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(10)
.minScore(0.7) // ✅ GOOD: Filters out weak matches
.build();// ✅ GOOD: Filter reduces search space, improves performance
Filter filter = Filter.metadataKey("category").isEqualTo("technical");
request.filter(filter);
// ❌ BAD: No filter searches entire store
// Slower and may return irrelevant results// Too few: May miss relevant content
.maxResults(2) // ❌ Too restrictive
// Balanced: Good for most use cases
.maxResults(5-10) // ✅ RECOMMENDED
// Too many: Slower, may include irrelevant content
.maxResults(100) // ❌ Too many for chat contextEmbeddingSearchResult<TextSegment> result = store.search(request);
if (result.matches().isEmpty()) {
// No relevant content found
return "I don't have enough information to answer that question.";
}
// Proceed with matches// Remove old versions
Filter oldVersions = Filter.metadataKey("version").isLessThan("2.0");
store.removeAll(oldVersions);
// Add new versions
ingest(updatedDocuments);// InMemoryEmbeddingStore RAM usage estimate:
// Per embedding: ~6-8 KB (1536 dims * 4 bytes + overhead)
// 10K embeddings: ~60-80 MB
// 100K embeddings: ~600-800 MB
// 1M embeddings: ~6-8 GB
// For large datasets, use persistent stores// ✅ GOOD: Batch add (10-100x faster)
List<String> ids = store.addAll(embeddings, segments);
// ❌ BAD: Individual adds in loop
for (int i = 0; i < embeddings.size(); i++) {
store.add(embeddings.get(i), segments.get(i));
}| Pitfall | Solution |
|---|---|
| Not setting minScore | Set threshold (0.7 recommended) |
| No metadata filters | Add category, language, version filters |
| Individual operations | Use batch addAll() |
| Using InMemory for production | Use persistent store (Pinecone, Weaviate, etc.) |
| Not handling empty results | Check matches().isEmpty() |
| maxResults too high | Limit to 5-10 for chat context |
| Not removing stale content | Implement update/delete strategy |
| Store | Persistence | Filtering | Performance | Scaling | Best For |
|---|---|---|---|---|---|
| InMemory | None | ✅ | Very Fast | Single machine | Testing, development |
| Pinecone | Cloud | ✅ | Fast | Distributed | Production, managed |
| Weaviate | Self-hosted | ✅ | Fast | Distributed | Production, self-hosted |
| Qdrant | Self-hosted | ✅ | Fast | Distributed | Production, self-hosted |
| Chroma | Self-hosted | ✅ | Medium | Single machine | Development, prototypes |
| Redis | Self-hosted | ✅ | Fast | Distributed | Production, Redis users |
Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-core@1.11.0