0 milvus前提知识:
本文只覆盖本项目需要的 Milvus 基础知识,重点是:
- Milvus 在 RAG 中的角色
langchain_milvus提供的主要抽象- 需要理解的核心概念、API 和参数
1. Milvus 的角色
Milvus 是向量数据库。
在 RAG 中,它负责两件事:
- 存储文档 chunk 的向量
- 根据问题向量检索最相近的 chunk
最小链路可以写成:
文档 -> 切块 -> embedding -> 存入 Milvus
问题 -> embedding -> 在 Milvus 检索 -> 返回相关 chunk
Milvus 不负责生成回答,它只负责:
存向量、找相似向量
2. 核心概念
2.1 Collection
Collection 可以理解成 Milvus 中的一张向量表。
一条记录通常对应一个 chunk,记录中除了向量,还会包含文本和 metadata。
2.2 Vector
向量是 embedding 模型把文本转换后的结果。
Milvus 不理解原始自然语言,但可以比较向量之间的相似度。
2.3 Dimension
维度就是向量长度,例如:
7681024
同一个 collection 的向量维度必须一致。
2.4 Search
Search 表示给定一个 query 向量,返回最相近的若干条记录。
2.5 Top-K
top-k 表示返回前多少条最相关结果。
在 LangChain 中通常对应:
search_kwargs={"k": ...}
3. langchain_milvus 的位置
langchain_milvus 是 LangChain 对 Milvus 的封装层。
关系可以理解成:
Milvus 数据库
↑
langchain_milvus
↑
VectorStore / Retriever
它的作用不是替代 Milvus,而是把 Milvus 接成 LangChain 可直接使用的接口。
4. langchain_milvus 主要 API
4.1 Milvus(...)
这是向量库对象本身。
典型写法:
vector_store = Milvus(
embedding_function=embedding,
collection_name=...,
connection_args=...,
)
作用:
- 连接 Milvus
- 绑定 embedding
- 关联指定 collection
- 提供 LangChain 风格的写入与检索接口
4.2 add_documents(...)
用于写入 Document 列表:
vector_store.add_documents(chunks)
背后会完成:
- 提取文本
- 提取 metadata
- 生成向量
- 写入 Milvus
4.3 similarity_search(...)
按文本问题直接做相似度检索。
它内部会:
- 先把问题做 embedding
- 再搜索 Milvus
- 最后把结果转回
Document
4.4 as_retriever(...)
把 vector store 包装成 LangChain Retriever:
retriever = vector_store.as_retriever(search_kwargs={"k": 4})
这是 LangChain RAG 代码里最常见的一步。
4.5 Retriever.invoke(...)
执行检索:
documents = retriever.invoke(question)
输入是问题,输出是相关 Document 列表。
5. 关键参数
5.1 collection_name
决定操作的是哪张 collection。
5.2 embedding_function
决定文本如何转换成向量。
5.3 EMBEDDING_DIM
决定期望的向量维度。
必须和 embedding 实际输出一致。
5.4 search_kwargs={"k": ...}
决定每次检索返回多少条结果。
5.5 metric_type
相似度度量方式。
文本 embedding 场景常用:
COSINE
6. 常见问题
6.1 向量维度不一致
如果:
- 配置维度
- embedding 实际输出维度
- collection schema 维度
三者不一致,就会出错,或者建出错误的 collection。
6.2 collection 复用
如果复用旧 collection,但配置已经变化,容易出现冲突。
测试不同维度或不同实验时,更安全的方式是使用新的 collection 名称。
6.3 高层封装的黑盒感
langchain_milvus 让代码更短,但也意味着:
- 底层细节被包起来了
- 出错时不如原生方式直观
它简化的是接入方式,不是底层原理。
LangChain + Milvus RAG 项目学习指南
本项目用于学习一个最小可运行的 LangChain RAG 系统:
- 使用
PyPDFLoader读取 PDF - 使用
RecursiveCharacterTextSplitter切分文档 - 使用 DashScope embedding 生成向量
- 使用 Milvus 存储和检索向量
- 使用 LangChain
Retriever+ Prompt + LLM 组织问答
当前推荐学习分支:
experiment/langchain-milvus-retriever
这条分支的重点是:
- 用
langchain-milvus理解 LangChain 风格的向量库接入 - 用
VectorStore/Retriever理解标准 RAG 链路 - 在保留 Milvus 的同时,观察 LangChain 封装层到底包装了什么
1. 学习目标
阅读和运行本项目时,应重点理解这些问题:
- RAG 与直接调用大模型的区别是什么
- 为什么长 PDF 需要切分成 chunk
chunk_size与chunk_overlap会如何影响检索效果- 什么是 embedding,什么是向量维度
- Milvus 中
collection、schema、index、search各自是什么 - LangChain 中
VectorStore与Retriever各自负责什么 langchain-milvus与原生pymilvus的代码组织差异是什么
2. 系统全景
项目的主链路如下:
PDF
-> Loader
-> Documents
-> Text Splitter
-> Chunks
-> Embedding
-> Milvus
-> Retriever
-> Prompt
-> LLM
-> Answer
可以再拆成两阶段:
阶段 A:建库
把论文变成可检索知识。
阶段 B:问答
把用户问题转成 query,检索相关 chunk,再交给 LLM 组织回答。
3. 项目结构
rag_app/
app.py
config.py
ingestion.py
milvus_store.py
chatbot.py
prompts.py
dashscope_embeddings.py
4. 模块说明
rag_app/app.py
项目入口,暴露两个命令:
ingest-paperschat
作用是接收命令并调用业务模块,不承担核心逻辑。
rag_app/config.py
统一读取 .env 配置,整理为 RagSettings。
重点配置包括:
EMBEDDING_MODELEMBEDDING_DIMMILVUS_URIMILVUS_TOKENMILVUS_DBMILVUS_COLLECTIONTOP_K
rag_app/ingestion.py
建库主流程:
load_documents
-> split_documents
-> add_documents
学习重点:
- LangChain
Document的结构 - chunk 切分的必要性
- chunk overlap 的作用
rag_app/milvus_store.py
将 Milvus 包装为 LangChain 可使用的 VectorStore。
学习重点:
- Milvus 本体负责 collection、schema、index、search
- LangChain 将其抽象为
add_documents()、similarity_search()、as_retriever() langchain-milvus并不改变 Milvus 原理,只是统一了调用接口
rag_app/chatbot.py
问答主链,关键结构是:
self.retriever = self.vector_store.as_retriever(
search_kwargs={"k": self.settings.k}
)
documents = self.retriever.invoke(question)
这体现了典型 RAG 分工:
VectorStore:存储与搜索能力Retriever:根据问题找证据LLM:阅读证据并组织回答
rag_app/prompts.py
定义提示词与回答规则。
重点不是文风,而是行为约束:
- 基于检索证据回答
- 不确定时明确说明
- 多子问题分项回答
- 尽量附带来源
rag_app/dashscope_embeddings.py
对 DashScope embedding 做项目级封装。
主要处理:
- 向量维度控制
- batch 限制
- 实际返回维度校验
5. 核心概念
5.1 Document
LangChain Document 通常包含:
page_contentmetadata
这表示 RAG 处理的不是纯文本,而是“文本 + 来源信息”。
5.2 Chunk
长文档不能直接整体做一个向量,因此需要切成更小的 chunk。
切分的原因包括:
- 让检索更精确
- 降低上下文冗余
- 让问题与局部内容匹配
5.3 Embedding
embedding 是把文本映射成向量。
Milvus 不理解自然语言,但可以比较向量之间的相似度。
5.4 Vector Dimension
向量维度是 schema 的一部分。
如果 collection 的向量字段按某个维度建好,后续写入的向量长度必须一致。
5.5 VectorStore
VectorStore 是 LangChain 对“向量存储 + 相似度搜索”的统一抽象。
在本项目中,底层实现是 Milvus。
5.6 Retriever
Retriever 是专门负责“根据问题找相关文档”的组件。
典型链路:
question -> retriever -> documents -> llm -> answer
6. 环境准备
安装依赖
python -m venv .venv
.\.venv\Scripts\activate
pip install -r requirements.txt
关键环境变量
DASHSCOPE_API_KEY=...
BASE_URL=...
MILVUS_URI=...
MILVUS_TOKEN=...
MILVUS_DB=paper_rag
MILVUS_COLLECTION=paper_chunks
EMBEDDING_MODEL=text-embedding-v4
EMBEDDING_DIM=1024
说明:
MILVUS_COLLECTION决定写入哪张 collectionEMBEDDING_DIM必须与实际输出向量长度一致- 测试不同维度时,建议使用新的 collection 名称
7. 常用命令
python -m rag_app.app --help
python -m rag_app.app ingest-papers 2310.11511v1.pdf
python -m rag_app.app chat
8. 学习顺序
第一遍:跑通
python -m rag_app.app ingest-papers 2310.11511v1.pdf
python -m rag_app.app chat
目标:
- 知道一个最小 RAG 项目怎样运行
第二遍:抓主线
重点看这几行:
vector_store.add_documents(chunks)
self.retriever = self.vector_store.as_retriever(...)
documents = self.retriever.invoke(question)
目标:
- 理解 LangChain 风格 RAG 的核心接口
第三遍:做实验
优先调整这些参数:
CHUNK_SIZECHUNK_OVERLAPTOP_KEMBEDDING_DIMMILVUS_COLLECTION
观察:
- 检索结果是否更集中
- 回答是否更具体
- 是否更容易丢失上下文
9. langchain-milvus 的典型问题
9.1 连接 alias 问题
langchain-milvus 内部混用了 MilvusClient 与 ORM alias 机制。
在某些版本组合下,可能出现:
ConnectionNotExistException: should create connection first.
这类问题通常不是凭证错误,而是连接管理衔接问题。
9.2 高层封装更黑盒
当代码写成:
vector_store.add_documents(chunks)
底层仍然会发生很多事:
- 文本与 metadata 提取
- embedding 调用
- collection 检查或初始化
- 写入与索引操作
优点是代码短,缺点是出错时不透明。
9.3 多层依赖的兼容性
链路涉及:
langchainlangchain-corelangchain-communitylangchain-milvuspymilvus
层数越多,兼容性风险越高。
10. 代码对照:langchain-milvus 包装了什么
10.1 建库写法
LangChain 风格
vector_store = get_vector_store(embeddings, settings)
vector_store.add_documents(chunks)
原生 pymilvus
texts = [chunk.page_content for chunk in chunks]
vectors = embeddings.embed_documents(texts)
rows = []
for chunk, vector in zip(chunks, vectors, strict=True):
rows.append(
{
"text": chunk.page_content,
"source": chunk.metadata.get("source", "unknown"),
"page": chunk.metadata.get("page", -1),
"vector": vector,
}
)
collection.insert(rows)
collection.flush()
langchain-milvus 在这里包装掉了:
- 从
Document提取文本和 metadata - embedding 调用衔接
- 写入结构转换
- 插入流程封装
10.2 检索写法
LangChain 风格
retriever = vector_store.as_retriever(search_kwargs={"k": 4})
documents = retriever.invoke(question)
原生 pymilvus
query_vector = embedding.embed_query(question)
results = collection.search(
data=[query_vector],
anns_field="vector",
param={"metric_type": "COSINE", "params": {}},
limit=4,
output_fields=["text", "source", "page"],
)
并手动转换为:
documents = []
for result in results[0]:
entity = result.entity
documents.append(
Document(
page_content=entity.get("text"),
metadata={
"source": entity.get("source", "unknown"),
"page": entity.get("page", "?"),
},
)
)
langchain-milvus 在这里包装掉了:
- query embedding 与搜索衔接
- 搜索结果解析
- 结果转
Document Retriever接口抽象
10.3 结论
langchain-milvus 包装的是接入细节,不是 RAG 原理。
它帮助简化:
- 文档转换
- 向量写入衔接
- 检索结果转换
- retriever 接口
它不会替代这些基础问题:
- 向量维度一致性
- chunk 设计
- top-k 选择
- embedding 质量
- 依赖兼容性
11. DashScope 维度参数说明
DashScope embedding 有两条常见调用路径:
OpenAI 兼容接口
参数名:
dimensions
DashScope SDK 原生接口
参数名:
dimension
本项目当前走的是 dashscope.TextEmbedding.call(...) 这条路径,因此必须使用:
dimension=768
如果误写成:
dimensions=768
可能会被静默忽略,并回退到模型默认维度。
源码:
结果示例:
(.venv) C:\Users\29924\Desktop\developtest\milvusTest>python -m rag_app.app ingest-papers 2310.11511v1.pdf
Starting ingestion...
Resolved input paths: [WindowsPath('2310.11511v1.pdf')]
Loading PDF: 2310.11511v1.pdf
Loaded 30 pages from 2310.11511v1.pdf
Loaded 30 source pages
Split into 150 chunks
Embedding config: {'model': 'text-embedding-v4', 'configured_dim': 768, 'embedding_object_dim': 768}
Probe document embedding dimension: 768
Adding chunk documents through langchain-milvus...
Stored 150 chunks into paper_chunks
Stored 150 chunks inside collection paper_chunks.
(.venv) C:\Users\29924\Desktop\developtest\milvusTest>python -m rag_app.app chat
Paper tutor ready. Type 'exit' to stop.
You: 讲讲self-rag
Timings:
- retrieval: 0.39s
- context_format: 0.00s
- llm_generation: 43.91s
- total: 44.31s
Tutor:
用户问题只包含一个子问题,即“讲讲self-rag”。
### 问题1: 讲讲SELF-RAG
**结论:**
SELF-RAG是一种改进的语言模型(LM),它通过在生成过程中引入自我反思机制来提升文本生成的质量、事实性和可验证性。
**解释:**
1. **自我反思机制:** SELF-RAG训练语言模型在生成任务输出的同时,生成一些特殊的标记(称为反射标记或reflection tokens),这些标记可以分为检索标记和批评标记。检索标记用于指示需要检索外部信息,而批评标记则用于评估生成内容的质量 [source: 2310.11511v1.pdf p1]。
2. **按需检索与处理:** 当模型判断出继续生成时需要补充外部信息时,会输出一个检索标记,触发检索器模型去获取相关信息。之后,SELF-RAG能够同时处理多个检索到的段落,评估它们的相关性,并基于此生成最终的任务输出 [source: 2310.11511v1.pdf p1]。这种方法相比传统的检索增强生成方法更加灵活,因为后者通常无论是否必要都会固定地检索一定数量的文档 [source: 2310.11511v1.pdf p2]。
3. **提高质量和可追溯性:** SELF-RAG不仅增强了生成文本的事实准确性,还提供了每个生成部分的引用来源及其自我评估结果,使得更容易进行事实验证 [source: 2310.11511v1.pdf p2]。此外,通过细粒度的自我反思过程,该模型能够选择最佳可能的输出,从而提高了生成内容的整体质量 [source: 2310.11511v1.pdf p4]。
**局限:**
根据当前提供的上下文,没有提到SELF-RAG的具体实现细节如使用的数据集名称、确切的训练步骤等技术细节。
**追问建议:**
- SELF-RAG是如何具体实现对检索到的信息进行相关性评价的?
- 在实际应用中,SELF-RAG相比其他RAG方法有哪些具体的性能优势?