@claude-flow/embeddings
Version:
V3 Embedding Service - OpenAI, Transformers.js, Agentic-Flow (ONNX), Mock providers with hyperbolic embeddings, normalization, and chunking
79 lines • 3.54 kB
TypeScript
/**
* ADR-121 Phase 10 — Maximal Marginal Relevance (MMR) diversity rerank.
*
* Plain top-k vector retrieval optimizes for relevance only — when a
* corpus contains near-duplicate chunks (e.g. multiple versions of the
* same doc, several paragraphs that paraphrase the same fact), the
* top-k typically returns redundant variants of one good answer.
*
* MMR (Carbonell & Goldstein, 1998) addresses this by iteratively
* picking the next-best item as a tradeoff between:
* - relevance to the query (sim(item, query))
* - dissimilarity from already-picked items (max sim(item, picked))
*
* score(item) = λ · sim(item, query) − (1 − λ) · max sim(item, picked)
*
* λ = 1 → pure relevance (same as plain top-k)
* λ = 0 → pure diversity (ignores query relevance)
* Typical production value: λ ≈ 0.5–0.7.
*
* This module ships the algorithm as a pure function so callers can
* compose it however they want — apply to AnnRouter results, to raw
* search hits, to memory recall, etc. The CLI's
* `embeddings_search_text_diverse` tool wraps search_text + mmrRerank
* for one-call diverse RAG.
*/
export interface MmrCandidate {
/** Caller-supplied identifier. */
readonly id: string;
/** Embedding vector. Required — MMR needs it for the diversity term. */
readonly vector: Float32Array | number[];
/** Optional relevance score from the prior search step. */
readonly score?: number;
/** Free-form payload — preserved through the rerank. */
readonly payload?: unknown;
}
export interface MmrOptions {
/** Number of items to return. Clamped to candidates.length. */
readonly k: number;
/**
* Relevance/diversity tradeoff in [0, 1].
* 1 = pure relevance (same as plain top-k by query-similarity).
* 0 = pure diversity (ignores query relevance entirely).
* Default 0.5 — balanced.
*/
readonly lambda?: number;
}
export interface MmrPickedHit {
readonly id: string;
readonly vector: Float32Array;
readonly payload?: unknown;
/** Final MMR score at the iteration this item was picked. */
readonly mmrScore: number;
/** Original relevance score (query similarity). */
readonly relevance: number;
/** Max similarity to already-picked items at pick time (0 for the first pick). */
readonly redundancy: number;
/** Order this item was selected — 0 is the highest-relevance pick. */
readonly pickOrder: number;
}
/**
* Iterative MMR over a candidate set. Time complexity:
* O(k · N · dim) where N = candidates.length, dim = vector length
*
* For typical RAG (k=10, N=50, dim=384) that's <200k ops — trivial.
*/
export declare function mmrRerank(candidates: ReadonlyArray<MmrCandidate>, queryVector: Float32Array | number[], options: MmrOptions): MmrPickedHit[];
/**
* Convenience: same as mmrRerank but returns just ids in pick order.
* Useful when the caller already has the full candidate metadata
* elsewhere and just needs the diversified ordering.
*/
export declare function mmrIds(candidates: ReadonlyArray<MmrCandidate>, queryVector: Float32Array | number[], options: MmrOptions): string[];
/**
* Diagnostic — measure how much MMR diversified the result vs plain
* top-k. Returns the **average pairwise similarity** of the picked set;
* lower = more diverse. Useful for the CI smoke + cost trackers.
*/
export declare function averagePairwiseSimilarity(picked: ReadonlyArray<MmrPickedHit>): number;
//# sourceMappingURL=mmr.d.ts.map