Skip to content

CMD137/PaperTutor

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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_sizechunk_overlap 会如何影响检索效果
  • 什么是 embedding,什么是向量维度
  • Milvus 中 collectionschemaindexsearch 各自是什么
  • LangChain 中 VectorStoreRetriever 各自负责什么
  • 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

建议阅读顺序:

  1. app.py
  2. config.py
  3. ingestion.py
  4. milvus_store.py
  5. chatbot.py
  6. prompts.py
  7. 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

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


12. 后续可扩展的学习方向

可以继续在这个项目上做这些扩展:

  1. 给 README 每章补思考题
  2. 给项目增加 tests/
  3. 增加检索结果可视化输出
  4. 比较不同 chunk 参数的实验结果
  5. 比较 langchain-milvus 与原生 pymilvus 的维护成本

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages