ResearchPilot 第三阶段总结报告

一、第三阶段基本信息

项目名称:

ResearchPilot------可追溯科研文献分析与问答系统

第三阶段版本:

V0.3.0:PDF 文本切分、向量化、语义检索与基础 RAG 问答

第三阶段是在 V0.2 已经完成"PDF 上传、解析、保存和查看"的基础上,把普通 PDF 文本进一步转换成可以被人工智能检索和问答的知识库。

第三阶段完整流程为:

复制代码
PDF逐页文本
    ↓
文本清理
    ↓
文本切分
    ↓
文本块保存到SQLite
    ↓
Embedding向量化
    ↓
向量保存到ChromaDB
    ↓
用户问题向量化
    ↓
语义检索相关文本块
    ↓
将检索结果发送给DeepSeek
    ↓
生成带页码和文本块引用的回答

二、第三阶段开发目标

V0.2 解决的是:

如何把一篇 PDF 读取出来,并把逐页文本保存到数据库。

V0.3 解决的是:

如何从一篇长论文中找到与用户问题最相关的内容,并基于这些内容生成可追溯回答。

一篇论文可能有几万甚至十几万字符,不能直接把整篇论文一次性发送给大模型。因此,第三阶段首先将论文拆成较小的文本块,再对文本块建立向量索引。


三、V0.3.1:PDF 文本切分

1. 新增文本切分模块

新增文件:

复制代码
src/text_chunker.py

主要负责:

复制代码
清理PDF文本
寻找自然切分位置
按照指定长度切分
保留相邻文本块重叠区域
记录原始PDF页码
生成全文连续文本块编号

核心函数包括:

复制代码
normalize_text()
split_text()
build_document_chunks()

2. 文本清理

PDF 提取出的文本通常存在:

复制代码
连续空格
多余换行
制表符
全角空格
不同操作系统换行符

因此先进行标准化处理,例如:

复制代码
text = text.replace("\r\n", "\n")
text = text.replace("\r", "\n")

再通过正则表达式合并连续空格和换行。

文本清理的目的不是改变论文含义,而是减少无效字符,提升切分和检索效果。


3. 文本块长度与重叠区域

当前默认参数为:

复制代码
每个文本块最大字符数:800
相邻文本块重叠字符数:150

切分效果类似:

复制代码
文本块1:字符0~800
文本块2:字符650~1450
文本块3:字符1300~2100

重叠区域的作用是防止一个完整句子或知识点刚好在切分边界被截断。

如果完全没有重叠:

复制代码
文本块1结尾:该方法主要采用......
文本块2开头:卷积神经网络进行特征提取

单独检索任意一个文本块时,语义可能不完整。

增加重叠后,相邻文本块会保留一部分共同内容,使上下文更加连续。


4. 自然切分位置

程序并不是机械地每 800 个字符直接切断,而是尝试在最大长度附近寻找:

复制代码
段落
换行
句号
问号
感叹号
分号
逗号
空格

例如,在第 760 个字符附近存在句号时,会优先在句号后切分,而不是强制切到第 800 个字符。

这种方式可以提高文本块的完整性。


5. 保留页码

当前版本规定:

一个文本块只属于一页 PDF,不跨页切分。

每个文本块包含:

复制代码
{
    "chunk_index": 1,
    "page_chunk_index": 1,
    "page_number": 3,
    "chunk_text": "文本块正文",
    "character_count": 782,
}

其中:

  • chunk_index:整篇论文中的文本块编号;
  • page_chunk_index:当前页面中的文本块编号;
  • page_number:原始 PDF 页码;
  • chunk_text:文本块内容;
  • character_count:文本块字符数。

保留页码是实现可追溯回答的重要基础。


四、pdf_chunks 数据库设计

第三阶段在 SQLite 中新增:

复制代码
pdf_chunks

主要字段包括:

字段 作用
id 文本块主键
document_id 所属 PDF 文档编号
page_number 原始 PDF 页码
chunk_index 整篇 PDF 中的文本块编号
page_chunk_index 当前页中的文本块编号
chunk_text 文本块正文
character_count 文本块字符数
chunk_size 切分时设置的最大字符数
overlap_size 切分时设置的重叠字符数
created_at 创建时间

数据库关系变为:

复制代码
pdf_documents
├── pdf_pages
└── pdf_chunks

一篇 PDF 对应多条页面记录,也对应多条文本块记录。

删除 PDF 时,SQLite 会通过外键级联删除:

复制代码
PDF基本信息
PDF逐页文本
PDF文本块

重新切分机制

如果用户修改参数:

复制代码
800 / 150

改为:

复制代码
1000 / 200

系统不会直接在旧数据后继续添加,而是:

复制代码
删除这篇PDF原来的文本块
    ↓
按照新参数重新切分
    ↓
保存新的文本块

这样可以避免同一篇论文同时存在多套重复文本块。


五、V0.3.2:Embedding 向量化

