@claude-flow/embeddings
Version:
V3 Embedding Service - OpenAI, Transformers.js, Agentic-Flow (ONNX), Mock providers with hyperbolic embeddings, normalization, and chunking
143 lines • 6.39 kB
TypeScript
/**
* ADR-121 Phase 16 — Adaptive primitive selection (BEYOND SOTA).
*
* Phase 14's topology benchmark proved each RAG primitive dominates
* exactly one corpus shape:
*
* easy → plain wins (no fusion needed)
* duplicate-heavy → MMR wins on subtopic-coverage
* multi-intent → RRF wins on intent-boundary preservation
* q-a-gap → HyDE wins on centroid-finding
*
* Production RAG systems don't route between primitives automatically
* — they pick one pipeline at design time or run all-of-them and
* vote/reduce. Both choices leave performance on the table.
*
* This module ships **adaptive primitive selection**: extract three
* cheap signals from the candidate set + query variants + hypothetical
* answers, then pick the right primitive (or the compound) based on
* which signals fire. Cost: one extra small-fan cosine pass over the
* candidate set and the variant/hypothetical embeddings.
*
* Signals:
*
* 1. duplicateDensity — mean pairwise cosine among the top-N
* candidates from a plain search. High = corpus has near-dup
* structure → MMR signal.
*
* 2. queryIntentCohesion — mean pairwise cosine among the query
* reformulation vectors. Low = reformulations cover distinct
* intents → RRF signal.
*
* 3. qaSpaceGap — 1 - cosine(question_vector, mean(hypothetical_vectors)).
* High = the question and the hypothetical answers live in
* different vector regions → HyDE signal.
*
* The router applies a small set of thresholds (defaults from the
* Phase 14 topology data) and returns a structured decision the
* caller can act on or override.
*/
export interface RetrievalFeatures {
/** Mean pairwise cosine among top-N candidates from a plain search. Range [-1, 1]. Higher = more duplicate-like. */
readonly duplicateDensity: number;
/** Mean pairwise cosine among query reformulation vectors. Range [-1, 1]. Higher = more cohesive (single intent). */
readonly queryIntentCohesion: number;
/** 1 - cosine(question_vec, mean(hypothetical_vecs)). Range [0, 2]. Higher = larger Q/A space gap. */
readonly qaSpaceGap: number;
/**
* Phase 17 — Mean IDF of unique query tokens (relative to a BM25
* index over the corpus). Higher = query has rare/technical
* tokens that dense embeddings tend to underweight → hybrid
* sparse+dense retrieval wins. 0 when no BM25 index was provided.
*/
readonly rareTokenDensity: number;
/** How many top candidates were used to compute duplicateDensity. */
readonly candidateCountUsed: number;
/** How many variants were used to compute intent cohesion. */
readonly variantCount: number;
/** How many hypotheticals were used to compute Q/A gap. */
readonly hypotheticalCount: number;
/** True if the caller provided a BM25 index for rareTokenDensity. */
readonly bm25IndexProvided: boolean;
}
export interface AdaptiveRouterOptions {
/**
* Threshold above which duplicateDensity triggers the MMR signal.
* Default 0.85 — duplicates are very close to each other in
* cosine space.
*/
readonly duplicateThreshold?: number;
/**
* Threshold below which queryIntentCohesion triggers the RRF
* signal. Default 0.55 — orthogonal-ish reformulations.
*/
readonly intentCohesionThreshold?: number;
/**
* Threshold above which qaSpaceGap triggers the HyDE signal.
* Default 0.35 — meaningful question/answer space drift.
*/
readonly qaGapThreshold?: number;
/**
* Phase 17 — Threshold above which rareTokenDensity (mean query IDF)
* triggers the HYBRID signal. Default 2.0 — IDF ≥ 2.0 means the
* query's tokens appear in <~13% of the corpus, where BM25's
* sparse lexical signal materially helps dense retrieval.
*/
readonly rareTokenThreshold?: number;
/**
* If 2+ signals fire, return `compound` instead of one of the
* individual primitives. Default true.
*/
readonly preferCompoundWhenMultipleSignals?: boolean;
}
export type AdaptivePrimitive = 'plain' | 'mmr' | 'rrf' | 'hyde' | 'hybrid' | 'compound';
export interface AdaptiveDecision {
/** The recommended primitive. */
readonly primitive: AdaptivePrimitive;
/** Human-readable explanation citing which signals fired. */
readonly reason: string;
/** Which signals were above their respective thresholds. */
readonly signals: Readonly<{
mmr: boolean;
rrf: boolean;
hyde: boolean;
hybrid: boolean;
}>;
/** Echo of the input features for traceability. */
readonly features: RetrievalFeatures;
}
/**
* Extract the routing signals from the available inputs.
*
* @param topCandidates — top-N hits from a cheap plain search,
* with vectors. Used for duplicateDensity.
* Pass `null` to disable that signal.
* @param queryVector — the user-question vector. Required for
* qaSpaceGap.
* @param variantVectors — N query reformulation vectors. Used for
* queryIntentCohesion. At least 2 required
* to compute the signal.
* @param hypotheticalVectors — N hypothetical-answer vectors. Used
* for qaSpaceGap. At least 1 required.
* @param bm25Input — optional {queryText, bm25Index} pair for the
* Phase 17 hybrid signal. Pass `null` to
* disable.
*
* Cost: O(N²·dim) for the pairwise cosines + O(|q|) for the BM25
* mean-IDF lookup.
*/
export declare function extractRetrievalFeatures(topCandidates: ReadonlyArray<{
vector: Float32Array | number[];
}> | null, queryVector: Float32Array | number[], variantVectors: ReadonlyArray<Float32Array | number[]>, hypotheticalVectors: ReadonlyArray<Float32Array | number[]>, bm25Input?: {
queryText: string;
index: {
df: ReadonlyMap<string, number>;
N: number;
};
} | null): RetrievalFeatures;
/**
* Apply the routing heuristic to a set of features. Returns the
* recommended primitive plus the reasoning trace.
*/
export declare function adaptiveRoute(features: RetrievalFeatures, options?: AdaptiveRouterOptions): AdaptiveDecision;
//# sourceMappingURL=adaptive-router.d.ts.map