当前位置: 首页 > news >正文

大模型应用开发(十八)_向量检索

6. Embedding

Embedding(嵌入向量)是一种把文字、图像、音频等“非数值信息”转换成可计算的数字向量的技术。

在自然语言处理中,它最常见的用途是把句子、段落或单词转换成一串浮点数列表(通常是几百或几千维的向量),以便计算机能理解和比较它们之间的语义关系。


举个例子

假设有三句话:

  1. “我喜欢苹果”
  2. “我爱吃水果”
  3. “我今天去跑步了”

模型会将它们转换成如下向量(示意):

[0.12, -0.34, 0.56, ...] # 我喜欢苹果 [0.10, -0.32, 0.60, ...] # 我爱吃水果 [-0.45, 0.22, 0.11, ...] # 我今天去跑步了

前两条的向量在空间上“更接近”,说明它们语义相似(都与“吃水果”相关),

而第三条则比较远,语义差别大。


Embedding 常见用途

场景说明
🔎 文本相似度判断两句话或文档的语义是否接近(比如检索问答)
📚 向量数据库将大量文本嵌入向量后存入数据库,用于 RAG 检索增强生成
🧠 聚类与分类用向量表示样本,再进行聚类或分类
🗣️ 语义搜索用户输入一句话,系统找出语义最相近的文本
🤖 推荐系统计算物品或用户的向量相似度进行推荐

文本向量化工具代码实例

通过环境变量动态选择 OpenAI 或国产免费 API(如硅基流动),将文本转换为机器可理解的数字向量,以便进行后续的语义搜索或文档匹配。

注:该代码需要去https://cloud.siliconflow.cn/注意账号获取密钥,这次用他的向量模型,免费的。

.env配置如下

DEEPSEEK_API_KEY = "yourkey" DEEPSEEK_BASE_URL = "<https://api.deepseek.com>" OPENAI_API_KEY = "yourkey" OPENAI_BASE_URL = "<https://api.aigc369.com/v1>" # 向量嵌入用 硅基流动 (免费) EMBEDDING_API_KEY=yourkey EMBEDDING_BASE_URL=https://api.siliconflow.cn/v1 EMBEDDING_MODEL=BAAI/bge-m3

具体代码如下

import os from dotenv import load_dotenv from langchain_openai import OpenAIEmbeddings # 1. 加载环境变量 load_dotenv() # 2. 逻辑开关:True 用 OpenAI 官方,False 用硅基流动(或其他兼容接口) use_openai = os.getenv("USE_OPENAI", "false").lower() == "true" if use_openai: config = { "api_key": os.getenv("OPENAI_API_KEY"), "base_url": os.getenv("OPENAI_BASE_URL"), # 默认是 <https://api.openai.com/v1> "model": "text-embedding-3-large" } else: # 硅基流动配置 (免费使用 BAAI 系列模型) config = { "api_key": os.getenv("EMBEDDING_API_KEY"), "base_url": os.getenv("EMBEDDING_BASE_URL"), # 例如 <https://api.siliconflow.cn/v1> "model": "BAAI/bge-m3" # 推荐模型,中文支持极好 } # 3. 初始化嵌入模型 embeddings = OpenAIEmbeddings( model=config["model"], openai_api_key=config["api_key"], openai_api_base=config["base_url"] ) # 4. 要嵌入的文本 texts = ["狗", "猫", "你好", "你好啊", "你叫什么名字?", "我叫王大锤", "很高兴认识你,大锤"] # 5. 计算并输出 try: results = embeddings.embed_documents(texts) print(f"--- 当前模型: {config['model']} ---") print(f"向量条数: {len(results)}") print(f"维度: {len(results[0])}") print(f"前 5 个数值: {results[0][:5]}") except Exception as e: print(f"运行失败,请检查 API Key 或 Base URL。错误信息: {e}")

6.1 检索增强生成系统

代码实例

它先利用向量数据库从本地文档中“捞出”相关线索,再交给 DeepSeek 模型进行逻辑筛选和总结,从而确保即使检索结果存在细微偏差,也能给出精准、不被干扰的最终答案。

注:这里由于向量模型质量不好,采用了模型纠偏,把检索结果给了模型让他来帮我选择。

具体代码

import os from dotenv import load_dotenv from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain.docstore.document import Document from langchain_community.vectorstores import FAISS from langchain.prompts import ChatPromptTemplate # 1. 加载环境变量 load_dotenv() # --- 配置:向量模型使用硅基流动,对话模型使用 DeepSeek --- # 向量配置 emb_config = { "api_key": os.getenv("EMBEDDING_API_KEY"), "base_url": os.getenv("EMBEDDING_BASE_URL"), "model": "BAAI/bge-m3" } # 对话配置 llm_config = { "api_key": os.getenv("DEEPSEEK_API_KEY"), "base_url": os.getenv("DEEPSEEK_BASE_URL"), "model": "deepseek-chat" } # 2. 初始化模型 embeddings = OpenAIEmbeddings( model=emb_config["model"], openai_api_key=emb_config["api_key"], openai_api_base=emb_config["base_url"] ) llm = ChatOpenAI( model=llm_config["model"], openai_api_key=llm_config["api_key"], openai_api_base=llm_config["base_url"] ) # 3. 原始文本库 texts = [ "我的个人爱好是去看电影。", "《带我飞往月球》是我最喜欢的歌曲之一。", "凯尔特人队是我最喜欢的球队。", "这是一篇关于波士顿凯尔特人的文件资料。", "篮球是一项伟大的竞技活动。", "波士顿凯尔特人队以20分的优势赢得了比赛", "《艾尔登之环》是过去15年最好的游戏之一。", "拉里·伯德是一位标志性的NBA球员。" ] documents = [Document(page_content=text) for text in texts] db = FAISS.from_documents(documents, embeddings) # 4. 核心 RAG 流程 def rag_answer(query): print(f"\\n[用户提问]: {query}") # 第一步:检索(为了确保搜到,我们取前 3 名) # BGE 模型建议加上指令前缀 processed_query = f"为这个句子生成表示以用于检索相关文章:{query}" retrieved_docs = db.similarity_search(processed_query, k=3) # 打印一下捞上来的鱼 print(f"[检索到的线索]: {[d.page_content for d in retrieved_docs]}") # 第二步:构造 Prompt 将线索喂给 DeepSeek context = "\\n".join([f"- {d.page_content}" for d in retrieved_docs]) prompt = ChatPromptTemplate.from_template(""" 你是一个严谨的助手。请仅基于以下提供的【参考资料】来回答用户的问题。 如果资料中没有相关信息,请直接回答“不知道”。 【参考资料】: {context} 【用户问题】: {question} """) # 第三步:LLM 生成答案 chain = prompt | llm response = chain.invoke({"context": context, "question": query}) print(f"[DeepSeek 回答]: {response.content}") print("-" * 60) # 5. 运行测试 if __name__ == "__main__": rag_answer("关于我的爱好你知道些什么?") rag_answer("我最喜欢的歌曲是什么?")

6.2 重写问题(Rephrase)

rephrase_prompt = hub.pull("langchain-ai/chat-langchain-rephrase")

LangChain Hub的用法。它的作用是:

从官方或社区的「提示词模板仓库(LangChain Hub)」中下载一个标准 Prompt 模板。


具体解释

LangChain Hub 是一个集中存放常用 Prompt 的平台,类似于“Prompt 代码仓库”。

上面那行代码:

rephrase_prompt = hub.pull("langchain-ai/chat-langchain-rephrase")

等价于做了这件事:

从 langchain-ai 的仓库里拉取一个名为 "chat-langchain-rephrase" 的提示模板,用于 重写用户输入的问题。


1.为什么要重写问题?

RAG 对话系统中,我们希望模型能结合上下文理解用户提问。

举个例子:

用户:RAG之父是谁? (上文问过“中国大模型RAG之父是谁”)

如果你直接把这个问题送去检索,Retriever 不知道“RAG之父”指谁。

所以我们要用一个 Prompt 让模型改写:

把用户的问题改写成包含上下文的独立问题: "RAG之父是谁?" ➜ "中国大模型RAG之父是谁?"

这就是chat-langchain-rephrasePrompt 的功能。


代码实例

具体代码

import os from dotenv import load_dotenv from langchain_community.document_loaders import TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import FAISS from langchain import hub from langchain.chains import create_history_aware_retriever, create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain.prompts import ChatPromptTemplate # 1. 加载环境变量 load_dotenv() # --- 配置:DeepSeek 对话 + 硅基流动向量 --- emb_config = { "api_key": os.getenv("EMBEDDING_API_KEY"), "base_url": os.getenv("EMBEDDING_BASE_URL"), "model": "BAAI/bge-m3" } llm_config = { "api_key": os.getenv("DEEPSEEK_API_KEY"), "base_url": os.getenv("DEEPSEEK_BASE_URL"), "model": "deepseek-chat" } # 2. 加载与分块 loader = TextLoader(r"D:\\python object\\DeepSeek\\LangChain\\RAG\\demo.txt", encoding='utf-8') docs = loader.load() text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=40) texts = text_splitter.split_documents(docs) print(f"✅ 文档加载完成,共分割 {len(texts)} 段") # 3. 初始化 Embedding (兼容 OpenAI 格式的硅基流动) embeddings = OpenAIEmbeddings( model=emb_config["model"], openai_api_key=emb_config["api_key"], openai_api_base=emb_config["base_url"] ) db = FAISS.from_documents(texts, embeddings) # 4. 检索器 (k=3 表示检索最相关的3个片段) retriever = db.as_retriever(search_kwargs={"k": 3}) # 5. 初始化 DeepSeek 作为 LLM llm = ChatOpenAI( model=llm_config["model"], openai_api_key=llm_config["api_key"], openai_api_base=llm_config["base_url"] ) # 6. 加载重写问题提示模板 (从历史对话中提炼独立问题) rephrase_prompt = hub.pull("langchain-ai/chat-langchain-rephrase") # 7. 创建具备“历史感知”的检索器 # 注意:这里由 DeepSeek 负责将“他毕业于哪?”改写为“XX(人名)毕业于哪?” history_aware_retriever = create_history_aware_retriever( llm=llm, retriever=retriever, prompt=rephrase_prompt ) # 8. 回答用 Prompt 模板 qa_prompt = ChatPromptTemplate.from_template(""" 你是一个专业的知识问答助手。请基于以下【参考资料】回答用户问题。 如果你在资料中找不到答案,请诚实回答不知道,不要胡乱猜测。 【参考资料】: {context} 【当前对话历史】: {chat_history} 【用户问题】: {input} """) # 9. 构建文档处理链 document_chain = create_stuff_documents_chain(llm, qa_prompt) # 10. 构建最终 RAG 对话链 rag_chain = create_retrieval_chain(history_aware_retriever, document_chain) # 11. 对话循环测试 chat_history = [] def ask(question, chat_history): # 调用对话链 response = rag_chain.invoke({ "input": question, "chat_history": chat_history }) answer = response.get("answer", "") context_docs = response.get("context", []) print(f"\\n🧠 问题:{question}") print(f"💬 答案:{answer}") # 输出引用来源 if context_docs: print("📚 参考片段:") for i, doc in enumerate(context_docs, 1): print(f" [{i}] {doc.page_content.strip()[:100]}...") # 这一步至关重要:手动更新对话历史到列表中 chat_history.append({"role": "user", "content": question}) chat_history.append({"role": "assistant", "content": answer}) if __name__ == "__main__": ask("中国大模型RAG之父是谁?", chat_history) ask("他毕业于哪所学校?", chat_history)

6.3 chain_type

在 LangChain 中,chain_type是构建文档问答(RAG)时的关键参数之一。它决定了检索到的文档如何与 LLM 结合使用。下面是一张完整的对比表格,帮你清楚理解常见的chain_type类型及其差异


1.LangChain 中常见的chain_type类型对比表

chain_type 名称核心逻辑工作方式适用场景优点缺点是否支持多文档
stuff直接“塞入”所有检索结果将所有文档拼接成一个大字符串,一次性喂给 LLM小规模文档、短上下文简单高效、实现最容易超出上下文窗口容易截断;无法处理长文档✅ 是
map_reduce分段总结再汇总“map”阶段每个文档单独生成回答;“reduce”阶段合并结果长文本、需要汇总总结的任务可处理超长内容,节省上下文结构复杂、速度慢✅ 是
refine逐步优化答案先用第1篇文档生成初稿,之后每篇文档依次优化答案文档之间互相关联、需要累积推理输出更完整连贯耗时长,对Prompt设计要求高✅ 是
map_rerank并行生成并评分每个文档单独回答并附带分数,最后选出最高分答案需要最可靠答案、检索结果差异大精确、可控性高计算量大、慢✅ 是
self_query模型自生成检索条件模型先生成检索查询再检索文档智能RAG(自动选择检索内容)语义匹配强依赖模型能力✅ 是
contextual_compression压缩冗余上下文先用LLM压缩冗余信息,再进入问答链冗长文档或重复内容较多降低token消耗需要额外LLM调用✅ 是
retrieval_qa通用封装自动将检索器与问答链拼接快速构建RAG原型一行构建、简单易用细节控制少✅ 是

2.举个例子:

from langchain.chains import RetrievalQA qa_chain = RetrievalQA.from_chain_type( llm=ChatOpenAI(), retriever=my_retriever, chain_type="stuff" # 👈 可改为 map_reduce、refine、map_rerank 等 )
示例说明
stuff把检索到的3段文字拼接成一个输入直接问LLM
map_reduce每段文字分别回答后再总结最终答案
refine先看第1段答一遍,然后依次用后面几段改进答案
map_rerank每段文字答一遍并评分,取分数最高的那个答案

3.推荐选择建议:

使用场景推荐 chain_type理由
简单问答、短文档stuff最快、最稳
文档很长map_reduce能处理超长文本
逻辑性强、答案需完善refine输出连贯、逐步优化
检索质量参差不齐map_rerank通过评分自动筛选最优答案

6.4 RAGFromPDF

运行代码:

python -m streamlit run "D:\\python object\\DeepSeek\\LangChain\\RAG\\RAGFromPDF\\main.py"

解析PDF项目代码,如有需求请私信。

http://www.cnnetsun.cn/news/106659.html

相关文章:

  • NVIDIA显卡设置终极指南:从问题诊断到性能优化的完整解决方案
  • 聚星成链,蓝卓牵头成立“工厂操作系统生态联盟”共建产业新生态
  • 每天一道面试题之架构篇|可靠订单状态机与事务消息架构设计
  • 10分钟掌握开源美颜SDK核心技术:从算法原理到商业应用实战
  • EmotiVoice支持哪些语言?多语种语音合成能力测试报告
  • AI语音合成进入情感时代:EmotiVoice带来全新听觉体验
  • EmotiVoice支持WebAssembly吗?浏览器端运行可能性分析
  • StaMPS雷达数据处理:从零搭建专业位移监测系统
  • yt-dlp-gui终极指南:轻松掌握Windows视频下载利器
  • EmotiVoice是否支持语音情感随机扰动?增强自然感功能
  • QRemeshify终极指南:快速创建高质量四边形网格的完整教程
  • 如何免费获得高质量语音合成能力?EmotiVoice给你答案
  • Hive SQL中COALESCE 函数和NVL()函数、IFNULL函数区别
  • 四边形网格生成实战指南:掌握QuadriFlow高效工作流
  • 如何快速解决AMD GPU识别问题:终极故障排查指南
  • OpenProject企业版深度解析:从开源到商业化的全面升级
  • Next.js认证系统实战:基于Clerk的完整解决方案
  • DeepBench如何帮助你在5分钟内完成深度学习硬件性能精准评估?
  • PCB文件处理终极指南:用Python轻松解析Gerber和Excellon文件
  • 革命性API测试工具:WireMock UI让接口模拟变得前所未有的简单
  • EmotiVoice能否用于智能家居控制反馈?轻量级语音提示生成
  • Lime编辑器极速上手:从零到精通的避坑指南
  • Wan2.2模型AI视频生成实战指南:从设备配置到创意实现
  • 有声读物制作神器!EmotiVoice让朗读充满感情色彩
  • FanControl完全指南:3步学会Windows风扇智能控制
  • 管理实战案例丨华恒智信助力某大型电力设计公司人才梯队构建项目——以标准、方法与引导三维体系,破解央企人才甄选与发展难题
  • 5个Llama模型访问难题的终极解决方案指南
  • 终极Element Plus自动化部署指南:Jenkins与GitHub Actions实战全解析
  • 虚拟偶像配音难题破解:EmotiVoice提供自然情感语音方案
  • 如何用Zotero和Obsidian打造终极学术写作工作流?3个实战场景揭秘