Skip to main content

A lightweight local document ingestion and retrieval package.

Project description

searchbox

searchbox 是一个面向本地知识库 / 文档检索场景的 Python 包,提供:

  • 内置 FastAPI 服务端
  • 基于 Milvus Lite 的本地向量存储
  • 文档抽取、分块、向量化、检索、重排的一体化流程
  • 面向多用户、多 collection 的数据隔离能力
  • 可切换的 embedding / reranking provider(mock、local、DashScope、vLLM)
  • 面向论文摘要库与自定义 collection 的扩展接口

项目定位不是“通用 RAG 全家桶”,而是一个轻量、可本地启动、接口明确的“知识检索底座”。安装后可直接通过 python -m searchbox start 启动,不依赖 Docker。


目录

  1. 项目概览
  2. 核心能力
  3. 项目结构
  4. 工作流程
  5. 安装
  6. 快速开始
  7. 配置文件说明
  8. Python API 使用说明
  9. 服务端 REST API
  10. Provider 说明
  11. 文件解析与分块策略
  12. 多用户、多 collection 与论文库
  13. 自定义 collection
  14. 测试与示例脚本
  15. 开发备注与已知事项
  16. 许可证

项目概览

searchbox 当前实现由两部分组成:

  1. 客户端封装:提供 MilvusCorpusSearchMilvusDocumentSearchMilvusClient 等 Python 接口。
  2. 内置服务端:位于 searchbox/server/,负责文本入库、向量检索、重排、Milvus 管理与 REST API 暴露。

默认运行模式如下:

  • 服务端启动后,使用本地 Milvus Lite .db 文件作为向量数据库。
  • 客户端通过 HTTP 调用内置服务端。
  • 文档入库时先抽取文本,再按字符数切块,再调用 embedding provider 生成向量。
  • 查询时先向量召回 chunk,再通过 reranker 做重排,最后按文件级聚合返回结果。

默认数据库文件名是 ./milvus_local.db,服务端还会维护一个 .searchbox_server_state.json 用于记录临时 collection 的 TTL 和论文卷册状态。


核心能力

1. 文档知识库检索

针对普通文档(txt / md / json / html / pdf 等):

  • 支持文件或目录递归入库
  • 支持按 user_id 做数据隔离
  • 支持文件级检索:返回最相关文档
  • 支持单文档 chunk 级检索:返回文档内最相关片段
  • 支持按 file_path 过滤检索范围
  • 同一路径重复入库时会先删除旧内容,再写入新版本,避免重复数据

2. 多 provider 推理适配

服务端可切换以下 embedding / reranking provider:

  • mock:测试用,使用哈希向量与伪重排
  • local:本地 HuggingFace 模型
  • dashscope:阿里云 DashScope API
  • vllm:外部 vLLM HTTP 服务

3. 多 collection 管理

服务端支持:

  • 默认 collection
  • 手动创建临时 / 永久 collection
  • TTL 自动过期清理
  • 按 collection 统计用户与文件

4. 论文摘要库

单独的 paper volume 机制,适合维护“论文摘要向量库”:

  • 按 volume 建立 collection
  • 按摘要向量检索论文
  • 支持删除论文、删除整个 volume

5. 自定义 collection

支持通过 REST API 创建带指定 schema 的 Milvus collection,包括:

  • 标量字段
  • dense vector 字段
  • BM25 sparse 字段

当前仓库对自定义 collection 暴露的是“schema 创建 / 描述 / 删除”接口,不包含通用插入与搜索封装。


项目结构

searchbox/
├── pyproject.toml                # 包配置与 optional dependencies
├── README.md                     # 项目说明
├── smoke_test.py                 # 端到端 smoke test
├── all_methods_demo.py           # 历史示例,和当前接口不完全一致
├── tests/
│   ├── test_milvus_document_search.py
│   └── test_server_fixes.py
│
├── searchbox/
│   ├── __init__.py               # 对外导出 API
│   ├── __main__.py               # CLI 入口:init / start / check
│   ├── config.py                 # 客户端配置加载与模板生成
│   ├── milvus.py                 # HTTP client + 高层检索封装
│   ├── extractors.py             # 文件文本抽取
│   ├── factory.py                # SearchFactory
│   ├── base.py                   # 通用搜索基类
│   ├── search_types.py           # SearchCandidate 数据结构
│   ├── sources.py                # 候选源抽象
│   ├── strategies.py             # 搜索策略抽象
│   ├── milvus_config.yaml        # 内置默认配置模板
│   └── server/
│       ├── __init__.py           # start_server / start_server_from_yaml
│       ├── app.py                # FastAPI 路由与服务拼装
│       ├── service.py            # KnowledgeService / PaperService
│       ├── chunking.py           # 文本切块逻辑
│       ├── store.py              # MilvusStore / PaperStore / CustomStore
│       └── providers/
│           ├── base.py
│           ├── mock.py
│           ├── local_qwen.py
│           ├── dashscope_qwen.py
│           └── vllm_qwen.py

