ruvector 0.1.19 β 0.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +252 -1378
- package/bin/ruvector.js +805 -0
- package/dist/index.d.mts +95 -0
- package/dist/index.d.ts +84 -20
- package/dist/index.js +330 -77
- package/dist/index.mjs +306 -0
- package/package.json +49 -30
- package/.claude-flow/metrics/agent-metrics.json +0 -1
- package/.claude-flow/metrics/performance.json +0 -87
- package/.claude-flow/metrics/task-metrics.json +0 -10
- package/PACKAGE_SUMMARY.md +0 -409
- package/bin/cli.js +0 -287
- package/dist/index.d.ts.map +0 -1
- package/dist/types.d.ts +0 -145
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/examples/api-usage.js +0 -211
- package/examples/cli-demo.sh +0 -85
package/README.md
CHANGED
|
@@ -1,1523 +1,397 @@
|
|
|
1
|
-
#
|
|
1
|
+
# RuVector
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/ruvector)
|
|
7
|
-
[](https://github.com/ruvnet/ruvector)
|
|
8
|
-
[](https://github.com/ruvnet/ruvector)
|
|
9
|
-
[](https://github.com/ruvnet/ruvector)
|
|
10
|
-
|
|
11
|
-
**The fastest vector database for Node.jsβbuilt in Rust, runs everywhere**
|
|
12
|
-
|
|
13
|
-
Ruvector is a next-generation vector database that brings **enterprise-grade semantic search** to Node.js applications. Unlike cloud-only solutions or Python-first databases, Ruvector is designed specifically for JavaScript/TypeScript developers who need **blazing-fast vector similarity search** without the complexity of external services.
|
|
14
|
-
|
|
15
|
-
> π **Sub-millisecond queries** β’ π― **52,000+ inserts/sec** β’ πΎ **~50 bytes per vector** β’ π **Runs anywhere**
|
|
16
|
-
|
|
17
|
-
Built by [rUv](https://ruv.io) with production-grade Rust performance and intelligent platform detectionβ**automatically uses native bindings when available, falls back to WebAssembly when needed**.
|
|
18
|
-
|
|
19
|
-
π **[Visit ruv.io](https://ruv.io)** | π¦ **[GitHub](https://github.com/ruvnet/ruvector)** | π **[Documentation](https://github.com/ruvnet/ruvector/tree/main/docs)**
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## π Why Ruvector?
|
|
24
|
-
|
|
25
|
-
### The Problem with Existing Vector Databases
|
|
26
|
-
|
|
27
|
-
Most vector databases force you to choose between three painful trade-offs:
|
|
28
|
-
|
|
29
|
-
1. **Cloud-Only Services** (Pinecone, Weaviate Cloud) - Expensive, vendor lock-in, latency issues, API rate limits
|
|
30
|
-
2. **Python-First Solutions** (ChromaDB, Faiss) - Poor Node.js support, require separate Python processes
|
|
31
|
-
3. **Self-Hosted Complexity** (Milvus, Qdrant) - Heavy infrastructure, Docker orchestration, operational overhead
|
|
32
|
-
|
|
33
|
-
**Ruvector eliminates these trade-offs.**
|
|
34
|
-
|
|
35
|
-
### The Ruvector Advantage
|
|
36
|
-
|
|
37
|
-
Ruvector is purpose-built for **modern JavaScript/TypeScript applications** that need vector search:
|
|
38
|
-
|
|
39
|
-
π― **Native Node.js Integration**
|
|
40
|
-
- Drop-in npm packageβno Docker, no Python, no external services
|
|
41
|
-
- Full TypeScript support with complete type definitions
|
|
42
|
-
- Automatic platform detection with native Rust bindings
|
|
43
|
-
- Seamless WebAssembly fallback for universal compatibility
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.npmjs.com/package/ruvector)
|
|
5
|
+
[](https://www.npmjs.com/package/ruvector)
|
|
44
6
|
|
|
45
|
-
|
|
46
|
-
- **52,000+ inserts/second** with native Rust (10x faster than Python alternatives)
|
|
47
|
-
- **<0.5ms query latency** with HNSW indexing and SIMD optimizations
|
|
48
|
-
- **~50 bytes per vector** with advanced memory optimization
|
|
49
|
-
- Scales from edge devices to millions of vectors
|
|
7
|
+
**A distributed vector database that learns.** Store embeddings, query with Cypher, scale horizontally, and let the index improve itself through Graph Neural Networks.
|
|
50
8
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- Agent memory and semantic caching
|
|
55
|
-
- Real-time recommendation engines
|
|
9
|
+
```bash
|
|
10
|
+
npx ruvector
|
|
11
|
+
```
|
|
56
12
|
|
|
57
|
-
|
|
58
|
-
- **Linux, macOS, Windows** with native performance
|
|
59
|
-
- **Browser support** via WebAssembly (experimental)
|
|
60
|
-
- **Edge computing** and serverless environments
|
|
61
|
-
- **Alpine Linux** and non-glibc systems supported
|
|
13
|
+
> **All-in-One Package**: The `ruvector` package includes everything β vector search, graph queries, GNN layers, distributed clustering, AI routing, and WASM support. No additional packages needed.
|
|
62
14
|
|
|
63
|
-
|
|
64
|
-
- No cloud API fees or usage limits
|
|
65
|
-
- No infrastructure to manage
|
|
66
|
-
- No separate database servers
|
|
67
|
-
- Open source MIT license
|
|
15
|
+
## What Problem Does RuVector Solve?
|
|
68
16
|
|
|
69
|
-
|
|
17
|
+
Traditional vector databases just store and search. When you ask "find similar items," they return results but never get smarter.
|
|
70
18
|
|
|
71
|
-
|
|
72
|
-
- π― **Automatic Platform Detection**: Uses native when available, falls back to WASM seamlessly
|
|
73
|
-
- π§ **AI-Native**: Built specifically for embeddings, RAG, semantic search, and agent memory
|
|
74
|
-
- π§ **CLI Tools Included**: Full command-line interface for database management
|
|
75
|
-
- π **Universal Deployment**: Works on all platformsβLinux, macOS, Windows, even browsers
|
|
76
|
-
- πΎ **Memory Efficient**: ~50 bytes per vector with advanced quantization
|
|
77
|
-
- π **Production Ready**: Battle-tested algorithms with comprehensive benchmarks
|
|
78
|
-
- π **Open Source**: MIT licensed, community-driven
|
|
19
|
+
**RuVector is different:**
|
|
79
20
|
|
|
80
|
-
|
|
21
|
+
1. **Store vectors** like any vector DB (embeddings from OpenAI, Cohere, etc.)
|
|
22
|
+
2. **Query with Cypher** like Neo4j (`MATCH (a)-[:SIMILAR]->(b) RETURN b`)
|
|
23
|
+
3. **The index learns** β GNN layers make search results improve over time
|
|
24
|
+
4. **Route AI requests** β Semantic routing and FastGRNN neural inference for LLM optimization
|
|
25
|
+
5. **Compress automatically** β 2-32x memory reduction with adaptive tiered compression
|
|
26
|
+
6. **Run anywhere** β Node.js, browser (WASM), or native Rust
|
|
81
27
|
|
|
82
|
-
|
|
28
|
+
## Quick Start
|
|
83
29
|
|
|
84
|
-
|
|
30
|
+
### Installation
|
|
85
31
|
|
|
86
32
|
```bash
|
|
33
|
+
# Install the package
|
|
87
34
|
npm install ruvector
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
**What happens during installation:**
|
|
91
|
-
- npm automatically detects your platform (Linux, macOS, Windows)
|
|
92
|
-
- Downloads the correct native binary for maximum performance
|
|
93
|
-
- Falls back to WebAssembly if native binaries aren't available
|
|
94
|
-
- No additional setup, Docker, or external services required
|
|
95
35
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
npx ruvector info
|
|
36
|
+
# Or try instantly without installing
|
|
37
|
+
npx ruvector
|
|
99
38
|
```
|
|
100
39
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
### Step 2: Your First Vector Database
|
|
104
|
-
|
|
105
|
-
Let's create a simple vector database and perform basic operations. This example demonstrates the complete CRUD (Create, Read, Update, Delete) workflow:
|
|
40
|
+
### Basic Usage
|
|
106
41
|
|
|
107
42
|
```javascript
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
async function tutorial() {
|
|
111
|
-
// Step 2.1: Create a new vector database
|
|
112
|
-
// The 'dimensions' parameter must match your embedding model
|
|
113
|
-
// Common sizes: 128, 384 (sentence-transformers), 768 (BERT), 1536 (OpenAI)
|
|
114
|
-
const db = new VectorDb({
|
|
115
|
-
dimensions: 128, // Vector size - MUST match your embeddings
|
|
116
|
-
maxElements: 10000, // Maximum vectors (can grow automatically)
|
|
117
|
-
storagePath: './my-vectors.db' // Persist to disk (omit for in-memory)
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
console.log('β
Database created successfully');
|
|
121
|
-
|
|
122
|
-
// Step 2.2: Insert vectors
|
|
123
|
-
// In real applications, these would come from an embedding model
|
|
124
|
-
const documents = [
|
|
125
|
-
{ id: 'doc1', text: 'Artificial intelligence and machine learning' },
|
|
126
|
-
{ id: 'doc2', text: 'Deep learning neural networks' },
|
|
127
|
-
{ id: 'doc3', text: 'Natural language processing' },
|
|
128
|
-
];
|
|
129
|
-
|
|
130
|
-
for (const doc of documents) {
|
|
131
|
-
// Generate random vector for demonstration
|
|
132
|
-
// In production: use OpenAI, Cohere, or sentence-transformers
|
|
133
|
-
const vector = new Float32Array(128).map(() => Math.random());
|
|
134
|
-
|
|
135
|
-
await db.insert({
|
|
136
|
-
id: doc.id,
|
|
137
|
-
vector: vector,
|
|
138
|
-
metadata: {
|
|
139
|
-
text: doc.text,
|
|
140
|
-
timestamp: Date.now(),
|
|
141
|
-
category: 'AI'
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
console.log(`β
Inserted: ${doc.id}`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Step 2.3: Search for similar vectors
|
|
149
|
-
// Create a query vector (in production, this would be from your search query)
|
|
150
|
-
const queryVector = new Float32Array(128).map(() => Math.random());
|
|
151
|
-
|
|
152
|
-
const results = await db.search({
|
|
153
|
-
vector: queryVector,
|
|
154
|
-
k: 5, // Return top 5 most similar vectors
|
|
155
|
-
threshold: 0.7 // Only return results with similarity > 0.7
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
console.log('\nπ Search Results:');
|
|
159
|
-
results.forEach((result, index) => {
|
|
160
|
-
console.log(`${index + 1}. ${result.id} - Score: ${result.score.toFixed(3)}`);
|
|
161
|
-
console.log(` Text: ${result.metadata.text}`);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// Step 2.4: Retrieve a specific vector
|
|
165
|
-
const retrieved = await db.get('doc1');
|
|
166
|
-
if (retrieved) {
|
|
167
|
-
console.log('\nπ Retrieved document:', retrieved.metadata.text);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Step 2.5: Get database statistics
|
|
171
|
-
const count = await db.len();
|
|
172
|
-
console.log(`\nπ Total vectors in database: ${count}`);
|
|
173
|
-
|
|
174
|
-
// Step 2.6: Delete a vector
|
|
175
|
-
const deleted = await db.delete('doc1');
|
|
176
|
-
console.log(`\nποΈ Deleted doc1: ${deleted ? 'Success' : 'Not found'}`);
|
|
177
|
-
|
|
178
|
-
// Final count
|
|
179
|
-
const finalCount = await db.len();
|
|
180
|
-
console.log(`π Final count: ${finalCount}`);
|
|
181
|
-
}
|
|
43
|
+
const ruvector = require('ruvector');
|
|
182
44
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**Expected Output:**
|
|
188
|
-
```
|
|
189
|
-
β
Database created successfully
|
|
190
|
-
β
Inserted: doc1
|
|
191
|
-
β
Inserted: doc2
|
|
192
|
-
β
Inserted: doc3
|
|
45
|
+
// Create a vector database
|
|
46
|
+
const db = new ruvector.VectorDB(384); // 384 dimensions
|
|
193
47
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
2. doc1 - Score: 0.856
|
|
198
|
-
Text: Artificial intelligence and machine learning
|
|
199
|
-
3. doc3 - Score: 0.801
|
|
200
|
-
Text: Natural language processing
|
|
48
|
+
// Insert vectors with metadata
|
|
49
|
+
db.insert('doc1', embedding1, { title: 'Introduction', category: 'tech' });
|
|
50
|
+
db.insert('doc2', embedding2, { title: 'Advanced Topics', category: 'tech' });
|
|
201
51
|
|
|
202
|
-
|
|
52
|
+
// Search for similar vectors
|
|
53
|
+
const results = db.search(queryEmbedding, 10);
|
|
54
|
+
console.log(results); // Top 10 similar documents
|
|
203
55
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
ποΈ Deleted doc1: Success
|
|
207
|
-
π Final count: 2
|
|
56
|
+
// Filter by metadata
|
|
57
|
+
const filtered = db.search(queryEmbedding, 10, { category: 'tech' });
|
|
208
58
|
```
|
|
209
59
|
|
|
210
|
-
###
|
|
60
|
+
### Graph Queries (Cypher)
|
|
211
61
|
|
|
212
|
-
|
|
62
|
+
```javascript
|
|
63
|
+
const { GraphDB } = require('ruvector');
|
|
213
64
|
|
|
214
|
-
|
|
215
|
-
import { VectorDb, VectorEntry, SearchQuery, SearchResult } from 'ruvector';
|
|
216
|
-
|
|
217
|
-
// Step 3.1: Define your custom metadata type
|
|
218
|
-
interface DocumentMetadata {
|
|
219
|
-
title: string;
|
|
220
|
-
content: string;
|
|
221
|
-
author: string;
|
|
222
|
-
date: Date;
|
|
223
|
-
tags: string[];
|
|
224
|
-
}
|
|
65
|
+
const graph = new GraphDB();
|
|
225
66
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
dimensions: 384, // sentence-transformers/all-MiniLM-L6-v2
|
|
230
|
-
maxElements: 10000,
|
|
231
|
-
storagePath: './typed-vectors.db'
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
// Step 3.3: Type-safe vector entry
|
|
235
|
-
const entry: VectorEntry<DocumentMetadata> = {
|
|
236
|
-
id: 'article-001',
|
|
237
|
-
vector: new Float32Array(384), // Your embedding here
|
|
238
|
-
metadata: {
|
|
239
|
-
title: 'Introduction to Vector Databases',
|
|
240
|
-
content: 'Vector databases enable semantic search...',
|
|
241
|
-
author: 'Jane Doe',
|
|
242
|
-
date: new Date('2024-01-15'),
|
|
243
|
-
tags: ['database', 'AI', 'search']
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// Step 3.4: Insert with type checking
|
|
248
|
-
await db.insert(entry);
|
|
249
|
-
console.log('β
Inserted typed document');
|
|
250
|
-
|
|
251
|
-
// Step 3.5: Type-safe search
|
|
252
|
-
const query: SearchQuery = {
|
|
253
|
-
vector: new Float32Array(384),
|
|
254
|
-
k: 10,
|
|
255
|
-
threshold: 0.8
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
// Step 3.6: Fully typed results
|
|
259
|
-
const results: SearchResult<DocumentMetadata>[] = await db.search(query);
|
|
260
|
-
|
|
261
|
-
// TypeScript knows the exact shape of metadata
|
|
262
|
-
results.forEach(result => {
|
|
263
|
-
console.log(`Title: ${result.metadata.title}`);
|
|
264
|
-
console.log(`Author: ${result.metadata.author}`);
|
|
265
|
-
console.log(`Tags: ${result.metadata.tags.join(', ')}`);
|
|
266
|
-
console.log(`Similarity: ${result.score.toFixed(3)}\n`);
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// Step 3.7: Type-safe retrieval
|
|
270
|
-
const doc = await db.get('article-001');
|
|
271
|
-
if (doc) {
|
|
272
|
-
// TypeScript autocomplete works perfectly here
|
|
273
|
-
const publishYear = doc.metadata.date.getFullYear();
|
|
274
|
-
console.log(`Published in ${publishYear}`);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
67
|
+
// Create nodes and relationships
|
|
68
|
+
graph.execute("CREATE (a:Person {name: 'Alice'})-[:KNOWS]->(b:Person {name: 'Bob'})");
|
|
69
|
+
graph.execute("CREATE (b)-[:WORKS_AT]->(c:Company {name: 'TechCorp'})");
|
|
277
70
|
|
|
278
|
-
|
|
71
|
+
// Query relationships
|
|
72
|
+
const friends = graph.execute("MATCH (p:Person)-[:KNOWS]->(friend) RETURN friend.name");
|
|
73
|
+
const colleagues = graph.execute(`
|
|
74
|
+
MATCH (p:Person {name: 'Alice'})-[:KNOWS]->(friend)-[:WORKS_AT]->(company)
|
|
75
|
+
RETURN friend.name, company.name
|
|
76
|
+
`);
|
|
279
77
|
```
|
|
280
78
|
|
|
281
|
-
|
|
282
|
-
- β
Full autocomplete for all methods and properties
|
|
283
|
-
- β
Compile-time type checking prevents errors
|
|
284
|
-
- β
IDE IntelliSense shows documentation
|
|
285
|
-
- β
Custom metadata types for your use case
|
|
286
|
-
- β
No `any` types - fully typed throughout
|
|
287
|
-
|
|
288
|
-
## π― Platform Detection
|
|
289
|
-
|
|
290
|
-
Ruvector automatically detects the best implementation for your platform:
|
|
79
|
+
### GNN-Enhanced Search
|
|
291
80
|
|
|
292
81
|
```javascript
|
|
293
|
-
const {
|
|
82
|
+
const { GNNLayer } = require('ruvector');
|
|
294
83
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
console.log(isWasm()); // true if using WebAssembly fallback
|
|
84
|
+
// Create a GNN layer (input_dim, output_dim, num_heads)
|
|
85
|
+
const layer = new GNNLayer(384, 512, 4);
|
|
298
86
|
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
## π§ CLI Tools
|
|
305
|
-
|
|
306
|
-
Ruvector includes a full command-line interface for database management:
|
|
87
|
+
// Enhance query with graph context
|
|
88
|
+
const query = getQueryEmbedding();
|
|
89
|
+
const neighbors = getNeighborEmbeddings();
|
|
90
|
+
const weights = computeEdgeWeights();
|
|
307
91
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
```bash
|
|
311
|
-
# Create a new vector database
|
|
312
|
-
npx ruvector create mydb.vec --dimensions 384 --metric cosine
|
|
313
|
-
|
|
314
|
-
# Options:
|
|
315
|
-
# --dimensions, -d Vector dimensionality (required)
|
|
316
|
-
# --metric, -m Distance metric (cosine, euclidean, dot)
|
|
317
|
-
# --max-elements Maximum number of vectors (default: 10000)
|
|
92
|
+
const enhanced = layer.forward(query, neighbors, weights);
|
|
93
|
+
// Use enhanced embedding for better search results
|
|
318
94
|
```
|
|
319
95
|
|
|
320
|
-
###
|
|
96
|
+
### Compression (2-32x Memory Savings)
|
|
321
97
|
|
|
322
|
-
```
|
|
323
|
-
|
|
324
|
-
npx ruvector insert mydb.vec vectors.json
|
|
325
|
-
|
|
326
|
-
# JSON format:
|
|
327
|
-
# [
|
|
328
|
-
# { "id": "doc1", "vector": [0.1, 0.2, ...], "metadata": {...} },
|
|
329
|
-
# { "id": "doc2", "vector": [0.3, 0.4, ...], "metadata": {...} }
|
|
330
|
-
# ]
|
|
331
|
-
```
|
|
98
|
+
```javascript
|
|
99
|
+
const { compress, decompress, CompressionTier } = require('ruvector');
|
|
332
100
|
|
|
333
|
-
|
|
101
|
+
// Automatic tier selection based on quality threshold
|
|
102
|
+
const compressed = compress(embedding, 0.3); // 30% quality threshold
|
|
334
103
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
104
|
+
// Or specify tier explicitly
|
|
105
|
+
const pq8 = compress(embedding, CompressionTier.PQ8); // 8x compression
|
|
106
|
+
const pq4 = compress(embedding, CompressionTier.PQ4); // 16x compression
|
|
107
|
+
const binary = compress(embedding, CompressionTier.Binary); // 32x compression
|
|
338
108
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
# --top-k, -k Number of results (default: 10)
|
|
342
|
-
# --threshold Minimum similarity score
|
|
109
|
+
// Decompress when needed
|
|
110
|
+
const restored = decompress(compressed);
|
|
343
111
|
```
|
|
344
112
|
|
|
345
|
-
###
|
|
113
|
+
### AI Agent Routing (Tiny Dancer)
|
|
346
114
|
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
npx ruvector stats mydb.vec
|
|
350
|
-
|
|
351
|
-
# Output:
|
|
352
|
-
# Total vectors: 10,000
|
|
353
|
-
# Dimensions: 384
|
|
354
|
-
# Metric: cosine
|
|
355
|
-
# Memory usage: ~500 KB
|
|
356
|
-
# Index type: HNSW
|
|
357
|
-
```
|
|
115
|
+
```javascript
|
|
116
|
+
const { Router } = require('ruvector');
|
|
358
117
|
|
|
359
|
-
|
|
118
|
+
// Create router for AI model selection
|
|
119
|
+
const router = new Router({
|
|
120
|
+
confidenceThreshold: 0.85,
|
|
121
|
+
maxUncertainty: 0.15
|
|
122
|
+
});
|
|
360
123
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
124
|
+
// Route to optimal model based on query complexity
|
|
125
|
+
const candidates = [
|
|
126
|
+
{ id: 'gpt-4', embedding: gpt4Embedding, cost: 0.03 },
|
|
127
|
+
{ id: 'gpt-3.5', embedding: gpt35Embedding, cost: 0.002 },
|
|
128
|
+
{ id: 'claude', embedding: claudeEmbedding, cost: 0.015 }
|
|
129
|
+
];
|
|
364
130
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
# --dimensions Vector dimensionality (default: 128)
|
|
131
|
+
const decision = router.route(queryEmbedding, candidates);
|
|
132
|
+
console.log(decision);
|
|
133
|
+
// { candidateId: 'gpt-3.5', confidence: 0.92, useLightweight: true }
|
|
369
134
|
```
|
|
370
135
|
|
|
371
|
-
|
|
136
|
+
## CLI Usage
|
|
372
137
|
|
|
373
138
|
```bash
|
|
374
|
-
# Show
|
|
139
|
+
# Show system info and backend status
|
|
375
140
|
npx ruvector info
|
|
376
141
|
|
|
377
|
-
#
|
|
378
|
-
|
|
379
|
-
# Implementation: native (Rust)
|
|
380
|
-
# Node.js: v18.17.0
|
|
381
|
-
# Performance: <0.5ms p50 latency
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
## π Performance Benchmarks
|
|
385
|
-
|
|
386
|
-
Tested on AMD Ryzen 9 5950X, 128-dimensional vectors:
|
|
387
|
-
|
|
388
|
-
### Native Performance (Rust)
|
|
389
|
-
|
|
390
|
-
| Operation | Throughput | Latency (p50) | Latency (p99) |
|
|
391
|
-
|-----------|------------|---------------|---------------|
|
|
392
|
-
| Insert | 52,341 ops/sec | 0.019 ms | 0.045 ms |
|
|
393
|
-
| Search (k=10) | 11,234 ops/sec | 0.089 ms | 0.156 ms |
|
|
394
|
-
| Search (k=100) | 8,932 ops/sec | 0.112 ms | 0.203 ms |
|
|
395
|
-
| Delete | 45,678 ops/sec | 0.022 ms | 0.051 ms |
|
|
396
|
-
|
|
397
|
-
**Memory Usage**: ~50 bytes per 128-dim vector (including index)
|
|
398
|
-
|
|
399
|
-
### Comparison with Alternatives
|
|
400
|
-
|
|
401
|
-
| Database | Insert (ops/sec) | Search (ops/sec) | Memory per Vector | Node.js | Browser |
|
|
402
|
-
|----------|------------------|------------------|-------------------|---------|---------|
|
|
403
|
-
| **Ruvector (Native)** | **52,341** | **11,234** | **50 bytes** | β
| β |
|
|
404
|
-
| **Ruvector (WASM)** | **~1,000** | **~100** | **50 bytes** | β
| β
|
|
|
405
|
-
| Faiss (HNSW) | 38,200 | 9,800 | 68 bytes | β | β |
|
|
406
|
-
| Hnswlib | 41,500 | 10,200 | 62 bytes | β
| β |
|
|
407
|
-
| ChromaDB | ~1,000 | ~20 | 150 bytes | β
| β |
|
|
408
|
-
|
|
409
|
-
*Benchmarks measured with 100K vectors, 128 dimensions, k=10*
|
|
410
|
-
|
|
411
|
-
## π Comparison with Other Vector Databases
|
|
412
|
-
|
|
413
|
-
Comprehensive comparison of Ruvector against popular vector database solutions:
|
|
414
|
-
|
|
415
|
-
| Feature | Ruvector | Pinecone | Qdrant | Weaviate | Milvus | ChromaDB | Faiss |
|
|
416
|
-
|---------|----------|----------|--------|----------|--------|----------|-------|
|
|
417
|
-
| **Deployment** |
|
|
418
|
-
| Installation | `npm install` β
| Cloud API βοΈ | Docker π³ | Docker π³ | Docker/K8s π³ | `pip install` π | `pip install` π |
|
|
419
|
-
| Node.js Native | β
First-class | β API only | β οΈ HTTP API | β οΈ HTTP API | β οΈ HTTP API | β Python | β Python |
|
|
420
|
-
| Setup Time | < 1 minute | 5-10 minutes | 10-30 minutes | 15-30 minutes | 30-60 minutes | 5 minutes | 5 minutes |
|
|
421
|
-
| Infrastructure | None required | Managed cloud | Self-hosted | Self-hosted | Self-hosted | Embedded | Embedded |
|
|
422
|
-
| **Performance** |
|
|
423
|
-
| Query Latency (p50) | **<0.5ms** | ~2-5ms | ~1-2ms | ~2-3ms | ~3-5ms | ~50ms | ~1ms |
|
|
424
|
-
| Insert Throughput | **52,341 ops/sec** | ~10,000 ops/sec | ~20,000 ops/sec | ~15,000 ops/sec | ~25,000 ops/sec | ~1,000 ops/sec | ~40,000 ops/sec |
|
|
425
|
-
| Memory per Vector (128d) | **50 bytes** | ~80 bytes | 62 bytes | ~100 bytes | ~70 bytes | 150 bytes | 68 bytes |
|
|
426
|
-
| Recall @ k=10 | 95%+ | 93% | 94% | 92% | 96% | 85% | 97% |
|
|
427
|
-
| **Platform Support** |
|
|
428
|
-
| Linux | β
Native | βοΈ API | β
Docker | β
Docker | β
Docker | β
Python | β
Python |
|
|
429
|
-
| macOS | β
Native | βοΈ API | β
Docker | β
Docker | β
Docker | β
Python | β
Python |
|
|
430
|
-
| Windows | β
Native | βοΈ API | β
Docker | β
Docker | β οΈ WSL2 | β
Python | β
Python |
|
|
431
|
-
| Browser/WASM | β
Yes | β No | β No | β No | β No | β No | β No |
|
|
432
|
-
| ARM64 | β
Native | βοΈ API | β
Yes | β
Yes | β οΈ Limited | β
Yes | β
Yes |
|
|
433
|
-
| Alpine Linux | β
WASM | βοΈ API | β οΈ Build from source | β οΈ Build from source | β No | β
Yes | β
Yes |
|
|
434
|
-
| **Features** |
|
|
435
|
-
| Distance Metrics | Cosine, L2, Dot | Cosine, L2, Dot | 11 metrics | 10 metrics | 8 metrics | L2, Cosine, IP | L2, IP, Cosine |
|
|
436
|
-
| Filtering | β
Metadata | β
Advanced | β
Advanced | β
Advanced | β
Advanced | β
Basic | β Limited |
|
|
437
|
-
| Persistence | β
File-based | βοΈ Managed | β
Disk | β
Disk | β
Disk | β
DuckDB | β Memory |
|
|
438
|
-
| Indexing | HNSW | Proprietary | HNSW | HNSW | IVF/HNSW | HNSW | IVF/HNSW |
|
|
439
|
-
| Quantization | β
PQ | β
Yes | β
Scalar | β
PQ | β
PQ/SQ | β No | β
PQ |
|
|
440
|
-
| Batch Operations | β
Yes | β
Yes | β
Yes | β
Yes | β
Yes | β
Yes | β
Yes |
|
|
441
|
-
| **Developer Experience** |
|
|
442
|
-
| TypeScript Types | β
Full | β
Generated | β οΈ Community | β οΈ Community | β οΈ Community | β οΈ Partial | β No |
|
|
443
|
-
| Documentation | β
Excellent | β
Excellent | β
Good | β
Good | β
Good | β
Good | β οΈ Technical |
|
|
444
|
-
| Examples | β
Many | β
Many | β
Good | β
Good | β
Many | β
Good | β οΈ Limited |
|
|
445
|
-
| CLI Tools | β
Included | β οΈ Limited | β
Yes | β
Yes | β
Yes | β οΈ Basic | β No |
|
|
446
|
-
| **Operations** |
|
|
447
|
-
| Monitoring | β
Metrics | β
Dashboard | β
Prometheus | β
Prometheus | β
Prometheus | β οΈ Basic | β No |
|
|
448
|
-
| Backups | β
File copy | βοΈ Automatic | β
Snapshots | β
Snapshots | β
Snapshots | β
File copy | β Manual |
|
|
449
|
-
| High Availability | β οΈ App-level | β
Built-in | β
Clustering | β
Clustering | β
Clustering | β No | β No |
|
|
450
|
-
| Auto-Scaling | β οΈ App-level | β
Automatic | β οΈ Manual | β οΈ Manual | β οΈ K8s HPA | β No | β No |
|
|
451
|
-
| **Cost** |
|
|
452
|
-
| Pricing Model | Free (MIT) | Pay-per-use | Free (Apache) | Free (BSD) | Free (Apache) | Free (Apache) | Free (MIT) |
|
|
453
|
-
| Monthly Cost (1M vectors) | **$0** | ~$70-200 | ~$20-50 (infra) | ~$30-60 (infra) | ~$50-100 (infra) | $0 | $0 |
|
|
454
|
-
| Monthly Cost (10M vectors) | **$0** | ~$500-1000 | ~$100-200 (infra) | ~$150-300 (infra) | ~$200-400 (infra) | $0 | $0 |
|
|
455
|
-
| API Rate Limits | None | Yes | None | None | None | None | None |
|
|
456
|
-
| **Use Cases** |
|
|
457
|
-
| RAG Systems | β
Excellent | β
Excellent | β
Excellent | β
Excellent | β
Excellent | β
Good | β οΈ Limited |
|
|
458
|
-
| Serverless | β
Perfect | β
Good | β No | β No | β No | β οΈ Possible | β οΈ Possible |
|
|
459
|
-
| Edge Computing | β
Excellent | β No | β No | β No | β No | β No | β οΈ Possible |
|
|
460
|
-
| Production Scale (100M+) | β οΈ Single node | β
Yes | β
Yes | β
Yes | β
Excellent | β οΈ Limited | β οΈ Manual |
|
|
461
|
-
| Embedded Apps | β
Excellent | β No | β No | β No | β No | β οΈ Possible | β
Good |
|
|
462
|
-
|
|
463
|
-
### When to Choose Ruvector
|
|
464
|
-
|
|
465
|
-
β
**Perfect for:**
|
|
466
|
-
- **Node.js/TypeScript applications** needing embedded vector search
|
|
467
|
-
- **Serverless and edge computing** where external services aren't practical
|
|
468
|
-
- **Rapid prototyping and development** with minimal setup time
|
|
469
|
-
- **RAG systems** with LangChain, LlamaIndex, or custom implementations
|
|
470
|
-
- **Cost-sensitive projects** that can't afford cloud API pricing
|
|
471
|
-
- **Offline-first applications** requiring local vector search
|
|
472
|
-
- **Browser-based AI** with WebAssembly fallback
|
|
473
|
-
- **Small to medium scale** (up to 10M vectors per instance)
|
|
474
|
-
|
|
475
|
-
β οΈ **Consider alternatives for:**
|
|
476
|
-
- **Massive scale (100M+ vectors)** - Consider Pinecone, Milvus, or Qdrant clusters
|
|
477
|
-
- **Multi-tenancy requirements** - Weaviate or Qdrant offer better isolation
|
|
478
|
-
- **Distributed systems** - Milvus provides better horizontal scaling
|
|
479
|
-
- **Zero-ops cloud solution** - Pinecone handles all infrastructure
|
|
480
|
-
|
|
481
|
-
### Why Choose Ruvector Over...
|
|
482
|
-
|
|
483
|
-
**vs Pinecone:**
|
|
484
|
-
- β
No API costs (save $1000s/month)
|
|
485
|
-
- β
No network latency (10x faster queries)
|
|
486
|
-
- β
No vendor lock-in
|
|
487
|
-
- β
Works offline and in restricted environments
|
|
488
|
-
- β No managed multi-region clusters
|
|
489
|
-
|
|
490
|
-
**vs ChromaDB:**
|
|
491
|
-
- β
50x faster queries (native Rust vs Python)
|
|
492
|
-
- β
True Node.js support (not HTTP API)
|
|
493
|
-
- β
Better TypeScript integration
|
|
494
|
-
- β
Lower memory usage
|
|
495
|
-
- β Smaller ecosystem and community
|
|
496
|
-
|
|
497
|
-
**vs Qdrant:**
|
|
498
|
-
- β
Zero infrastructure setup
|
|
499
|
-
- β
Embedded in your app (no Docker)
|
|
500
|
-
- β
Better for serverless environments
|
|
501
|
-
- β
Native Node.js bindings
|
|
502
|
-
- β No built-in clustering or HA
|
|
503
|
-
|
|
504
|
-
**vs Faiss:**
|
|
505
|
-
- β
Full Node.js support (Faiss is Python-only)
|
|
506
|
-
- β
Easier API and better developer experience
|
|
507
|
-
- β
Built-in persistence and metadata
|
|
508
|
-
- β οΈ Slightly lower recall at same performance
|
|
509
|
-
|
|
510
|
-
## π― Real-World Tutorials
|
|
511
|
-
|
|
512
|
-
### Tutorial 1: Building a RAG System with OpenAI
|
|
513
|
-
|
|
514
|
-
**What you'll learn:** Create a production-ready Retrieval-Augmented Generation system that enhances LLM responses with relevant context from your documents.
|
|
515
|
-
|
|
516
|
-
**Prerequisites:**
|
|
517
|
-
```bash
|
|
518
|
-
npm install ruvector openai
|
|
519
|
-
export OPENAI_API_KEY="your-api-key-here"
|
|
520
|
-
```
|
|
142
|
+
# Initialize a new index
|
|
143
|
+
npx ruvector init my-index.bin --dimension 384 --type hnsw
|
|
521
144
|
|
|
522
|
-
|
|
145
|
+
# Insert vectors from JSON file
|
|
146
|
+
npx ruvector insert my-index.bin vectors.json
|
|
523
147
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
const OpenAI = require('openai');
|
|
527
|
-
|
|
528
|
-
class RAGSystem {
|
|
529
|
-
constructor() {
|
|
530
|
-
// Initialize OpenAI client
|
|
531
|
-
this.openai = new OpenAI({
|
|
532
|
-
apiKey: process.env.OPENAI_API_KEY
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
// Create vector database for OpenAI embeddings
|
|
536
|
-
// text-embedding-ada-002 produces 1536-dimensional vectors
|
|
537
|
-
this.db = new VectorDb({
|
|
538
|
-
dimensions: 1536,
|
|
539
|
-
maxElements: 100000,
|
|
540
|
-
storagePath: './rag-knowledge-base.db'
|
|
541
|
-
});
|
|
542
|
-
|
|
543
|
-
console.log('β
RAG System initialized');
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
// Step 1: Index your knowledge base
|
|
547
|
-
async indexDocuments(documents) {
|
|
548
|
-
console.log(`π Indexing ${documents.length} documents...`);
|
|
549
|
-
|
|
550
|
-
for (let i = 0; i < documents.length; i++) {
|
|
551
|
-
const doc = documents[i];
|
|
552
|
-
|
|
553
|
-
// Generate embedding for the document
|
|
554
|
-
const response = await this.openai.embeddings.create({
|
|
555
|
-
model: 'text-embedding-ada-002',
|
|
556
|
-
input: doc.content
|
|
557
|
-
});
|
|
558
|
-
|
|
559
|
-
// Store in vector database
|
|
560
|
-
await this.db.insert({
|
|
561
|
-
id: doc.id || `doc_${i}`,
|
|
562
|
-
vector: new Float32Array(response.data[0].embedding),
|
|
563
|
-
metadata: {
|
|
564
|
-
title: doc.title,
|
|
565
|
-
content: doc.content,
|
|
566
|
-
source: doc.source,
|
|
567
|
-
date: doc.date || new Date().toISOString()
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
console.log(` β
Indexed: ${doc.title}`);
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
const count = await this.db.len();
|
|
575
|
-
console.log(`\nβ
Indexed ${count} documents total`);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// Step 2: Retrieve relevant context for a query
|
|
579
|
-
async retrieveContext(query, k = 3) {
|
|
580
|
-
console.log(`π Searching for: "${query}"`);
|
|
581
|
-
|
|
582
|
-
// Generate embedding for the query
|
|
583
|
-
const response = await this.openai.embeddings.create({
|
|
584
|
-
model: 'text-embedding-ada-002',
|
|
585
|
-
input: query
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
// Search for similar documents
|
|
589
|
-
const results = await this.db.search({
|
|
590
|
-
vector: new Float32Array(response.data[0].embedding),
|
|
591
|
-
k: k,
|
|
592
|
-
threshold: 0.7 // Only use highly relevant results
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
console.log(`π Found ${results.length} relevant documents\n`);
|
|
596
|
-
|
|
597
|
-
return results.map(r => ({
|
|
598
|
-
content: r.metadata.content,
|
|
599
|
-
title: r.metadata.title,
|
|
600
|
-
score: r.score
|
|
601
|
-
}));
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// Step 3: Generate answer with retrieved context
|
|
605
|
-
async answer(question) {
|
|
606
|
-
// Retrieve relevant context
|
|
607
|
-
const context = await this.retrieveContext(question, 3);
|
|
608
|
-
|
|
609
|
-
if (context.length === 0) {
|
|
610
|
-
return "I don't have enough information to answer that question.";
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// Build prompt with context
|
|
614
|
-
const contextText = context
|
|
615
|
-
.map((doc, i) => `[${i + 1}] ${doc.title}\n${doc.content}`)
|
|
616
|
-
.join('\n\n');
|
|
617
|
-
|
|
618
|
-
const prompt = `Answer the question based on the following context. If the context doesn't contain the answer, say so.
|
|
619
|
-
|
|
620
|
-
Context:
|
|
621
|
-
${contextText}
|
|
622
|
-
|
|
623
|
-
Question: ${question}
|
|
624
|
-
|
|
625
|
-
Answer:`;
|
|
626
|
-
|
|
627
|
-
console.log('π€ Generating answer...\n');
|
|
628
|
-
|
|
629
|
-
// Generate completion
|
|
630
|
-
const completion = await this.openai.chat.completions.create({
|
|
631
|
-
model: 'gpt-4',
|
|
632
|
-
messages: [
|
|
633
|
-
{ role: 'system', content: 'You are a helpful assistant that answers questions based on provided context.' },
|
|
634
|
-
{ role: 'user', content: prompt }
|
|
635
|
-
],
|
|
636
|
-
temperature: 0.3 // Lower temperature for more factual responses
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
return {
|
|
640
|
-
answer: completion.choices[0].message.content,
|
|
641
|
-
sources: context.map(c => c.title)
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
}
|
|
148
|
+
# Search with a query vector
|
|
149
|
+
npx ruvector search my-index.bin --query "[0.1, 0.2, ...]" -k 10
|
|
645
150
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
const rag = new RAGSystem();
|
|
649
|
-
|
|
650
|
-
// Step 1: Index your knowledge base
|
|
651
|
-
const documents = [
|
|
652
|
-
{
|
|
653
|
-
id: 'doc1',
|
|
654
|
-
title: 'Ruvector Introduction',
|
|
655
|
-
content: 'Ruvector is a high-performance vector database for Node.js built in Rust. It provides sub-millisecond query latency and supports over 52,000 inserts per second.',
|
|
656
|
-
source: 'documentation'
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
id: 'doc2',
|
|
660
|
-
title: 'Vector Databases Explained',
|
|
661
|
-
content: 'Vector databases store data as high-dimensional vectors, enabling semantic similarity search. They are essential for AI applications like RAG systems and recommendation engines.',
|
|
662
|
-
source: 'blog'
|
|
663
|
-
},
|
|
664
|
-
{
|
|
665
|
-
id: 'doc3',
|
|
666
|
-
title: 'HNSW Algorithm',
|
|
667
|
-
content: 'Hierarchical Navigable Small World (HNSW) is a graph-based algorithm for approximate nearest neighbor search. It provides excellent recall with low latency.',
|
|
668
|
-
source: 'research'
|
|
669
|
-
}
|
|
670
|
-
];
|
|
671
|
-
|
|
672
|
-
await rag.indexDocuments(documents);
|
|
673
|
-
|
|
674
|
-
// Step 2: Ask questions
|
|
675
|
-
console.log('\n' + '='.repeat(60) + '\n');
|
|
676
|
-
|
|
677
|
-
const result = await rag.answer('What is Ruvector and what are its performance characteristics?');
|
|
678
|
-
|
|
679
|
-
console.log('π Answer:', result.answer);
|
|
680
|
-
console.log('\nπ Sources:', result.sources.join(', '));
|
|
681
|
-
}
|
|
151
|
+
# Show index statistics
|
|
152
|
+
npx ruvector stats my-index.bin
|
|
682
153
|
|
|
683
|
-
|
|
154
|
+
# Run performance benchmarks
|
|
155
|
+
npx ruvector benchmark --dimension 384 --num-vectors 10000
|
|
684
156
|
```
|
|
685
157
|
|
|
686
|
-
|
|
687
|
-
```
|
|
688
|
-
β
RAG System initialized
|
|
689
|
-
π Indexing 3 documents...
|
|
690
|
-
β
Indexed: Ruvector Introduction
|
|
691
|
-
β
Indexed: Vector Databases Explained
|
|
692
|
-
β
Indexed: HNSW Algorithm
|
|
693
|
-
|
|
694
|
-
β
Indexed 3 documents total
|
|
158
|
+
## Features
|
|
695
159
|
|
|
696
|
-
|
|
160
|
+
### Core Capabilities
|
|
697
161
|
|
|
698
|
-
|
|
699
|
-
|
|
162
|
+
| Feature | Description |
|
|
163
|
+
|---------|-------------|
|
|
164
|
+
| **Vector Search** | HNSW index, <0.5ms latency, SIMD acceleration |
|
|
165
|
+
| **Cypher Queries** | `MATCH`, `WHERE`, `CREATE`, `RETURN` β Neo4j syntax |
|
|
166
|
+
| **GNN Layers** | Multi-head attention on graph topology |
|
|
167
|
+
| **Hyperedges** | Connect 3+ nodes simultaneously |
|
|
168
|
+
| **Metadata Filtering** | Combine semantic + structured search |
|
|
169
|
+
| **Collections** | Namespace isolation, multi-tenancy |
|
|
700
170
|
|
|
701
|
-
|
|
171
|
+
### AI & ML
|
|
702
172
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
-
|
|
173
|
+
| Feature | Description |
|
|
174
|
+
|---------|-------------|
|
|
175
|
+
| **Tensor Compression** | f32βf16βPQ8βPQ4βBinary (2-32x reduction) |
|
|
176
|
+
| **Differentiable Search** | Soft attention k-NN for end-to-end training |
|
|
177
|
+
| **Semantic Router** | Route queries to optimal endpoints |
|
|
178
|
+
| **Tiny Dancer** | FastGRNN neural inference for LLM cost optimization |
|
|
707
179
|
|
|
708
|
-
|
|
709
|
-
```
|
|
180
|
+
### Platform Support
|
|
710
181
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
---
|
|
182
|
+
| Platform | Package | Notes |
|
|
183
|
+
|----------|---------|-------|
|
|
184
|
+
| **Node.js** | `ruvector` | Native bindings via napi-rs |
|
|
185
|
+
| **Browser** | `@ruvector/wasm` | Full WASM support |
|
|
186
|
+
| **Bun** | `ruvector` | Native bindings |
|
|
187
|
+
| **Deno** | `@ruvector/wasm` | WASM fallback |
|
|
719
188
|
|
|
720
|
-
|
|
189
|
+
## Benchmarks
|
|
721
190
|
|
|
722
|
-
|
|
191
|
+
| Operation | Dimensions | Time | Throughput |
|
|
192
|
+
|-----------|------------|------|------------|
|
|
193
|
+
| **HNSW Search (k=10)** | 384 | 61Β΅s | 16,400 QPS |
|
|
194
|
+
| **HNSW Search (k=100)** | 384 | 164Β΅s | 6,100 QPS |
|
|
195
|
+
| **Cosine Distance** | 1536 | 143ns | 7M ops/sec |
|
|
196
|
+
| **Dot Product** | 384 | 33ns | 30M ops/sec |
|
|
197
|
+
| **Insert** | 384 | 20Β΅s | 50,000/sec |
|
|
723
198
|
|
|
724
|
-
|
|
199
|
+
Run your own benchmarks:
|
|
725
200
|
```bash
|
|
726
|
-
|
|
201
|
+
npx ruvector benchmark --dimension 384 --num-vectors 10000
|
|
727
202
|
```
|
|
728
203
|
|
|
729
|
-
|
|
204
|
+
## npm Packages
|
|
730
205
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
// Step 1: Initialize the embedding model
|
|
742
|
-
async initialize() {
|
|
743
|
-
console.log('π Initializing semantic search engine...');
|
|
744
|
-
|
|
745
|
-
// Load sentence-transformers model (runs locally, no API needed!)
|
|
746
|
-
console.log('π₯ Loading embedding model...');
|
|
747
|
-
this.embedder = await pipeline(
|
|
748
|
-
'feature-extraction',
|
|
749
|
-
'Xenova/all-MiniLM-L6-v2'
|
|
750
|
-
);
|
|
751
|
-
|
|
752
|
-
// Create vector database (384 dimensions for all-MiniLM-L6-v2)
|
|
753
|
-
this.db = new VectorDb({
|
|
754
|
-
dimensions: 384,
|
|
755
|
-
maxElements: 50000,
|
|
756
|
-
storagePath: './semantic-search.db'
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
console.log('β
Search engine ready!\n');
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
// Step 2: Generate embeddings
|
|
763
|
-
async embed(text) {
|
|
764
|
-
const output = await this.embedder(text, {
|
|
765
|
-
pooling: 'mean',
|
|
766
|
-
normalize: true
|
|
767
|
-
});
|
|
768
|
-
|
|
769
|
-
// Convert to Float32Array
|
|
770
|
-
return new Float32Array(output.data);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
// Step 3: Index documents
|
|
774
|
-
async indexDocuments(documents) {
|
|
775
|
-
console.log(`π Indexing ${documents.length} documents...`);
|
|
776
|
-
|
|
777
|
-
for (const doc of documents) {
|
|
778
|
-
const vector = await this.embed(doc.content);
|
|
779
|
-
|
|
780
|
-
await this.db.insert({
|
|
781
|
-
id: doc.id,
|
|
782
|
-
vector: vector,
|
|
783
|
-
metadata: {
|
|
784
|
-
title: doc.title,
|
|
785
|
-
content: doc.content,
|
|
786
|
-
category: doc.category,
|
|
787
|
-
url: doc.url
|
|
788
|
-
}
|
|
789
|
-
});
|
|
790
|
-
|
|
791
|
-
console.log(` β
${doc.title}`);
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
const count = await this.db.len();
|
|
795
|
-
console.log(`\nβ
Indexed ${count} documents\n`);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// Step 4: Semantic search
|
|
799
|
-
async search(query, options = {}) {
|
|
800
|
-
const {
|
|
801
|
-
k = 5,
|
|
802
|
-
category = null,
|
|
803
|
-
threshold = 0.3
|
|
804
|
-
} = options;
|
|
805
|
-
|
|
806
|
-
console.log(`π Searching for: "${query}"`);
|
|
807
|
-
|
|
808
|
-
// Generate query embedding
|
|
809
|
-
const queryVector = await this.embed(query);
|
|
810
|
-
|
|
811
|
-
// Search vector database
|
|
812
|
-
const results = await this.db.search({
|
|
813
|
-
vector: queryVector,
|
|
814
|
-
k: k * 2, // Get more results for filtering
|
|
815
|
-
threshold: threshold
|
|
816
|
-
});
|
|
817
|
-
|
|
818
|
-
// Filter by category if specified
|
|
819
|
-
let filtered = results;
|
|
820
|
-
if (category) {
|
|
821
|
-
filtered = results.filter(r => r.metadata.category === category);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// Return top k after filtering
|
|
825
|
-
const final = filtered.slice(0, k);
|
|
826
|
-
|
|
827
|
-
console.log(`π Found ${final.length} results\n`);
|
|
828
|
-
|
|
829
|
-
return final.map(r => ({
|
|
830
|
-
id: r.id,
|
|
831
|
-
title: r.metadata.title,
|
|
832
|
-
content: r.metadata.content,
|
|
833
|
-
category: r.metadata.category,
|
|
834
|
-
score: r.score,
|
|
835
|
-
url: r.metadata.url
|
|
836
|
-
}));
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// Step 5: Find similar documents
|
|
840
|
-
async findSimilar(documentId, k = 5) {
|
|
841
|
-
const doc = await this.db.get(documentId);
|
|
842
|
-
|
|
843
|
-
if (!doc) {
|
|
844
|
-
throw new Error(`Document ${documentId} not found`);
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
const results = await this.db.search({
|
|
848
|
-
vector: doc.vector,
|
|
849
|
-
k: k + 1 // +1 because the document itself will be included
|
|
850
|
-
});
|
|
851
|
-
|
|
852
|
-
// Remove the document itself from results
|
|
853
|
-
return results
|
|
854
|
-
.filter(r => r.id !== documentId)
|
|
855
|
-
.slice(0, k);
|
|
856
|
-
}
|
|
857
|
-
}
|
|
206
|
+
| Package | Description |
|
|
207
|
+
|---------|-------------|
|
|
208
|
+
| [`ruvector`](https://www.npmjs.com/package/ruvector) | All-in-one package (recommended) |
|
|
209
|
+
| [`@ruvector/wasm`](https://www.npmjs.com/package/@ruvector/wasm) | Browser/WASM bindings |
|
|
210
|
+
| [`@ruvector/graph`](https://www.npmjs.com/package/@ruvector/graph) | Graph database with Cypher |
|
|
211
|
+
| [`@ruvector/gnn`](https://www.npmjs.com/package/@ruvector/gnn) | Graph Neural Network layers |
|
|
212
|
+
| [`@ruvector/tiny-dancer`](https://www.npmjs.com/package/@ruvector/tiny-dancer) | AI agent routing (FastGRNN) |
|
|
213
|
+
| [`@ruvector/router`](https://www.npmjs.com/package/@ruvector/router) | Semantic routing engine |
|
|
858
214
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
await engine.initialize();
|
|
863
|
-
|
|
864
|
-
// Sample documents (in production, load from your database)
|
|
865
|
-
const documents = [
|
|
866
|
-
{
|
|
867
|
-
id: '1',
|
|
868
|
-
title: 'Understanding Neural Networks',
|
|
869
|
-
content: 'Neural networks are computing systems inspired by biological neural networks. They learn to perform tasks by considering examples.',
|
|
870
|
-
category: 'AI',
|
|
871
|
-
url: '/docs/neural-networks'
|
|
872
|
-
},
|
|
873
|
-
{
|
|
874
|
-
id: '2',
|
|
875
|
-
title: 'Introduction to Machine Learning',
|
|
876
|
-
content: 'Machine learning is a subset of artificial intelligence that provides systems the ability to learn and improve from experience.',
|
|
877
|
-
category: 'AI',
|
|
878
|
-
url: '/docs/machine-learning'
|
|
879
|
-
},
|
|
880
|
-
{
|
|
881
|
-
id: '3',
|
|
882
|
-
title: 'Web Development Best Practices',
|
|
883
|
-
content: 'Modern web development involves responsive design, performance optimization, and accessibility considerations.',
|
|
884
|
-
category: 'Web',
|
|
885
|
-
url: '/docs/web-dev'
|
|
886
|
-
},
|
|
887
|
-
{
|
|
888
|
-
id: '4',
|
|
889
|
-
title: 'Deep Learning Applications',
|
|
890
|
-
content: 'Deep learning has revolutionized computer vision, natural language processing, and speech recognition.',
|
|
891
|
-
category: 'AI',
|
|
892
|
-
url: '/docs/deep-learning'
|
|
893
|
-
}
|
|
894
|
-
];
|
|
895
|
-
|
|
896
|
-
// Index documents
|
|
897
|
-
await engine.indexDocuments(documents);
|
|
898
|
-
|
|
899
|
-
// Example 1: Basic semantic search
|
|
900
|
-
console.log('Example 1: Basic Search\n' + '='.repeat(60));
|
|
901
|
-
const results1 = await engine.search('AI and neural nets');
|
|
902
|
-
results1.forEach((result, i) => {
|
|
903
|
-
console.log(`${i + 1}. ${result.title} (Score: ${result.score.toFixed(3)})`);
|
|
904
|
-
console.log(` ${result.content.slice(0, 80)}...`);
|
|
905
|
-
console.log(` Category: ${result.category}\n`);
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
// Example 2: Category-filtered search
|
|
909
|
-
console.log('\nExample 2: Category-Filtered Search\n' + '='.repeat(60));
|
|
910
|
-
const results2 = await engine.search('learning algorithms', {
|
|
911
|
-
category: 'AI',
|
|
912
|
-
k: 3
|
|
913
|
-
});
|
|
914
|
-
results2.forEach((result, i) => {
|
|
915
|
-
console.log(`${i + 1}. ${result.title} (Score: ${result.score.toFixed(3)})`);
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
// Example 3: Find similar documents
|
|
919
|
-
console.log('\n\nExample 3: Find Similar Documents\n' + '='.repeat(60));
|
|
920
|
-
const similar = await engine.findSimilar('1', 2);
|
|
921
|
-
console.log('Documents similar to "Understanding Neural Networks":');
|
|
922
|
-
similar.forEach((doc, i) => {
|
|
923
|
-
console.log(`${i + 1}. ${doc.metadata.title} (Score: ${doc.score.toFixed(3)})`);
|
|
924
|
-
});
|
|
925
|
-
}
|
|
215
|
+
```bash
|
|
216
|
+
# Install all-in-one (recommended)
|
|
217
|
+
npm install ruvector
|
|
926
218
|
|
|
927
|
-
|
|
219
|
+
# Or install specific packages
|
|
220
|
+
npm install @ruvector/graph @ruvector/gnn
|
|
928
221
|
```
|
|
929
222
|
|
|
930
|
-
|
|
931
|
-
- β
Runs completely locally (no API keys needed)
|
|
932
|
-
- β
Understands semantic meaning, not just keywords
|
|
933
|
-
- β
Category filtering for better results
|
|
934
|
-
- β
"Find similar" functionality
|
|
935
|
-
- β
Fast: ~10ms query latency
|
|
223
|
+
## API Reference
|
|
936
224
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
### Tutorial 3: AI Agent Memory System
|
|
940
|
-
|
|
941
|
-
**What you'll learn:** Implement a memory system for AI agents that remembers past experiences and learns from them.
|
|
225
|
+
### VectorDB
|
|
942
226
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
dimensions: 768,
|
|
955
|
-
storagePath: `./memory/${agentId}-episodic.db`
|
|
956
|
-
});
|
|
957
|
-
|
|
958
|
-
this.semanticMemory = new VectorDb({
|
|
959
|
-
dimensions: 768,
|
|
960
|
-
storagePath: `./memory/${agentId}-semantic.db`
|
|
961
|
-
});
|
|
962
|
-
|
|
963
|
-
console.log(`π§ Memory system initialized for agent: ${agentId}`);
|
|
964
|
-
}
|
|
965
|
-
|
|
966
|
-
// Step 1: Store an experience (episodic memory)
|
|
967
|
-
async storeExperience(experience) {
|
|
968
|
-
const {
|
|
969
|
-
state,
|
|
970
|
-
action,
|
|
971
|
-
result,
|
|
972
|
-
reward,
|
|
973
|
-
embedding
|
|
974
|
-
} = experience;
|
|
975
|
-
|
|
976
|
-
const experienceId = `exp_${Date.now()}_${Math.random()}`;
|
|
977
|
-
|
|
978
|
-
await this.episodicMemory.insert({
|
|
979
|
-
id: experienceId,
|
|
980
|
-
vector: new Float32Array(embedding),
|
|
981
|
-
metadata: {
|
|
982
|
-
state: state,
|
|
983
|
-
action: action,
|
|
984
|
-
result: result,
|
|
985
|
-
reward: reward,
|
|
986
|
-
timestamp: Date.now(),
|
|
987
|
-
type: 'episodic'
|
|
988
|
-
}
|
|
989
|
-
});
|
|
990
|
-
|
|
991
|
-
console.log(`πΎ Stored experience: ${action} -> ${result} (reward: ${reward})`);
|
|
992
|
-
return experienceId;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
// Step 2: Store learned knowledge (semantic memory)
|
|
996
|
-
async storeKnowledge(knowledge) {
|
|
997
|
-
const {
|
|
998
|
-
concept,
|
|
999
|
-
description,
|
|
1000
|
-
embedding,
|
|
1001
|
-
confidence = 1.0
|
|
1002
|
-
} = knowledge;
|
|
1003
|
-
|
|
1004
|
-
const knowledgeId = `know_${Date.now()}`;
|
|
1005
|
-
|
|
1006
|
-
await this.semanticMemory.insert({
|
|
1007
|
-
id: knowledgeId,
|
|
1008
|
-
vector: new Float32Array(embedding),
|
|
1009
|
-
metadata: {
|
|
1010
|
-
concept: concept,
|
|
1011
|
-
description: description,
|
|
1012
|
-
confidence: confidence,
|
|
1013
|
-
learned: Date.now(),
|
|
1014
|
-
uses: 0,
|
|
1015
|
-
type: 'semantic'
|
|
1016
|
-
}
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
console.log(`π Learned: ${concept}`);
|
|
1020
|
-
return knowledgeId;
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
// Step 3: Recall similar experiences
|
|
1024
|
-
async recallExperiences(currentState, k = 5) {
|
|
1025
|
-
console.log(`π Recalling similar experiences...`);
|
|
1026
|
-
|
|
1027
|
-
const results = await this.episodicMemory.search({
|
|
1028
|
-
vector: new Float32Array(currentState.embedding),
|
|
1029
|
-
k: k,
|
|
1030
|
-
threshold: 0.6 // Only recall reasonably similar experiences
|
|
1031
|
-
});
|
|
1032
|
-
|
|
1033
|
-
// Sort by reward to prioritize successful experiences
|
|
1034
|
-
const sorted = results.sort((a, b) => b.metadata.reward - a.metadata.reward);
|
|
1035
|
-
|
|
1036
|
-
console.log(`π Recalled ${sorted.length} relevant experiences`);
|
|
1037
|
-
|
|
1038
|
-
return sorted.map(r => ({
|
|
1039
|
-
state: r.metadata.state,
|
|
1040
|
-
action: r.metadata.action,
|
|
1041
|
-
result: r.metadata.result,
|
|
1042
|
-
reward: r.metadata.reward,
|
|
1043
|
-
similarity: r.score
|
|
1044
|
-
}));
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
// Step 4: Query knowledge base
|
|
1048
|
-
async queryKnowledge(query, k = 3) {
|
|
1049
|
-
const results = await this.semanticMemory.search({
|
|
1050
|
-
vector: new Float32Array(query.embedding),
|
|
1051
|
-
k: k
|
|
1052
|
-
});
|
|
1053
|
-
|
|
1054
|
-
// Update usage statistics
|
|
1055
|
-
for (const result of results) {
|
|
1056
|
-
const knowledge = await this.semanticMemory.get(result.id);
|
|
1057
|
-
if (knowledge) {
|
|
1058
|
-
knowledge.metadata.uses += 1;
|
|
1059
|
-
// In production, update the entry
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
return results.map(r => ({
|
|
1064
|
-
concept: r.metadata.concept,
|
|
1065
|
-
description: r.metadata.description,
|
|
1066
|
-
confidence: r.metadata.confidence,
|
|
1067
|
-
relevance: r.score
|
|
1068
|
-
}));
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
// Step 5: Reflect and learn from experiences
|
|
1072
|
-
async reflect() {
|
|
1073
|
-
console.log('\nπ€ Reflecting on experiences...');
|
|
1074
|
-
|
|
1075
|
-
// Get all experiences
|
|
1076
|
-
const totalExperiences = await this.episodicMemory.len();
|
|
1077
|
-
console.log(`π Total experiences: ${totalExperiences}`);
|
|
1078
|
-
|
|
1079
|
-
// Analyze success rate
|
|
1080
|
-
// In production, you'd aggregate experiences and extract patterns
|
|
1081
|
-
console.log('π‘ Analysis complete');
|
|
1082
|
-
|
|
1083
|
-
return {
|
|
1084
|
-
totalExperiences: totalExperiences,
|
|
1085
|
-
knowledgeItems: await this.semanticMemory.len()
|
|
1086
|
-
};
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
// Step 6: Get memory statistics
|
|
1090
|
-
async getStats() {
|
|
1091
|
-
return {
|
|
1092
|
-
episodicMemorySize: await this.episodicMemory.len(),
|
|
1093
|
-
semanticMemorySize: await this.semanticMemory.len(),
|
|
1094
|
-
agentId: this.agentId
|
|
1095
|
-
};
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
// Example Usage: Simulated agent learning to navigate
|
|
1100
|
-
async function main() {
|
|
1101
|
-
const agent = new AgentMemory('agent-001');
|
|
1102
|
-
|
|
1103
|
-
// Simulate embedding function (in production, use a real model)
|
|
1104
|
-
function embed(text) {
|
|
1105
|
-
return Array(768).fill(0).map(() => Math.random());
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
console.log('\n' + '='.repeat(60));
|
|
1109
|
-
console.log('PHASE 1: Learning from experiences');
|
|
1110
|
-
console.log('='.repeat(60) + '\n');
|
|
1111
|
-
|
|
1112
|
-
// Store some experiences
|
|
1113
|
-
await agent.storeExperience({
|
|
1114
|
-
state: { location: 'room1', goal: 'room3' },
|
|
1115
|
-
action: 'move_north',
|
|
1116
|
-
result: 'reached room2',
|
|
1117
|
-
reward: 0.5,
|
|
1118
|
-
embedding: embed('navigating from room1 to room2')
|
|
1119
|
-
});
|
|
1120
|
-
|
|
1121
|
-
await agent.storeExperience({
|
|
1122
|
-
state: { location: 'room2', goal: 'room3' },
|
|
1123
|
-
action: 'move_east',
|
|
1124
|
-
result: 'reached room3',
|
|
1125
|
-
reward: 1.0,
|
|
1126
|
-
embedding: embed('navigating from room2 to room3')
|
|
1127
|
-
});
|
|
1128
|
-
|
|
1129
|
-
await agent.storeExperience({
|
|
1130
|
-
state: { location: 'room1', goal: 'room3' },
|
|
1131
|
-
action: 'move_south',
|
|
1132
|
-
result: 'hit wall',
|
|
1133
|
-
reward: -0.5,
|
|
1134
|
-
embedding: embed('failed navigation attempt')
|
|
1135
|
-
});
|
|
1136
|
-
|
|
1137
|
-
// Store learned knowledge
|
|
1138
|
-
await agent.storeKnowledge({
|
|
1139
|
-
concept: 'navigation_strategy',
|
|
1140
|
-
description: 'Moving north then east is efficient for reaching room3 from room1',
|
|
1141
|
-
embedding: embed('navigation strategy knowledge'),
|
|
1142
|
-
confidence: 0.9
|
|
1143
|
-
});
|
|
1144
|
-
|
|
1145
|
-
console.log('\n' + '='.repeat(60));
|
|
1146
|
-
console.log('PHASE 2: Applying memory');
|
|
1147
|
-
console.log('='.repeat(60) + '\n');
|
|
1148
|
-
|
|
1149
|
-
// Agent encounters a similar situation
|
|
1150
|
-
const currentState = {
|
|
1151
|
-
location: 'room1',
|
|
1152
|
-
goal: 'room3',
|
|
1153
|
-
embedding: embed('navigating from room1 to room3')
|
|
1154
|
-
};
|
|
1155
|
-
|
|
1156
|
-
// Recall relevant experiences
|
|
1157
|
-
const experiences = await agent.recallExperiences(currentState, 3);
|
|
1158
|
-
|
|
1159
|
-
console.log('\nπ Recalled experiences:');
|
|
1160
|
-
experiences.forEach((exp, i) => {
|
|
1161
|
-
console.log(`${i + 1}. Action: ${exp.action} | Result: ${exp.result} | Reward: ${exp.reward} | Similarity: ${exp.similarity.toFixed(3)}`);
|
|
1162
|
-
});
|
|
1163
|
-
|
|
1164
|
-
// Query relevant knowledge
|
|
1165
|
-
const knowledge = await agent.queryKnowledge({
|
|
1166
|
-
embedding: embed('how to navigate efficiently')
|
|
1167
|
-
}, 2);
|
|
1168
|
-
|
|
1169
|
-
console.log('\nπ Relevant knowledge:');
|
|
1170
|
-
knowledge.forEach((k, i) => {
|
|
1171
|
-
console.log(`${i + 1}. ${k.concept}: ${k.description} (confidence: ${k.confidence})`);
|
|
1172
|
-
});
|
|
1173
|
-
|
|
1174
|
-
console.log('\n' + '='.repeat(60));
|
|
1175
|
-
console.log('PHASE 3: Reflection');
|
|
1176
|
-
console.log('='.repeat(60) + '\n');
|
|
1177
|
-
|
|
1178
|
-
// Reflect on learning
|
|
1179
|
-
const stats = await agent.reflect();
|
|
1180
|
-
const memoryStats = await agent.getStats();
|
|
1181
|
-
|
|
1182
|
-
console.log('\nπ Memory Statistics:');
|
|
1183
|
-
console.log(` Episodic memories: ${memoryStats.episodicMemorySize}`);
|
|
1184
|
-
console.log(` Semantic knowledge: ${memoryStats.semanticMemorySize}`);
|
|
1185
|
-
console.log(` Agent ID: ${memoryStats.agentId}`);
|
|
227
|
+
```typescript
|
|
228
|
+
class VectorDB {
|
|
229
|
+
constructor(dimension: number, options?: VectorDBOptions);
|
|
230
|
+
|
|
231
|
+
insert(id: string, values: number[], metadata?: object): void;
|
|
232
|
+
insertBatch(vectors: Vector[]): void;
|
|
233
|
+
search(query: number[], k?: number, filter?: object): SearchResult[];
|
|
234
|
+
get(id: string): Vector | null;
|
|
235
|
+
delete(id: string): boolean;
|
|
236
|
+
save(path: string): void;
|
|
237
|
+
static load(path: string): VectorDB;
|
|
1186
238
|
}
|
|
1187
|
-
|
|
1188
|
-
main().catch(console.error);
|
|
1189
239
|
```
|
|
1190
240
|
|
|
1191
|
-
|
|
1192
|
-
```
|
|
1193
|
-
π§ Memory system initialized for agent: agent-001
|
|
1194
|
-
|
|
1195
|
-
============================================================
|
|
1196
|
-
PHASE 1: Learning from experiences
|
|
1197
|
-
============================================================
|
|
1198
|
-
|
|
1199
|
-
πΎ Stored experience: move_north -> reached room2 (reward: 0.5)
|
|
1200
|
-
πΎ Stored experience: move_east -> reached room3 (reward: 1.0)
|
|
1201
|
-
πΎ Stored experience: move_south -> hit wall (reward: -0.5)
|
|
1202
|
-
π Learned: navigation_strategy
|
|
1203
|
-
|
|
1204
|
-
============================================================
|
|
1205
|
-
PHASE 2: Applying memory
|
|
1206
|
-
============================================================
|
|
1207
|
-
|
|
1208
|
-
π Recalling similar experiences...
|
|
1209
|
-
π Recalled 3 relevant experiences
|
|
241
|
+
### GraphDB
|
|
1210
242
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
3. Action: move_south | Result: hit wall | Reward: -0.5 | Similarity: 0.654
|
|
243
|
+
```typescript
|
|
244
|
+
class GraphDB {
|
|
245
|
+
constructor();
|
|
1215
246
|
|
|
1216
|
-
|
|
1217
|
-
|
|
247
|
+
execute(cypher: string): QueryResult;
|
|
248
|
+
createNode(label: string, properties: object): string;
|
|
249
|
+
createRelationship(from: string, to: string, type: string): void;
|
|
250
|
+
createHyperedge(nodeIds: string[], type: string): string;
|
|
251
|
+
}
|
|
252
|
+
```
|
|
1218
253
|
|
|
1219
|
-
|
|
1220
|
-
PHASE 3: Reflection
|
|
1221
|
-
============================================================
|
|
254
|
+
### GNNLayer
|
|
1222
255
|
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
256
|
+
```typescript
|
|
257
|
+
class GNNLayer {
|
|
258
|
+
constructor(inputDim: number, outputDim: number, numHeads: number);
|
|
1226
259
|
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
Agent ID: agent-001
|
|
260
|
+
forward(query: number[], neighbors: number[][], weights: number[]): number[];
|
|
261
|
+
train(data: TrainingData, epochs: number): void;
|
|
262
|
+
}
|
|
1231
263
|
```
|
|
1232
264
|
|
|
1233
|
-
|
|
1234
|
-
- β
Reinforcement learning agents
|
|
1235
|
-
- β
Chatbot conversation history
|
|
1236
|
-
- β
Game AI that learns from gameplay
|
|
1237
|
-
- β
Personal assistant memory
|
|
1238
|
-
- β
Robotic navigation systems
|
|
1239
|
-
|
|
1240
|
-
## ποΈ API Reference
|
|
1241
|
-
|
|
1242
|
-
### Constructor
|
|
265
|
+
### Router (Tiny Dancer)
|
|
1243
266
|
|
|
1244
267
|
```typescript
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
})
|
|
268
|
+
class Router {
|
|
269
|
+
constructor(config?: RouterConfig);
|
|
270
|
+
|
|
271
|
+
route(query: number[], candidates: Candidate[]): RoutingDecision;
|
|
272
|
+
reloadModel(): void;
|
|
273
|
+
circuitBreakerStatus(): 'closed' | 'open' | 'half-open';
|
|
274
|
+
}
|
|
1253
275
|
```
|
|
1254
276
|
|
|
1255
|
-
|
|
277
|
+
## Use Cases
|
|
1256
278
|
|
|
1257
|
-
|
|
1258
|
-
Insert a vector into the database.
|
|
279
|
+
### RAG (Retrieval-Augmented Generation)
|
|
1259
280
|
|
|
1260
281
|
```javascript
|
|
1261
|
-
const
|
|
1262
|
-
id: 'doc_1',
|
|
1263
|
-
vector: new Float32Array([0.1, 0.2, 0.3, ...]),
|
|
1264
|
-
metadata: { title: 'Document 1' }
|
|
1265
|
-
});
|
|
1266
|
-
```
|
|
282
|
+
const ruvector = require('ruvector');
|
|
1267
283
|
|
|
1268
|
-
|
|
1269
|
-
|
|
284
|
+
async function ragQuery(question) {
|
|
285
|
+
const questionEmbedding = await embed(question);
|
|
286
|
+
const context = db.search(questionEmbedding, 5);
|
|
1270
287
|
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
vector: new Float32Array([0.1, 0.2, 0.3, ...]),
|
|
1274
|
-
k: 10,
|
|
1275
|
-
threshold: 0.7
|
|
1276
|
-
});
|
|
1277
|
-
```
|
|
288
|
+
const prompt = `
|
|
289
|
+
Context: ${context.map(c => c.metadata.text).join('\n')}
|
|
1278
290
|
|
|
1279
|
-
|
|
1280
|
-
|
|
291
|
+
Question: ${question}
|
|
292
|
+
Answer:
|
|
293
|
+
`;
|
|
1281
294
|
|
|
1282
|
-
|
|
1283
|
-
const entry = await db.get('doc_1');
|
|
1284
|
-
if (entry) {
|
|
1285
|
-
console.log(entry.vector, entry.metadata);
|
|
295
|
+
return await llm.complete(prompt);
|
|
1286
296
|
}
|
|
1287
297
|
```
|
|
1288
298
|
|
|
1289
|
-
|
|
1290
|
-
Remove a vector from the database.
|
|
299
|
+
### Recommendation System
|
|
1291
300
|
|
|
1292
301
|
```javascript
|
|
1293
|
-
const
|
|
1294
|
-
console.log(deleted ? 'Deleted' : 'Not found');
|
|
1295
|
-
```
|
|
302
|
+
const { GraphDB } = require('ruvector');
|
|
1296
303
|
|
|
1297
|
-
|
|
1298
|
-
Get the total number of vectors.
|
|
304
|
+
const graph = new GraphDB();
|
|
1299
305
|
|
|
1300
|
-
|
|
1301
|
-
const
|
|
1302
|
-
|
|
306
|
+
// Find recommendations based on user behavior
|
|
307
|
+
const recommendations = graph.execute(`
|
|
308
|
+
MATCH (user:User {id: $userId})-[:VIEWED]->(item:Product)
|
|
309
|
+
MATCH (item)-[:SIMILAR_TO]->(rec:Product)
|
|
310
|
+
WHERE NOT (user)-[:VIEWED]->(rec)
|
|
311
|
+
RETURN rec ORDER BY rec.score DESC LIMIT 10
|
|
312
|
+
`);
|
|
1303
313
|
```
|
|
1304
314
|
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
### HNSW Parameters
|
|
315
|
+
### Semantic Search with Filters
|
|
1308
316
|
|
|
1309
317
|
```javascript
|
|
1310
|
-
const
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
m: 16, // Higher = better recall, more memory
|
|
1315
|
-
storagePath: './large-db.db'
|
|
318
|
+
const results = db.search(queryEmbedding, 20, {
|
|
319
|
+
category: 'electronics',
|
|
320
|
+
price: { $lt: 500 },
|
|
321
|
+
inStock: true
|
|
1316
322
|
});
|
|
1317
323
|
```
|
|
1318
324
|
|
|
1319
|
-
|
|
1320
|
-
- `ef_construction`: 100-400 (higher = better recall, slower indexing)
|
|
1321
|
-
- `m`: 8-64 (higher = better recall, more memory)
|
|
1322
|
-
- Default values work well for most use cases
|
|
1323
|
-
|
|
1324
|
-
### Distance Metrics
|
|
1325
|
-
|
|
1326
|
-
```javascript
|
|
1327
|
-
// Cosine similarity (default, best for normalized vectors)
|
|
1328
|
-
const db1 = new VectorDb({
|
|
1329
|
-
dimensions: 128,
|
|
1330
|
-
distanceMetric: 'cosine'
|
|
1331
|
-
});
|
|
325
|
+
## Architecture
|
|
1332
326
|
|
|
1333
|
-
// Euclidean distance (L2, best for spatial data)
|
|
1334
|
-
const db2 = new VectorDb({
|
|
1335
|
-
dimensions: 128,
|
|
1336
|
-
distanceMetric: 'euclidean'
|
|
1337
|
-
});
|
|
1338
|
-
|
|
1339
|
-
// Dot product (best for pre-normalized vectors)
|
|
1340
|
-
const db3 = new VectorDb({
|
|
1341
|
-
dimensions: 128,
|
|
1342
|
-
distanceMetric: 'dot'
|
|
1343
|
-
});
|
|
1344
327
|
```
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
});
|
|
328
|
+
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
329
|
+
β ruvector β
|
|
330
|
+
β (All-in-One npm Package) β
|
|
331
|
+
βββββββββββββββ¬ββββββββββββββ¬ββββββββββββββ¬βββββββββββββββ€
|
|
332
|
+
β VectorDB β GraphDB β GNNLayer β Router β
|
|
333
|
+
β (Search) β (Cypher) β (ML) β (AI Routing) β
|
|
334
|
+
βββββββββββββββ΄ββββββββββββββ΄ββββββββββββββ΄βββββββββββββββ
|
|
335
|
+
β
|
|
336
|
+
ββββββββββββββββββββΌβββββββββββββββββββ
|
|
337
|
+
β β β
|
|
338
|
+
ββββββΌβββββ ββββββΌβββββ ββββββΌβββββ
|
|
339
|
+
β Native β β WASM β β FFI β
|
|
340
|
+
β (napi) β β(wasm32) β β (C) β
|
|
341
|
+
βββββββββββ βββββββββββ βββββββββββ
|
|
1360
342
|
```
|
|
1361
343
|
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
Automatically installs the correct implementation for:
|
|
1365
|
-
|
|
1366
|
-
### Native (Rust) - Best Performance
|
|
1367
|
-
- **Linux**: x64, ARM64 (GNU libc)
|
|
1368
|
-
- **macOS**: x64 (Intel), ARM64 (Apple Silicon)
|
|
1369
|
-
- **Windows**: x64 (MSVC)
|
|
1370
|
-
|
|
1371
|
-
Performance: **<0.5ms latency**, **50K+ ops/sec**
|
|
344
|
+
The package automatically selects the best available backend (native > WASM).
|
|
1372
345
|
|
|
1373
|
-
|
|
1374
|
-
- Any platform where native module isn't available
|
|
1375
|
-
- Browser environments (experimental)
|
|
1376
|
-
- Alpine Linux (musl) and other non-glibc systems
|
|
346
|
+
## Comparison
|
|
1377
347
|
|
|
1378
|
-
|
|
348
|
+
| Feature | RuVector | Pinecone | Qdrant | ChromaDB |
|
|
349
|
+
|---------|----------|----------|--------|----------|
|
|
350
|
+
| **Latency** | **61Β΅s** | ~2ms | ~1ms | ~50ms |
|
|
351
|
+
| **Graph Queries** | β
Cypher | β | β | β |
|
|
352
|
+
| **Self-Learning** | β
GNN | β | β | β |
|
|
353
|
+
| **AI Routing** | β
| β | β | β |
|
|
354
|
+
| **Browser/WASM** | β
| β | β | β |
|
|
355
|
+
| **Compression** | 2-32x | β | β | β |
|
|
356
|
+
| **Open Source** | β
MIT | β | β
| β
|
|
|
1379
357
|
|
|
1380
|
-
|
|
358
|
+
## Documentation
|
|
1381
359
|
|
|
1382
|
-
|
|
360
|
+
- [Getting Started Guide](https://github.com/ruvnet/ruvector/blob/main/docs/guide/GETTING_STARTED.md)
|
|
361
|
+
- [Cypher Reference](https://github.com/ruvnet/ruvector/blob/main/docs/api/CYPHER_REFERENCE.md)
|
|
362
|
+
- [GNN Architecture](https://github.com/ruvnet/ruvector/blob/main/docs/gnn-layer-implementation.md)
|
|
363
|
+
- [Performance Tuning](https://github.com/ruvnet/ruvector/blob/main/docs/optimization/PERFORMANCE_TUNING_GUIDE.md)
|
|
364
|
+
- [API Reference](https://github.com/ruvnet/ruvector/tree/main/docs/api)
|
|
1383
365
|
|
|
1384
|
-
|
|
366
|
+
## Contributing
|
|
1385
367
|
|
|
1386
368
|
```bash
|
|
1387
|
-
# Install Rust toolchain
|
|
1388
|
-
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
|
1389
|
-
|
|
1390
369
|
# Clone repository
|
|
1391
370
|
git clone https://github.com/ruvnet/ruvector.git
|
|
1392
371
|
cd ruvector
|
|
1393
372
|
|
|
1394
|
-
#
|
|
1395
|
-
cd npm/packages/core
|
|
1396
|
-
npm run build:napi
|
|
1397
|
-
|
|
1398
|
-
# Build wrapper package
|
|
1399
|
-
cd ../ruvector
|
|
373
|
+
# Install dependencies
|
|
1400
374
|
npm install
|
|
1401
|
-
npm run build
|
|
1402
375
|
|
|
1403
376
|
# Run tests
|
|
1404
377
|
npm test
|
|
1405
|
-
```
|
|
1406
|
-
|
|
1407
|
-
**Requirements:**
|
|
1408
|
-
- Rust 1.77+
|
|
1409
|
-
- Node.js 18+
|
|
1410
|
-
- Cargo
|
|
1411
|
-
|
|
1412
|
-
## π Ecosystem
|
|
1413
|
-
|
|
1414
|
-
### Related Packages
|
|
1415
|
-
|
|
1416
|
-
- **[ruvector-core](https://www.npmjs.com/package/ruvector-core)** - Core native bindings (lower-level API)
|
|
1417
|
-
- **[ruvector-wasm](https://www.npmjs.com/package/ruvector-wasm)** - WebAssembly implementation for browsers
|
|
1418
|
-
- **[ruvector-cli](https://www.npmjs.com/package/ruvector-cli)** - Standalone CLI tools
|
|
1419
|
-
|
|
1420
|
-
### Platform-Specific Packages (auto-installed)
|
|
1421
|
-
|
|
1422
|
-
- **[ruvector-core-linux-x64-gnu](https://www.npmjs.com/package/ruvector-core-linux-x64-gnu)**
|
|
1423
|
-
- **[ruvector-core-linux-arm64-gnu](https://www.npmjs.com/package/ruvector-core-linux-arm64-gnu)**
|
|
1424
|
-
- **[ruvector-core-darwin-x64](https://www.npmjs.com/package/ruvector-core-darwin-x64)**
|
|
1425
|
-
- **[ruvector-core-darwin-arm64](https://www.npmjs.com/package/ruvector-core-darwin-arm64)**
|
|
1426
|
-
- **[ruvector-core-win32-x64-msvc](https://www.npmjs.com/package/ruvector-core-win32-x64-msvc)**
|
|
1427
378
|
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
### Native Module Not Loading
|
|
1431
|
-
|
|
1432
|
-
If you see "Cannot find module 'ruvector-core-*'":
|
|
1433
|
-
|
|
1434
|
-
```bash
|
|
1435
|
-
# Reinstall with optional dependencies
|
|
1436
|
-
npm install --include=optional ruvector
|
|
1437
|
-
|
|
1438
|
-
# Verify platform
|
|
1439
|
-
npx ruvector info
|
|
1440
|
-
|
|
1441
|
-
# Check Node.js version (18+ required)
|
|
1442
|
-
node --version
|
|
379
|
+
# Build
|
|
380
|
+
npm run build
|
|
1443
381
|
```
|
|
1444
382
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
If you're using WASM fallback and need better performance:
|
|
1448
|
-
|
|
1449
|
-
1. **Install native toolchain** for your platform
|
|
1450
|
-
2. **Rebuild native module**: `npm rebuild ruvector`
|
|
1451
|
-
3. **Verify native**: `npx ruvector info` should show "native (Rust)"
|
|
383
|
+
See [CONTRIBUTING.md](https://github.com/ruvnet/ruvector/blob/main/docs/development/CONTRIBUTING.md) for guidelines.
|
|
1452
384
|
|
|
1453
|
-
|
|
385
|
+
## License
|
|
1454
386
|
|
|
1455
|
-
|
|
1456
|
-
- **Windows ARM**: Not yet supported, uses WASM fallback
|
|
1457
|
-
- **Node.js < 18**: Not supported, upgrade to Node.js 18+
|
|
1458
|
-
|
|
1459
|
-
## π Documentation
|
|
1460
|
-
|
|
1461
|
-
- π [Homepage](https://ruv.io)
|
|
1462
|
-
- π¦ [GitHub Repository](https://github.com/ruvnet/ruvector)
|
|
1463
|
-
- π [Full Documentation](https://github.com/ruvnet/ruvector/tree/main/docs)
|
|
1464
|
-
- π [Getting Started Guide](https://github.com/ruvnet/ruvector/blob/main/docs/guide/GETTING_STARTED.md)
|
|
1465
|
-
- π [API Reference](https://github.com/ruvnet/ruvector/blob/main/docs/api/NODEJS_API.md)
|
|
1466
|
-
- π― [Performance Tuning](https://github.com/ruvnet/ruvector/blob/main/docs/optimization/PERFORMANCE_TUNING_GUIDE.md)
|
|
1467
|
-
- π [Issue Tracker](https://github.com/ruvnet/ruvector/issues)
|
|
1468
|
-
- π¬ [Discussions](https://github.com/ruvnet/ruvector/discussions)
|
|
1469
|
-
|
|
1470
|
-
## π€ Contributing
|
|
1471
|
-
|
|
1472
|
-
We welcome contributions! See [CONTRIBUTING.md](https://github.com/ruvnet/ruvector/blob/main/docs/development/CONTRIBUTING.md) for guidelines.
|
|
1473
|
-
|
|
1474
|
-
### Quick Start
|
|
1475
|
-
|
|
1476
|
-
1. Fork the repository
|
|
1477
|
-
2. Create a feature branch: `git checkout -b feature/amazing-feature`
|
|
1478
|
-
3. Commit changes: `git commit -m 'Add amazing feature'`
|
|
1479
|
-
4. Push to branch: `git push origin feature/amazing-feature`
|
|
1480
|
-
5. Open a Pull Request
|
|
1481
|
-
|
|
1482
|
-
## π Community & Support
|
|
1483
|
-
|
|
1484
|
-
- **GitHub**: [github.com/ruvnet/ruvector](https://github.com/ruvnet/ruvector) - β Star and follow
|
|
1485
|
-
- **Discord**: [Join our community](https://discord.gg/ruvnet) - Chat with developers
|
|
1486
|
-
- **Twitter**: [@ruvnet](https://twitter.com/ruvnet) - Follow for updates
|
|
1487
|
-
- **Issues**: [Report bugs](https://github.com/ruvnet/ruvector/issues)
|
|
1488
|
-
|
|
1489
|
-
### Enterprise Support
|
|
1490
|
-
|
|
1491
|
-
Need custom development or consulting?
|
|
1492
|
-
|
|
1493
|
-
π§ [enterprise@ruv.io](mailto:enterprise@ruv.io)
|
|
1494
|
-
|
|
1495
|
-
## π License
|
|
1496
|
-
|
|
1497
|
-
**MIT License** - see [LICENSE](https://github.com/ruvnet/ruvector/blob/main/LICENSE) for details.
|
|
1498
|
-
|
|
1499
|
-
Free for commercial and personal use.
|
|
1500
|
-
|
|
1501
|
-
## π Acknowledgments
|
|
1502
|
-
|
|
1503
|
-
Built with battle-tested technologies:
|
|
1504
|
-
|
|
1505
|
-
- **HNSW**: Hierarchical Navigable Small World graphs
|
|
1506
|
-
- **SIMD**: Hardware-accelerated vector operations via simsimd
|
|
1507
|
-
- **Rust**: Memory-safe, zero-cost abstractions
|
|
1508
|
-
- **NAPI-RS**: High-performance Node.js bindings
|
|
1509
|
-
- **WebAssembly**: Universal browser compatibility
|
|
387
|
+
MIT License β free for commercial and personal use.
|
|
1510
388
|
|
|
1511
389
|
---
|
|
1512
390
|
|
|
1513
391
|
<div align="center">
|
|
1514
392
|
|
|
1515
|
-
**Built
|
|
1516
|
-
|
|
1517
|
-
[](https://www.npmjs.com/package/ruvector)
|
|
1518
|
-
[](https://github.com/ruvnet/ruvector)
|
|
1519
|
-
[](https://twitter.com/ruvnet)
|
|
393
|
+
**Built by [rUv](https://ruv.io)** β’ [GitHub](https://github.com/ruvnet/ruvector) β’ [npm](https://npmjs.com/package/ruvector)
|
|
1520
394
|
|
|
1521
|
-
|
|
395
|
+
*Vector search that gets smarter over time.*
|
|
1522
396
|
|
|
1523
397
|
</div>
|