LangChain4j OpenAI Integration providing Java access to OpenAI APIs including chat models, embeddings, image generation, audio transcription, and moderation.
Embedding models convert text into dense vector representations that capture semantic meaning. These embeddings enable similarity search, clustering, classification, and semantic search applications. OpenAI provides several embedding models optimized for different use cases and dimensionalities.
Embeddings are the foundation for retrieval-augmented generation (RAG), semantic search, recommendation systems, and anomaly detection. The text-embedding-3 models offer improved performance and configurable dimensions for storage optimization.
Synchronous embedding model that generates vector representations of text segments. Supports batch processing for efficient embedding of multiple text segments.
public class OpenAiEmbeddingModel extends DimensionAwareEmbeddingModel {
public static OpenAiEmbeddingModelBuilder builder();
// Core embedding methods
public Response<Embedding> embed(String text);
public Response<Embedding> embed(TextSegment textSegment);
public Response<List<Embedding>> embedAll(List<TextSegment> textSegments);
// Model information
public Integer knownDimension();
public String modelName();
}Builder for configuring OpenAiEmbeddingModel instances with authentication, model selection, and batching options.
public static class OpenAiEmbeddingModelBuilder {
// Core configuration
public OpenAiEmbeddingModelBuilder modelName(String modelName);
public OpenAiEmbeddingModelBuilder modelName(OpenAiEmbeddingModelName modelName);
public OpenAiEmbeddingModelBuilder baseUrl(String baseUrl);
public OpenAiEmbeddingModelBuilder apiKey(String apiKey);
public OpenAiEmbeddingModelBuilder organizationId(String organizationId);
public OpenAiEmbeddingModelBuilder projectId(String projectId);
// Embedding configuration
public OpenAiEmbeddingModelBuilder dimensions(Integer dimensions);
public OpenAiEmbeddingModelBuilder user(String user);
public OpenAiEmbeddingModelBuilder encodingFormat(String encodingFormat);
// Batch processing
public OpenAiEmbeddingModelBuilder maxSegmentsPerBatch(Integer maxSegmentsPerBatch);
// HTTP configuration
public OpenAiEmbeddingModelBuilder httpClientBuilder(HttpClientBuilder httpClientBuilder);
public OpenAiEmbeddingModelBuilder timeout(Duration timeout);
public OpenAiEmbeddingModelBuilder maxRetries(Integer maxRetries);
public OpenAiEmbeddingModelBuilder customHeaders(Map<String, String> customHeaders);
public OpenAiEmbeddingModelBuilder customHeaders(Supplier<Map<String, String>> customHeadersSupplier);
public OpenAiEmbeddingModelBuilder customQueryParams(Map<String, String> customQueryParams);
// Logging
public OpenAiEmbeddingModelBuilder logRequests(Boolean logRequests);
public OpenAiEmbeddingModelBuilder logResponses(Boolean logResponses);
public OpenAiEmbeddingModelBuilder logger(Logger logger);
// Build
public OpenAiEmbeddingModel build();
}import dev.langchain4j.model.openai.OpenAiEmbeddingModel;
import dev.langchain4j.model.openai.OpenAiEmbeddingModelName;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.model.output.Response;
// Create embedding model
OpenAiEmbeddingModel model = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_3_SMALL)
.build();
// Embed single text
String text = "Artificial intelligence is transforming the world.";
Response<Embedding> response = model.embed(text);
Embedding embedding = response.content();
System.out.println("Embedding dimension: " + embedding.dimension());
System.out.println("First 5 values: " + Arrays.toString(
Arrays.copyOf(embedding.vector(), 5)
));
System.out.println("Tokens used: " + response.tokenUsage().totalTokenCount());
// Embed multiple texts
List<TextSegment> segments = List.of(
TextSegment.from("The quick brown fox jumps over the lazy dog."),
TextSegment.from("A journey of a thousand miles begins with a single step."),
TextSegment.from("To be or not to be, that is the question.")
);
Response<List<Embedding>> batchResponse = model.embedAll(segments);
List<Embedding> embeddings = batchResponse.content();
System.out.println("Generated " + embeddings.size() + " embeddings");
System.out.println("Total tokens: " + batchResponse.tokenUsage().totalTokenCount());
for (int i = 0; i < embeddings.size(); i++) {
Embedding emb = embeddings.get(i);
System.out.println("Embedding " + i + ": dimension=" + emb.dimension());
}import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import dev.langchain4j.store.embedding.EmbeddingMatch;
// Create embedding model
OpenAiEmbeddingModel embeddingModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_3_SMALL)
.build();
// Create document corpus
List<TextSegment> documents = List.of(
TextSegment.from("Python is a high-level programming language."),
TextSegment.from("Java is a statically-typed object-oriented language."),
TextSegment.from("JavaScript runs in web browsers."),
TextSegment.from("Machine learning is a subset of artificial intelligence."),
TextSegment.from("Neural networks are inspired by biological neurons.")
);
// Embed all documents
Response<List<Embedding>> embeddingsResponse = embeddingModel.embedAll(documents);
List<Embedding> documentEmbeddings = embeddingsResponse.content();
// Store embeddings
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore<>();
for (int i = 0; i < documents.size(); i++) {
embeddingStore.add(documentEmbeddings.get(i), documents.get(i));
}
// Perform semantic search
String query = "Tell me about AI and deep learning";
Embedding queryEmbedding = embeddingModel.embed(query).content();
List<EmbeddingMatch<TextSegment>> matches = embeddingStore.findRelevant(
queryEmbedding,
3 // Top 3 results
);
System.out.println("Query: " + query);
System.out.println("\nTop matches:");
for (int i = 0; i < matches.size(); i++) {
EmbeddingMatch<TextSegment> match = matches.get(i);
System.out.println((i + 1) + ". Score: " + match.score());
System.out.println(" Text: " + match.embedded().text());
}// Use smaller dimensions for storage optimization
OpenAiEmbeddingModel compactModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_3_SMALL)
.dimensions(512) // Reduce from default 1536 to 512
.build();
Response<Embedding> compactEmbedding = compactModel.embed("Sample text");
System.out.println("Compact dimension: " + compactEmbedding.content().dimension());
// Use larger model for higher quality
OpenAiEmbeddingModel largeModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_3_LARGE)
.build();
Response<Embedding> largeEmbedding = largeModel.embed("Sample text");
System.out.println("Large dimension: " + largeEmbedding.content().dimension());import java.util.ArrayList;
// Configure batch size
OpenAiEmbeddingModel batchModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_3_SMALL)
.maxSegmentsPerBatch(100) // Process 100 segments per API call
.timeout(Duration.ofMinutes(2))
.build();
// Prepare large dataset
List<TextSegment> largeDataset = new ArrayList<>();
for (int i = 0; i < 500; i++) {
largeDataset.add(TextSegment.from("Document " + i + " content..."));
}
// Embed all (automatically batched)
Response<List<Embedding>> batchResponse = batchModel.embedAll(largeDataset);
System.out.println("Embedded " + batchResponse.content().size() + " documents");
System.out.println("Total tokens: " + batchResponse.tokenUsage().totalTokenCount());// Calculate cosine similarity between embeddings
public static double cosineSimilarity(Embedding embedding1, Embedding embedding2) {
float[] vec1 = embedding1.vector();
float[] vec2 = embedding2.vector();
double dotProduct = 0.0;
double norm1 = 0.0;
double norm2 = 0.0;
for (int i = 0; i < vec1.length; i++) {
dotProduct += vec1[i] * vec2[i];
norm1 += vec1[i] * vec1[i];
norm2 += vec2[i] * vec2[i];
}
return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2));
}
// Use in practice
OpenAiEmbeddingModel model = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_3_SMALL)
.build();
Embedding emb1 = model.embed("I love machine learning").content();
Embedding emb2 = model.embed("Artificial intelligence is fascinating").content();
Embedding emb3 = model.embed("Pizza is delicious").content();
double similarity12 = cosineSimilarity(emb1, emb2);
double similarity13 = cosineSimilarity(emb1, emb3);
System.out.println("ML vs AI similarity: " + similarity12); // High similarity
System.out.println("ML vs Pizza similarity: " + similarity13); // Low similaritypublic enum OpenAiEmbeddingModelName {
TEXT_EMBEDDING_3_SMALL("text-embedding-3-small", 1536),
TEXT_EMBEDDING_3_LARGE("text-embedding-3-large", 3072),
TEXT_EMBEDDING_ADA_002("text-embedding-ada-002", 1536);
public String toString();
public Integer dimension();
public static Integer knownDimension(String modelName);
}| Model | Dimensions | Use Case | Performance | Cost |
|---|---|---|---|---|
| text-embedding-3-small | 1536 (configurable) | General purpose, cost-effective | Good | Low |
| text-embedding-3-large | 3072 (configurable) | High-quality semantic search | Best | Medium |
| text-embedding-ada-002 | 1536 | Legacy, backward compatibility | Good | Low |
public class Embedding {
public float[] vector();
public List<Float> vectorAsList();
public int dimension();
public static Embedding from(float[] vector);
public static Embedding from(List<Float> vector);
}public class TextSegment {
public String text();
public Metadata metadata();
public static TextSegment from(String text);
public static TextSegment from(String text, Metadata metadata);
}public interface EmbeddingModel {
Response<Embedding> embed(String text);
Response<Embedding> embed(TextSegment textSegment);
Response<List<Embedding>> embedAll(List<TextSegment> textSegments);
}public abstract class DimensionAwareEmbeddingModel implements EmbeddingModel {
public abstract Integer knownDimension();
}public class Response<T> {
public T content();
public TokenUsage tokenUsage();
public FinishReason finishReason();
}Configurable output dimensions for text-embedding-3 models:
Lower dimensions reduce:
Trade-off: Slightly reduced semantic quality
Format for returned embeddings:
Most applications should use default "float" format.
Controls batching for embedAll() method:
Optional string to track end-users:
Maximum time to wait for API response:
Number of retry attempts on failure:
Use text-embedding-3-small when:
Use text-embedding-3-large when:
Use text-embedding-ada-002 when:
// Test different dimensions for your use case
for (int dim : List.of(256, 512, 1024, 1536)) {
OpenAiEmbeddingModel model = OpenAiEmbeddingModel.builder()
.apiKey(apiKey)
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_3_SMALL)
.dimensions(dim)
.build();
// Evaluate quality vs. size trade-off
evaluateModel(model, dim);
}// Good: Batch multiple embeddings
List<TextSegment> segments = List.of(
TextSegment.from("Text 1"),
TextSegment.from("Text 2"),
TextSegment.from("Text 3")
);
Response<List<Embedding>> response = model.embedAll(segments);
// Less efficient: Individual calls
for (TextSegment segment : segments) {
Response<Embedding> response = model.embed(segment); // Multiple API calls
}import java.util.stream.Collectors;
// Split very large datasets into manageable chunks
List<TextSegment> allSegments = loadLargeDataset();
int chunkSize = 1000;
for (int i = 0; i < allSegments.size(); i += chunkSize) {
int end = Math.min(i + chunkSize, allSegments.size());
List<TextSegment> chunk = allSegments.subList(i, end);
Response<List<Embedding>> response = model.embedAll(chunk);
storeEmbeddings(response.content());
// Rate limiting
Thread.sleep(1000); // 1 second between chunks
}// Clean and normalize text before embedding
public TextSegment preprocessText(String rawText) {
String cleaned = rawText
.trim()
.replaceAll("\\s+", " ") // Normalize whitespace
.replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", "") // Remove control chars
.toLowerCase(); // Optional: lowercase for consistency
// Truncate if too long (OpenAI limit: 8191 tokens)
if (cleaned.length() > 30000) { // Approximate token limit
cleaned = cleaned.substring(0, 30000);
}
return TextSegment.from(cleaned);
}import java.util.concurrent.ConcurrentHashMap;
public class EmbeddingCache {
private final OpenAiEmbeddingModel model;
private final ConcurrentHashMap<String, Embedding> cache;
public EmbeddingCache(OpenAiEmbeddingModel model) {
this.model = model;
this.cache = new ConcurrentHashMap<>();
}
public Embedding embed(String text) {
return cache.computeIfAbsent(text, t -> {
Response<Embedding> response = model.embed(t);
return response.content();
});
}
public void clear() {
cache.clear();
}
public int size() {
return cache.size();
}
}Finding documents similar to a query based on meaning rather than keyword matching.
Grouping similar documents together based on embedding similarity.
Training classifiers using embeddings as features.
Recommending items similar to user preferences based on embedding similarity.
Identifying outliers by finding embeddings far from cluster centers.
Retrieving relevant context for language model prompts based on semantic similarity.
Finding near-duplicate or similar content by comparing embeddings.
Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-open-ai@1.11.0