工作流程

文档入库流程

add_path / add_paths / add_text
        ↓
FileTextExtractor 抽取文本
        ↓
split_text 按段落边界分块
        ↓
Embedder 生成向量
        ↓
MilvusStore 写入 collection

文件级检索流程

query
  ↓
Embedder(query)
  ↓
Milvus 向量召回 top-p chunks
  ↓
Reranker 对 chunks 重排
  ↓
按 file_path 做 max-pooling 聚合
  ↓
返回 top-k 文件

单文档片段检索流程

query + file_path
        ↓
限定该文件内的 chunks 做向量召回
        ↓
Reranker 重排
        ↓
返回 top-k chunk 命中

安装

1. 基础安装

pip install .

这会安装包本体,但如果你要启动服务端,通常还需要额外依赖。

2. 服务端依赖

pip install "searchbox[server]"

包含:

  • fastapi
  • uvicorn[standard]
  • pydantic
  • pymilvus
  • milvus
  • pyyaml
  • httpx

3. 本地模型依赖

pip install "searchbox[server,local]"

额外包含:

  • torch
  • transformers

4. DashScope 依赖

pip install "searchbox[server,dashscope]"

5. 全量安装

pip install "searchbox[all]"

快速开始

方式一:直接用默认 mock 配置体验流程

这是当前最推荐的首次使用方式:

  • 无需额外模型服务
  • 无需 GPU
  • 最适合先验证安装、配置、入库、检索链路是否正常

注意:mock 只适合功能验证,不代表真实语义检索质量。

生成配置文件:

python -m searchbox init

建议先把数据库路径改到一个明确可写的子目录,例如:

milvus_db:
  uri: "./data/milvus_local.db"

然后创建目录:

mkdir -p data

启动服务:

python -m searchbox start

健康检查:

python -m searchbox check
# 或
curl http://localhost:18765/health

在 Python 中使用:

from searchbox import MilvusCorpusSearch

search = MilvusCorpusSearch.from_config("milvus_config.yaml", user_id="alice")

search.add_text(
    text="检索增强生成系统通常需要文档切块、召回与重排。",
    file_path="docs/intro.txt",
    title="Intro",
)

results = search.search_pretty("什么是重排", top_k=3)
for item in results:
    print(item["score"], item["path"], item["snippet"])

方式二:使用 vLLM 模型服务

如果你希望得到更真实的语义检索效果,推荐使用 vllm provider。当前项目的 vllm 方案要求:

  • 一个 embedding 服务
  • 一个 reranking 服务
  • searchbox 服务再去调用它们

方案 A:联网直接加载 Hugging Face 模型

强烈建议把 vllm 放到单独的 Python / Conda 环境里启动,而不是和 searchbox 主环境混用。原因是 vllm 依赖较重,常见问题包括:

  • libstdc++ / CXXABI 版本冲突
  • CUDA / PyTorch / Triton 版本不匹配
  • 与当前业务环境中的 sqlite3icutransformers 等依赖互相干扰

一个更稳的做法是新建独立环境,例如:

conda create -n vllm_env python=3.12 -y
conda activate vllm_env
conda install -c conda-forge libstdcxx-ng libgcc-ng -y
pip install vllm

如果需要联网从 Hugging Face 拉模型,再按需执行:

huggingface-cli login

先分别启动两个 vLLM 服务:

# embedding 服务
vllm serve Qwen/Qwen3-Embedding-0.6B --port 8806

# rerank 服务
vllm serve Qwen/Qwen3-Reranker-0.6B \
  --port 8807 \
  --hf_overrides '{"architectures": ["Qwen3ForSequenceClassification"],"classifier_from_token": ["no", "yes"],"is_original_qwen3_reranker": true}'