1. 新增向量化模块

新增文件:

复制代码
src/embedding_service.py

主要负责:

复制代码
加载Embedding模型
把论文文本块转换成向量
把用户问题转换成向量
缓存已经加载的模型
返回向量维度

当前使用的多语言 Embedding 模型支持中文和英文检索。

向量维度为:

复制代码
384维

也就是说,一段论文文本最终会转换为类似:

复制代码
[
    0.013,
    -0.027,
    0.041,
    ...
]

总共 384 个浮点数。


2. 什么是 Embedding

Embedding 可以理解为:

把文字转换成计算机可以比较的数字坐标。

例如

复制代码
阻塞性睡眠呼吸暂停的治疗方法

和:

复制代码
OSA有哪些干预措施

虽然使用的文字不同,但语义相近,因此它们转换成向量后,在向量空间中的距离也会比较近。

传统关键词检索主要比较:

复制代码
是否出现相同词语

向量检索主要比较:

复制代码
语义是否相似

3. query 和 passage 前缀

当前 Embedding 模型在检索场景中使用:

复制代码
passage: 论文文本块
query: 用户问题

例如:

复制代码
passage_text = f"passage: {chunk_text}"
query_text = f"query: {question}"

这是为了告诉模型:

复制代码
这段文字是待检索文档
这段文字是用户查询

从而获得更适合检索任务的向量。


4. 向量归一化

程序生成向量时使用了归一化:

复制代码
normalize_embeddings=True

归一化后,向量长度被统一,后续可以更稳定地使用余弦距离比较语义相似度。


六、ChromaDB 向量数据库

1. 新增向量数据库模块

新增文件:

复制代码
src/vector_store.py

主要负责:

复制代码
初始化ChromaDB
创建向量集合
保存文本块向量
删除旧向量
统计向量数量
执行PDF内语义检索

ChromaDB 本地数据保存在:

复制代码
data/chroma/

该目录已经加入 .gitignore,不会上传 GitHub。

其他电脑拉取项目后,可以重新根据 SQLite 文本块生成向量索引。


2. SQLite 与 ChromaDB 的区别

SQLite 保存的是结构化原始数据:

复制代码
PDF信息
逐页文本
文本块正文
页码
文本块编号

ChromaDB 保存的是:

复制代码
文本块向量
文本块元数据
用于相似度检索的索引

两者职责不同:

复制代码
SQLite:保存真实、可读的数据
ChromaDB:负责高效语义检索

3. 向量唯一标识

每个文本块生成稳定的向量 ID,例如:

复制代码
document_2_chunk_32

表示:

复制代码
PDF文档ID:2
文本块编号:32

重新生成向量时,相同文本块可以通过相同 ID 覆盖,不会无限产生重复数据。


4. 当前测试结果

当前 PDF 的数据为:

复制代码
SQLite文本块数量:111
ChromaDB向量数量:111

这说明:

复制代码
111个文本块
→ 全部完成向量化
→ 全部保存到ChromaDB

两边数量一致,是向量化完整性的重要检查标准。


七、PDF 语义检索

用户输入问题后,系统执行:

复制代码
用户问题
    ↓
转换成384维查询向量
    ↓
在指定PDF的111个向量中搜索
    ↓
返回距离最近的若干文本块

检索结果包含:

复制代码
排名
PDF页码
文本块编号
文本块原文
向量距离
近似相似度

例如:

复制代码
第1名
PDF第3页
文本块32
相似度约79.73%

需要注意:

相似度不是答案正确率,也不是大模型置信度。

它只表示:

复制代码
用户问题向量
与
论文文本块向量
在向量空间中的接近程度

八、V0.3.3:基础 RAG 论文问答

1. 新增 RAG 模块

新增文件:

复制代码
src/rag_service.py

主要负责:

复制代码
调用向量检索
整理检索文本块
构造论文上下文
调用DeepSeek
生成完整回答
返回引用来源
处理API异常
统计Token使用量

2. RAG 的含义

RAG 全称是:

复制代码
Retrieval-Augmented Generation
检索增强生成

完整流程为:

复制代码
用户问题
    ↓
Retrieval:检索论文相关内容
    ↓
Augmented:把检索内容加入大模型上下文
    ↓
Generation:大模型根据上下文生成回答

它与直接调用大模型的区别是:

复制代码
普通大模型问答:
问题 → 大模型自身知识 → 回答

RAG问答:
问题 → 检索指定论文 → 大模型根据论文回答

3. RAG 上下文构造

检索到的每个文本块会被整理为:

复制代码
[第3页-文本块32]
具体论文内容......

[第5页-文本块48]
具体论文内容......

然后与用户问题一起发送给 DeepSeek。

这样模型在回答时可以知道每段材料的来源。


4. 防止模型编造

系统提示词要求模型:

复制代码
只能根据检索到的论文内容回答
不得使用外部知识补充
资料不足时必须明确说明
不得虚构作者、数据、方法和结论
每个重要结论必须标注来源
优先使用中文回答

