尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

LangChain文本向量与检索器实践

LangChain文本向量与检索器实践
📅 发布时间:2026/7/20 16:58:09

让大模型真正懂你的数据:LangChain 文本向量、检索器与 RAG 实践

大语言模型擅长理解和生成语言,却不会自动知道企业内部的制度、项目文档或昨天刚更新的数据。要让模型回答这些问题,关键不是继续堆叠提示词,而是建立一条稳定的数据通路:把文档变成可比较的向量,存入适合相似度检索的存储,再把检索结果交给模型生成答案。

LangChain 将这条通路拆成了几个清晰的组件:嵌入模型负责把文本转换为向量,向量存储负责索引和搜索,检索器负责提供统一的查询接口,最后由链把上下文和问题组装后交给聊天模型。理解这些组件的边界,才能把 RAG 应用从“能跑”做成“可维护、可扩展”。

一、文本为什么要变成向量

计算机可以高效处理数字,却不能直接根据一段文字的含义判断两篇文档是否相近。嵌入(Embedding)做的事情,就是把单词、句子、商品、用户或图片转换为一个固定长度的数字列表,并尽量保留它们的语义关系。

例如,一段文本经过模型处理后可能得到这样的结果:

[0.023, 0.487, -0.129, ..., 0.325]

这个列表的长度叫向量维度。维度越高,通常能表达更细的语义差异,但计算、存储和索引成本也会增加。向量可以看作高维空间中的一个点,文本含义相近时,它们在这个空间里往往更接近。

常见的相似度度量包括:

  • 欧氏距离:两点之间的直线距离,距离越小通常越相似。
  • 余弦相似度:比较两个向量的方向,弱化文本长度带来的影响。语义检索中更常用这种方式,因为它更关注“表达的含义是否一致”。

向量检索解决的是传统数据库不擅长的问题。SQL 的等值查询适合查找明确的字段值,而向量检索可以找到“关于数据库分表的内容”,即使原文没有出现完全相同的关键词。

二、嵌入模型的职责与调用方式

嵌入模型是表示型模型,目标是生成语义表示,而不是直接写出一段回答。聊天模型负责“生成”,嵌入模型负责“表示”,二者承担的任务不同,不能互相替代。

LangChain 为不同模型提供方提供了独立的集成包。以 OpenAI 为例:

pipinstall-Ulangchain-openai

初始化模型时,密钥应放在环境变量中:

importosfromlangchain_openaiimportOpenAIEmbeddings os.environ["OPENAI_API_KEY"]="your-api-key"embeddings=OpenAIEmbeddings(model="text-embedding-3-large")

基础嵌入接口有两个重要方法:

documents_vector=embeddings.embed_documents(["向量数据库用于语义检索","检索器把查询转换为文档列表",])query_vector=embeddings.embed_query("如何做语义检索?")

embed_documents接收多个文档,返回二维列表,适合离线建立索引;embed_query接收一个查询字符串,返回一维向量,适合用户提问时实时调用。模型提供方可能对文档和查询使用不同的预处理策略,因此这两个接口不应混用。

三、从原始文档到可搜索索引

一个可复用的索引流程通常是:加载文档、切分文本、生成嵌入、写入向量存储。

fromlangchain_community.document_loadersimportUnstructuredMarkdownLoaderfromlangchain_text_splittersimportCharacterTextSplitterfromlangchain_openaiimportOpenAIEmbeddings loader=UnstructuredMarkdownLoader("docs/knowledge.md")raw_documents=loader.load()splitter=CharacterTextSplitter.from_tiktoken_encoder(encoding_name="cl100k_base",chunk_size=500,chunk_overlap=80,)documents=splitter.split_documents(raw_documents)embeddings=OpenAIEmbeddings(model="text-embedding-3-large")texts=[doc.page_contentfordocindocuments]vectors=embeddings.embed_documents(texts)print(len(documents),len(vectors[0]))

切分参数直接影响检索质量。块太大,检索结果会夹带大量无关内容,增加上下文成本;块太小,语义可能被截断。适度重叠可以减少关键信息刚好落在边界两侧的情况。代码、表格和标题明显的文档,还可以使用针对结构的分割器,尽量保持一个逻辑单元的完整性。

索引是离线、批量的准备过程。生产系统通常会在文档新增或更新时增量处理,而不是每次用户提问都重新计算全部向量。

四、向量存储:把向量变成可用的数据服务