然后把 milvus_config.yaml 改成:

embedding:
  provider: "vllm"
  dim: 1024
  metric_type: "IP"
  model: "Qwen/Qwen3-Embedding-0.6B"

reranking:
  provider: "vllm"
  model: "Qwen/Qwen3-Reranker-0.6B"

vllm:
  embed_base_url: "http://127.0.0.1:8806"
  rerank_base_url: "http://127.0.0.1:8807"
  embed_api_key: "EMPTY"
  rerank_api_key: "EMPTY"
  timeout: 60.0

最后启动 searchbox

python -m searchbox start

方案 B:本地模型目录方式

如果你不想让 vllm serve 直接联网拉模型,可以先把模型下载到本地目录,再用目录路径启动:

huggingface-cli download Qwen/Qwen3-Embedding-0.6B --local-dir /path/to/models/Qwen3-Embedding-0.6B
huggingface-cli download Qwen/Qwen3-Reranker-0.6B --local-dir /path/to/models/Qwen3-Reranker-0.6B

然后启动:

vllm serve /path/to/models/Qwen3-Embedding-0.6B --port 8806

vllm serve /path/to/models/Qwen3-Reranker-0.6B \
  --port 8807 \
  --hf_overrides '{"architectures": ["Qwen3ForSequenceClassification"],"classifier_from_token": ["no", "yes"],"is_original_qwen3_reranker": true}'

这里要特别注意:

  • Qwen/Qwen3-Embedding-0.6B 这样的字符串默认是 Hugging Face 模型名,不是要求你手动在当前目录创建同名目录
  • 如果你传的是本地路径,那就用真实存在的模型目录路径
  • 当前 searchboxvllm provider 期望的是服务根地址,不要把 embed_base_url / rerank_base_url 写成带 /v1 的地址

完整 vLLM 配置示例

如果你希望直接把 milvus_config.yaml 改成可运行的 vllm 版本,可以参考下面的完整配置片段:

server:
  host: "127.0.0.1"
  port: 18765

milvus_db:
  uri: "./data/milvus_local.db"
  token: ""
  db_name: "default"
  collection: "knowledge"

embedding:
  provider: "vllm"
  dim: 1024
  metric_type: "IP"
  model: "Qwen/Qwen3-Embedding-0.6B"   # 或本地目录路径

reranking:
  provider: "vllm"
  model: "Qwen/Qwen3-Reranker-0.6B"    # 或本地目录路径

vllm:
  embed_base_url: "http://127.0.0.1:8806"
  rerank_base_url: "http://127.0.0.1:8807"
  embed_api_key: "EMPTY"
  rerank_api_key: "EMPTY"
  timeout: 60.0

milvus_service:
  base_url: "http://localhost:18765"
  timeout: 60.0

search:
  recall_top_p: 20
  default_top_k: 5
  score_threshold: null
  collection: null

ingest:
  chunk_max_chars: 2000
  chunk_overlap: 200

推荐启动顺序:

# 1) 启动 embedding vLLM
vllm serve Qwen/Qwen3-Embedding-0.6B --port 8806

# 2) 启动 rerank vLLM
vllm serve Qwen/Qwen3-Reranker-0.6B \
  --port 8807 \
  --hf_overrides '{"architectures": ["Qwen3ForSequenceClassification"],"classifier_from_token": ["no", "yes"],"is_original_qwen3_reranker": true}'

# 3) 启动 searchbox
mkdir -p data
python -m searchbox start

如果你使用本地模型目录,把上面两个 vllm serve 后面的模型名替换成真实路径即可。

如何选择

  • 只想先验证功能是否可用:优先 mock
  • 想要更真实的检索效果,并且有可用 GPU / 推理服务:用 vllm
  • 本地模型太重、又没有现成 vLLM 服务:再考虑 local 或其他 provider

方式三:在代码里后台启动服务

from searchbox import start_server, MilvusCorpusSearch

thread = start_server(
    config={
        "milvus_uri": "./data/milvus_local.db",
        "embed_provider": "mock",
        "rerank_provider": "mock",
        "embed_dim": 1024,
    },
    host="127.0.0.1",
    port=18765,
    background=True,
)

search = MilvusCorpusSearch(user_id="alice", base_url="http://127.0.0.1:18765")
search.add_text("hello retrieval", file_path="demo.txt", title="Demo")
print(search.search("retrieval"))

方式四:通过 YAML 启动

from searchbox import start_server_from_yaml

start_server_from_yaml("milvus_config.yaml")

配置文件说明

默认模板文件位于 searchbox/milvus_config.yaml,执行 python -m searchbox init 会复制到当前目录。

配置结构

server:
  host: "127.0.0.1"
  port: 18765

milvus_db:
  uri: "./milvus_local.db"
  token: ""
  db_name: "default"
  collection: "knowledge"

embedding:
  provider: "mock"
  dim: 1024
  metric_type: "IP"
  model: "Qwen/Qwen3-Embedding-0.6B"
  batch_size: 32
  max_length: 8192

reranking:
  provider: "mock"
  model: "Qwen/Qwen3-Reranker-4B"

vllm:
  embed_base_url: "http://127.0.0.1:8806"
  rerank_base_url: "http://127.0.0.1:8807"
  embed_api_key: ""
  rerank_api_key: ""
  timeout: 60.0

dashscope:
  api_key: ""

milvus_service:
  base_url: "http://localhost:18765"
  timeout: 60.0

search:
  recall_top_p: 20
  default_top_k: 5
  score_threshold: null
  collection: null

ingest:
  chunk_max_chars: 2000
  chunk_overlap: 200

配置项分工

server

服务端监听地址与端口,只在启动服务端时使用。

milvus_db

Milvus 连接与默认 collection:

  • uri:本地 Milvus Lite 数据库路径,建议使用明确可写的子目录,例如 ./data/milvus_local.db
  • token:远程 Milvus 鉴权时使用
  • db_name:逻辑数据库名
  • collection:默认知识库 collection 名称

注意:

  • Milvus Lite 除了数据库文件,还会在同目录创建 lock 文件
  • 因此 milvus_db.uri 所在目录必须可写
  • 如果把数据库直接放到只读目录,通常会在首次入库或检索时报错

embedding

控制 embedding provider:

  • providermock / local / dashscope / vllm
  • dim:向量维度,必须与模型输出一致
  • metric_type:Milvus 向量检索度量方式,默认 IP
  • model:provider 对应模型名或路径
  • batch_size / max_length:仅 local 模式使用

reranking

控制 reranker provider 和模型名。

vllm

provider=vllm 时生效:

  • embedding 与 reranking 走不同 base URL
  • 支持独立 API key
  • 支持请求超时设置

dashscope

provider=dashscope 时需要填写 api_key

milvus_service

客户端访问服务端时使用:

  • base_url
  • timeout

search

客户端默认检索参数:

  • recall_top_p:向量召回 chunk 数
  • default_top_k:最终返回结果数
  • score_threshold:结果过滤阈值
  • collection:默认请求的 collection

ingest

客户端默认入库分块参数:

  • chunk_max_chars
  • chunk_overlap

Python API 使用说明

1. MilvusCorpusSearch

多文件语料检索入口。

创建实例

from searchbox import MilvusCorpusSearch

# 推荐:从 YAML 读取客户端配置
search = MilvusCorpusSearch.from_config("milvus_config.yaml", user_id="alice")

# 使用默认配置(base_url=http://localhost:18765)
search = MilvusCorpusSearch.from_config(None, user_id="alice")

# 直接传参
search = MilvusCorpusSearch(
    user_id="alice",
    base_url="http://localhost:18765",
    collection=None,
    recall_top_p=20,
    default_top_k=5,
    score_threshold=0.3,
    chunk_max_chars=2000,
    chunk_overlap=200,
    timeout=60.0,
)

入库文件 / 目录

# 单文件
search.add_path("/data/report.pdf")

# 目录递归入库
search.add_path("/data/docs/")

# 禁止递归
search.add_path("/data/docs/", recursive=False)

# 包含隐藏文件
search.add_path("/data/docs/", include_hidden=True)

# 批量路径
search.add_paths(["/data/docs/", "/data/notes/a.md"])

直接入库文本

result = search.add_text(
    text="这是一段不会落地到本地文件的文本。",
    file_path="virtual/doc-001",
    title="虚拟文档",
)

文件级检索

results = search.search("量子计算", top_k=5)

返回格式:

