edgewise v0.4.1

Semantic search and RAG

Build an index#

ts
import { embed } from 'edgewise';
import { vectorIndex } from 'edgewise/helpers';

const index = await vectorIndex<{ title: string }>({ name: 'help-articles', model: 'embed:default' });

if (index.size === 0) {
  const { embeddings } = await embed({ model: 'embed:default', values: articles.map((a) => a.body), purpose: 'document' });
  await index.add(embeddings.map((vector, i) => ({ id: articles[i].id, vector, meta: { title: articles[i].title } })));
  await index.save();
}

vectorIndex is an exact nearest-neighbour index over normalized vectors, fast up to about 100,000 vectors. save() writes it to the Origin Private File System in browsers and to <cache>/indexes on servers. The next vectorIndex() with the same name loads it, as long as the model matches.

Query#

ts
const hits = await index.query('how do I change my email?', { k: 5, minScore: 0.3 });
// [{ id: 'a42', score: 0.71, meta: { title: 'Update your account email' } }, …]

query embeds the text with the index's model and purpose: 'query'. Use search(vector) when you already have a vector.

Retrieval-augmented generation#

ts
import { generate } from 'edgewise';

const hits = await index.query(question, { k: 4 });
const context = hits.map((h) => articles.find((a) => a.id === h.id)!.body).join('\n---\n');

const { text } = await generate({
  model: 'text:default',
  system: 'Answer only from the context. Say "I don\'t know" if the answer is not there.',
  input: `Context:\n${context}\n\nQuestion: ${question}`,
});

Find duplicates#

ts
const pairs = await index.pairs({ minScore: 0.92 }); // [{ a, b, score }]

GPU scoring#

Scoring runs on the CPU for small indexes. With a hardware GPU (WebGPU in the browser, vgpu on servers) and more than about four million floats, Edgewise scores on the GPU with a WGSL kernel. Force it either way with vectorIndex({ …, gpu: 'on' | 'off' }).

Edgewise 0.4.1 · MIT licence · Edit this page