Repository navigation
NU-011 Query agent: VectorContextRetriever with SSE streaming #25
Description
Part of #30.
The query agent: answer a natural-language question from the graph, with citations, streamed.
Build
vector_retriever = VectorContextRetriever(store, similarity_top_k=k, path_depth=2)
retriever = index.as_retriever(sub_retrievers=[vector_retriever])That single class is the retrieval design: HNSW entry, graph expansion. Retrieval is
configured, not built. Queries must filter to the currently configured embedding model id/dimension
(ADR-0004) — comparing against a stale vector from an interrupted migration produces a meaningless
similarity score silently, right inside this ranking.
- Answer generation cites
Decisionnodes with author, timestamp and resolving Evidence edge. - No matching Decision → explicit "no matching decision" citing nearest entities. Never a
fabricated answer. - Stream over SSE. Query answering is synchronous end to end —
web → api → ai → retrieve → generate → stream. There is no broker in the path and no async bridge to build.
Not in this slice
BM25/Tags, RRF, LLMRerank. Vector-entry-then-expand produces one ranked pipeline, not two
lists, so there is nothing for RRF to fuse — it becomes meaningful when BM25 arrives as a genuine
second list. LLMRerank is a quality knob that masks retrieval defects: it can rescue a bad
candidate set and leave you believing retrieval worked. Adding it last is the correct order.
The control run is the point
A3 runs the same query with path_depth=0. It must degrade or fail. If it still passes, the
graph contributed nothing, retrieval is doing chunk-store work, and this slice's finding is
negative — which is the single most valuable outcome available here, and worth knowing early.
Offline, similarity_top_k=3 — tight enough to admit a near-miss, small enough that including
everything (this is a 4-document corpus) would prove nothing about ranking. Whichever embeds A1/A3
(golden test double or a real local model), the same precondition gate applies before trusting
either with a full A1 run: A ranks top, B does not appear in the top 3 (forcing A1 through
the graph edge), C appears but below A — golden vectors are pinned to guarantee this
directly (a generic hash/keyword-overlap formula isn't reliable here either: C is deliberately
designed to share surface tokens with the real decision while being unrelated, which can fool a
naive formula); a real local model isn't guaranteed to produce this ranking on four documents by
default, so check it explicitly rather than assuming. Assert the ordering itself, not just that the
final answer comes out right — a lucky answer with the wrong ranking underneath proves nothing.
Closes
A1, A3, A8.
Activity
[-]Query agent: VectorContextRetriever with SSE streaming[/-][+]NU-010 Query agent: VectorContextRetriever with SSE streaming[/+][-]NU-010 Query agent: VectorContextRetriever with SSE streaming[/-][+]NU-011 Query agent: VectorContextRetriever with SSE streaming[/+]