[
    {
        "id": "/data/paper1.pdf",
        "title": "paper1.pdf",
        "content": "最相关的 chunk 文本...",
        "score": 0.91,
        "metadata": {
            "file_path": "/data/paper1.pdf",
            "milvus_score": 0.91,
        },
    }
]

便于展示的结果

pretty = search.search_pretty("量子计算", top_k=5, snippet_length=280)

返回格式:

[
    {
        "path": "/data/paper1.pdf",
        "file_name": "paper1.pdf",
        "score": 0.91,
        "snippet": "截断后的摘要文本...",
        "metadata": {...},
    }
]

文件管理

files = search.list_files()
deleted = search.delete_file("/data/paper1.pdf")
health = search.health()

支持的扩展名

exts = search.supported_extensions()

当前支持:

  • .txt
  • .md
  • .rst
  • .py
  • .toml
  • .yaml
  • .yml
  • .csv
  • .tsv
  • .html
  • .htm
  • .json
  • .pdf

2. MilvusDocumentSearch

单文档 chunk 级检索入口,适合回答“某一篇文档里,哪一段最相关”。

创建实例

from searchbox import MilvusDocumentSearch

doc = MilvusDocumentSearch.from_config(
    config="milvus_config.yaml",
    user_id="alice",
    file_path="/data/book.pdf",
)

检索片段

results = doc.search("实验设置在哪一节", top_k=3)

返回格式:

[
    {
        "id": "/data/book.pdf#3",
        "title": "book.pdf",
        "content": "最相关 chunk 文本...",
        "score": 0.84,
        "metadata": {
            "file_path": "/data/book.pdf",
            "chunk_id": 3,
            "start_offset": 1200,
            "end_offset": 1680,
            "milvus_score": 0.84,
        },
    }
]

展示友好结果

pretty = doc.search_pretty("实验设置在哪一节", top_k=3)

字段包含:

  • path
  • file_name
  • chunk_id
  • start_offset
  • end_offset
  • score
  • snippet

3. MilvusClient

底层 HTTP 客户端,适合你自己封装 SDK 或服务调用。

from searchbox import MilvusClient

client = MilvusClient(base_url="http://localhost:18765", timeout=60.0)

client.ingest(
    user_id="alice",
    files=[{"file_path": "a.txt", "text": "hello world"}],
)

print(client.search(user_id="alice", query="hello"))
print(client.search_chunks(user_id="alice", file_path="a.txt", query="hello"))
print(client.list_files(user_id="alice"))
print(client.health())

4. start_server / start_server_from_yaml

from searchbox import start_server, start_server_from_yaml
  • start_server(config=..., background=True):编程式启动
  • start_server_from_yaml("milvus_config.yaml"):从 YAML 启动

5. MilvusConfig 与配置工具

from searchbox import (
    MilvusConfig,
    load_milvus_config,
    generate_config_template,
    check_service,
)

可用于:

  • 读取 YAML
  • 生成配置模板
  • 检查服务是否存活

服务端 REST API

以下接口来自 searchbox/server/app.py

1. 健康检查

  • GET /health

示例返回:

{
  "ok": true,
  "version": "1.0.0",
  "default_collection": "knowledge",
  "embed_provider": "mock",
  "rerank_provider": "mock",
  "active_collections": 1,
  "active_volumes": 0
}

2. 文档入库与检索

  • POST /ingest
  • POST /search
  • POST /search/chunks
  • GET /files
  • DELETE /files
  • GET /chunks

POST /ingest

请求体:

{
  "user_id": "alice",
  "collection": "knowledge",
  "chunk": {"max_chars": 2000, "overlap": 200},
  "files": [
    {
      "file_path": "docs/a.txt",
      "text": "hello world",
      "metadata": {"title": "A"}
    }
  ]
}

POST /search

请求体:

{
  "user_id": "alice",
  "query": "hello",
  "recall_top_p": 20,
  "top_k": 5,
  "include_content": true,
  "score_threshold": 0.3,
  "file_paths": ["docs/a.txt"],
  "collection": "knowledge"
}

POST /search/chunks

请求体:

{
  "user_id": "alice",
  "file_path": "docs/a.txt",
  "query": "hello",
  "recall_top_p": 20,
  "top_k": 5,
  "score_threshold": 0.3,
  "collection": "knowledge"
}

