马铃薯研究
面向土豆硬件和真人的矢量文档搜索系统和MCP服务器-只需部署、摄取和使用。
尊重您的系统资源,只将向量和轻量级定位器嵌入到原始源文件中,而不是将所有内容复制到向量数据库中。此外,还支持IVF-PQ索引,以进一步减少占用空间并加快搜索速度。
目前支持ZIM存档、PDF、Microsoft Office和ODF格式的摄取。
为什么?
标准向量数据库存储嵌入向量 和 把全文放在一起。例如,如果你的源语料库是几百GB的压缩文本,向量数据库会解压缩并复制所有内容,迅速膨胀到数TB。如果你在自带矢量模式下使用它们来避免这种情况,你必须自己管理。
马铃薯搜索商店仅限:
- 嵌入向量(通过FAISS乘积量化压缩)
- 文档定位器:
(backend_name, locator_string, char_start, char_end)
在查询时,它搜索精简索引,解析指针,并根据需要从原始源文件中读取实际文本。
建筑
HTTP API (FastAPI, port 8391)
↓
Query Engine: embed query → search all shards → merge by score → fetch text
↓
┌────────────────────────────────────────────────────────────┐
│ Per-Backend Shards │
│ │
│ data/shards/wikipedia-en/ data/shards/my-docs/ │
│ ├── faiss.index ├── faiss.index │
│ └── refs.sqlite └── refs.sqlite │
│ │
│ Each shard has its own FAISS index + SQLite ref store. │
│ Shards can be ingested, dropped, and rebuilt │
│ independently. │
└────────────────────────────────────────────────────────────┘
↓
Storage Backend Plugins
┌─────┬───────────┬──────┐
│ ZIM │ Plaintext │ ... │
└─────┴───────────┴──────┘每个配置的后端都有自己的 碎片 --一个包含FAISS索引和SQLite引用存储的隔离目录。这允许对每个源进行独立的生命周期管理:您可以摄取、删除或重建任何单个分片,而无需接触其他分片。
安全说明
这旨在在本地或 _高度信任_ 网络,例如为此工作使用一个命名空间/分段。尚未实现任何形式的身份验证。 不要将其暴露给不受信任的网络.
快速开始
1.安装发动机
cd engine
# Using pipenv (recommended)
pipenv install
# Or with pip
pip install -e .
# With ZIM support
pip install -e ".[zim]"2.配置后端
mkdir -p data
cp engine/backends.example.json data/backends.json
# Edit data/backends.json with your actual paths示例 data/backends.json:
{
"backends": [
{
"id": "wikipedia-en",
"type": "zim",
"description": "English Wikipedia — full text of all articles",
"paths": ["/media/archive/wikipedia_en.zim"],
"min_text_length": 200
},
{
"id": "notes",
"type": "plaintext",
"description": "Personal notes and documentation",
"paths": ["/home/user/notes"]
}
]
}每个条目都需要:
id--此后端的唯一名称。用作shard目录名称,并在CLI/API命令中使用。如果省略,则默认为type.type--后端类型(zim或plaintext).paths--后端的源路径列表。
可选字段:
description--此后端包含的内容的人类可读描述。通过API和MCP公开,以便代理可以发现和选择相关后端。
您可以有多个具有不同ID的相同类型的条目(例如,不同ZIM存档的单独分片)。
3.摄入
对于小型语料库(\ str: return self._backend_id
def iterate_documents(self) -> Iterator[Document]: """ Yield every document from your source. Called during ingestion. Each Document has: - locator: opaque string YOU define, used to re-fetch later - title: human-readable title - text: full plaintext content (harness handles chunking) - metadata: optional dict """ for item in your_format_reader(self._config): yield Document( locator=item.unique_id, # you define the format title=item.title, text=item.get_text(), metadata={"source": self._config}, )
def retrieve_text(self, locator: str, char_start: int, char_end: int) -> str: """ Re-read a document and return text[char_start:char_end]. Called at query time. Must be fast (the LLM call is the bottleneck, but don't do anything gratuitously slow here). """ return self.retrieve_document(locator)[char_start:char_end]
def retrieve_document(self, locator: str) -> str: """Return the full text of a document. Called by the get_document MCP tool and REST endpoint.""" return your_format_reader.get_by_id(locator)
### 第二步:注册
在中添加块 `engine/potatosearch/cli.py`s `_register_backends_from_config()`:
elif btype == "myformat": from potatosearch.backends.my_backend import MyBackend backend = MyBackend( some_config=entry["config_value"], backend_id=backend_id, )
在 `backends.json`:
{ "id": "my-data", "type": "myformat", "description": "My custom data source", "config_value": "/path/to/data" }
### 后端设计规则
1. **后端是无状态读取器。** 它们不会嵌入、块化或索引任何东西。
1. **后端名称来自配置。** 接受a `backend_id` 关键字参数,并从 `name` 财产。这允许同一后端类型的多个实例。
1. **定位器是不透明的字符串。** 线束按原样存储它们,并在查询时将其传递回去。这样设计它们 `retrieve_text()` 可以快速找到文档。
1. **`iterate_documents()` 一定很懒。** 一次生成一个文件。不要将整个语料库加载到内存中。
1. **`retrieve_text()` 和 `retrieve_document()` 必须返回摄入过程中产生的相同文本**,否则char偏移量将出错。如果您的格式涉及任何文本转换(HTML剥离、编码规范化),请在所有方法中应用相同的转换。最简单的模式是实现 `retrieve_document()` 并有 `retrieve_text()` 给它一片。
## 测试
cd engine pipenv run pytest tests/ -v
## 开发完整性/AI使用
[Jacob See的发展诚信声明v1.0](./INTEGRITY.md)
## 许可证
仅限AGPL-3.0