Skip to content

RAG retrieve

Retrieval takes a query (or query vector) and asks the vector store for the most relevant chunks. It sits between embed (which produced the query vector) and postprocess / generate (which refines and uses the results). All implementations satisfy:

type Retriever interface {
    Retrieve(ctx, queryVector []float32, topK int) ([]*rag.SearchResult, error)
}

Beyond plain vector search, the package ships keyword (BM25), hybrid, fusion / ensemble, MMR, auto-merging / parent (small-to-big), routing, SQL (NL2SQL), summary-then-chunk, LLM rerank, memx-native dual-mode, and a family of query transformers (HyDE, multi-query, step-back, sub-question).

Implementations

simple — pass-through to the store

rag:
  retrieve:
    type: simple
    top_k: 10

The baseline: invokes store.Search directly. Source: pkg/rag/retrieve/retrieve.go (SimpleRetriever).

mmr — Maximal Marginal Relevance over the store

rag:
  retrieve:
    type: mmr
    top_k: 10
    lambda: 0.5
Field Type Default Description
lambda float 0.5 1.0 = pure relevance, 0.0 = pure diversity.

Fetches topK*3 candidates, then iteratively selects the next result maximising lambda*relevance - (1-lambda)*max_similarity_to_already_picked. Use when result diversity matters more than raw top-1 quality. Source: pkg/rag/retrieve/retrieve.go (MMRRetriever).

embedder-mmr — MMR on top of another retriever

rag:
  retrieve:
    type: embedder-mmr
    base: simple
    embedder: ${EMBEDDER_REF}
    lambda: 0.5
    top_k: 10

Same algorithm as mmr but operates on the output of any base retriever; uses embed.Embedder to embed chunks that lack a pre-computed vector. Source: pkg/rag/retrieve/mmr.go.

hybrid — vector + keyword in one pass

rag:
  retrieve:
    type: hybrid
    top_k: 10
    alpha: 0.7
Field Type Default Description
alpha float 0.7 Weight on vector score; 1-alpha on keyword score.

Annotates store.Search results with a keyword-overlap score and blends. Source: pkg/rag/retrieve/retrieve.go (HybridRetriever).

dual-hybrid — two retrievers (vector + keyword) blended

rag:
  retrieve:
    type: dual-hybrid
    vector: simple
    keyword: bm25
    vector_weight: 0.7
    keyword_weight: 0.3
    top_k: 10

Runs the two retrievers in parallel, normalises each side's scores to [0,1], and combines by weight. Cleaner than hybrid when the keyword side is BM25 over its own index. Source: pkg/rag/retrieve/hybrid.go.

bm25 — pure in-memory BM25

rag:
  retrieve:
    type: bm25
    k1: 1.2
    b: 0.75
    top_k: 10
Field Type Default Description
k1 float 1.2 Term-saturation parameter.
b float 0.75 Length normalisation.
synonyms map — Term → synonym list (optional RAGFlow-style expansion).
synonym_weight float 0.5 Weight applied to synonym matches.
field_boosts map — Per-metadata-field score multiplier (e.g. {title: 10}).

BM25Index.Add(results) indexes documents; NewBM25Retriever(index) queries them. Supports synonym expansion and per-field boosts (RAGFlow title^10 / important_kwd^30 style). Source: pkg/rag/retrieve/bm25.go.

fusion — Reciprocal Rank Fusion across N retrievers

rag:
  retrieve:
    type: fusion
    retrievers: [vector, bm25, mmr]
    k: 60
    top_k: 10
Field Type Default Description
k int 60 RRF constant; larger = less weight on top ranks.

For each retriever, each chunk gets 1/(K+rank+1); scores are summed across retrievers. The canonical multi-retriever combiner. Source: pkg/rag/retrieve/fusion.go (FusionRetriever).

ensemble — weighted RRF across N retrievers

rag:
  retrieve:
    type: ensemble
    retrievers: [vector, bm25]
    weights: [0.6, 0.4]
    k: 60
    top_k: 10

Identical to fusion but with per-retriever weights. Runs retrievers in parallel. Source: pkg/rag/retrieve/ensemble.go.

auto_merging — promote children to parent when enough match

rag:
  retrieve:
    type: auto_merging
    child_store: kb_children
    parent_store: kb_parents
    merge_threshold: 0.5
    top_k: 10
Field Type Default Description
child_store ref — Vector store containing fine-grained child chunks.
parent_store ref — Vector store containing coarser parent chunks.
merge_threshold float 0.5 Fraction of a parent's children that must match before promoting.

Pairs with chunk: hierarchical or chunk: parent-child. There's also a single-store variant (RetrieverAutoMerging in auto_merging.go) that infers parents from parent_id / parent_content in a single retriever's output. Source: pkg/rag/retrieve/fusion.go (AutoMergingRetriever), pkg/rag/retrieve/auto_merging.go (RetrieverAutoMerging).

parent — search children, return parents

rag:
  retrieve:
    type: parent
    child_store: kb_children
    parent_store: kb_parents
    top_k: 10

Small-to-big retrieval: matches small children, then looks up their parents for fuller context. Unlike auto_merging, parents are always returned (no threshold). Source: pkg/rag/retrieve/retrieve.go (ParentRetriever).

rerank — bigram cross-encoder heuristic

rag:
  retrieve:
    type: rerank
    store: kb
    fetch_k: 30
    top_k: 10

Fetches fetch_k candidates, reranks using a bigram-overlap proxy for a cross-encoder (no external model). Cheap and dependency-free. For real cross-encoders, use the postprocess page's cross-encoder-rerank or cohere-rerank. Source: pkg/rag/retrieve/retrieve.go (RerankRetriever).

llm-rerank — LLM-judged relevance rerank