3. collection 管理

  • POST /collections
  • GET /collections
  • GET /collections/{name}
  • PATCH /collections/{name}
  • DELETE /collections/{name}
  • DELETE /collection(兼容旧接口)
  • GET /collections/{name}/users
  • DELETE /collections/{name}/users/{user_id}

特性

  • 创建时可指定 temporary=true
  • 临时 collection 支持 ttl_hours
  • 过期 collection 会在请求触发时被清理

创建请求示例:

{
  "name": "tmp_demo",
  "temporary": true,
  "ttl_hours": 24
}

4. 论文摘要库 API

  • POST /papers/collections
  • GET /papers/collections
  • GET /papers/collections/{volume}
  • DELETE /papers/collections/{volume}
  • POST /papers/ingest
  • DELETE /papers/files
  • POST /papers/search

论文入库示例

{
  "volume": "acl_2025",
  "papers": [
    {
      "file_path": "papers/001.pdf",
      "title": "A Retrieval Paper",
      "abstract": "This paper studies...",
      "metadata": {"authors": ["A", "B"]}
    }
  ]
}

5. 管理接口

  • GET /admin/collections
  • GET /admin/collection/stats
  • GET /admin/files
  • GET /admin/papers

适合做管理后台或调试脚本。

6. 自定义 collection 接口

  • POST /custom-collections
  • GET /custom-collections/{name}
  • DELETE /custom-collections/{name}

可定义字段类型:

  • int8 / int16 / int32 / int64
  • float / double
  • bool
  • varchar
  • json

额外支持索引类型:

  • DENSE
  • BM25

Provider 说明

1. mock

特点:

  • 无需模型与外网
  • 最适合测试流程与 API
  • 是当前推荐的默认起步方式
  • 检索精度非常有限

实现方式:

  • embedding:基于文本 md5 派生伪向量
  • reranking:再次用 mock 向量做相似度排序

2. local

特点:

  • 本地加载 HuggingFace 模型
  • 不依赖远程 API
  • 更适合有 GPU 的机器

当前默认模型名:

  • embedding:Qwen/Qwen3-Embedding-0.6B
  • reranking:Qwen/Qwen3-Reranker-4B

注意:

  • embedding 维度必须与配置中的 embedding.dim 一致
  • LocalQwenReranker 使用生成式 yes/no 概率近似相关性得分
  • CPU 也能运行,但速度可能较慢

3. dashscope

特点:

  • 调用阿里云 DashScope API
  • 无需本地 GPU
  • 需要配置 dashscope.api_key

默认模型名:

  • embedding:text-embedding-v3
  • reranking:gte-rerank

4. vllm

特点:

  • 适合已有独立推理服务的场景
  • embedding 与 reranking 分别连接不同 HTTP 服务
  • mock 更接近真实语义检索效果

推荐使用方式:

  • embedding:Qwen/Qwen3-Embedding-0.6B
  • reranking:Qwen/Qwen3-Reranker-0.6B
  • 初次使用可以直接让 vllm serve 联网拉模型
  • 如果要更稳定可控,可以提前下载到本地,再用本地目录启动
  • 最好在独立环境中运行 vllm

约定接口:

  • embedding:POST /pooling
  • reranking:POST /v1/rerank

配置示例:

embedding:
  provider: "vllm"
  dim: 1024
  metric_type: "IP"
  model: "Qwen/Qwen3-Embedding-0.6B"

reranking:
  provider: "vllm"
  model: "Qwen/Qwen3-Reranker-0.6B"

vllm:
  embed_base_url: "http://127.0.0.1:8806"
  rerank_base_url: "http://127.0.0.1:8807"
  embed_api_key: "EMPTY"
  rerank_api_key: "EMPTY"
  timeout: 60.0

注意:

  • 当前项目的 vllm provider 不是直接用 OpenAI Python SDK
  • 它内部调用的是:
    • embedding:/pooling
    • reranking:/v1/rerank
  • 因此 base_url 应填写服务根地址,例如 http://127.0.0.1:8806,不要额外带 /v1

运行建议

1. 本地 Lite 模式的索引类型

当前项目默认面向 Milvus Lite 本地模式,dense vector 索引使用 FLAT

原因是:

  • Milvus Lite local mode 不支持 HNSW
  • 本地模式常见支持的是 FLATIVF_FLATAUTOINDEX

