| 组件 | 作用 | 常用选择 |
|---|---|---|
| Document Loader | 加载原始文档 | MinerU, Docling |
| Text Splitter | 切分文档为 chunk | RecursiveCharacterTextSplitter |
| Embeddings | 文本转向量 | DashScopeEmbeddings, BGE-M3, qwen3-embedding:0.6b |
| Vector Store | 存储和检索向量 | InMemory(开发), Chroma(中小), Milvus(大规模) |
| Retriever | 标准检索接口 | vectorstore.as_retriever() |
一.文档加载(Document Loaders)
1.1 工作目录有示例文件却无法解析
python
#原代码
Document_loaders/sample.txt #--- 相对路径,依赖工作目录
相对路径 Document_loaders/sample.txt 解析的起点是当前工作目录(cwd),不是脚本所在目录。
实际解析:D:\python\project\Rag\Document_loaders\sample.txt ← 这个目录不存在

python
#修改
# 基于脚本所在目录构建路径,避免工作目录不同导致 FileNotFoundError
BASE_DIR = Path(__file__).parent
SAMPLE_PATH = BASE_DIR / "sample.txt"
langchain-community 正在被废弃,LangChain 官方不再维护它,正在把各功能拆成独立的包。
1.2 为什么执行CSVLoader的时候应输出内容不是sample.txt,而是新创建了SAMPLE_PATH?
python
#原代码
with open("SAMPLE_PATH","w",...) # ← 传的是字符串 "SAMPLE_PATH",不是变量 SAMPLE_PATH
loader = CSVLoader(file_path="SAMPLE_PATH", ...) # ← 同样的错误
给 SAMPLE_PATH 加了引号,所以 Python 把它当成一个字面量文件名字符串 "SAMPLE_PATH",而不是第 7 行定义的 Path 变量 SAMPLE_PATH(指向 sample.txt)。
python
#修改后
with open(SAMPLE_PATH,"w",...)
loader = CSVLoader(file_path=str(SAMPLE_PATH), ...)
1.3 Flash和Precision对比

本质区别
两种模式的根本差异在于服务端处理深度:
Flash 是轻量同步接口------直接抽取文本,公式/表格用正则快速识别,不做版面分析和图片提取,所以秒级返回但只产出纯 Markdown
Precision 是异步任务接口------提交后进入队列,服务端用 VLM 模型做完整版面分析(标题层级、阅读顺序、图片定位、公式 LaTeX 化、表格 HTML 化),轮询完成后返回全量结果
1.4 SDK,langchain,OCR对比

.env中格式:MINERU_TOKEN = 你的密钥。
注:MinerU不收费
二.文本切分(Text Splitters)
2.1 结构感知切分类名搞混
|----|---------------------------------------------------------------|----------------------------------------|
| 类 | MarkdownTextSplitter | MarkdownHeaderTextSplitter |
| 作用 | 按字符数切分(和 RecursiveCharacterTextSplitter 类似,只是自带 Markdown 分隔符) | 按 Markdown 标题层级切分,将标题信息写入 metadata |
| 参数 | 不接收 headers_to_split_on | 接收 headers_to_split_on=(关键字参数) |
2.2 五种常用 LangChain 文本切分方式对比
| 方法 | 切分单位 | 分隔符策略 | 保留结构 | 适用场景 |
|---|---|---|---|---|
| CharacterTextSplitter | 字符数 | 单一分隔符(如 \n) 在分隔符处切分 | 否 | 简单文本,行边界明确 |
| RecursiveCharacterTextSplitter | 字符数 | 多级分隔符依次尝试 \n\n → \n → . → 空格 | 否 | 通用文本,RAG 首选 |
| .from_tiktoken_encoder() | Token 数 | 先按分隔符尝试 再按 token 计数对齐 | 否 | 需精确控制 LLM token 用量 |
| MarkdownHeaderTextSplitter | 文档结构 | 按标题层级切分 # / ## / ### | 是 | Markdown / 技术文档 |
| 代码切分 .from_language() | 字符数 | 按语言语法切分 函数/类边界 | 部分 | 代码库文档 |
三. 向量化(Embeddings)
3.1 Ollama和DashScope对比

四. 向量库(Vector Stores)
4.1 md内容过少导致输出结果与想象的不一样
python
recursive_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=200,
)
4.1.1 相似度检索只查询第一页为什么两页内容同时输出
md 全文才 8 行、不到 400 字符,而 chunk_size=1000,所以 RecursiveCharacterTextSplitter 把整个文档切成1 个 chunk。
解决:
-
减小 chunk_size,让两页分开。
-
换更有区分度的查询词。
4.1.2 基于metadata 时filter 查的是 doc_2无任何数据输出
chunk_size=1000 只切出 1 个 chunk (doc_1)。你 filter 查的是 doc_2,库里根本不存在,所以空结果。
解决:缩小 chunk_size 让文档切成多块
4.2 similarity_search_with_relevance_scores检索成功后无分数
similarity_search_with_relevance_scores 是 LangChain VectorStore 的通用方法,Chroma 底层对 relevance score 的计算支持不稳定。
解决:换成 Chroma 原生的 similarity_search_with_score,直接返回原始距离分数
区别:
similarity_search_with_relevance_scores:LangChain 通用方法,底层依赖各 VectorStore 实现_relevance_score归一化函数,Chroma 对此支持不稳定,可能不返回分数similarity_search_with_score:Chroma 原生方法,直接返回 L2 距离,一定有分数
Chroma 返回的是 L2 距离,值越小越相似
五.检索器(Retriever)