手动保存向量并逐个计算距离很快就会遇到性能和管理问题。向量存储一般会提供:

  • 专用索引:使用近似最近邻等算法缩小候选范围,在规模和精度之间取得平衡。
  • 高效计算:利用底层向量库、SIMD 或 GPU 并行执行相似度计算。
  • 数据管理:支持新增、获取、删除、持久化、分布式扩展和元数据过滤。

LangChain 把不同后端统一成向量存储接口。开发阶段可以先使用内存存储验证链路:

fromlangchain_core.vectorstoresimportInMemoryVectorStore vector_store=InMemoryVectorStore(embedding=embeddings)ids=vector_store.add_documents(documents)found=vector_store.get_by_ids(ids[:2])vector_store.delete(ids=ids[:1])

内存存储适合测试和小规模实验,进程重启后数据会消失。需要持久化或多实例部署时,可以接入 Redis、Pinecone、Chroma、Qdrant、Milvus 等后端。选择后端时,应同时考虑数据规模、延迟、过滤需求、运维方式和成本,而不是只看向量检索速度。

元数据决定检索是否可控

每个 LangChainDocument至少包含文本内容和可选的元数据:

fromlangchain_core.documentsimportDocument doc=Document(page_content="向量检索根据语义返回相关文档",metadata={"source":"handbook.md","category":"engineering","version":3},)

元数据可以先于向量相似度做过滤,例如只搜索某个产品、某个版本或某个时间范围的资料。它能缩小候选集,也能避免把不同业务域的内容混在一起。使用 Redis 等后端时,应在初始化配置中声明字段类型,例如标签字段用tag,数值字段用numeric,否则后续过滤可能无法建立正确的索引。

五、相似性搜索与 MMR

最基本的搜索方式是similarity_search:把查询嵌入成向量,在向量库中找到最相近的k个文档。

docs=vector_store.similarity_search(query="如何设计数据库表?",k=4,)

需要调试召回质量时,可以同时返回分数:

scored_docs=vector_store.similarity_search_with_score(query="如何设计数据库表?",k=4,)fordoc,scoreinscored_docs:print(score,doc.metadata)

不同后端的分数定义可能不同,必须先确认“分数越高越相似”还是“分数越低越相似”,不能直接跨数据库比较阈值。

单纯按相似度取前几名,可能得到内容高度重复的片段。最大边际相关性(MMR)会先取一个较大的候选集,再兼顾查询相关性和结果之间的差异性:

docs=vector_store.max_marginal_relevance_search(query="如何提升服务性能?",k=4,fetch_k=16,)

fetch_k是第一阶段候选池大小,k是最终返回数量。候选池太小,MMR 没有足够空间做多样化;候选池太大,则会增加计算量。MMR 特别适合摘要、推荐和 RAG,因为它能减少上下文重复,让模型看到更多互补信息。

六、检索器:统一不同数据源的查询入口

信息检索系统的目标,是从大规模数据中快速找到与用户需求相关的内容。关系数据库擅长结构化条件和关联查询,倒排索引擅长词法匹配,向量数据库擅长语义相似度。它们都可以被包装成检索器。

LangChain 检索器的契约很简单:输入查询字符串,输出标准化的Document列表。向量存储可以直接转换为检索器:

retriever=vector_store.as_retriever(search_type="similarity",search_kwargs={"k":4},)docs=retriever.invoke("如何设计数据库表?")

还可以切换搜索策略:

retriever=vector_store.as_retriever(search_type="mmr",search_kwargs={"k":4,"fetch_k":16},)

检索器本身是一个Runnable,因此可以使用invoke,也能参与表达式组合。不过检索通常是同步、阻塞的,retriever.stream()不会把检索过程拆成逐块输出;真正可流式传输的通常是后续聊天模型生成的答案。

当内置检索器不够灵活时,也可以用@chain把自定义查询逻辑包装成相同的输入输出形态:

fromtypingimportListfromlangchain_core.documentsimportDocumentfromlangchain_core.runnablesimportchain@chaindefcustom_retriever(query:str)->List[Document]:returnvector_store.similarity_search(query,k=4)

这样可以把元数据筛选、权限判断或多路召回写进函数,同时继续复用 LangChain 的链式组合能力。

七、把检索器接入 RAG

RAG 的基本流程可以概括为:

  1. 用查询生成向量并召回相关文档。
  2. 把文档内容拼接成上下文。
  3. 将原始问题和上下文一起交给聊天模型。
  4. 通过输出解析器得到最终答案。

