@mks-agenticslab/embeddings
v0.1.0
Published
Embeddings + RRF hybrid recall + LLM rerank + query intent (Gemini + pgvector halfvec). Used by axios, jarvis, agent-memory.
Maintainers
Readme
@mks-agenticslab/embeddings
Superficie compartida de embeddings + retrieval híbrido para todos los consumidores de RAG del ecosistema mks: jarvis-memory (observaciones de sesiones), xlikesfinder (corpus de likes de X) y en el futuro axon (RAG de proyectos vía MCP).
Superficie
| Pieza | Qué da |
|---|---|
| GeminiEmbeddingClient | gemini-embedding-001 768d, embed + embedBatch (todos-o-nada), retry con backoff |
| CachedEmbeddingClient | Decorador LRU (+disco jsonl opcional) — el recall repetido queda <100ms sin hop a Gemini |
| MockEmbeddingClient / ZeroEmbeddingClient / createFailingEmbeddingClient | embedders deterministas/fallidos para tests (batch incluido) |
| hybridRecall(query, opts) | Orquestador: embed 1× (o queryEmbedding pre-suplido) → halves FTS/vectorial en paralelo (inyectadas) → fusión RRF k=60 → degradación graceful con diagnósticos (usedFts, usedVector, counts) |
| multiQueryRecall + expandQuery | Query coloquial → N paráfrasis LLM (duck-typed, fail-open) → hybridRecall por variante → fusión RRF ponderada |
| LlmReranker | Segunda pasada LLM top-20→top-5 (fail-open: conserva el orden original si el LLM no coopera) |
| chunkMarkdown | Chunking heading-aware con overlap para docs/transcripts largos |
| evaluateRecall + formatMetrics | Golden set → recall@k / MRR@k / precision@k / latencia media |
| rehydrate(hits, byId) | Rehidrata preservando el orden RRF |
| orTsQuery(text) | Query tsquery OR para la mitad léxica en Postgres (plainto_tsquery ANDa todo y casa 0 con frases coloquiales) |
| rrfMerge(lists, k, weights?) | Reciprocal Rank Fusion, ponderable por lista |
| PgVectorStore / IVectorStore | upsert batch (multi-row VALUES) + search coseno con filtro por meta jsonb ({project, kind}) + count |
| formatPgVector / toPgVectorLiteral | number[] ↔ literal pgvector |
| EMBEDDING_DIM (768), DEFAULT_EMBEDDING_MODEL | Contrato de dimensión única para todos |
Contrato del consumidor
El consumidor aporta SOLO las halves (su esquema, sus filtros):
import { createGeminiEmbeddingClient, hybridRecall, orTsQuery } from '@mks-agenticslab/embeddings';
const r = await hybridRecall('que stack usa el proyecto', {
embedder: createGeminiEmbeddingClient(),
ftsHalf: (q, n) => ftsSqlHits(orTsQuery(q), n), // to_tsquery('simple', $or) + ts_rank
vectorHalf: (vec, n) => pgvectorHits(vec, n), // embedding <=> $vec
topK: 10,
});
// r.value.hits → [{id, score, ranks}] · r.value.diagnostics → usedFts/usedVector/countsNotas operativas
- Batch de escritura:
embedBatch+UPDATE … FROM unnest($ids::uuid[], $vecs::text[])en un round trip (verjarvis-memory/EmbedWorker.processBatch). Con drizzle, los arrays deben ir envueltos ensql.param()— un${arr}desnudo se expande a lista. - Dimensión: la columna pgvector es
vector(768)literal (no parametrizable). - Resolución: workspace/bun-link usa
src/(condiciónbun); builds publicados usandist/(rolldown + d.ts). Reconstruirdisttras tocarsrcsi corren tests con Node/vitest.
