TreeSearch
无需向量嵌入的文档检索库,保留完整章节结构实现精准 RAG 问答
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
无需向量嵌入的文档检索库,保留完整章节结构实现精准 RAG 问答
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
在 GitHub Issues 区,有用户描述了这样一个典型困境:公司内部积累了大量技术文档——API 文档、设计文档、RFC 合集,总量超过上千份。当他试图用传统 RAG 方案(向量嵌入 + 相似度搜索)为这些文档构建检索系统时,检索结果却总是不尽如人意:要么返回的是毫无上下文的碎片段落,要么整个章节被切得支离破碎,AI 在回答"如何配置 Redis 集群"这类问题时,给出的方案残缺不全。
这个场景,几乎是每一个尝试 RAG 工程的开发者都曾遭遇过的痛点。文档切分(Chunking) 和 向量化(Embedding) 是传统 RAG 的两个核心步骤,但它们恰恰也是上下文丢失的根源:把一份结构完整的技术文档切成若干 512 token 的块之后,每个块自身的语义是完整的,但块与块之间的关联关系——章节标题、层级结构、逻辑先后——全部被抹掉了。
TreeSearch 正是从这个痛点切入的。作者 shibing624(知乎/GitHub 知名 NLP 开源作者,以前的明星项目包括 pycorrector、text2vec 等)设计了一套"保留文档结构"的检索方案:不再盲目切分,而是先将文档解析为树结构,再用 SQLite FTS5 全文搜索引擎在树结构上进行结构感知检索。
TreeSearch 的核心设计思想可以概括为三个步骤:
第一步:解析为树结构。 不同于传统 RAG 把文档直接切块,TreeSearch 将文档解析为带有层级关系的树形结构。以 Markdown 文档为例,一个典型的文档结构可能是:
- 标题1
- 子标题1.1
- 正文段落
- 代码块
- 子标题1.2
- 正文段落
- 标题2
- 子标题2.1
- ...
这个树结构中,每个节点都携带了完整的上下文信息——它是谁的子节点、它下面有哪些内容、它在整篇文档的哪个位置。对于 Python 代码文件,TreeSearch 还会使用 Python AST 解析器提取类名、函数签名等结构信息;对于 HTML/JSON 等格式,也有专门的解析器处理。
第二步:构建 FTS5 索引。 解析完成后,TreeSearch 将整棵树存入 SQLite 数据库,利用 FTS5(Full-Text Search 5)全文搜索引擎建立倒排索引。与向量数据库(如 ChromaDB、Milvus)不同,FTS5 是一种基于关键词的全文搜索技术,完全不需要嵌入模型,也不依赖任何外部服务。FTS5 支持列权重加权——比如给"标题"列赋予更高权重,让匹配到标题关键词的结果排名更靠前。
第三步:结构感知的检索。 检索时,TreeSearch 支持两种搜索模式:
此外还有 Auto 模式(默认),系统会智能判断文档类型,自动选择合适的搜索策略。
最关键的一点:整个过程不需要 LLM,不需要 API Key,不需要嵌入模型,不需要向量数据库。 所有计算都在本地 SQLite 上完成,检索延迟在毫秒级别。
当前 RAG 领域的一个主流研究方向是"如何更好地切分文档"——从固定长度切分,到递归字符切分,到基于语义的结构化切分。但 TreeSearch 提供了一个截然不同的思路:不要切分,保留结构。
这个思路的合理性在于:许多技术文档本身就有良好的结构(章节标题、代码块),这些结构本身就是极好的语义锚点。一旦把这些结构解析为树,再结合 FTS5 的列权重机制,检索质量往往比盲目切分更高。
从 benchmark 数据来看,TreeSearch 在 QASPER(学术问答)和 CodeSearchNet(代码搜索)两个数据集上的表现都相当有竞争力。特别是代码搜索场景,MRR 0.91 已经接近生产可用的水平。
此外,项目还提供了 Rust CLI 版本(命令名 ts),可以通过 Homebrew 或 Cargo 安装,完全不依赖 Python 运行时,对非 Python 生态的开发者也很友好。
安装非常简洁:
pip install -U pytreesearch
Python API 使用:
from treesearch import TreeSearch
# 直接传入目录,自动递归发现所有支持的文件
ts = TreeSearch("project_root/", "docs/")
results = ts.search("认证系统如何工作?")
for doc in results["documents"]:
for node in doc["nodes"]:
print(f"[{node['score']:.2f}] {node['title']}")
print(f" {node['text'][:200]}")
CLI 搜索:
treesearch "认证系统如何工作?" src/ docs/
treesearch index --paths src/ docs/
treesearch search --db ./index.db --query "auth"
安装可选依赖可以支持更多文件格式:pip install pytreesearch[all] 可解析 PDF、DOCX、HTML 等。
需要客观指出的是,TreeSearch 并不适合所有场景:
语义理解能力有限。作为纯关键词搜索方案,它无法理解同义词、语义关联。比如搜索"心脏病"不会匹配"心血管疾病"相关内容,这在需要语义理解的场景下是硬伤。
不支持跨模态检索。无法处理图片、音频、视频等多模态内容。
没有内置重排序(Rerank)。对于需要更高精度检索的场景(如法律文档检索),需要在 TreeSearch 之上叠加专门的 Rerank 模型。
Python AST 解析仅覆盖部分语言。内置的 AST 解析器目前支持 Python,如果要处理 Java/Go/JS/C++ 等代码,主要依赖正则表达式,精度不如真正的 AST 解析。
TreeSearch 是一个纯 Python 项目,核心依赖只有三个:tqdm(进度条)、jieba(中文分词)、pathspec(.gitignore 解析)。所有可选依赖(PDF 解析、HTML 解析、LLM 集成等)都通过 optional-dependencies 按需安装,保持了极低的核心体积。
代码采用模块化架构,核心模块包括:
| 模块 | 职责 |
|---|---|
indexer.py | 解析文档,构建树结构,写入 SQLite FTS5 索引 |
fts.py | FTS5 索引的底层操作,包括分词、权重配置 |
search.py / tree_searcher.py | 检索逻辑,Flat/Tree/Auto 三种模式 |
tokenizer.py | 统一的分词器,封装 jieba 和英文分词 |
parsers/ | 各文件类型的解析器(Markdown、Python AST、HTML 等) |
cli.py | 命令行工具,支持 index/search 等子命令 |
作者在代码中实现了完整的 ParserRegistry(解析器注册表)模式,方便扩展新的文件格式解析器。代码注释充分,模块边界清晰,是学习"如何写一个生产级 Python 库"的良好参考。
TreeSearch 的出现代表了 RAG 检索层的一个有趣分支——从"更好地切分"转向"保留并利用结构"。随着各行业 RAG 应用的深入落地,对高质量结构化检索的需求正在快速增长。TreeSearch 以极低的依赖成本(仅 SQLite)、毫秒级的检索速度,为中小型团队提供了一个无需维护向量数据库的可行方案。
从项目活跃度来看(持续更新,v1.1.1),作者仍在积极维护,值得关注其在 LLamaIndex 和 LangChain 集成方面的进展,以及是否会在未来版本中加入轻量级语义匹配能力。
总结:TreeSearch 是一个设计精巧的文档检索工具,特别适合技术文档问答、代码库搜索、长文档结构化检索等场景。如果你正在为 RAG 应用的检索质量发愁,不妨先用
pip install pytreesearch体验一下——毫秒级响应、零 API 成本、保留完整文档结构,可能是你一直在寻找的答案。