影响是:

  • FLAT 在小规模本地知识库里更稳、更兼容
  • 大规模数据下搜索速度可能不如 HNSW
  • 但检索结果本身不会因为 FLAT 而“更差”,它是精确搜索

对于当前项目的典型场景(少量 PDF、本地实验、功能验证),FLAT 是更合适的默认值。

2. 开发安装方式

本地开发建议使用 editable install:

pip install -e ".[server]"

这样修改 searchbox/ 下源码后,无需重复打包安装,重启脚本或服务即可生效。

3. 用户目录使用方式

项目支持在“非仓库目录”直接使用,典型流程如下:

cd /path/to/your/workdir
python -m searchbox init
python -m searchbox start

然后在同目录编写脚本:

from searchbox import MilvusCorpusSearch

search = MilvusCorpusSearch.from_config("milvus_config.yaml", user_id="alice")

这也是推荐的终端用户使用方式。


文件解析与分块策略

1. 文件解析

FileTextExtractor 当前支持:

  • 纯文本类:.txt.md.rst.py.toml.yaml.yml.csv.tsv
  • HTML:.html.htm
  • JSON:.json
  • PDF:.pdf

处理方式:

  • 文本文件:按 UTF-8 读取,忽略非法字符
  • HTML:正则去标签后压缩空白
  • JSON:递归展开字典 / 列表为文本
  • PDF:优先调用 pdftotext -layout,失败时回退到简单字节级文本提取

注意:PDF fallback 仅为兜底方案,复杂版式文档可能效果一般。若系统安装了 pdftotext,效果通常更可靠。

2. 分块逻辑

分块函数位于 searchbox/server/chunking.py

规则:

  • 基于字符数切块,不是基于 token
  • max_chars 下限 200
  • overlap 会限制在 max_chars // 2 以内
  • 优先尝试在段落边界 \n\n 处分割
  • 其次尝试在换行 \n 处分割
  • 保存 chunk_idstart_offsetend_offset

这使得 chunk 检索结果可以直接回定位到原文偏移区间。


多用户、多 collection 与论文库

1. 多用户隔离

普通知识库数据在 MilvusStore 中带有 user_id 字段。

搜索表达式会自动附加:

user_id == "your_user_id"

因此:

  • 同一 collection 内不同用户数据相互隔离
  • list_filessearchdelete_file 等接口都基于 user_id

2. 多 collection

服务端默认 collection 名称由配置中的 milvus_db.collection 指定,默认是 knowledge

你也可以在请求中传 collection

  • 让不同业务线使用不同知识库
  • 用临时 collection 做实验
  • 用永久 collection 做正式环境

3. 临时 collection TTL

POST /collections 可创建临时 collection,服务端会记录过期时间。后续任意请求触发 _evict_expired() 时,过期 collection 会被删除。

适合:

  • 临时会话知识库
  • 实验性数据集
  • 每任务独立索引

4. 论文库 volume

论文库使用独立的 PaperStore,与普通 chunk 库不同:

  • 入库对象是论文摘要,不是 chunk
  • 不区分 user_id
  • 每个 volume 对应一个 collection,命名规则为 paper_<规范化后的volume>

自定义 collection

CustomStore 支持创建带 schema 的 Milvus collection。

约束与特性:

  • 必须且只能有一个主键字段
  • 最多允许 4 个索引字段
  • BM25 索引仅适用于 varchar
  • DENSE 会额外创建对应的 float vector 字段
  • schema 开启 enable_dynamic_field=True

示例请求:

{
  "name": "hybrid_docs",
  "fields": [
    {"name": "doc_id", "field_type": "varchar", "is_primary": true, "max_length": 128},
    {"name": "title", "field_type": "varchar", "max_length": 512},
    {"name": "body", "field_type": "varchar", "max_length": 65535, "index_type": "BM25"},
    {"name": "embedding", "field_type": "varchar", "max_length": 128, "index_type": "DENSE", "dim": 1024}
  ]
}

说明:当前项目只提供 schema 生命周期接口;如果你要在这个 collection 上做完整数据读写,需要自行补充插入 / 查询逻辑。


测试与示例脚本

1. smoke_test.py

这是当前仓库里最贴近现实现状的端到端示例,覆盖:

  • 后台启动服务
  • 文本入库
  • 文件级检索
  • chunk 级检索
  • 同路径重复入库替换旧数据

运行:

python smoke_test.py

