Interview question
Build hybrid RAG retrieval with access control and verified citations
Builds a hybrid retrieval pipeline that enforces tenant scope before ranking, assembles a bounded context, and verifies returned citations.
TL;DR
Builds a hybrid retrieval pipeline that enforces tenant scope before ranking, assembles a bounded context, and verifies returned citations.
Authorization-aware retrieval, lexical and vector fusion, reranking, context budgets, citation provenance, abstention, and retrieval evaluation.
Practice the problem like a real interview: restate, reason, implement, and test.
Implement the retrieval boundary for a multi-tenant policy assistant. Combine lexical and vector candidates, but enforce the caller's tenant and document permissions inside each retrieval query. Fuse and rerank candidates, construct a bounded context, require citations by chunk ID, and reject an answer when its citations do not support its claims.
Move to the linked follow-up, next path step, prerequisite, or deeper variant.
Move forward in the planned practice sequence.
Question: "How long are production audit records retained?"
Authorized candidates: policy-17#c4, handbook-8#c2
Unauthorized but semantically close candidate: other-tenant-policy#c9 -> never enters ranking
Answer cites policy-17#c4 -> verifier checks the cited chunk was supplied and contains supporting text.
async def answer_policy_question(question: str, actor: Principal) -> RagResult:
scope = await permissions.authorized_document_scope(actor)
lexical, semantic = await gather(
search.lexical(question, tenant=actor.tenant_id, document_ids=scope, limit=30),
search.vector(question, tenant=actor.tenant_id, document_ids=scope, limit=30),
)
candidates = reciprocal_rank_fusion(lexical, semantic)
candidates = deduplicate_chunks(candidates)
ranked = await reranker.rank(question, candidates[:40])
context = select_within_budget(ranked, token_budget=6_000, diversify_by_document=True)
if not context:
return RagResult.abstain("no_authorized_evidence")
generated = await model.answer(
question=question,
chunks=[{"id": c.id, "text": c.text} for c in context],
require_citations=True,
)
verification = citation_verifier.check(generated, context)
if not verification.material_claims_supported:
return RagResult.abstain("unsupported_citation", diagnostics=verification.safe_codes)
return RagResult.answer(generated.text, verification.citations)
Retrieval cost depends on the search indexes; fusion is O(k log k) for bounded candidate sets, and reranking/model calls dominate latency. Authorization scope size must be represented efficiently rather than copied into an unbounded filter.
Aporeon is shaped by Aleksandar Tomovski, a software developer with experience on both sides of technical interviews. Content is reviewed for accuracy, natural spoken delivery, useful depth, and honest trade-offs.
Help improve the interview library.
Say thanks with a standalone, one-time $5 contribution. No account required.