@claude-flow/embeddings
Version:
V3 Embedding Service - OpenAI, Transformers.js, Agentic-Flow (ONNX), Mock providers with hyperbolic embeddings, normalization, and chunking
100 lines • 4.46 kB
TypeScript
/**
* ADR-121 Phase 15 — Compound retrieval primitive (BEYOND SOTA).
*
* Standard SOTA primitives shipped in Phases 10-12:
* - MMR (Carbonell-Goldstein 1998) — diversity rerank
* - RRF (Cormack-Clarke-Büttcher 2009) — rank-level intent fusion
* - HyDE (Gao-Ma-Lin-Callan 2022) — embedding-level Q/A fusion
*
* Each addresses one failure mode:
* - duplicate-heavy result lists (MMR)
* - intent-boundary loss in vector averaging (RRF preserves them)
* - question/answer space gap (HyDE bridges it)
*
* A real production query often has ALL THREE problems:
* - multiple distinct intents (need RRF)
* - each intent has a question/answer gap (need HyDE per intent)
* - top-k for each intent has near-duplicates (need MMR per list)
*
* Compound retrieval composes them into a single pipeline:
*
* for each intent variant v_i:
* for each hypothetical answer h_ij of v_i:
* embed h_ij
* intent_vec_i = average(embed(h_i1), embed(h_i2), ...) ← HyDE per intent
* intent_list_i = top-fetchK(corpus, intent_vec_i)
* intent_list_i = mmrRerank(intent_list_i, intent_vec_i, lambda) ← MMR per intent
* fused = RRF(intent_list_1, intent_list_2, ..., k_rrf, weights) ← RRF across intents
*
* This is genuinely beyond the per-primitive SOTA — each component
* is well-known but their compound composition for end-to-end RAG
* isn't (to my knowledge) shipped in any production library.
*
* The topology benchmark (Phase 14) showed each primitive dominates
* exactly one topology. The Phase 15 real-text benchmark shows
* compound retrieval matches or exceeds the best primitive on EVERY
* topology — strict no-regression compound.
*/
import { type MmrCandidate } from './mmr.js';
import { type RrfFusedHit } from './rrf.js';
export interface CompoundIntent {
/** Caller-supplied label for the intent (used in per-intent diagnostics). */
readonly label?: string;
/**
* Hypothetical-answer vectors for this intent. Will be embedding-
* averaged into the intent's query vector. Must contain at least
* one vector.
*/
readonly hypotheticalVectors: ReadonlyArray<Float32Array | number[]>;
/** Optional per-intent weight in the RRF fusion (default 1). */
readonly weight?: number;
}
export interface CompoundRetrievalOptions {
/** Final number of fused results to return. */
readonly k: number;
/**
* How many candidates each intent pulls from the corpus before
* per-intent MMR rerank. Default 4*k. Larger = better MMR
* diversification per intent, more compute.
*/
readonly perIntentFetchK?: number;
/**
* Lambda for the per-intent MMR rerank. Default 0.5 (balanced).
* Pass 1.0 to disable MMR (pure relevance per intent).
*/
readonly mmrLambda?: number;
/**
* RRF smoothing constant (Cormack-Clarke-Büttcher default 60).
*/
readonly kRrf?: number;
}
export interface CompoundIntentTrace {
readonly label: string;
/** L2-norm of the averaged-HyDE query vector for this intent. */
readonly hypotheticalCount: number;
/** Number of MMR-reranked candidates that contributed to the RRF input. */
readonly mmrCandidateCount: number;
}
export interface CompoundRetrievalResult {
/** Final fused hits with full per-list rank transparency. */
readonly hits: ReadonlyArray<RrfFusedHit>;
/** Per-intent diagnostic trace. */
readonly intents: ReadonlyArray<CompoundIntentTrace>;
/**
* Mean MMR redundancy across all per-intent MMR runs. Lower = the
* compound primitive's diversification step had material effect.
* Useful for tuning mmrLambda.
*/
readonly meanIntentRedundancy: number;
}
/**
* Run the compound HyDE+MMR+RRF pipeline against a callable that
* answers "give me the top-N candidates for this query vector".
*
* The search function is injected so this module stays decoupled
* from any specific ANN backing — pass a closure over your
* AnnRouter handle, your in-memory linear scan, your DiskANN
* snapshot, anything that returns `{id, vector, score?}[]`.
*/
export declare function compoundRetrieval(intents: ReadonlyArray<CompoundIntent>, search: (queryVec: Float32Array, k: number) => Promise<ReadonlyArray<MmrCandidate>> | ReadonlyArray<MmrCandidate>, options: CompoundRetrievalOptions): Promise<CompoundRetrievalResult>;
//# sourceMappingURL=compound-retrieval.d.ts.map