当用户询问论文中不存在的信息时,例如:

复制代码
作者小时候在哪所小学读书?

系统应回答:

复制代码
当前检索到的论文内容不足以回答这个问题。

而不是凭空编造。


5. 可追溯引用

回答中的引用格式为:

复制代码
[第3页-文本块32]

页面下方还会展示:

复制代码
引用依据1
PDF第3页
文本块32
原始论文内容
相似度

用户可以展开引用依据,检查大模型回答是否真正来源于论文原文。

这使系统具备了初步的可解释性和可追溯性。


九、第三阶段新增和修改的主要文件

第三阶段主要新增:

复制代码
src/text_chunker.py
src/embedding_service.py
src/vector_store.py
src/rag_service.py
.streamlit/config.toml

主要修改:

复制代码
src/database.py
frontend/streamlit_app.py
requirements.txt
requirements-lock.txt
.gitignore
.env.example

本地但不上传 GitHub:

复制代码
.env
data/research_pilot.db
data/chroma/
Embedding模型缓存

十、第三阶段遇到的问题及解决方法

1. Hugging Face 镜像无法连接

曾出现:

复制代码
无法连接 https://hf-mirror.com

原因是电脑环境中存在:

复制代码
HF_ENDPOINT=https://hf-mirror.com

清除该环境变量后,恢复访问 Hugging Face 官方地址,并成功下载模型。

该问题体现了:

复制代码
操作系统环境变量
Conda环境变量
项目.env配置

三者可能同时影响程序行为。


2. 模型首次下载较慢

Embedding 模型首次运行需要下载几百 MB 文件。

下载完成后会保存在本地缓存,后续启动一般不需要重新下载。


3. Windows 符号链接警告

Hugging Face 提示 Windows 无法使用符号链接。

该警告不会影响模型运行,只可能增加缓存占用空间。


4. torchvision 报错

终端曾大量出现:

复制代码
ModuleNotFoundError: No module named 'torchvision'

原因不是文本向量模型必须依赖图像处理,而是 Streamlit 文件监视器扫描 Transformers 中大量可选视觉模块。

解决方式是关闭 Streamlit 文件监视器:

复制代码
[server]
fileWatcherType = "none"

配置文件为:

复制代码
.streamlit/config.toml

因此不需要为了文本 Embedding 功能额外安装图像处理依赖。


5. GitHub 连接被重置

开发过程中多次出现:

复制代码
Recv failure: Connection was reset

这属于网络问题,而不是代码错误。

正确处理方式是:

复制代码
提交成功、推送失败
→ 不重复提交
→ 只重新执行git push

十一、第三阶段核心知识点

第三阶段主要学习并实践了:

复制代码
长文本清理
滑动窗口切分
文本重叠
自然边界切分
Embedding向量
向量归一化
余弦相似度
ChromaDB持久化
向量检索
元数据过滤
Top-K召回
RAG检索增强生成
Prompt约束
大模型API调用
Token统计
引用溯源
异常处理
本地缓存
环境变量
敏感密钥管理

十二、第三阶段成果总结

第三阶段最终完成了:

复制代码
PDF逐页文本
→ 文本清理
→ 文本切分
→ SQLite文本块存储
→ Embedding向量化
→ ChromaDB向量存储
→ PDF内语义检索
→ DeepSeek生成论文回答
→ 页码与文本块引用
→ 引用原文展示

ResearchPilot 已经从普通 PDF 管理工具升级为一个具备基础 RAG 能力的科研文献问答系统。

V0.1 解决:

如何搜索论文。

V0.2 解决:

如何读取和保存论文全文。

V0.3 解决:

如何从论文中检索相关内容,并生成可追溯回答。

相关推荐
Hi李耶1 小时前
【LeetCode】9-回文数
算法·leetcode·职场和发展
红叶舞1 小时前
基于线段树的数据结构
数据结构·python·算法
创世宇图1 小时前
Video2Txt:160 行代码实现本地视频转文字
python·faster-whisper·video2txt·large-v3-turbo
断点之下2 小时前
从“理扑克牌”到“分组优化”——直接插入排序与希尔排序详解
数据结构·算法·排序算法
落苜蓿蓝2 小时前
Java 循环中对象复用导致属性覆盖?从 JVM 内存模型讲解原因
java·jvm·python
起个破名想半天了2 小时前
算法与数据结构之DFS深度优先遍历
数据结构·算法·深度优先
李伟_Li慢慢2 小时前
凸包算法
人工智能·算法
徐礼昭|商派软件市场负责人2 小时前
AI Agent 蜂群协作与经验基因化:从单体执行到自组织系统的工程路径
大数据·人工智能·算法·智能体·多agent
小白说大模型2 小时前
Python 工程化设计模式:AI 项目中的异步流水线与策略模式实战
人工智能·python·设计模式