下面是一条完整但精简的 LCEL 链:

fromlangchain_openaiimportChatOpenAIfromlangchain_core.output_parsersimportStrOutputParserfromlangchain_core.promptsimportChatPromptTemplatefromlangchain_core.runnablesimportRunnablePassthrough model=ChatOpenAI(model="gpt-4o-mini")prompt=ChatPromptTemplate.from_messages([("human",""" 你是一个严谨的问答助手。只根据上下文回答问题;上下文没有答案时,直接说不知道。 问题:{question} 上下文:{context} 回答: """),])defformat_docs(docs):return"\n\n".join(doc.page_contentfordocindocs)rag_chain=({"context":retriever|format_docs,"question":RunnablePassthrough(),}|prompt|model|StrOutputParser())forchunkinrag_chain.stream("如何设计数据库表?"):print(chunk,end="",flush=True)

RunnablePassthrough会把原始问题原样传给提示词模板,同时让另一条分支负责检索和格式化上下文。这样,问题与上下文可以在同一个模板中汇合。需要注意,检索阶段仍然是准备工作,最终看到的流式输出来自模型生成阶段,而不是检索器本身。

八、让结果稳定的工程要点

保证维度一致。创建向量索引时的维度必须与嵌入模型输出维度一致;更换模型时,通常需要重建索引,不能把不同维度或不同语义空间的向量混在一起。

固定模型与版本。文档索引和在线查询必须使用同一套嵌入模型及兼容配置。模型升级后应通过离线评测确认召回质量,再决定是否迁移全部数据。

把切分当成数据建模。先确定文档的逻辑结构,再选择块大小、重叠长度和分割器。对标题、代码、表格进行特殊处理,往往比盲目增大k更有效。

让元数据可用。来源、租户、权限、版本、更新时间等信息应在入库时写入,并在检索前过滤。多租户系统尤其不能只依赖向量相似度来隔离数据。

区分召回和生成。检索器返回的是证据片段,不是最终答案。提示词要明确要求模型只使用给定上下文,并在证据不足时拒答,避免把“相似”误当成“事实”。

用评测而不是感觉调参。记录问题、召回文档、相似度分数和最终回答,分别评估召回率、上下文相关性、答案准确性和延迟。k、fetch_k、过滤条件和切分参数都应通过一组固定问题对比验证。

结语

文本向量把“含义”变成了可以计算的坐标,向量存储把这些坐标组织成可扩展的索引,检索器则把不同后端统一成简单的查询接口。再借助 LCEL,将检索结果与原始问题交给聊天模型,便形成了一条清晰的 RAG 数据通路。

真正可靠的应用并不取决于某个单独组件,而取决于整条链路是否闭环:数据切分合理、嵌入空间稳定、检索结果相关且多样、元数据过滤正确,最后让模型在有证据的范围内生成答案。掌握这套组件化思路后,无论后端使用内存存储、Redis 还是托管向量数据库,都可以在同一个编程模型下逐步演进。

相关新闻

  • 2026年五常大米厂家推荐全指南:五维评测,精准选型高价值合作伙伴 - 资讯快报
  • 文学翻译中的文化转译与风格再现
  • 别急着上 LangGraph:小团队上线 Agent 前,先算清权限与日志的账

最新新闻

  • Unlock Music Electron:打破音乐枷锁,让加密音频重获自由
  • 数字经济专业被捧成“黄金赛道”,2026年真实就业情况到底怎么样?
  • Steam创意工坊下载终极方案:WorkshopDL完全免费跨平台模组获取指南
  • 如何快速美化Mac微信界面:5大主题模式终极个性化指南
  • Linux服务器挖矿木马应急响应实战:从告警到根因定位的完整排查指南
  • 重庆江津区江南职教中心2026年招生简章——数控技术应用 - 学习招生

日新闻

  • Python开发内部工具:7大核心库实战解析
  • 合肥雷达官方2026年7月最新信息:客户服务网点地址与售后热线权威公示 - 亨得利官方服务中心
  • PCA实战指南:从变量纠缠诊断到主成分业务解读

周新闻

  • SaaS软件行业GEO实践:AI搜索时代的品牌可见性与获客新路径
  • 什么是PCTFE?医药高端包装的“防潮王牌“材料
  • 【JVM调优实战】16-可视化利器-JConsole-VisualVM-JMC

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号