LangChain + Milvus RAG :PaperTutor论文助教

0 milvus前提知识:

本文只覆盖本项目需要的 Milvus 基础知识,重点是:

  • Milvus 在 RAG 中的角色
  • langchain_milvus 提供的主要抽象
  • 需要理解的核心概念、API 和参数

1. Milvus 的角色

Milvus 是向量数据库。

在 RAG 中,它负责两件事:

  1. 存储文档 chunk 的向量
  2. 根据问题向量检索最相近的 chunk

最小链路可以写成:

文档 -> 切块 -> embedding -> 存入 Milvus
问题 -> embedding -> 在 Milvus 检索 -> 返回相关 chunk

Milvus 不负责生成回答,它只负责:

存向量、找相似向量


2. 核心概念

2.1 Collection

Collection 可以理解成 Milvus 中的一张向量表。

一条记录通常对应一个 chunk,记录中除了向量,还会包含文本和 metadata。

2.2 Vector

向量是 embedding 模型把文本转换后的结果。

Milvus 不理解原始自然语言,但可以比较向量之间的相似度。

2.3 Dimension

维度就是向量长度,例如:

  • 768
  • 1024

同一个 collection 的向量维度必须一致。

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

按文本问题直接做相似度检索。

它内部会:

  • 先把问题做 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 中 collectionschemaindexsearch 各自是什么
  • 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-papers
  • chat

作用是接收命令并调用业务模块,不承担核心逻辑。

rag_app/config.py

统一读取 .env 配置,整理为 RagSettings

重点配置包括:

  • EMBEDDING_MODEL
  • EMBEDDING_DIM
  • MILVUS_URI
  • MILVUS_TOKEN
  • MILVUS_DB
  • MILVUS_COLLECTION
  • TOP_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_content
  • metadata

这表示 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 决定写入哪张 collection
  • EMBEDDING_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_SIZE
  • CHUNK_OVERLAP
  • TOP_K
  • EMBEDDING_DIM
  • MILVUS_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 多层依赖的兼容性

链路涉及:

  • langchain
  • langchain-core
  • langchain-community
  • langchain-milvus
  • pymilvus

层数越多,兼容性风险越高。


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

可能会被静默忽略,并回退到模型默认维度。

源码:

CMD137/PaperTutor

结果示例:

(.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方法有哪些具体的性能优势?
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