Skip to content

Retrieval

Retrieval is what stands between a corpus and a prompt: split the documents, find the passages that bear on a question, and cut them down to the few a model can afford to read.

Each stage is its own tag, so swapping one leaves the others alone.

StageTagImplemented by
Split into passagesChunker@effect-uai/retrieval, or a hosted service
Turn passages into vectorsEmbeddingModelOpenAI, Gemini, Jina
Merge rankings that disagreenone, a functionRank.rrf, below
Score the shortlistRerankerJina

The tags live in @effect-uai/core. @effect-uai/retrieval implements the chunkers and carries the pieces that are plain functions rather than providers:

Terminal window
pnpm add @effect-uai/retrieval @effect-uai/core effect

Merge searches that disagree

Keyword search hands you BM25 scores, vector search hands you cosine distances, and averaging the two numbers is meaningless. Reciprocal rank fusion throws the scores away and uses positions:

import * as Rank from "@effect-uai/retrieval/Rank"
const fused = Rank.rrf([keywordIds, vectorIds], { weights: [1, 2] })
// [{ value: 42, score: 0.032 }, ...] best first

Weight a leg you trust more. An item that appears in only one list keeps the credit it earned there rather than being penalised for the absence, so lists of different lengths fuse fine. Lower k (default 60) to make first place count for more.

Fuse ids or other primitives rather than freshly built objects, which compare by reference and will not line up across lists.

See also

  • Chunking: the four chunkers, offsets, and the Chunker tag.
  • Reranking: the last stage, and its score contract.
  • Tokenizers: size chunks by real tokens rather than an estimate.
  • Agentic search: every stage above wired together as a tool an agent calls.