rag:
  retrieve:
    type: llm-rerank
    model: ${LLM_REF}
    batch_size: 10

Sends batches of (query, document) to a ChatModel asking for a 0-10 relevance score, then sorts. Slow but very high quality. Falls back to the original order on parse failure. Source: pkg/rag/retrieve/llm_rerank.go.

multi-query — N hand-picked query vectors

rag:
  retrieve:
    type: multi-query
    queries: [...]
    top_k: 10

For each precomputed query vector, fetches topK and unions the deduplicated results. Use when the caller has the queries in hand. Source: pkg/rag/retrieve/retrieve.go (MultiQueryRetriever).

multi-query-llm — LLM-generated query expansion

rag:
  retrieve:
    type: multi-query-llm
    inner: simple
    model: ${LLM_REF}
    embedder: ${EMBEDDER_REF}
    num_queries: 3

LLM generates num_queries alternative phrasings of the user's query; each is embedded and retrieved; results are deduplicated. Source: pkg/rag/retrieve/query_transform.go (MultiQueryLLMRetriever, MultiQueryTransformer).

hyde — Hypothetical Document Embeddings

rag:
  retrieve:
    type: hyde
    inner: simple
    model: ${LLM_REF}
    embedder: ${EMBEDDER_REF}

LLM hallucinates a hypothetical answer to the query, embeds it, and retrieves against that vector. Often beats query-only retrieval for detailed technical questions. Source: pkg/rag/retrieve/query_transform.go (HyDETransformer, HyDERetriever).

step-back — abstract-then-retrieve

rag:
  retrieve:
    type: step-back
    inner: simple
    model: ${LLM_REF}
    embedder: ${EMBEDDER_REF}

LLM produces a more abstract / general version of the query (e.g. "What is the population of Paris?" → "What is the population of European capitals?"). Retrieves with the abstract query — useful when the user query is too specific to find context. Source: pkg/rag/retrieve/query_transform.go (StepBackTransformer, StepBackRetriever).

sub-question — decompose then retrieve

rag:
  retrieve:
    type: sub-question
    inner: simple
    model: ${LLM_REF}
    embedder: ${EMBEDDER_REF}
    max_questions: 3

LLM splits the query into up to max_questions sub-questions; each sub-question is retrieved separately and results are merged. Source: pkg/rag/retrieve/query_transform.go (SubQuestionTransformer, SubQuestionRetriever).

router (vector-keyed) — route by vector selector

rag:
  retrieve:
    type: router
    retrievers:
      tech: vector_tech
      hr:   bm25_hr
    default: tech

RouterRetriever picks the named retriever using a Selector func(vec) string. Source: pkg/rag/retrieve/fusion.go (RouterRetriever).

query-router — route by text-based selector

rag:
  retrieve:
    type: query-router
    retrievers:
      tech: vector_tech
      hr:   bm25_hr
    selector:
      type: keywords
      routes:
        tech: [api, sdk, helix]
        hr:   [salary, leave, hiring]
    default: tech

QueryRouterRetriever uses a RouteSelector interface; the built-in KeywordRouteSelector matches case-insensitive keyword patterns. Source: pkg/rag/retrieve/router.go.

sql — NL2SQL retrieval

rag:
  retrieve:
    type: sql
    model: ${LLM_REF}
    dsn: postgres://user:pass@host:5432/db
    driver: postgres
    table_schemas:
      users: |
        CREATE TABLE users (id INT, name TEXT, email TEXT)

LLM generates SQL from a natural-language query, given the table schemas as context; rows are returned as SearchResult. Use for structured-data sub-questions inside a RAG pipeline (e.g. analytics queries mixed with document retrieval). Source: pkg/rag/retrieve/sql.go.

summary — summary-then-chunk

rag:
  retrieve:
    type: summary
    summary_store: kb_summaries
    chunk_store: kb_chunks
    model: ${LLM_REF}
    embedder: ${EMBEDDER_REF}

DocumentSummaryRetriever first searches LLM-generated document summaries to identify relevant documents, then retrieves chunks only from those documents. Drastically reduces the search space on large corpora. Source: pkg/rag/retrieve/summary.go.

memx — memx-native dual-mode retriever

rag:
  retrieve:
    type: memx
    conn_string: http://localhost:9000
    database: default
    table_name: memx_documents
    strategy: hybrid
    metric: cosine
    text_query: ...
Field Type Default Description
strategy string dense dense / simple (vector), text / bm25, hybrid / fusion (RRF).
metric string cosine cosine, l2, ip.
text_query string — BM25/hybrid query text.

Selects ES-API fast path for http(s):// and SQL mode for postgres://. Lets one retriever pick between dense, BM25, or hybrid without composing multiple Helix retrievers. Source: pkg/rag/retrieve/memx.go.

Choosing between them

If you need… Pick
Default top-K vector search simple
Diverse top-K mmr (or embedder-mmr over another retriever)
Keyword + vector dual-hybrid (with bm25 + simple)
Multi-retriever combine fusion (equal weights) or ensemble (weighted)
Small chunks for ranking, big chunks for context parent or auto_merging
Rerank with a real model llm-rerank (in pipeline) or postprocess cohere-rerank
Query is too narrow hyde (or step-back)
Query is multi-part sub-question
Choose retriever per query query-router with keywords selector
Structured-data sub-queries sql
Massive corpus, coarse-then-fine summary
memx backend, mixed dense+BM25 memx (single retriever)

See also

  • embed — produces the queryVector consumed here.
  • store — the backend(s) retrievers read from.
  • postprocess — filter / rerank the results.
  • generate — consumes []*rag.SearchResult to build the answer.
  • chunk — hierarchical / parent-child are prerequisites for auto_merging / parent.