Skip to content

Retrieval: replace SelfQueryRetriever with a plain semantic retriever? #171

Description

@adamjohnwright

Proposed by Helia: drop SelfQueryRetriever, keep BM25 plus vector search. This records the evidence, because the measurement did not come out the way that would make it a free change.

The case for dropping it

  • Cost. SelfQueryRetriever makes one LLM call per collection per query variant to translate the question into a structured query. With 4 collections and 5 query variants (4 generated + the original) that is 20 LLM calls per user message, plus 1 for the expansion. A plain semantic retriever has no LLM in the loop.
  • Upgrade risk. It depends on lark and on structured-output behaviour that has moved across LangChain versions. It is the component most likely to break on 1.x, and it is one of five places HybridRetriever reaches into LangChain internals.

The case against assuming it is free

Measured with bin/retrieval_baseline, 20 questions, k=10, Release95.

Overlap between SelfQuery and plain vector search:

collection mean overlap identical results
complexes 0.33 0/20
ewas 0.46 3/20
reactions 0.60 4/20
summations 0.54 1/20
overall 0.48

Run-to-run stability, same code, same questions, two runs:

retriever self-overlap byte-identical
bm25 1.00 80/80
vector 0.99 78/80
selfquery 1.00 78/80

SelfQuery is stable, not noisy. Its ~half-different results are real and repeatable, so removing it is a genuine retrieval change rather than dropping a source of churn. Note it does not only build a metadata filter — it also rewrites the query string before searching, which is likely part of the divergence.

What the difference looks like

"How does TP53 regulate PTEN transcription?" — top hit:

  • selfquery: PTEN gene transcription is stimulated by TP53
  • vector: TP53 binds the PTEN promoter

Both defensible. Set overlap cannot say which is better; that needs a quality eval (the ragas work), not a diff.

Suggested order

Settle #169 (duplicates consume half the top-k on reactions) and #170 (BM25 and vector are concatenated, not fused) first. Both change what the vector side returns, so measuring SelfQuery against a fixed baseline is more meaningful afterwards.

Reproduce:

./bin/retrieval_baseline capture --out c.json --with-selfquery
./bin/retrieval_baseline overlap c.json

🤖 Generated with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions