news 2026/8/24 13:36:03

RAG23-RAG28

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RAG23-RAG28

RAG23LangChain 文档加载器 DocumentLoader & CSVLoader 笔记

一、核心概念

1. 文档加载器

  • 作用:提供标准接口,读取 PDF/CSV/JSON 等不同来源数据,统一转为 LangChain 的Document对象,做到一致化处理。
  • 所有加载器(内置 / 自定义)都继承实现BaseLoader接口。

2. Document 类(文档统一载体)

所有文档加载器最终返回Document实例

from langchain_core.documents import Document doc = Document( page_content="Hello, world!", # ✅文档正文内容 metadata={"source": "https://example.com"} # ✅元数据,字典格式,记录来源、行号等信息 )
  • page_content:文档文本内容
  • metadata:元数据,记录来源文件、行号、页码等附加信息

3. BaseLoader 的两个核心方法

表格

方法说明适用场景
load()一次性全部加载,返回List[Document]小文件;全部读到内存
lazy_load()延迟流式加载,返回生成器,for 循环迭代获取超大文件,防止内存溢出

所有加载器都具备这两个方法。

4. CSVLoader

专门用来读取 csv 文件,每一行 csv 生成一个Document对象。

  • 每一行 csv → 一个 Document 实例
  • page_content:该行各个字段拼接文本
  • metadata:记录文件 source、row 行号
  • 关键参数:
    • file_path:文件路径
    • encoding:文件编码,一般utf‑8
    • csv_args:字典,底层传给 python csv 库,可配置分隔符delimiter、引号quotechar、无表头时指定fieldnames字段名

⚠️fieldnames无表头 csv 才使用;如果 csv 自带表头,不要配置,否则会把表头当成数据行。

二、完整可运行代码

示例 1:基础 CSVLoader load () 一次性加载

from langchain_community.document_loaders.csv_loader import CSVLoader # 1. 创建加载器 loader = CSVLoader( file_path="./data/stu.csv", encoding="utf-8" ) # 2. load()一次性全部加载到内存,返回Document列表 documents = loader.load() # 遍历打印,查看每一个Document对象 for doc in documents: print(type(doc)) print("page_content:\n", doc.page_content) print("metadata:", doc.metadata) print("-" * 50)

示例 2:自定义 csv 解析参数 csv_args

from langchain_community.document_loaders.csv_loader import CSVLoader loader = CSVLoader( file_path="./data/stu.csv", encoding="utf-8", csv_args={ "delimiter": ",", # 指定字段分隔符 "quotechar": '"', # 字符串包裹引号 # "fieldnames": ["name","age","gender"] # 无表头csv才打开这个配置 } ) documents = loader.load() for d in documents: print(d)

示例 3:lazy_load () 流式大文件加载(生成器,节省内存)

from langchain_community.document_loaders.csv_loader import CSVLoader loader = CSVLoader( file_path="./data/stu.csv", encoding="utf-8" ) # lazy_load 返回生成器,不会一次性全部载入内存,适合超大csv for doc in loader.lazy_load(): print(doc.page_content) print(doc.metadata) print("="*40)

三、运行注意事项

  1. 目录结构:
P3_LangChainRAG开发 ├─ data │ └─ stu.csv └─ 22CSVLoader的使用.py
  1. 安装依赖
pip install langchain langchain-community langchain-core
  1. stu.csv 示例内容
name,age,gender 王梓涵,25,男 刘若曦,22,女 陈俊宇,20,男 赵思瑶,28,女 黄浩然,15,男 林雨桐,20,女 周博文,20,男 吴诗琪,24,女 马子轩,22,男 孙悦然,27,女
  1. 输出效果:每一行 csv 生成一个 Document 对象,metadata包含source文件路径和row行号。

四、面试简答速记

  1. Document 有哪两个核心属性?
  • page_content:文档正文;metadata:元数据字典。
  1. load()lazy_load()区别?
  • load():一次性加载全部文档返回列表,小文件;大文件会内存溢出。
  • lazy_load():生成器流式迭代读取,边读边处理,适合大文件,避免内存爆掉。
  1. CSVLoader 读取 csv,一行 csv 对应几个 Document? 一行 csv 生成一个 Document 对象

官方文档地址:https://docs.langchain.com/oss/python/integrations/document_loaders

RAG24、LangChain JSONLoader 笔记

一、概述

JSONLoader:把 JSON 文件加载为 LangChain 的Document文档对象,用于 RAG 知识库构建。

⚠️ 依赖第三方库jq,需要手动安装

pip install jq

底层依靠 jq 做 JSON 解析,通过jq_schema语法抽取 JSON 里面的数据。

jq_schema 抽取语法规则

表格

语法含义
.代表 JSON 根对象
[]代表数组
.name抽取根下 name 字段
.hobby[1]抽取 hobby 数组的第 2 个元素(下标从 0 开始)
.other.addr嵌套对象取值,取 other 里面 addr
.[]遍历数组,取出数组中每一个字典对象
.[].name遍历数组,取出数组每个对象的 name 字段

三种 JSON 文件格式

  1. 普通对象 stu.json
{ "name": "周杰伦", "age": 11, "hobby": ["唱", "跳", "RAP"], "other": { "addr": "深圳", "tel": "12332112321" } }
  1. 数组 JSON stus.json:外层[]包裹,内部多个对象
[ {"name": "周杰伦", "age": 11, "gender": "男"}, {"name": "蔡依临", "age": 12, "gender": "女"}, {"name": "王力宏", "age": 11, "gender": "男"} ]
  1. JsonLines 文件 stu_json_lines.jsonjson_lines=True每行一个独立 json 对象,整体没有外层数组
{"name": "周杰伦", "age": 11, "gender": "男"} {"name": "蔡依临", "age": 12, "gender": "女"} {"name": "王力宏", "age": 11, "gender": "男"}

二、JSONLoader 构造参数

from langchain_community.document_loaders import JSONLoader loader = JSONLoader( file_path="xxx.json", # 必填,json文件路径 jq_schema=".", # 必填,jq抽取表达式 text_content=True, # 可选,默认True:抽取结果转为字符串作为page_content;False保留dict对象 json_lines=False # 可选,默认False;True代表文件是JsonLines格式(每行一个json) )
  • file_path:文件路径,必填
  • jq_schema:jq 抽取语法,必填
  • text_contentTrue:把抽取内容转字符串放到page_contentFalsepage_content为字典对象
  • json_lines:是否是 JsonLines 文件,每行一条 json,默认 False

调用loader.load()返回List[Document]

三、完整可运行代码

文件目录:./data/下放三个 json 文件

from langchain_community.document_loaders import JSONLoader print("====案例1:读取普通对象stu.json,抽取name字段====") loader1 = JSONLoader( file_path="./data/stu.json", jq_schema=".name" ) docs1 = loader1.load() for doc in docs1: print(doc.page_content) print(doc.metadata) print("\n====案例2:读取stu.json,抽取hobby数组第二个元素====") loader2 = JSONLoader( file_path="./data/stu.json", jq_schema=".hobby[1]" ) docs2 = loader2.load() print(docs2[0].page_content) print("\n====案例3:读取数组 stus.json,遍历数组取出全部对象====") loader3 = JSONLoader( file_path="./data/stus.json", jq_schema=".[]" ) docs3 = loader3.load() for idx, doc in enumerate(docs3): print(f"{idx+1}: {doc.page_content}") print("\n====案例4:读取数组 stus.json,只抽取所有name====") loader4 = JSONLoader( file_path="./data/stus.json", jq_schema=".[].name" ) docs4 = loader4.load() for doc in docs4: print(doc.page_content) print("\n====案例5:读取JsonLines格式 stu_json_lines.json====") loader5 = JSONLoader( file_path="./data/stu_json_lines.json", jq_schema=".", json_lines=True ) docs5 = loader5.load() for doc in docs5: print(doc.page_content)

四、重点总结

  1. RAG25必须安装依赖pip install jq,否则报错
  2. jq_schema是核心,控制提取哪些内容;.代表根,.[]遍历数组
  3. json_lines=True专门处理每行一个独立 JSON的文件,不要用于普通数组 json
  4. text_content=Falsepage_content是字典;True会自动序列化为字符串,RAG 场景一般保持默认 True
  5. load()返回List[Document],每个 Document 包含page_contentmetadata(会自带 source、seq_num 元数据)

五、常见坑

  1. jq 语法写错,返回空文档;注意数组下标从 0 开始
  2. 混淆普通数组 json 和 json‑lines 文件,数组 json 不要设置json_lines=True
  3. 文件路径错误,相对路径注意 py 文件执行位置
  4. 没有安装 jq 库直接运行,直接抛出异常

RAG25、课程笔记:TextLoader 和 RecursiveCharacterTextSplitter

1、TextLoader 文本加载器

作用

读取.txt文本文件,把整个文件全部内容封装成 1 个 Document 对象,返回[Document],所以len(docs)=1

导入

from langchain_community.document_loaders import TextLoader
  • 参数
    • 文件路径:file_path
    • encoding:文件编码,中文 txt 一般填utf-8,防止乱码
  • 方法
    • .load():加载文档,返回 Document 列表

注意:TextLoader 不会做文本切分,不管 txt 多大,全部塞进一个 Document,大文件必须配合文本分割器做分片。

2、RecursiveCharacterTextSplitter 递归字符文本分割器

LangChain官方默认推荐的分割器,开箱即用效果最好。

核心特点

  1. 递归按照separators分隔符列表依次切割,优先按换行、句号等自然语义切割,兼顾上下文完整性 + 控制分片大小
  2. chunk_size:每个分片最大字符数
  3. chunk_overlap:分片之间重叠字符,解决被切到句子中间丢失上下文的问题。
  4. separators:分割优先级列表,优先用前面符号切割,切完还超长度就用下一个符号。
  5. length_function=len:使用 len 函数统计字符长度。
  6. 方法:.split_documents(docs),对 loader 加载出来的 Document 列表做分片,返回多个小 Document。

依赖安装

pip install langchain-text-splitters

完整可运行代码

from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # 1. 加载txt文本文件 loader = TextLoader( file_path="./data/Python基础语法.txt", encoding="utf-8" ) # 得到完整文档,只有1个Document docs = loader.load() print(f"加载后原始文档数量: {len(docs)}") # 2. 创建递归字符分割器 splitter = RecursiveCharacterTextSplitter( chunk_size=500, # 每一块最大字符数 chunk_overlap=50, # 块与块重叠字符 # 分割优先级:优先双换行,其次单换行,再句号、感叹号等 separators=["\n\n", "\n", "。", "!", "?", ".", "!", "?", " ", ""], length_function=len # 使用len统计字符长度 ) # 3. 执行文档切分 split_docs = splitter.split_documents(docs) print(f"切分之后分片数量:{len(split_docs)}") # 遍历打印每一个分片 for idx, doc in enumerate(split_docs): print("=" * 30 + f" 分片{idx+1} " + "=" * 30) print(doc.page_content) print("=" * 70)

知识点总结

  1. TextLoader:只负责读取 txt,输出单个 Document 对象的列表,不做分片。
  2. RecursiveCharacterTextSplitter:RAG 开发最常用分片工具
    • 按自然语义递归切割,不是暴力按字符截断
    • chunk_overlap重叠很关键:保证语义不会因为切割丢失
    • separators 有优先级,优先用列表靠前的符号分割
  3. RAG 标准流水线:Loader加载文档 → TextSplitter切分文档 → 向量化存入向量库

面试高频问题

Q:为什么要设置 chunk_overlap? A:防止一个完整语义句子被切分到两个 chunk,检索的时候上下文断裂;分片之间保留一部分重叠文本,保证语义连续性。

Q:RecursiveCharacterTextSplitter 和普通 CharacterTextSplitter 区别? A:普通分割器只用一个分隔符切割;递归分割器是一组分隔符递归尝试,优先用大粒度分隔符,保证尽可能在语义边界切分,效果更好。

RAG26、课程笔记:PyPDFLoader PDF 文档加载器

1、简介

PyPDFLoader:LangChain 社区提供的 PDF 文件加载器,底层依赖pypdf库,只提取 PDF 里面的文本内容,不能解析图片、扫描版 PDF

安装依赖

pip install pypdf

导入

from langchain_community.document_loaders import PyPDFLoader

构造参数

表格

参数说明
file_path必填,pdf 文件路径
mode读取模式:page(默认):每一页生成 1 个 Document 对象single:把整个 PDF 全部内容合并为1 个 Document
password可选,加密 PDF 的访问密码

两种加载方法

  1. .load():一次性全部加载,返回List[Document],小文件用;大 PDF 会占用较多内存。
  2. .lazy_load()惰性加载,迭代器,一页一页读取,不会一次性把全部内容载入内存,处理大 PDF 推荐使用

Document 对象的metadata元数据会自动携带页码信息{"page": 页码}

完整可运行代码

from langchain_community.document_loaders import PyPDFLoader # 1.实例化加载器 loader = PyPDFLoader( file_path="./data/pdf1.pdf", mode="page", # 默认page模式:一页一个Document # password="" # 如果pdf加密,填写密码 ) # ----------------方式1:load() 一次性全部加载---------------- docs = loader.load() print(f"总页数/文档数量:{len(docs)}") for idx, doc in enumerate(docs): print("=" * 40 + f" 第{doc.metadata['page']+1}页 " + "="*40) print(doc.page_content) # ----------------方式2:lazy_load() 惰性加载(大文件推荐)---------------- i = 0 for doc in loader.lazy_load(): i += 1 print("=" * 30, i) print(f"页码元数据:{doc.metadata}") print(doc.page_content)

结合 RecursiveCharacterTextSplitter 完整 RAG 流水线(PDF → 分片)

PDF 一页的文本依然很长,实际 RAG 项目中,PDF 加载完成后,仍然要交给分割器做语义分片

from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # 1.加载PDF loader = PyPDFLoader(file_path="./data/pdf1.pdf") pdf_docs = loader.load() # 2.初始化分割器 splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50, separators=["\n\n", "\n", "。", "!", "?", ".", "!", "?", " ", ""], length_function=len ) # 3.对PDF文档做切分 split_docs = splitter.split_documents(pdf_docs) print(f"原始pdf页数:{len(pdf_docs)},切分后分片总数:{len(split_docs)}") # 查看分片 for chunk in split_docs[:3]: print("-"*50) print(chunk.page_content) print(f"来源页码:{chunk.metadata['page']}")

重点总结

  1. mode="page":一页对应一个 Document,metadata 自带页码,方便溯源;single模式全部合并成 1 个 Document。
  2. .load():一次性加载;.lazy_load()惰性迭代读取,大 PDF 优先用 lazy_load,降低内存占用
  3. 局限:只能解析可复制文本的 PDF;扫描件、图片型 PDF 无法提取文字,此时要用 PyMuPDFLoader / UnstructuredLoader 或者 OCR 工具
  4. 项目流程:PyPDFLoader加载PDF → RecursiveCharacterTextSplitter分片 → 向量化存入向量库

面试小问题

Q:load()lazy_load()的区别? A:

  • load():把所有文档全部读到内存,返回完整列表,小文件方便;大 PDF 内存开销大。
  • lazy_load()返回迭代器,按需一页一页读取,不会一次性加载全部内容,内存友好,适合大体积 PDF 文件。

Q:PyPDFLoader 可以处理扫描版 PDF 吗? A:不行。扫描 PDF 本质是图片,没有文本流,PyPDF 拿不到文字,需要 OCR 识别方案。

RAG27、Vector stores 向量存储 课程笔记

这节课是 RAG 的核心,向量存储就是用来保存文本转出来的向量,做相似度检索。分为内存版(InMemoryVectorStore)持久化磁盘版(Chroma)

一、RAG 向量存储完整流程

分为两大阶段

  1. 索引 / 存储阶段(把文档入库)原始文档 → Embedding嵌入模型 → 嵌入向量 → 存入向量数据库
  2. 查询 / 检索阶段(用户提问)用户查询文本 → Embedding嵌入模型 → 查询向量 → 相似度搜索 → 返回Top‑k最相似文档

通俗理解: 把一堆文档变成一堆数字数组(向量)存起来;用户提问,也转成向量,计算和库里哪个向量最接近,把对应的原文拿出来给大模型参考。

二、LangChain 向量存储统一 3 个接口(所有向量库都有这 3 套方法)

  1. add_documents(documents, ids):新增文档,指定 id
  2. delete(ids=[...]):根据 id 删除文档
  3. similarity_search(query, k=N):相似度检索,k代表返回几条最相似的结果

k=4:就是取匹配度最高的 4 条文档

三、第一种:内存向量存储 InMemoryVectorStore

✅特点:数据放在内存,程序关闭数据全部丢失,只适合练习、测试,不能生产环境使用。

完整可运行代码

from langchain_core.vectorstores import InMemoryVectorStore from langchain_community.embeddings import DashScopeEmbeddings from langchain_community.document_loaders import CSVLoader # 1.初始化内存向量存储,指定阿里百炼的嵌入模型 vector_store = InMemoryVectorStore(embedding=DashScopeEmbeddings()) # 2.加载csv文档 info.csv loader = CSVLoader( file_path="./data/info.csv", encoding="utf-8", source_column="source" # metadata里标记数据来源 ) documents = loader.load() # 3.把文档写入向量库,手动生成id vector_store.add_documents( documents=documents, ids=["id"+str(i) for i in range(1, len(documents)+1)] ) # 4.根据id删除文档 vector_store.delete(ids=["id1","id2"]) # 5.相似度检索 k=3 返回3条结果 result = vector_store.similarity_search( query="Python是不是简单易学", k=3 ) # 打印检索结果 for doc in result: print("page_content:", doc.page_content) print("metadata:", doc.metadata) print("-"*50)

运行输出解读

返回的是list[Document]对象

  • page_content:原始文本内容
  • metadata:元数据,记录来源、行号 row、文档 id 等信息
  • exit code 0:代表代码无报错执行成功。

内存版坑点

程序一旦停止运行,内存释放,所有向量全部消失。重启代码,需要重新加载文档、重新向量化。

四、第二种:Chroma 外部持久化向量存储

✅特点:向量数据保存到本地磁盘文件(sqlite 数据库),程序关闭数据不会丢,下次启动可以直接读取,适合做项目开发。

需要先安装依赖

pip install langchain-chroma chromadb

完整可运行代码

from langchain_chroma import Chroma from langchain_community.embeddings import DashScopeEmbeddings from langchain_community.document_loaders import CSVLoader # 1.初始化Chroma向量库 vector_store = Chroma( collection_name="test", # 集合名,相当于表名 embedding_function=DashScopeEmbeddings(), # 嵌入模型 persist_directory="./chroma_db" # 磁盘文件夹,数据保存在这里 ) # 2.加载csv文档 loader = CSVLoader( file_path="./data/info.csv", encoding="utf-8", source_column="source" ) documents = loader.load() # 3.写入向量库 vector_store.add_documents( documents=documents, ids=["id"+str(i) for i in range(1, len(documents)+1)] ) # 4.删除文档 vector_store.delete(ids=["id1","id2"]) # 5.相似度检索 result = vector_store.similarity_search( query="Python是不是简单易学", k=3 ) for doc in result: print(doc.page_content) print(doc.metadata) print("-"*50)

Chroma 底层原理

运行之后项目目录生成chroma_db文件夹,里面是chroma.sqlite3数据库文件。

  • embeddings 表:存放二进制格式向量数组
  • segments 表:存放原始文本片段

可以直接用数据库工具打开 sqlite 文件查看底层表结构。

Chroma 重点注意

  1. 持久化:关闭程序,向量还保存在磁盘,再次运行代码不需要重新 add_documents,直接 new Chroma 读取文件夹就可以检索。
  2. 如果重复执行add_documents,会重复插入相同文档,产生重复向量。

五、内存版 vs Chroma 对比表

表格

对比项InMemoryVectorStore(内存)Chroma(磁盘持久化)
数据存储位置内存本地 sqlite 磁盘文件
程序重启数据全部丢失数据保留
适用场景课程练习、demo 快速测试本地 RAG 项目开发
接口方法add_documents / delete / similarity_search完全一模一样的 API

✨LangChain 设计思想:两套向量存储对外 API 完全统一,你写好业务代码,想切换存储,只需要改初始化那一行,后面增删查代码不用改动。

六、常见看不懂的知识点通俗解释

  1. 什么是 Embedding 向量?一段文字,交给嵌入模型,输出一串浮点数数字数组,语义越接近的文本,向量数字越接近。相似度搜索本质在计算向量之间的距离。
  2. k 参数是什么?similarity_search(xxx,k=3),k 就是我要从向量库里,拿出语义匹配度最高的 k 条文档给大模型做参考。k 不能太大,会把无关内容带进来。
  3. ids 参数干嘛用?每一条文档给一个唯一字符串 id,后续想删除哪条数据,直接传 id 列表,就可以精准删除对应向量和文本。
  4. Document 对象是什么?LangChain 封装文档对象:page_content存正文,metadata存附加信息(来源、行号),所有 loader 加载完文件输出都是list[Document]
  5. CSVLoader 参数source_columncsv 文件有一列叫 source,这一列的值自动保存到 Document 的 metadata,用来标记这条数据来自哪里。

七、踩坑清单

  1. InMemoryVectorStore:跑完程序数据就没了,不要拿来做正式项目。
  2. Chroma 如果重复运行 add_documents,会重复导入,产生重复向量。
  3. DashScopeEmbeddings 需要配置环境变量DASHSCOPE_API_KEY,否则向量化会报错。
  4. csv 文件必须保存 utf‑8 编码,否则 CSVLoader 读取中文乱码。

八、面试简答(巩固)

Q:InMemoryVectorStore 和 Chroma 有什么区别? A:InMemoryVectorStore 数据存内存,程序退出丢失,适合练习;Chroma 持久化到本地 sqlite 磁盘,重启数据保留。LangChain 提供统一接口,增删检索代码完全一致。

Q:similarity_search 的 k 参数含义? A:k 代表返回相似度最高的文档数量。

Q:向量存储在 RAG 中起到什么作用? A:存储文档对应的 embedding 向量;用户提问时把提问文本转为向量,做相似度检索,召回相关原文,交给大模型参考生成答案。

RAG28、课程:向量检索构建提示词

课程核心理解(通俗大白话)

这就是极简版 RAG 完整流程

  1. 先把一些参考文档放到内存向量库InMemoryVectorStore(内存版,程序关掉数据就消失,不用磁盘文件,适合上课练习)
  2. 用户输入问题怎么减肥?
  3. 向量库做相似度检索,拿出最相关的 2 条参考文本
  4. 把检索出来的参考资料塞到 Prompt 模板的{context}占位符,用户问题塞到{input}占位符
  5. 交给大模型:你只能参考我给你的资料来回答,不要瞎编
  6. 通过 LangChain 的管道符|组装 chain 链路,执行拿到回答

重点:InMemoryVectorStore内存向量库,不会保存到硬盘,程序关闭所有数据清空,只适合学习测试;生产用 Chroma/Milvus。

完整可直接运行代码 28 向量检索构建提示词.py

""" 提示词:用户的提问 + 向量库中检索到的参考资料 极简RAG演示 InMemoryVectorStore内存向量库 """ from langchain_community.chat_models import ChatTongyi from langchain_core.vectorstores import InMemoryVectorStore from langchain_community.embeddings import DashScopeEmbeddings from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 1.初始化大模型 model = ChatTongyi(model="qwen3-max") # 2.构建提示词模板 prompt = ChatPromptTemplate.from_messages( [ ("system", "以我提供的已知参考资料为主,简洁和专业的回答用户问题。参考资料:{context}。"), ("user", "用户提问: {input}") ] ) # 3.初始化内存向量库,指定阿里embedding向量化模型 vector_store = InMemoryVectorStore(embedding=DashScopeEmbeddings(model="text-embedding-v4")) # 4.add_texts:把参考文本列表存入向量库(内部自动做embedding) vector_store.add_texts([ "减肥就是要少吃多练", "在减脂期间吃东西很重要,清淡少油控制卡路里摄入并运动起来", "跑步是很好的运动哦" ]) # 用户问题 input_text = "怎么减肥?" # 5.相似度检索 k=2,取出最匹配的2条文档 result = vector_store.similarity_search(input_text, k=2) # 6.循环拼接检索出来的文档内容,组装参考上下文 reference_text = "[" for doc in result: # doc.page_content 就是原始文本内容 reference_text += doc.page_content reference_text += "]" # 小工具函数:打印中间生成的prompt,方便调试看传给大模型的完整消息 def print_prompt(prompt_value): print(prompt_value.to_string()) print("="*20) return prompt_value # 7.使用LCEL管道 | 组装执行链 chain = prompt | print_prompt | model | StrOutputParser() # 8.invoke传入参数字典,填充模板里面两个占位符 context、input res = chain.invoke({"input": input_text, "context": reference_text}) print("大模型最终回答:") print(res)

📝课程笔记

1. InMemoryVectorStore 内存向量库

  • 特点:全部数据在内存,程序退出全部丢失,不会生成本地文件
  • 适合:课堂快速实验,不用管理 chroma_db 文件夹
  • 方法:
    • add_texts(字符串列表):批量存入文本,内部自动调用 Embedding 转为向量
    • similarity_search(query, k=N):相似度检索,返回 Top‑k 最相似的 Document 对象
  • 返回值 result 是 Document 对象列表:
    • doc.page_content:原始文本内容
    • doc.metadata:元数据信息

2. RAG 在这里完整执行步骤

  1. 向向量库写入知识库文本
  2. 用户提问
  3. similarity_search检索获取相关文档片段
  4. 循环遍历检索结果,拼接成reference_text参考上下文
  5. 提示词模板有两个占位符
    • {context}:放向量库检索出来的参考资料
    • {input}:放用户真实问题
  6. LCEL 链路:prompt | print_prompt | model | StrOutputParser()
    • prompt:填充占位符生成完整消息
    • print_prompt自定义中间函数:打印中间 prompt(调试神器,看你到底传给模型什么文字)
    • model:通义千问大模型
    • StrOutputParser():把 ChatMessage 对象提取成普通字符串
  7. chain.invoke({"input":xxx, "context":xxx})传入字典给两个占位符赋值

3. 容易看不懂的地方拆解

reference_text = "["循环拼接
reference_text = "[" for doc in result: reference_text += doc.page_content reference_text += "]"

通俗讲:把检索出来 2 段文字拼在一起,外面包[ ],作为完整参考资料丢进 prompt 的{context}

print_prompt自定义函数为什么可以放进管道|

LCEL 管道|支持放入普通函数,输入是上一步输出,return 给下一级。 作用:调试!运行时控制台打印出完整发给大模型的 prompt 字符串,方便排查为什么模型回答不对。

③ invoke 传参字典
chain.invoke({"input": input_text, "context": reference_text})

模板里面有几个占位符,invoke 字典就要传几个 key。模板写了{context}{input},字典就必须带上这两个 key。

4. 和 Chroma 向量库区别对比

表格

项目InMemoryVectorStoreChroma
存储位置内存本地磁盘文件夹 persist_directory
持久化❌关闭程序数据消失✅保存到磁盘,下次运行还在
适用场景上课快速 demo真实 RAG 项目开发

5. 常见踩坑点

  1. 忘记配置DASHSCOPE_API_KEY环境变量,运行 Embedding 直接报错
  2. similarity_search(k=2)k 不能大于向量库里面文档总条数
  3. invoke 字典 key 名必须和模板占位符名字完全一致,大小写敏感
  4. InMemoryVectorStore 重启代码,必须重新执行add_texts添加数据,内存清空了

6. 本节课 RAG 核心逻辑(简答题,面试常考)

  1. 向量存储检索匹配相关参考信息
  2. 将用户提问、检索出来的参考资料一起填入提示词模板
  3. 将组装完整提示词交给大模型得到回答

核心思想:不修改模型权重,外部给资料,让模型基于给的资料回答

运行前确认

  1. 环境变量配置好DASHSCOPE_API_KEY
  2. 已经安装依赖包
pip install langchain langchain-community langchain-core dashscope
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 13:30:14

K8s(Kubernetes)简介及部署

​ 是容器编排管理平台,用来批量管理 Docker 这类容器,实现容器自动化部署、扩缩容、故障自愈,管理大量容器化应用。 原理 把多台服务器组成集群,划分两类角色: Master 控制节点:集群大脑,接收用…

作者头像 李华
网站建设 2026/8/24 13:28:27

单片机毕设项目:基于 51/STM32 单片机的育苗温室多维度环境智能管理系统设计 基于 51/STM32 单片机的小型智能温室硬件控制系统设计(017704)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/8/24 13:27:17

基于python+深度学习的面部健康特征判别系统的研究与实现

💗博主介绍:✌全网粉丝20W,CSDN全栈领域优质创作者,博客之星、掘金/华为云/阿里云等平台优质作者,计算机毕设实战导师。目前专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌ 💗主要服务内…

作者头像 李华
网站建设 2026/8/24 13:25:51

AI Agent自动化短剧生成:告别抽卡式创作,实现单人全流程制作

这次我们来看一个名为“告别抽卡 一人Agent直出ai短剧”的项目。简单说,这是一个利用AI Agent技术,让单个人就能完成从剧本到视频的AI短剧全流程制作的工具或方法。它瞄准的核心痛点,是传统AI视频制作中依赖“抽卡”(即反复随机生…

作者头像 李华
网站建设 2026/8/24 13:21:39

Python如何控制gpio

如何使用连接和操作GPIO引脚?我想晓得, 使用时该以怎样的方式去连接, 连接树莓派上的GPIO引脚, 还有常用的办法, 用来控制这些引脚的输入出, 输出入, 输入输出。连接和操作GPIO引脚的方法例如RPi.GPIO库 , 这种可被使用的GPIO库 , 能够去控制树莓派的GPIO引脚。借助…

作者头像 李华
网站建设 2026/8/24 13:20:06

低代码平台数智化:市场新拐点下的开发突围指南

当“降本增效”撞上“智能化瓶颈”过去两年,我们看到了太多关于低代码平台“降本增效”的宣传。但真正在一线推动数字化转型的企业从业者,心里都有一本账:表单和流程搭建确实快了,可业务部门对“智能化”的期待,却往往…

作者头像 李华