A lightweight TypeScript module for generating text embeddings locally, storing them in SQLite, and retrieving semantically similar records using cosine distance.
This project explores the retrieval component commonly used in Retrieval-Augmented Generation (RAG) systems.
It combines locally generated text embeddings with SQLite-based vector storage to support similarity searches over stored text records.
The module is intended as a foundation for applications such as document search, knowledge retrieval, and context selection for language-model workflows.
Scope: This repository implements embedding, storage, and retrieval functionality. It does not currently implement a complete question-answering pipeline or language-model response generation.
- Generate text embeddings locally using
node-llama-cpp - Load a GGUF embedding model
- Store text records and embeddings in SQLite
- Use the
sqlite-vecextension for vector operations - Search records using cosine distance
- Return matching record IDs ordered by similarity
- Limit the number of search results
- Organize records into caller-specified SQLite tables
- Access embedding, save, and search functionality through TypeScript functions
| Component | Technology |
|---|---|
| Language | TypeScript |
| Runtime | Node.js |
| Embedding engine | node-llama-cpp |
| Embedding model | Nomic Embed Text v1.5 (GGUF) |
| Database | SQLite |
| Database driver | sqlite3 |
| Vector extension | sqlite-vec |
| Similarity metric | Cosine distance |
INPUT TEXT
|
v
+------------------+
| node-llama-cpp |
| GGUF Embedder |
+------------------+
|
v
EMBEDDING VECTOR
|
+------+------+
| |
v v
SAVE PATH SEARCH PATH
| |
v v
SQLite DB Query Vector
| |
| v
| Cosine Distance
| |
+------+------+
|
v
MATCHING IDS
Embedding
The module initializes a local GGUF embedding model and converts input text into numerical vectors.
Storage
The Save() function generates an embedding and stores the record ID, original text, and vector in SQLite.
Retrieval
The Search() function embeds a query, compares it with stored vectors using vec_distance_cosine, and returns the closest record IDs.
The implementation uses a full similarity-ordering query rather than a dedicated approximate nearest-neighbor index.
src/
βββ embed.ts # Model loading and embedding generation
βββ db.ts # SQLite connection and extension loading
βββ rag.ts # Public embedding, storage, and search functions
βββ test-embed.ts # Embedding demonstration script
βββ test-db.ts # Database demonstration script
βββ test-rag.ts # End-to-end retrieval demonstration script
model/ # Local GGUF model (provided separately)
sqlite-vec/ # Native extension (provided separately)
rag.db # Local SQLite database created at runtime
Compiled JavaScript is written to dist/ when the TypeScript build runs.
You will need:
- A compatible Node.js installation
- npm
- Native build support required by the project's dependencies
- A compatible GGUF embedding model
- The
sqlite-vecnative extension for your operating system
The project has not been verified across all Node.js versions or operating systems.
git clone https://github.com/TheeValcode/RAG-SQLITE-VEC-MODULE.git
cd RAG-SQLITE-VEC-MODULEnpm installCreate a model directory in the repository root.
Download the compatible Nomic Embed Text v1.5 GGUF model and save it using this filename:
model/nomic-embed-text-v1.5.Q5_K_M.gguf
The filename is referenced directly in src/embed.ts.
The model is not bundled with the repository.
Download a compatible sqlite-vec extension from its official releases:
https://github.com/asg017/sqlite-vec/releases
The current src/db.ts implementation expects the extension at:
sqlite-vec/vec0.so
This path targets a Linux-style shared library.
For Windows or macOS, the extension filename and path must be adjusted to match the platform.
The extension is loaded using SQLite's loadExtension() method.
npm run buildThe TypeScript compiler outputs JavaScript to the dist/ directory.
Runtime note: The existing embedding-model and SQLite-extension paths are resolved relative to the executing JavaScript file. Depending on whether scripts run from src/ or compiled dist/, those paths may require adjustment. The project should be tested locally before treating the setup as verified.
The module exposes three primary functions from src/rag.ts.
Embed(text: string): Promise<number[]>Converts input text into a numerical embedding vector.
The embedding context must be initialized before calling this function.
Save(
id: number,
text: string,
tablename: string
): Promise<boolean>Generates an embedding and saves the ID, text, and vector to the specified SQLite table.
If the table does not exist, the function attempts to create it.
Existing records with the same ID are replaced.
Important: Table names are interpolated into SQL statements. Only trusted, validated table identifiers should be passed to this function.
Search(
text: string,
tablename: string,
qty: number
): Promise<number[]>Embeds a query and searches for similar stored vectors.
Results are ordered by ascending cosine distance and returned as record IDs.
The function does not currently return document text or similarity scores.
The following illustrates the module's intended use:
import { initEmbedder } from './embed.js';
import { loadVectorExtension } from './db.js';
import { Embed, Save, Search } from './rag.js';
async function main() {
await initEmbedder();
await loadVectorExtension();
const vector = await Embed('Hello world');
console.log('Embedding dimensions:', vector.length);
await Save(1, 'Banana is a yellow fruit', 'fruits');
await Save(2, 'Apples can be red or green', 'fruits');
await Save(3, 'Oranges are citrus fruits', 'fruits');
const ids = await Search('yellow fruit', 'fruits', 2);
console.log('Matching document IDs:', ids);
}
main().catch(console.error);This example assumes the runtime dependencies and native extension have been configured correctly.
The repository includes three demonstration scripts:
| File | Purpose |
|---|---|
src/test-embed.ts |
Generate and inspect an embedding |
src/test-db.ts |
Exercise database setup |
src/test-rag.ts |
Exercise embedding, storage, and retrieval |
The package currently defines these commands:
npm start
npm run test-db
npm run test-ragnpm start invokes the embedding demonstration script.
The default npm test script is a placeholder and does not run an automated test suite.
These scripts have not been independently verified as passing across supported environments.
- Requires a locally available GGUF model
- Requires a separately installed native vector extension
- Uses platform-specific extension paths
- Does not implement document chunking
- Does not implement metadata filtering
- Does not implement reranking
- Does not generate language-model responses
- Returns matching record IDs rather than full document objects
- Does not validate caller-supplied SQL table identifiers
- Does not provide a complete automated test suite
- Cross-platform extension loading
- Configurable model paths
- Input validation for table identifiers
- Document chunking
- Metadata filtering
- Return document text and similarity scores
- Batch embedding support
- Automated tests
- Optional integration with an LLM response pipeline
Sophia Val-Izevbigie
Exploring semantic retrieval with TypeScript, local embeddings, and SQLite.