0
# Embeddings
1
2
Vector embeddings for semantic similarity, search, and retrieval-augmented generation (RAG) applications. Convert text into high-dimensional vectors for AI applications.
3
4
## Capabilities
5
6
### OpenAIEmbeddings Class
7
8
The primary embeddings class providing access to OpenAI's text embedding models.
9
10
```typescript { .api }
11
/**
12
* OpenAI embeddings integration
13
* Converts text into high-dimensional vectors for semantic similarity and search
14
*/
15
class OpenAIEmbeddings extends Embeddings {
16
17
constructor(fields?: Partial<OpenAIEmbeddingsParams>);
18
19
/** Model configuration */
20
model: string; // Default: "text-embedding-ada-002"
21
batchSize: number; // Batch size for API calls (default: 512)
22
stripNewLines: boolean; // Strip newlines from text (default: true)
23
dimensions?: number; // Output dimensions (text-embedding-3-* only)
24
25
/** Client configuration */
26
openAIApiKey?: string; // OpenAI API key
27
organization?: string; // OpenAI organization ID
28
baseURL?: string; // Custom base URL
29
timeout?: number; // Request timeout in milliseconds
30
maxRetries?: number; // Maximum retry attempts
31
32
/** Performance options */
33
maxConcurrency?: number; // Maximum concurrent requests
34
35
/** Embed multiple documents */
36
embedDocuments(texts: string[]): Promise<number[][]>;
37
38
/** Embed a single query */
39
embedQuery(text: string): Promise<number[]>;
40
41
/** Make embedding requests with retry logic */
42
embeddingWithRetry<T>(
43
request: OpenAIClient.EmbeddingCreateParams,
44
options?: OpenAICallOptions
45
): Promise<T>;
46
47
/** Get number of tokens in text */
48
getNumTokens(text: string): Promise<number>;
49
}
50
```
51
52
### OpenAI Embeddings Parameters
53
54
Configuration interface for OpenAI embeddings.
55
56
```typescript { .api }
57
interface OpenAIEmbeddingsParams extends EmbeddingsParams {
58
/** Model name for embeddings */
59
model: string;
60
61
/** Number of texts to batch together for embedding */
62
batchSize: number;
63
64
/** Whether to strip newlines from input text */
65
stripNewLines: boolean;
66
67
/** Output dimensions for embedding-3 models */
68
dimensions?: number;
69
70
/** OpenAI API configuration */
71
openAIApiKey?: string;
72
organization?: string;
73
baseURL?: string;
74
timeout?: number;
75
maxRetries?: number;
76
maxConcurrency?: number;
77
}
78
```
79
80
## Usage Examples
81
82
### Basic Embeddings
83
84
```typescript
85
import { OpenAIEmbeddings } from "@langchain/openai";
86
87
const embeddings = new OpenAIEmbeddings({
88
model: "text-embedding-3-small",
89
apiKey: process.env.OPENAI_API_KEY
90
});
91
92
// Embed a single query
93
const queryEmbedding = await embeddings.embedQuery(
94
"What is the capital of France?"
95
);
96
console.log(`Query embedding dimensions: ${queryEmbedding.length}`);
97
98
// Embed multiple documents
99
const documents = [
100
"Paris is the capital of France.",
101
"Berlin is the capital of Germany.",
102
"Tokyo is the capital of Japan.",
103
"London is the capital of the United Kingdom."
104
];
105
106
const documentEmbeddings = await embeddings.embedDocuments(documents);
107
console.log(`Embedded ${documentEmbeddings.length} documents`);
108
console.log(`Each embedding has ${documentEmbeddings[0].length} dimensions`);
109
```
110
111
### Vector Similarity Search
112
113
```typescript
114
import { OpenAIEmbeddings } from "@langchain/openai";
115
116
const embeddings = new OpenAIEmbeddings({
117
model: "text-embedding-3-small"
118
});
119
120
// Create a knowledge base
121
const knowledgeBase = [
122
"The Eiffel Tower is in Paris, France.",
123
"The Statue of Liberty is in New York, USA.",
124
"The Colosseum is in Rome, Italy.",
125
"Big Ben is in London, England.",
126
"The Sydney Opera House is in Sydney, Australia."
127
];
128
129
// Embed all documents
130
const docEmbeddings = await embeddings.embedDocuments(knowledgeBase);
131
132
// Function to calculate cosine similarity
133
function cosineSimilarity(a: number[], b: number[]): number {
134
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
135
const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
136
const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
137
return dotProduct / (magnitudeA * magnitudeB);
138
}
139
140
// Search function
141
async function searchKnowledgeBase(query: string, topK = 3) {
142
const queryEmbedding = await embeddings.embedQuery(query);
143
144
const similarities = docEmbeddings.map((docEmb, index) => ({
145
index,
146
document: knowledgeBase[index],
147
similarity: cosineSimilarity(queryEmbedding, docEmb)
148
}));
149
150
return similarities
151
.sort((a, b) => b.similarity - a.similarity)
152
.slice(0, topK);
153
}
154
155
// Find relevant documents
156
const results = await searchKnowledgeBase("famous landmarks in Europe");
157
results.forEach((result, i) => {
158
console.log(`${i + 1}. (${result.similarity.toFixed(3)}) ${result.document}`);
159
});
160
```
161
162
### Batch Processing with Optimization
163
164
```typescript
165
const embeddings = new OpenAIEmbeddings({
166
model: "text-embedding-3-large",
167
batchSize: 100, // Process 100 texts per batch
168
maxConcurrency: 5, // Max 5 concurrent requests
169
timeout: 30000, // 30 second timeout
170
maxRetries: 3
171
});
172
173
// Process large dataset efficiently
174
async function embedLargeDataset(texts: string[]) {
175
console.log(`Processing ${texts.length} texts...`);
176
177
const startTime = Date.now();
178
const embeddings_result = await embeddings.embedDocuments(texts);
179
const endTime = Date.now();
180
181
console.log(`Completed in ${(endTime - startTime) / 1000}s`);
182
console.log(`Average time per text: ${(endTime - startTime) / texts.length}ms`);
183
184
return embeddings_result;
185
}
186
187
// Example with 1000 texts
188
const largeDocs = Array.from({ length: 1000 }, (_, i) =>
189
`This is document number ${i + 1} with some sample content for testing embeddings performance.`
190
);
191
192
const results = await embedLargeDataset(largeDocs);
193
```
194
195
### Different Model Comparisons
196
197
```typescript
198
// Compare different embedding models
199
const models = [
200
"text-embedding-ada-002",
201
"text-embedding-3-small",
202
"text-embedding-3-large"
203
];
204
205
const sampleText = "Machine learning is a subset of artificial intelligence.";
206
207
for (const model of models) {
208
const embedder = new OpenAIEmbeddings({ model });
209
const embedding = await embedder.embedQuery(sampleText);
210
211
console.log(`${model}:`);
212
console.log(` Dimensions: ${embedding.length}`);
213
console.log(` First 5 values: [${embedding.slice(0, 5).map(x => x.toFixed(4)).join(', ')}]`);
214
}
215
```
216
217
### Custom Dimensions (Embedding-3 Models)
218
219
```typescript
220
// Use custom dimensions to reduce storage and improve performance
221
const compactEmbeddings = new OpenAIEmbeddings({
222
model: "text-embedding-3-small",
223
dimensions: 512 // Reduce from default 1536 to 512
224
});
225
226
const standardEmbeddings = new OpenAIEmbeddings({
227
model: "text-embedding-3-small"
228
// Uses default 1536 dimensions
229
});
230
231
const text = "This is a test for dimension comparison.";
232
233
const compact = await compactEmbeddings.embedQuery(text);
234
const standard = await standardEmbeddings.embedQuery(text);
235
236
console.log(`Compact dimensions: ${compact.length}`); // 512
237
console.log(`Standard dimensions: ${standard.length}`); // 1536
238
239
// Note: Reduced dimensions may impact quality for some use cases
240
```
241
242
### RAG (Retrieval-Augmented Generation) Setup
243
244
```typescript
245
import { OpenAIEmbeddings } from "@langchain/openai";
246
import { ChatOpenAI } from "@langchain/openai";
247
248
class SimpleRAG {
249
private embeddings: OpenAIEmbeddings;
250
private chatModel: ChatOpenAI;
251
private documents: string[] = [];
252
private docEmbeddings: number[][] = [];
253
254
constructor() {
255
this.embeddings = new OpenAIEmbeddings({
256
model: "text-embedding-3-small"
257
});
258
259
this.chatModel = new ChatOpenAI({
260
model: "gpt-4o-mini",
261
temperature: 0
262
});
263
}
264
265
async addDocuments(docs: string[]) {
266
this.documents.push(...docs);
267
const newEmbeddings = await this.embeddings.embedDocuments(docs);
268
this.docEmbeddings.push(...newEmbeddings);
269
}
270
271
async search(query: string, topK = 3): Promise<string[]> {
272
const queryEmbedding = await this.embeddings.embedQuery(query);
273
274
const similarities = this.docEmbeddings.map((docEmb, index) => ({
275
index,
276
similarity: this.cosineSimilarity(queryEmbedding, docEmb)
277
}));
278
279
return similarities
280
.sort((a, b) => b.similarity - a.similarity)
281
.slice(0, topK)
282
.map(item => this.documents[item.index]);
283
}
284
285
async answer(question: string): Promise<string> {
286
const relevantDocs = await this.search(question);
287
288
const context = relevantDocs.join('\n\n');
289
const prompt = `
290
Context:
291
${context}
292
293
Question: ${question}
294
295
Answer the question based on the provided context. If the answer cannot be found in the context, say "I cannot answer based on the provided information."
296
`;
297
298
const response = await this.chatModel.invoke(prompt);
299
return response.content as string;
300
}
301
302
private cosineSimilarity(a: number[], b: number[]): number {
303
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
304
const magnitudeA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
305
const magnitudeB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
306
return dotProduct / (magnitudeA * magnitudeB);
307
}
308
}
309
310
// Usage
311
const rag = new SimpleRAG();
312
313
await rag.addDocuments([
314
"The solar system contains eight planets: Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, and Neptune.",
315
"Earth is the third planet from the Sun and the only known planet with life.",
316
"Jupiter is the largest planet in the solar system and has over 70 moons.",
317
"Mars is often called the Red Planet due to its reddish appearance."
318
]);
319
320
const answer = await rag.answer("What is the largest planet?");
321
console.log(answer); // "Jupiter is the largest planet in the solar system..."
322
```
323
324
### Error Handling and Monitoring
325
326
```typescript
327
import { OpenAIEmbeddings } from "@langchain/openai";
328
329
const embeddings = new OpenAIEmbeddings({
330
model: "text-embedding-3-small",
331
maxRetries: 3,
332
timeout: 60000
333
});
334
335
async function robustEmbedding(texts: string[]) {
336
try {
337
const result = await embeddings.embedDocuments(texts);
338
return result;
339
} catch (error) {
340
console.error("Embedding failed:", error);
341
342
if (error.code === 'rate_limit_exceeded') {
343
console.log("Rate limit hit, implementing backoff...");
344
// Implement exponential backoff
345
await new Promise(resolve => setTimeout(resolve, 5000));
346
return robustEmbedding(texts);
347
}
348
349
if (error.code === 'context_length_exceeded') {
350
console.log("Text too long, chunking...");
351
// Split into smaller chunks
352
const chunks = texts.map(text =>
353
text.length > 8000 ? text.substring(0, 8000) : text
354
);
355
return embeddings.embedDocuments(chunks);
356
}
357
358
throw error;
359
}
360
}
361
362
// Monitor token usage
363
async function embedWithMonitoring(texts: string[]) {
364
const startTime = Date.now();
365
366
// Estimate tokens (rough approximation)
367
const estimatedTokens = texts.reduce((sum, text) =>
368
sum + Math.ceil(text.length / 4), 0
369
);
370
371
console.log(`Embedding ${texts.length} texts (~${estimatedTokens} tokens)`);
372
373
const result = await embeddings.embedDocuments(texts);
374
375
const duration = Date.now() - startTime;
376
console.log(`Completed in ${duration}ms (${(duration / texts.length).toFixed(1)}ms per text)`);
377
378
return result;
379
}
380
```
381
382
## Model Support
383
384
### Available Models
385
386
The OpenAI Embeddings class supports these models:
387
388
| Model | Dimensions | Max Input | Cost | Use Case |
389
|-------|------------|-----------|------|----------|
390
| `text-embedding-ada-002` | 1536 | 8191 tokens | Lower | General purpose (legacy) |
391
| `text-embedding-3-small` | 1536* | 8191 tokens | Lowest | High efficiency |
392
| `text-embedding-3-large` | 3072* | 8191 tokens | Higher | Maximum performance |
393
394
*Supports custom dimensions
395
396
### Model Selection Guide
397
398
```typescript
399
// For high-volume, cost-sensitive applications
400
const efficientEmbeddings = new OpenAIEmbeddings({
401
model: "text-embedding-3-small",
402
dimensions: 512 // Reduce dimensions for cost savings
403
});
404
405
// For maximum quality and performance
406
const highQualityEmbeddings = new OpenAIEmbeddings({
407
model: "text-embedding-3-large"
408
// Uses full 3072 dimensions
409
});
410
411
// For legacy compatibility
412
const legacyEmbeddings = new OpenAIEmbeddings({
413
model: "text-embedding-ada-002"
414
});
415
```
416
417
### Performance Characteristics
418
419
```typescript
420
// Optimize for throughput
421
const throughputOptimized = new OpenAIEmbeddings({
422
model: "text-embedding-3-small",
423
batchSize: 2048, // Large batches
424
maxConcurrency: 10, // High concurrency
425
dimensions: 256 // Smaller dimensions
426
});
427
428
// Optimize for quality
429
const qualityOptimized = new OpenAIEmbeddings({
430
model: "text-embedding-3-large",
431
batchSize: 100, // Smaller batches for stability
432
maxConcurrency: 3, // Conservative concurrency
433
// Full dimensions for maximum quality
434
});
435
```
436
437
## Best Practices
438
439
### Text Preprocessing
440
441
```typescript
442
const embeddings = new OpenAIEmbeddings({
443
model: "text-embedding-3-small",
444
stripNewLines: true // Remove newlines by default
445
});
446
447
// Custom preprocessing
448
function preprocessText(text: string): string {
449
return text
450
.toLowerCase() // Normalize case
451
.replace(/\s+/g, ' ') // Normalize whitespace
452
.trim() // Remove leading/trailing space
453
.substring(0, 8000); // Ensure within token limits
454
}
455
456
const documents = [
457
"This is SAMPLE text with weird spacing\n\n",
458
"Another document with\nNewlines and CAPS"
459
];
460
461
const preprocessed = documents.map(preprocessText);
462
const embeddings_result = await embeddings.embedDocuments(preprocessed);
463
```
464
465
### Caching Strategies
466
467
```typescript
468
class EmbeddingCache {
469
private cache = new Map<string, number[]>();
470
private embeddings: OpenAIEmbeddings;
471
472
constructor() {
473
this.embeddings = new OpenAIEmbeddings({
474
model: "text-embedding-3-small"
475
});
476
}
477
478
async embedQuery(text: string): Promise<number[]> {
479
const key = this.hashText(text);
480
481
if (this.cache.has(key)) {
482
console.log("Cache hit!");
483
return this.cache.get(key)!;
484
}
485
486
console.log("Cache miss, computing embedding...");
487
const embedding = await this.embeddings.embedQuery(text);
488
this.cache.set(key, embedding);
489
490
return embedding;
491
}
492
493
private hashText(text: string): string {
494
// Simple hash function - use a proper one in production
495
return Buffer.from(text).toString('base64');
496
}
497
}
498
499
const cachedEmbeddings = new EmbeddingCache();
500
```
501
502
### Chunking Long Documents
503
504
```typescript
505
function chunkDocument(text: string, maxChunkSize = 7000): string[] {
506
const sentences = text.split(/[.!?]+/).filter(s => s.trim().length > 0);
507
const chunks: string[] = [];
508
let currentChunk = "";
509
510
for (const sentence of sentences) {
511
if (currentChunk.length + sentence.length > maxChunkSize && currentChunk) {
512
chunks.push(currentChunk.trim());
513
currentChunk = "";
514
}
515
currentChunk += sentence + ". ";
516
}
517
518
if (currentChunk.trim()) {
519
chunks.push(currentChunk.trim());
520
}
521
522
return chunks;
523
}
524
525
// Usage with long documents
526
const longDocument = "Very long document text..."; // Imagine this is 20,000+ characters
527
528
const chunks = chunkDocument(longDocument);
529
const chunkEmbeddings = await embeddings.embedDocuments(chunks);
530
531
// Store with metadata for retrieval
532
const documentChunks = chunks.map((chunk, index) => ({
533
text: chunk,
534
embedding: chunkEmbeddings[index],
535
documentId: "doc_123",
536
chunkIndex: index
537
}));
538
```