检索 Retrieval

Retriever 只负责「给定查询字符串,返回 Node 列表」,不做 LLM 合成。QueryEngine 内部第一段就是 Retriever。把它单独拿出来,才能做混合检索、当 Agent 工具、或在 Workflow 的某一步里调用。

retriever = index.as_retriever(similarity_top_k=5)
nodes = retriever.retrieve("假期如何申请?")
for n in nodes:
    print(n.score, n.metadata, n.get_content()[:200])

异步:await retriever.aretrieve(query)。分数含义取决于后端(余弦 / 内积 / 距离),不要跨向量库比较绝对值。


VectorIndexRetriever

as_retriever 等价的显式写法:

from llama_index.core.retrievers import VectorIndexRetriever

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

as_query_engine(similarity_top_k=...) 只是把这个参数传给内部 retriever。调试召回时,先固定 k,打印内容,再接到 synthesizer 上。


后处理:过滤与重排

官方查询文档里的后处理器示例:

组件作用
SimilarityPostprocessor丢掉低于 similarity_cutoff 的节点
KeywordNodePostprocessorrequired_keywords / exclude_keywords
PrevNextNodePostprocessor按 Node 关系把前后块拼回来(小块检索、大块生成)
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=["政策"], exclude_keywords=["草稿"]),
        SimilarityPostprocessor(similarity_cutoff=0.65),
    ],
)

生产上常用 reranker(交叉编码器)对 top-k 再排序。具体类名与安装包以当前 Node Postprocessor 文档为准,不要抄过期 import。


元数据过滤

摄入时写入的 metadata 可在查询时过滤(租户、年份、文件类型)。向量库不同,过滤语法略有差异,思想一致:先缩小候选,再算相似度。

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)

字段名必须与摄入时一致。若当前版本的 MetadataFilters 参数有出入,以官方 Vector Store 集成页为准。


提升召回(与 RAG 通识同一套)

手段在 LlamaIndex 中的落点
加大 ksimilarity_top_k
更合理切块SentenceSplitter / IngestionPipeline
混合检索向量 + 关键词;部分 store(如 Qdrant、pgvector)提供 hybrid 开关
查询改写Chat Engine 的 condense,或 Workflow 里先 LLM 扩写 query
多路检索多个 Retriever,再融合 / Router Query Engine
评测固定问题集,看 source_nodes 是否含金标准段落

本站 RAG 讲这些手段的「为什么」;这里只映射到 API。Agent 自己决定检索词、多跳搜索,就是 Agentic RAG:把 retriever 或 query engine 做成 FunctionAgent 工具(见 查询引擎)。


只检索、自己生成

from llama_index.llms.openai import OpenAI

llm = OpenAI(model="gpt-4o-mini")
nodes = retriever.retrieve("退货窗口几天?")
context = "\n\n".join(n.get_content() for n in nodes)
prompt = f"只根据资料回答,不知道就说不知道。\n\n{context}\n\n问题:退货窗口几天?"
print(llm.complete(prompt))

这条路便于单测(对 retrieve 断言),也便于接到 LangChainCrewAI:它们拿到的是字符串工具结果,不必依赖 LlamaIndex 的 synthesizer。


下一步

评论