01 前言Retriever 是 RAG 的入口。它接收一个 query返回一组 List[Document]。模型不是先出场资料先出场。前面几章我们讲了 Loader、Splitter、Embedding、VectorStore。它们解决的是“资料怎么进库”。这一章讲 Retriever解决的是“用户问的时候资料怎么被找出来”。很多人做 RAG第一反应是换模型、调 Prompt、加长上下文。方向没错但不是第一优先级。真正影响答案质量的往往是 Retriever它有没有把正确资料找出来。检索错了模型会一本正经地胡说。检索少了答案缺关键信息。检索脏了模型会被无关上下文带偏。02 Retriever 到底是什么通俗说Retriever 就是“检索器”。用户给它一个问题它负责从知识库、向量库、关键词索引、数据库、外部 API 里找相关资料。它不负责生成答案。它只负责找资料。它的输入很简单一个字符串 query。它的输出也很清晰List[Document]。每个 Document 里有 page_content、metadata、id。别混淆VectorStore 是底层仓库Retriever 是上层查询入口。VectorStore 可以作为 Retriever 的后端但 Retriever 不一定只能查 VectorStore。03 官方文档怎么定义它LangChain 的语义搜索教程把 Documents、Text Splitters、Embeddings、Vector Stores 和 Retrievers 放在同一条知识库链路里。官方说明这些抽象用于从向量数据库和其他来源取回数据再放到 LLM 工作流里推理。RAG 教程也把流程拆成两段Indexing 负责离线入库Retrieval and generation 负责运行时检索和生成。也就是说Retriever 是在线链路的核心开关。源码里BaseRetriever 的定位更直接它是一个文档检索系统的抽象基类拿字符串 query返回相关 Document 列表。04 源码入口BaseRetriever.invoke()LangChain 新版组件基本都走 Runnable 接口。Retriever 也一样。业务代码不应该再到处调用老式的 get_relevant_documents而是调用 retriever.invoke(query)。invoke 是门面。它做三件事整理 config启动 callback trace调用真正的检索方法。真正的检索逻辑在 _get_relevant_documents。# 源码链路压缩版不是完整源码retriever.invoke(query)- ensure_config(config)- callback_manager.on_retriever_start(...)- self._get_relevant_documents(query, run_managerrun_manager)- run_manager.on_retriever_end(result)- return List[Document]源码重点_get_relevant_documents 是子类必须实现的方法。你写自己的检索器本质就是重写这个方法。05 自定义 Retriever 的本质重写一个方法BaseRetriever 是抽象类。它规定统一入口和统一返回值但不规定你怎么找资料。你可以用向量检索也可以用 BM25也可以查 MySQL也可以请求一个内部搜索服务。只要最后返回 List[Document]就能接入 LangChain 的 RAG、Agent、Tool、LangSmith。from langchain_core.retrievers import BaseRetrieverfrom langchain_core.documents import Documentclass MyRetriever(BaseRetriever):def _get_relevant_documents(self, query: str, *, run_manager):# 这里可以查 ES、Milvus、MySQL、HTTP APIreturn [Document(page_content相关内容, metadata{source: demo})]这段代码不要只看成 Demo。它背后的设计很关键Retriever 只暴露检索能力不暴露底层细节。业务层只认 invoke(query)不关心你底层是 ES、Milvus 还是混合检索。这就是工程价值。换检索方案不改上层业务。06 VectorStoreRetriever最常用的 Retriever大多数 RAG 项目Retriever 都是从 VectorStore 来的。代码一般是这样vectorstore.as_retriever()。源码里as_retriever() 会返回一个 VectorStoreRetriever。它不是新建一份数据而是把原来的 VectorStore 包起来变成统一的 Retriever 接口。VectorStoreRetriever 里面有三个关键属性vectorstore、search_type、search_kwargs。retriever vectorstore.as_retriever(search_typemmr,search_kwargs{k: 5, fetch_k: 30, lambda_mult: 0.4})docs retriever.invoke(LangChain Retriever 是什么)07 search_type三种模式决定检索风格VectorStoreRetriever 的 search_type 不是装饰参数。它直接决定底层怎么找资料。similarity 是默认模式。它只看相似度简单直接。mmr 会兼顾相似度和多样性适合长文档、重复 Chunk 多的知识库。similarity_score_threshold 会设置最低相关度门槛相关度不够就不返回。它适合对准确性要求高的场景。# 源码逻辑压缩版if search_type similarity:return vectorstore.similarity_search(query, **kwargs)if search_type similarity_score_threshold:docs_and_scores vectorstore.similarity_search_with_relevance_scores(query, **kwargs)return [doc for doc, score in docs_and_scores]if search_type mmr:return vectorstore.max_marginal_relevance_search(query, **kwargs)建议先用 similarity 跑通链路如果结果重复换 MMR如果无关资料太多加 score_threshold。08 search_kwargs真正调效果的是这些参数很多人调 RAG只调 Prompt。其实 Retriever 参数更重要。k 控制最终返回几条文档。不是越多越好。返回太多Prompt 会被噪声塞满。fetch_k 是 MMR 的候选池大小。先多拿再挑出既相关又分散的结果。lambda_mult 控制相似度和多样性的平衡。越接近 1越偏相似越接近 0越偏多样。score_threshold 控制最低相关度。低于门槛就不要宁缺毋滥。filter 用元数据过滤结果。比如只查某个业务线、某个产品、某个时间范围、某个文档来源。09 Retriever 变成工具Agentic RAG 的关键普通 RAG 是固定流程用户一问就先检索。Agentic RAG 更灵活Agent 先判断需不需要查资料需要时才调用检索工具。LangChain 提供 create_retriever_tool可以把 Retriever 包成 StructuredTool。这样 Agent 就可以像调用天气、订单、行情工具一样调用知识库。from langchain_core.tools import create_retriever_tooltool create_retriever_tool(retriever,namesearch_docs,description检索知识库返回和问题相关的资料,response_formatcontent_and_artifact,)源码里这个工具内部会调用 retriever.invoke(query)然后把每个 Document 格式化成文本。如果 response_format 是 content_and_artifact它还会把原始 docs 作为 artifact 返回。这样模型看到的是文本系统还能保留 Document 元数据后续做引用、溯源、评分。10 生产级 Retriever不要只看能不能跑能返回文档不代表 Retriever 合格。生产系统要看四个指标命中率、相关度、覆盖率、延迟。命中率标准答案所在文档有没有被找出来。相关度TopK 里有多少是真正有用的。覆盖率多跳问题需要的多个信息点有没有都找齐。延迟一次检索耗时能不能撑住线上并发。工程经验Retriever 必须做日志。每次请求至少记录 query、改写 query、返回文档 id、score、metadata、耗时、最终是否被模型引用。# 建议记录的检索日志{query: 用户原始问题,rewritten_query: 问题改写后文本,retriever: VectorStoreRetriever,search_type: mmr,search_kwargs: {k: 5, fetch_k: 30},docs: [{id: doc-001, score: 0.86, source: manual.pdf}],latency_ms: 42}11 常见坑为什么你的 RAG 答案不准坑一只用向量检索向量检索适合语义相似但对编号、专有名词、精确字段不一定稳。企业知识库建议做混合检索。坑二Chunk 切得太碎太碎会丢上下文Retriever 找到的只是半句话。需要 Parent Document 或上下文窗口补全。坑三k 设置太大返回太多文档看似信息丰富实际容易把模型带偏。坑四没有元数据过滤不同业务线、不同版本、不同时间的资料混在一起答案就会乱。坑五没有评测集凭感觉调参数最后只能得到“看起来还行”的系统。12 总结Retriever 是 RAG 的胜负手。Loader、Splitter、Embedding、VectorStore 负责把资料放进库。Retriever 负责在用户提问时把正确资料找出来。源码上看BaseRetriever 统一了 invoke 入口真正检索逻辑由 _get_relevant_documents 实现。VectorStoreRetriever 是最常用实现它把 VectorStore 包成统一检索入口并通过 search_type 选择 similarity、MMR 或 threshold 检索。做企业级 RAG不要只盯着模型。先把 Retriever 做准模型才有发挥空间。下一章预告下一章进入 Rerank 与上下文压缩为什么召回 TopK 后还要再精排一次内容来源LangChain 系列之RetrieverRAG 的核心不是生成而是检索功能变化与行业影响解析_热闻岛
LangChain 系列之Retriever:RAG 的核心不是生成,而是检索
发布时间:2026/6/14 9:23:09
01 前言Retriever 是 RAG 的入口。它接收一个 query返回一组 List[Document]。模型不是先出场资料先出场。前面几章我们讲了 Loader、Splitter、Embedding、VectorStore。它们解决的是“资料怎么进库”。这一章讲 Retriever解决的是“用户问的时候资料怎么被找出来”。很多人做 RAG第一反应是换模型、调 Prompt、加长上下文。方向没错但不是第一优先级。真正影响答案质量的往往是 Retriever它有没有把正确资料找出来。检索错了模型会一本正经地胡说。检索少了答案缺关键信息。检索脏了模型会被无关上下文带偏。02 Retriever 到底是什么通俗说Retriever 就是“检索器”。用户给它一个问题它负责从知识库、向量库、关键词索引、数据库、外部 API 里找相关资料。它不负责生成答案。它只负责找资料。它的输入很简单一个字符串 query。它的输出也很清晰List[Document]。每个 Document 里有 page_content、metadata、id。别混淆VectorStore 是底层仓库Retriever 是上层查询入口。VectorStore 可以作为 Retriever 的后端但 Retriever 不一定只能查 VectorStore。03 官方文档怎么定义它LangChain 的语义搜索教程把 Documents、Text Splitters、Embeddings、Vector Stores 和 Retrievers 放在同一条知识库链路里。官方说明这些抽象用于从向量数据库和其他来源取回数据再放到 LLM 工作流里推理。RAG 教程也把流程拆成两段Indexing 负责离线入库Retrieval and generation 负责运行时检索和生成。也就是说Retriever 是在线链路的核心开关。源码里BaseRetriever 的定位更直接它是一个文档检索系统的抽象基类拿字符串 query返回相关 Document 列表。04 源码入口BaseRetriever.invoke()LangChain 新版组件基本都走 Runnable 接口。Retriever 也一样。业务代码不应该再到处调用老式的 get_relevant_documents而是调用 retriever.invoke(query)。invoke 是门面。它做三件事整理 config启动 callback trace调用真正的检索方法。真正的检索逻辑在 _get_relevant_documents。# 源码链路压缩版不是完整源码retriever.invoke(query)- ensure_config(config)- callback_manager.on_retriever_start(...)- self._get_relevant_documents(query, run_managerrun_manager)- run_manager.on_retriever_end(result)- return List[Document]源码重点_get_relevant_documents 是子类必须实现的方法。你写自己的检索器本质就是重写这个方法。05 自定义 Retriever 的本质重写一个方法BaseRetriever 是抽象类。它规定统一入口和统一返回值但不规定你怎么找资料。你可以用向量检索也可以用 BM25也可以查 MySQL也可以请求一个内部搜索服务。只要最后返回 List[Document]就能接入 LangChain 的 RAG、Agent、Tool、LangSmith。from langchain_core.retrievers import BaseRetrieverfrom langchain_core.documents import Documentclass MyRetriever(BaseRetriever):def _get_relevant_documents(self, query: str, *, run_manager):# 这里可以查 ES、Milvus、MySQL、HTTP APIreturn [Document(page_content相关内容, metadata{source: demo})]这段代码不要只看成 Demo。它背后的设计很关键Retriever 只暴露检索能力不暴露底层细节。业务层只认 invoke(query)不关心你底层是 ES、Milvus 还是混合检索。这就是工程价值。换检索方案不改上层业务。06 VectorStoreRetriever最常用的 Retriever大多数 RAG 项目Retriever 都是从 VectorStore 来的。代码一般是这样vectorstore.as_retriever()。源码里as_retriever() 会返回一个 VectorStoreRetriever。它不是新建一份数据而是把原来的 VectorStore 包起来变成统一的 Retriever 接口。VectorStoreRetriever 里面有三个关键属性vectorstore、search_type、search_kwargs。retriever vectorstore.as_retriever(search_typemmr,search_kwargs{k: 5, fetch_k: 30, lambda_mult: 0.4})docs retriever.invoke(LangChain Retriever 是什么)07 search_type三种模式决定检索风格VectorStoreRetriever 的 search_type 不是装饰参数。它直接决定底层怎么找资料。similarity 是默认模式。它只看相似度简单直接。mmr 会兼顾相似度和多样性适合长文档、重复 Chunk 多的知识库。similarity_score_threshold 会设置最低相关度门槛相关度不够就不返回。它适合对准确性要求高的场景。# 源码逻辑压缩版if search_type similarity:return vectorstore.similarity_search(query, **kwargs)if search_type similarity_score_threshold:docs_and_scores vectorstore.similarity_search_with_relevance_scores(query, **kwargs)return [doc for doc, score in docs_and_scores]if search_type mmr:return vectorstore.max_marginal_relevance_search(query, **kwargs)建议先用 similarity 跑通链路如果结果重复换 MMR如果无关资料太多加 score_threshold。08 search_kwargs真正调效果的是这些参数很多人调 RAG只调 Prompt。其实 Retriever 参数更重要。k 控制最终返回几条文档。不是越多越好。返回太多Prompt 会被噪声塞满。fetch_k 是 MMR 的候选池大小。先多拿再挑出既相关又分散的结果。lambda_mult 控制相似度和多样性的平衡。越接近 1越偏相似越接近 0越偏多样。score_threshold 控制最低相关度。低于门槛就不要宁缺毋滥。filter 用元数据过滤结果。比如只查某个业务线、某个产品、某个时间范围、某个文档来源。09 Retriever 变成工具Agentic RAG 的关键普通 RAG 是固定流程用户一问就先检索。Agentic RAG 更灵活Agent 先判断需不需要查资料需要时才调用检索工具。LangChain 提供 create_retriever_tool可以把 Retriever 包成 StructuredTool。这样 Agent 就可以像调用天气、订单、行情工具一样调用知识库。from langchain_core.tools import create_retriever_tooltool create_retriever_tool(retriever,namesearch_docs,description检索知识库返回和问题相关的资料,response_formatcontent_and_artifact,)源码里这个工具内部会调用 retriever.invoke(query)然后把每个 Document 格式化成文本。如果 response_format 是 content_and_artifact它还会把原始 docs 作为 artifact 返回。这样模型看到的是文本系统还能保留 Document 元数据后续做引用、溯源、评分。10 生产级 Retriever不要只看能不能跑能返回文档不代表 Retriever 合格。生产系统要看四个指标命中率、相关度、覆盖率、延迟。命中率标准答案所在文档有没有被找出来。相关度TopK 里有多少是真正有用的。覆盖率多跳问题需要的多个信息点有没有都找齐。延迟一次检索耗时能不能撑住线上并发。工程经验Retriever 必须做日志。每次请求至少记录 query、改写 query、返回文档 id、score、metadata、耗时、最终是否被模型引用。# 建议记录的检索日志{query: 用户原始问题,rewritten_query: 问题改写后文本,retriever: VectorStoreRetriever,search_type: mmr,search_kwargs: {k: 5, fetch_k: 30},docs: [{id: doc-001, score: 0.86, source: manual.pdf}],latency_ms: 42}11 常见坑为什么你的 RAG 答案不准坑一只用向量检索向量检索适合语义相似但对编号、专有名词、精确字段不一定稳。企业知识库建议做混合检索。坑二Chunk 切得太碎太碎会丢上下文Retriever 找到的只是半句话。需要 Parent Document 或上下文窗口补全。坑三k 设置太大返回太多文档看似信息丰富实际容易把模型带偏。坑四没有元数据过滤不同业务线、不同版本、不同时间的资料混在一起答案就会乱。坑五没有评测集凭感觉调参数最后只能得到“看起来还行”的系统。12 总结Retriever 是 RAG 的胜负手。Loader、Splitter、Embedding、VectorStore 负责把资料放进库。Retriever 负责在用户提问时把正确资料找出来。源码上看BaseRetriever 统一了 invoke 入口真正检索逻辑由 _get_relevant_documents 实现。VectorStoreRetriever 是最常用实现它把 VectorStore 包成统一检索入口并通过 search_type 选择 similarity、MMR 或 threshold 检索。做企业级 RAG不要只盯着模型。先把 Retriever 做准模型才有发挥空间。下一章预告下一章进入 Rerank 与上下文压缩为什么召回 TopK 后还要再精排一次内容来源LangChain 系列之RetrieverRAG 的核心不是生成而是检索功能变化与行业影响解析_热闻岛