2. tests/test_server_fixes.py

关注点:

  • 重复入库同一 file_path 时会先删旧数据,再插入新数据

3. tests/test_milvus_document_search.py

意图是验证单文档搜索封装;但从当前源码看,测试与 MilvusDocumentSearch 的最新构造参数不完全同步,若后续维护测试,建议按当前实现更新。

4. all_methods_demo.py

该文件引用了当前仓库中已不存在的旧接口(如 docsearchSqliteDocumentRepository 等),属于历史遗留示例,不能直接作为当前版本使用文档。


开发备注与已知事项

1. 当前主线接口是 Milvus 版

从源码看,当前对外稳定接口主要是:

  • MilvusCorpusSearch
  • MilvusDocumentSearch
  • MilvusClient
  • start_server / start_server_from_yaml

base.pysources.pystrategies.py 等保留了通用搜索抽象,但当前项目主流程已经围绕 Milvus 服务端展开。

2. 文件级检索的聚合策略

服务端会:

  1. 先召回 chunk
  2. rerank 每个 chunk
  3. 对同一文件只保留最高分 chunk 作为该文件得分

所以最终结果是“文件级 max-pooling 聚合”,不是多 chunk 得分求和。

3. 重复入库行为

对同一个 user_id + file_path 再次入库时,旧 chunk 会被删掉再重建。这是源码里的明确设计,不会累计重复版本。

4. PDF 解析依赖系统工具

如果环境中没有 pdftotext,会退回到一个非常轻量的 PDF 文本提取逻辑;对于扫描版 PDF 或复杂布局 PDF,建议自行接入更强抽取方案。

5. 搜索分数含义

最终返回的 score 来自 reranker 分数,不一定等于 Milvus 原始向量分数。客户端结果中的 metadata.milvus_score 当前也复用了最终返回值,而不是单独暴露向量召回原始得分。

6. 关闭客户端连接

MilvusCorpusSearchMilvusDocumentSearchMilvusClient 都提供 close() 与上下文管理能力,长生命周期服务中建议显式关闭。

7. setuptools / pymilvus 兼容性

当前项目的服务端依赖对以下组合较敏感:

  • pymilvus
  • milvus-lite
  • setuptools

原因是部分 pymilvus 版本在导入时仍依赖 pkg_resources,而较新的 setuptools 已经移除了它。

因此项目当前在 pyproject.toml 中显式限制了:

  • setuptools>=65.0.0,<82.0.0
  • pymilvus[milvus-lite]>=2.5.0,<2.6.0

如果你手动升级了这些包,启动服务时报 pkg_resourcesFunction / FunctionType、或 Milvus Lite 相关错误,优先检查是否偏离了这组版本约束。

8. Milvus Lite 可写目录要求

健康检查成功并不代表底层 Milvus Lite 一定已经正确打开数据库。

常见现象是:

  • GET /health 正常
  • 但第一次 /ingest/search 才报错

这通常是因为:

  • milvus_db.uri 指向的目录不可写
  • 或其旁边的 lock 文件无法创建

推荐始终使用类似下面的配置:

milvus_db:
  uri: "./data/milvus_local.db"

并确保:

mkdir -p data

许可证

本项目使用 MIT License,见 LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

searchbox-0.3.1.tar.gz (64.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

searchbox-0.3.1-py3-none-any.whl (51.1 kB view details)

Uploaded Python 3

File details

Details for the file searchbox-0.3.1.tar.gz.

File metadata

  • Download URL: searchbox-0.3.1.tar.gz
  • Upload date:
  • Size: 64.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for searchbox-0.3.1.tar.gz
Algorithm Hash digest
SHA256 29be07c29cac869deffb24b04a53bec734201fba30ac2e96f383d73052f1074b
MD5 ed890b7afb9f640938697ed5f0402aaf
BLAKE2b-256 00bde4657422a9ad3c882069e78754197ec89134f37abf0f6e0955c869acf8bf

See more details on using hashes here.

File details

Details for the file searchbox-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: searchbox-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 51.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for searchbox-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5b98e58b40b52e77115ad45fa84b96d3929c6675cf6cf1e284b905679b8ab875
MD5 6c00f47022a1b7963187b4ded3b20b5d
BLAKE2b-256 3dd73f5ef9d247b5e112af9a954167a28d369237308eddff6c61afc6cff58756

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page