Retrieval

A retriever only answers “given a query string, return Nodes.” It does not call the LLM. That is the first stage inside a QueryEngine. Pulling it out lets you mix retrievers, wrap it as an agent tool, or call it from a Workflow step.

retriever = index.as_retriever(similarity_top_k=5)
nodes = retriever.retrieve("How do I request time off?")
for n in nodes:
    print(n.score, n.metadata, n.get_content()[:200])

Async: await retriever.aretrieve(query). Score scales differ by backend (cosine / inner product / distance)—do not compare raw scores across stores.


VectorIndexRetriever

Explicit form of as_retriever:

from llama_index.core.retrievers import VectorIndexRetriever

retriever = VectorIndexRetriever(
    index=index,
    similarity_top_k=10,
)

as_query_engine(similarity_top_k=...) forwards that argument to the inner retriever. Debug recall with a fixed k and printed text before attaching a synthesizer.


Postprocessors: filter and rerank

From the official querying guide:

ComponentRole
SimilarityPostprocessorDrop nodes below similarity_cutoff
KeywordNodePostprocessorrequired_keywords / exclude_keywords
PrevNextNodePostprocessorExpand hits using prev/next relationships (small-chunk retrieve, larger generate)
from llama_index.core.postprocessor import (
    SimilarityPostprocessor,
    KeywordNodePostprocessor,
)
from llama_index.core.query_engine import RetrieverQueryEngine

engine = RetrieverQueryEngine.from_args(
    retriever,
    node_postprocessors=[
        KeywordNodePostprocessor(required_keywords=["policy"], exclude_keywords=["draft"]),
        SimilarityPostprocessor(similarity_cutoff=0.65),
    ],
)

Production often adds a reranker (cross-encoder) on the top-k. Class names and extra packages change—use current Node Postprocessor docs rather than stale imports.


Metadata filters

metadata written at ingest time can filter at query time (tenant, year, file type). Syntax varies slightly by vector store; the idea is the same: shrink candidates, then score.

from llama_index.core.vector_stores import MetadataFilters, MetadataFilter, FilterOperator
from llama_index.core.vector_stores.types import FilterCondition

filters = MetadataFilters(
    filters=[
        MetadataFilter(key="department", value="hr", operator=FilterOperator.EQ),
    ],
    condition=FilterCondition.AND,
)
retriever = index.as_retriever(similarity_top_k=5, filters=filters)

Keys must match ingest. If your installed version’s MetadataFilters API differs, follow the official vector-store page.


Better recall (same ideas as the RAG course)

TechniqueLlamaIndex lever
Larger ksimilarity_top_k
Better chunksSentenceSplitter / IngestionPipeline
Hybrid searchDense + keyword; some stores (Qdrant, pgvector) expose hybrid flags
Query rewriteChat-engine condense, or an LLM rewrite step in a Workflow
Multi-retrieverSeveral retrievers, then fusion / a router query engine
EvalFrozen questions; check that source_nodes contain gold spans

The RAG tutorial explains why. Here we map where. When the model chooses query strings and hops, that is agentic RAG: expose the retriever or query engine as a FunctionAgent tool (Query Engines).


Retrieve only, generate yourself

from llama_index.llms.openai import OpenAI

llm = OpenAI(model="gpt-4o-mini")
nodes = retriever.retrieve("How many days is the return window?")
context = "\n\n".join(n.get_content() for n in nodes)
prompt = f"Answer only from the notes. If unknown, say so.\n\n{context}\n\nQ: return window?"
print(llm.complete(prompt))

This is easy to unit-test (assert on retrieve) and easy to hand to LangChain or CrewAI: they receive a string tool result and do not need LlamaIndex’s synthesizer.


Next steps

评论