Spec: retriever rewrite - #179
Merged
Merged
Conversation
First use of Spec Kit, on the decision three open PRs are queued behind.
The specification records what the retriever does today -- including the five
places it reaches into LangChain internals, with line numbers -- and separates
the parts that are settled from the four that are not:
D1 is SelfQueryRetriever replaced by plain semantic search? Helia's proposal.
Removes 20 LLM calls per message and the component most likely to break on
LangChain 1.x. But the measurement in #171 shows SelfQuery is stable run to
run and agrees with plain vector on only 0.48 of documents and 0.19 of
positions, so this is a real behaviour change, not the removal of noise.
D2 per-collection budget or global?
D3 documents or tokens? (1.6x spread measured; not currently binding)
D4 does multi-query expansion stay? Its value has never been measured.
Every factual claim was checked against the code rather than written from
memory, which caught two: the mypy baseline holds four `retrievers.*.rag`
entries rather than three, since userguide arrived with feature/userguide-qa,
and the reach table now carries line numbers so it can be re-checked.
Success criteria are things that can be observed -- no LangChain internals
remain, sync and async agree, two callers get different budgets in one process,
and the four baseline entries are deleted rather than carried forward.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
D1 is Helia's call: SelfQueryRetriever is replaced by plain semantic search, BM25 stays. Recorded with its consequences rather than as a simplification, because it is not one -- retrieval results change materially (#171 measured SelfQuery as stable run to run, agreeing with plain vector on 0.48 of documents and 0.19 of positions), metadata filtering is lost as a capability rather than just as code, and 339 lines across the metadata_info files fall out of the retrieval path while remaining in use by the evaluator and the baseline harness. What it buys: LLM calls in retrieval drop from 21 per message to 1, and the component most likely to break on LangChain 1.x goes away. D2, D3 and D4 are mine, each with the reasoning that decided it: D2 budget stays per collection. The decisive argument is technical: each collection is fused independently, so RRF scores from different collections are not comparable quantities and a global top-N would sort by a meaningless comparison. Coverage is the secondary reason. D3 budget counted in documents. Tokens are the better unit in principle and #139 was right, but 40 documents span 5,796-9,531 tokens at roughly 7% of the window -- a ceiling there would tighten a bound that is not binding. Kept as one named parameter so a token bound can be added later. D4 multi-query expansion stays for now, and is measured separately afterwards. Not because it is known to be valuable -- that has never been measured -- but because D1 already changes retrieval materially, and removing both at once would make any quality difference impossible to attribute. FR-003, FR-005, FR-009 and SC-005 updated so the requirements match the decisions rather than drifting from them. The #171 figures predate the #169 and #170 fixes, so they describe a retriever that no longer exists. Recapturing them is recorded as the first verification step before implementing D1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First use of Spec Kit, on the decision three open PRs are queued behind (#116, #133, and the config work in #112/#151).
This is a specification, not an implementation. It exists to make four decisions explicit and cheap to make.
What it records
What the retriever does today, including the five places it reaches into LangChain internals — with line numbers, so the table can be re-checked rather than trusted:
csv_chroma.py:143MultiQueryRetrievercsv_chroma.py:59,144NoneviaSkipJsonSchemacsv_chroma.py:192-194MultiQueryRetrieverto steal its.llm_chaincsv_chroma.py:200_retrieversoutside pydanticcsv_chroma.py:206EnsembleRetriever(retrievers=[])to borrow one methodThose are why the LangChain upgrade is blocked.
The four open decisions
SelfQueryRetrieverwith plain semantic search? Helia's proposal. It removes 20 LLM calls per message and the component most likely to break on 1.x. But Retrieval: replace SelfQueryRetriever with a plain semantic retriever? #171 measured SelfQuery as stable run to run, agreeing with plain vector on only 0.48 of documents and 0.19 of positions — so this is a real behaviour change, not the removal of noise. Those numbers predate the Retrieval: duplicate documents consume half the top-k budget on reactions #169/Retrieval: BM25 and vector results are concatenated, not fused #170 fixes and want recapturing.Notes
Every factual claim was checked against the code rather than written from memory, which caught two errors: the mypy baseline holds four
retrievers.*.ragentries, not three —userguidearrived withfeature/userguide-qa— and the reach table needed line numbers.Success criteria are observable rather than aspirational: no LangChain internals remain, sync and async agree on identical inputs, two callers get different budgets in the same process, and the four mypy baseline entries are deleted rather than carried forward.
Checked against
.specify/memory/constitution.md; all six articles are addressed.Nothing is implemented here. The next step is D1–D4, then
/speckit-plan.🤖 Generated with Claude Code