深入学 LangChain 官方文档(十一)Retrieval 检索入口首讲
本篇对应的官方文档
- Retrieval:检索解决的问题、知识库构建组件,以及 2-Step、Agentic、Hybrid RAG 的架构差异。
- Build a semantic search engine with LangChain:
Document、切分、embedding、vector store 与语义查询的最小实现链路。本篇讲解范围
本篇主要从“客服怎样依据最新退款政策回答”出发,建立索引与查询双阶段、Retrieval 与 RAG 的关系、三类 RAG 架构及最小代码闭环。生产向量数据库选型、复杂 rerank、多模态检索、Graph RAG 和完整评测平台留给后续专题。
上一章把执行政策放到了明确的调用边界,新的问题马上跟了上来:模型需要回答的内容,未必已经在当前上下文里。
用户问客服 Agent:“耳机已经拆封,还能七天无理由退货吗?”模型当然能直接给出一句话,但这句话很难让人放心。
退款政策会更新,不同商品可能有例外,企业内部规则也不在模型训练数据里。即使碰巧答对,系统仍然解释不了它依据的是哪个版本、哪一条规定。
Retrieval(检索)改变的是回答前的信息路径,不需要修改模型参数。问题到来后,系统先从外部知识源取回相关证据,再把数量有限、来源可追踪的内容交给模型。
检索和生成接在一起,才是通常所说的 Retrieval-Augmented Generation,也就是 RAG(检索增强生成)。
这里有两个词要抓住。“运行时”意味着知识不必在训练阶段进入模型;“相关”意味着系统只取当前问题需要的片段,不会把整本政策手册塞进上下文。
接下来沿着取证链往下拆:先划清 Retrieval、Memory 与业务数据库的责任,再把原始政策处理成带来源的Document和 chunk。
随后看 embedding、vector store 与 retriever 怎样返回候选证据,最后比较三类 RAG 架构,并把空结果、噪声、过期和越权放进工程验收。
闭卷回答依赖模型已有参数,无法跟随企业政策更新;运行时取证会在问题到来后查询当前知识源,把相关片段连同来源一起交给模型。RAG 的增量不是笼统地“知道更多”,而是让本次回答建立在可更新、可追踪的外部证据上。
沿着取证路径继续走,第一步是把“找证据”和“写答案”分开。
一、Retrieval 负责取证,RAG 负责基于证据生成
官方文档先点出模型的两项限制:上下文窗口装不下整个语料库,训练得到的知识也不会自动跟随企业政策更新。Retrieval 接收查询,从外部系统取回相关信息,正面处理这两个限制。
但检索结果还不是面向用户的回答。它通常是一组Document,每个对象包含page_content和可选metadata。
应用还要决定片段怎样整理、放进哪一段 model context,以及证据不够时怎样要求模型停止猜测。把检索、注入和生成连起来,才构成 RAG。
三者的输出边界很清楚:
- Retrieval 的输出是候选证据;
- Generation 的输出是面向用户的回答;
- RAG 的质量取决于证据能否被正确取回,也取决于模型是否只在证据边界内作答。
如果检索漏掉“拆封耳机不适用”的例外条款,模型写得再流畅也补不回来。反过来,正确条款已经取回,prompt 却允许模型随意混入常识,答案还是会跑出证据范围。
所以 RAG 不是接上向量库就结束,而是一条要逐段验收的证据供应链。
二、Retrieval、Memory 与业务数据库各自回答不同问题
第 09 篇讲过 Memory 以后,很容易把所有“将来还要读取的信息”放进同一个概念。退款政策、用户偏好和订单状态确实都会再次出现,责任却完全不同。
Retrieval 回答“当前问题需要哪些外部知识证据”,适合政策、手册、FAQ、技术文档和历史报告。
Memory 保存的是用户或线程已经发生的内容,以及可以复用的偏好,例如用户希望中文简洁回答。业务数据库维护当前权威事实,例如订单是否发货、退款是否到账。
一次客服回答可能同时用到三类信息。此时要看的是每条路径最终对哪类事实负责,而不是底层用了什么存储产品。
政策条款从知识库检索,表达偏好从 Memory 读取,订单状态回交易系统查询,三条路径分别承担知识证据、交互连续性和业务真相。把业务事实向量化后当作唯一答案,或把政策正文塞进用户记忆,都会让更新与权威边界失控。
有些企业已经建好了 SQL、CRM、文档搜索或内部知识 API。使用 LangChain 并不要求把这些系统全部搬进新的向量库。
现有系统可以直接作为 Agentic RAG 的工具,也可以由确定性步骤先查,再把结果注入 2-Step RAG。LangChain 提供的是组合接口,不是强制迁移方案。
三、检索系统分成索引阶段和查询阶段
最小语义检索系统包含两条发生时间不同的链路。
索引阶段读取原始资料,把文件、网页或数据库记录转成标准Document。长文档经过 text splitter 切成更小的 chunk,embedding model 再把文本映射为向量,vector store 同时保存向量、原文与 metadata。
这条链路随政策发布或更新运行,不会在每次用户提问时重做整本手册。
查询阶段才发生在用户提问时。问题被映射到同一向量空间,系统执行相似度搜索或 retriever 查询,取回少量候选Document,再交给后面的 RAG 链路。
两阶段共用 embedding 语义和 metadata 规则,负载、延迟与失败方式却不相同。
索引链把来源文档处理成可搜索的向量和元数据,查询链只处理当前 query 并返回 top-kDocument。索引失败会造成知识缺失或过期,查询失败则表现为空结果、低相关结果或延迟,两条链必须分开监控。
这个区分会直接影响更新策略。退款政策第 3.2 条修改后,应该只重建受影响的文档或 chunk,并更新版本字段。没有稳定文档 ID 却反复全量追加,很容易留下新旧重复。
查询端面对的是另一组约束:租户、语言、商品分类和生效日期都可能进入过滤条件,不能只凭语义相似度取前几名。
四、Document、chunk 与 metadata 共同定义证据单元
LangChain 用Document统一表达检索内容。page_content保存参与搜索和生成的正文。
metadata则保存回溯和过滤需要的信息,例如source、section、version、effective_date、tenant_id与权限标签。
原始政策通常太长,需要先切分。chunk 过大,一个向量会混入多个主题,查询“耳机拆封”可能拉回整章售后制度;chunk 过小,主规则与例外条件又会被拆开,模型只看见“支持七天退货”,漏掉下一句“不适用于拆封音像和特定卫生商品”。
政策被切成可以独立召回的 chunk,每个 chunk 同时保留正文与来源、章节、版本、生效日期等 metadata。切分边界决定语义是否完整,metadata 决定结果能否过滤、引用、更新和删除,两者共同构成证据单元。
切分不只是字符计数。标题层级、段落、表格行、代码块和条款编号都可能是语义边界。初期可以用通用 splitter 建立基线,再拿真实问题观察:命中片段能否独立表达判断,前后文是否必须一起返回,重复 chunk 是否挤占 top-k。
metadata 也不能只留文件名。客服答案要引用“2026-07 版售后政策 3.2 条”,这些字段就必须在索引阶段保存。华东租户只能读取自己的内部政策时,tenant_id过滤要在检索前生效,不能等内容取回后再让模型忽略。
文档生命周期还需要稳定标识。可以给原始文档保存document_id,切分结果保存可重复计算的chunk_id,再记录内容哈希。
政策只改一节时,索引任务就能删掉旧 chunk、写入新 chunk,而不是把整份文件又追加一遍。缺少稳定 ID 的知识库看似结果丰富,实际可能是同一条款的三个历史版本一起占满 top-k。
删除也属于索引合同。员工手册撤回、租户解除授权或用户要求删除资料后,原文件、向量、缓存与派生摘要都要同步处理。只在 metadata 标记“已删除”,旧向量却仍能进入候选集,等于把合规问题推给生成阶段。
可靠知识库必须回答得出:一条证据从哪里来,现在是否有效,还有哪些派生数据需要一起失效。
五、embedding 搜索的是语义邻近,不是事实正确
embedding model 把文本转成数值向量。语义相近的文本通常会落在更近的位置,所以用户问“拆开包装还能退吗”,也可能命中“商品启封后不适用无理由退货”,两边不需要使用完全相同的关键词。
query 与文档 chunk 经同一 embedding model 进入向量空间,“拆开包装”和“商品启封”因为语义接近而距离更近。这个距离只表示相关性,不能证明条款有效、来源可信或答案正确;版本与权限仍由 metadata 和业务规则约束。
相似度不是事实置信度。旧条款可能与问题高度相似,却早已失效;营销文章可能更贴近用户措辞,却不具备政策权威性;互相冲突的文档也可能一起进入前几名。
VectorStore 通常支持字符串或向量查询、同步或异步调用、是否返回分数,以及 similarity 或 maximum marginal relevance 等策略。
similarity_search(query, k=4)只是起点,生产系统还要叠加 metadata filter、最小相关阈值、去重与多源排序。
Retriever 把“给定非结构化 query,返回一组Document”抽象成统一接口。内部可以使用向量搜索、关键词检索、数据库查询、外部搜索服务,甚至组合多个 retriever。上层 RAG 只依赖返回的Document,底层策略就可以替换。
这层抽象也方便测试。开发阶段可以用内存向量库验证消息与生成链路,生产时再换成企业搜索 API;只要Document与 metadata 合同不变,上层无需重写。
反过来,工具只返回一段没有来源边界的长字符串,后续的过滤、引用、去重和评测就都失去了对象。
候选形成可以拆成四步:先应用租户与权限过滤,再计算语义相关性;随后选择 top-k 或兼顾多样性的结果;最后检查分数、来源和重复度,判断证据是否足够进入生成。
检索不是从全库直接抓几个最近向量。租户、权限、版本和生效日期先缩小合法候选集,相似度与多样性策略再形成 top-k。过滤过晚会产生越权,k 过小容易漏掉例外,k 过大则会把噪声带进上下文。
候选证据下一步怎样进入模型,取决于检索固定发生在生成之前,还是由 Agent 或校验循环决定检索时机。
六、三类 RAG 架构的差别在“谁决定何时检索”
官方总览把常见 RAG 分成 2-Step、Agentic 和 Hybrid。三者可以共用同一个知识库,区别落在检索时机、控制权和验证步骤。
2-Step RAG:每次回答前固定检索。用户问题先进入 retriever,证据和问题再一起交给模型。调用次数有上限,延迟比较可预测,适合 FAQ、文档问答和“没有证据就不应回答”的场景。
代价是用户只说“谢谢”时也可能触发无用检索,复杂问题通常也只有一次查询机会。
2-Step 的固定路径是 query → retrieve → context → model → answer。检索一定发生,控制强、调用数可预测;答案质量也直接受单次 query、top-k 和上下文拼装影响。
Agentic RAG:把检索暴露为工具。Agent 先判断当前问题是否需要外部知识,第一次结果不足时还可以改写 query 再查。
研究助手、多知识源或需要在检索与其他工具间交替的任务更适合这种方式。代价是延迟和调用次数不稳定,还要防止 Agent 跳过检索、反复检索或选错知识源。
Agent loop 把 retriever 当作工具,模型根据当前 messages 决定是否查询以及查询什么,Document再以ToolMessage回到下一轮推理。检索时机更灵活,也因此需要调用限制、准确的工具描述和无证据拒答规则。
Hybrid RAG:在固定链和 Agent 之间加入校验。常见流程先改写含糊问题,检索后判断相关性,不足时重新检索,生成后再检查答案是否得到证据支持。它适合质量要求高的行业问答,但每个判断节点都会增加成本,循环也必须有明确上限。
Hybrid 在检索前后加入 query 改写、相关性判断和答案校验,证据不足就回到检索,不让模型直接补全。循环换来更强控制,也必须设置终止条件并记录每次改写,避免质量检查演变成无限调用。
选择架构时不用按“高级程度”排序。退款政策每次都必须引用文档,2-Step 往往简单可靠;需要跨多个来源调查原因时,Agentic 更灵活;监管场景要求证据校验和稳定拒答,再考虑加入 Hybrid 节点。
七、把检索结果注入上下文时,要保留来源边界
拿到Document以后,常见做法是把若干page_content拼成 context,再连同用户问题交给模型。片段不是越多越好,至少要保留明确的分隔、来源标识和指令边界。
可以为每个片段编号,并附上 source、section、version。system prompt 要求模型只根据这些片段回答,证据不够时说明缺少依据,关键结论引用对应编号。这样做不能从数学上消灭幻觉,却让追踪和评测有了具体对象。
多个片段共同构成一个判断时,还要处理它们之间的关系。主规则和例外条款分别命中,不能简单按分数排序后截断。
可以恢复同一章节的邻近片段,或用 metadata 把条件和结论放回一起。不同版本彼此冲突时,也应由应用先判断有效版本,而不是交给模型碰运气。
Token 预算要在拼装前确定。系统指令、用户问题、检索证据和回答分别预留空间,再在证据预算内按相关性、权威性与多样性挑选片段。把 k 从 4 直接提到 20 往往只会增加延迟和噪声;每个进入 model context 的 chunk 都应该补充一条必要证据。
答案引用最好绑定内部文档 ID,不要只让模型手写“来源:售后政策”。生成后,应用根据引用 ID 渲染标题和链接,并核对该 ID 确实属于本轮候选集。文档以后移动或改名,追踪关系仍然存在,模型也更难凭空编造来源。
知识片段中即使出现“忽略之前规则”,它仍然是待引用的数据,不会因此升级为系统指令。消息层级和分隔格式要足够清楚,敏感工具权限也不能交给检索文本决定。Retrieval 负责提供知识,没有权限改写 Agent 的控制政策。
八、四类失败需要回到不同环节修复
RAG 回答错误时,先改 prompt 往往治标不治本。把失败归类以后,才能找到真正需要修复的位置。
空结果:用户措辞与文档差异太大、过滤过严、索引漏文档或阈值过高。应该检查索引覆盖、query 改写和 filter,不能让模型在空 context 里猜。
噪声结果:chunk 过大、k 过高、重复文档太多或来源混杂。修复点在切分、去重、rerank 和来源权重。
过期冲突:新旧政策并存,或两个权威来源结论不同。需要用版本、生效日期和权威等级过滤,无法自动裁决的冲突要交给用户或人工流程。
越权结果:权限过滤发生在向量搜索之后,或缓存键没有包含租户和角色。模型的一句“不要泄露”挡不住这种错误,非法文档必须在检索层就被排除。
空结果回查索引覆盖和 query,噪声回查切分与排序,过期冲突回查版本治理,越权回查过滤与缓存隔离。它们都会表现成“模型答错”,真正的修复位置却分布在四条不同路径上。
失败责任清楚以后,最小代码只需要保留建库、查询、返回证据和生成回答四个动作。
九、最小代码闭环:先建证据库,再让 Agent 按需检索
示例用三条简化政策构建内存向量库。Document.metadata保存条款和版本,search_refund_policy把检索封装成工具;Agent 收到问题以后自行决定是否调用,再根据工具结果回答。
fromlangchain.agentsimportcreate_agentfromlangchain.toolsimporttoolfromlangchain_core.documentsimportDocumentfromlangchain_core.vectorstoresimportInMemoryVectorStorefromlangchain_openaiimportChatOpenAI,OpenAIEmbeddings documents=[Document(page_content="未拆封商品自签收次日起七日内可申请无理由退货。",metadata={"section":"3.1","version":"2026-07","source":"售后政策"},),Document(page_content="耳机等直接接触皮肤的商品,包装启封后不适用无理由退货。",metadata={"section":"3.2","version":"2026-07","source":"售后政策"},),Document(page_content="商品存在质量问题时,可提交检测结果进入质量退货流程。",metadata={"section":"4.1","version":"2026-07","source":"售后政策"},),]vector_store=InMemoryVectorStore(embedding=OpenAIEmbeddings(model="text-embedding-3-small"))vector_store.add_documents(documents)@tooldefsearch_refund_policy(query:str)->str:"""检索当前退款政策,并返回带条款和版本的候选证据。"""results=vector_store.similarity_search(query,k=2)ifnotresults:return"未检索到可用政策;不要根据常识回答。"return"\n\n".join(f"[{doc.metadata['source']}{doc.metadata['version']}"f"第{doc.metadata['section']}条]\n{doc.page_content}"fordocinresults)model=ChatOpenAI(model="qwen3.7-plus",api_key="YOUR_API_KEY",base_url="YOUR_OPENAI_COMPATIBLE_ENDPOINT",)agent=create_agent(model=model,tools=[search_refund_policy],system_prompt=("回答退款问题前先检索政策。只依据工具返回的条款作答;""证据不足时明确说明,并在结论后标注条款与版本。"),)result=agent.invoke({"messages":[{"role":"user","content":"耳机拆封后还能无理由退货吗?"}]})print(result["messages"][-1].content)输入先进入 Agent loop。模型根据工具描述生成search_refund_policy调用,工具用 query 做相似度搜索,返回两个带 metadata 的证据片段。
工具结果进入下一轮模型调用,最终答案从result["messages"][-1]取得。
没有结果时,工具明确返回“不要根据常识回答”,让空证据成为一条可见状态。
这段代码只实现最小机制。生产系统还要在搜索前加入租户、权限、版本和生效日期过滤;embedding 与 vector store 需要持久化;结果要记录文档 ID,方便答案追踪。
外部接口失败也要与“确实没有匹配文档”区分。InMemoryVectorStore适合演示,不能替代生产知识库。
闭环从来源摄取和版本化索引开始,经过权限过滤、语义检索、上下文注入与引用式回答,再把真实问题、命中文档和答案结果交给评测。链路对象都可追踪以后,团队才能判断错误来自知识、检索还是生成。
对象能够逐层追踪,评测也就不能再停留在笼统的答案印象上。
十、评测对象不是“回答好不好”这一项
RAG 至少要分三层评测。检索层检查目标证据是否进入 top-k、无关片段比例、权限和版本过滤;生成层检查答案是否得到证据支持、关键条件有没有遗漏、引用能否对应真实片段;系统层再观察延迟、成本、空结果率与更新时效。
评测集应该来自真实问题,不能只让开发者照着文档标题编写。用户会使用简称、错别字、上下文指代和模糊说法,“拆了还能退吗”比“耳机包装启封后是否适用无理由退货”更接近生产流量。
每个问题最好标记期望证据 ID,而不只是保存一个标准答案,这样检索错误与生成错误才能分开。
上线后还要记录 query、filter、命中文档 ID、分数、版本、最终引用和用户反馈,同时对敏感字段脱敏。文档更新时重跑受影响问题,可以提前发现新版本破坏旧正确答案的回归。
还要单独准备一组系统本来就不该回答的问题:知识库没有覆盖的商品、权限之外的内部政策、无法自动裁决的冲突条款。合格结果是稳定进入拒答、澄清或人工升级,不是勉强给出一句听起来合理的话。把“不知道”纳入评测,RAG 才能堵住召回率之外的猜测缺口。
成本也要按阶段拆开。索引成本随文档更新发生,在线成本来自 query embedding、检索、可能的 rerank 和模型调用。高峰期延迟上升时,只有分别记录各阶段耗时,才能判断向量库变慢、过滤失效,还是 Agent 发起了额外检索。
十一、回到主线:可靠回答始于可靠证据
Retrieval 的机制并不神秘:模型不知道或当前窗口装不下的知识,在问题到来时从外部系统取回。
真正困难的是把它变成可靠供应链——来源要权威,chunk 要语义完整,metadata 要支持版本与权限,查询要召回相关证据,生成要守住证据边界,失败还要能够定位。
实践顺序可以收成一条线:先划清知识、记忆与业务事实的责任;再分开索引和查询;用Document + metadata建立可回溯证据;根据控制需求选择 2-Step、Agentic 或 Hybrid RAG;最后从检索、生成和系统三个层次验收。
到这里,单个 Agent 已经拥有模型、工具、状态、记忆、Middleware 和 Retrieval。但能力继续增加,新的压力也会出现:一个上下文窗口要同时装下多少领域知识,一组工具还能不能由同一个角色准确选择,不同团队维护的专业能力又由谁协调?
下一篇我们将进入 Multi-agent 与 Frontend的学习。它不会推倒这些零件,而是继续回答两件事:当单 Agent 的上下文和工具开始过载时,控制权怎样拆分;后端执行状态又怎样变成用户能看懂、能操作的界面状态。