字节笔记本
2026年8月29日
Quivr:把本地文件向量化后随时检索对话
把 PDF、Markdown、会议纪要丢给模型问「上周结论是什么」,这就是本地 RAG 最常见的需求。2023 年那套 Docker + Supabase 网页已经不是当前入口。现在的 Quivr 是能嵌进现有 Python 项目的 RAG 库:quivr-core,默认方案都帮你选好了。源码在 QuivrHQ/quivr(Apache 2.0,旧地址 StanGirard/quivr 会跳过来),文档在 core.quivr.com。下面按「怎么装、怎么喂文件、怎么问、怎么改检索流程」写一遍。
它和站内那篇 AnythingLLM 不是同一条路。AnythingLLM 是带界面的知识库应用,装完就能点。Quivr Core 是库:你自己写十几行 Python,选 LLM、向量库和切分策略,再接到自己的服务里。想要现成网页可以用他们的托管产品;要可控、可改流水线,走 quivr-core。
先分清两个包
网上还能搜到 docker-compose up、localhost:3000、复制一堆 Supabase 密钥的教程,那些对应的是旧的全栈社区版。现在官方 README 的安装命令就一句:
python3 -m venv .venv
source .venv/bin/activate
pip install quivr-core
python -c "from quivr_core import Brain; print('ok')"PyPI 上包名是 quivr-core,要求 Python 3.11+。不要 pip install quivr:那个同名包是 Arrow 数据容器,和这个第二大脑项目无关。装错了会 ImportError: cannot import name 'Brain',先卸掉再装对的那个。
默认走 OpenAI。先把 key 放进环境变量,别写进仓库:
export OPENAI_API_KEY="sk-..."文档里也写了 Anthropic、Mistral,以及本机 Ollama。向量库默认 FAISS,也可以换成 PGVector。文件侧有 LocalStorage(默认落到 ~/.cache/quivr/files)和内存里的 TransparentStorage。
五分钟喂一批文件
最小例子来自官方 README,跑通就说明解析、切分、嵌入、检索这条链是通的:
import tempfile
from quivr_core import Brain
if __name__ == "__main__":
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt") as temp_file:
temp_file.write("Gold is a liquid of blue-like colour.")
temp_file.flush()
brain = Brain.from_files(
name="test_brain",
file_paths=[temp_file.name],
)
answer = brain.ask("what is gold? answer in french")
print("answer:", answer)换成自己的材料,把路径列表扔进去就行。PDF、TXT、Markdown 都能吃;解析这块可以接到他们的 Megaparse。Brain.from_files 会把文件放进 storage、抽文本、写入向量库(默认 FAISS)、建索引。问的时候走内置 RAG workflow。返回值是 ParsedRAGResponse,终端里一般打印 answer.answer。
from quivr_core import Brain
brain = Brain.from_files(
name="project-notes",
file_paths=["./design.md", "./meeting-2026-08.pdf"],
)
info = brain.print_info()
reply = brain.ask("上周评审里,缓存失效策略最后定的是哪一种?")
print(reply.answer)某个文件解析失败时,可以加 skip_file_error=True,先把能进的进完,再回头看日志。已经切好的 LangChain Document 也可以用 Brain.from_langchain_documents 直接建 brain,省掉再走一遍文件解析。
只想先看检索到了哪些块、还不急着生成,用 asearch:
import asyncio
from quivr_core import Brain
brain = Brain.from_files(name="notes", file_paths=["./handbook.pdf"])
results = asyncio.run(brain.asearch("发版前检查清单", n_results=5))
for item in results:
print(item.chunk.page_content[:300])把检索流程写进 YAML
默认 workflow 对很多问答够用。要改历史窗口、重排、温度,不必改 Python,写一份 RetrievalConfig:
workflow_config:
name: "standard RAG"
nodes:
- name: "START"
edges: ["filter_history"]
- name: "filter_history"
edges: ["rewrite"]
- name: "rewrite"
edges: ["retrieve"]
- name: "retrieve"
edges: ["generate_rag"]
- name: "generate_rag"
edges: ["END"]
max_history: 10
reranker_config:
supplier: "cohere"
model: "rerank-multilingual-v3.0"
top_n: 5
llm_config:
max_input_tokens: 4000
temperature: 0.7节点顺序是:滤对话历史 → 改写问题 → 检索 → 生成。最后那个节点的名字要和 YAML 里一致,流式输出才接得上。重排用了 Cohere 的多语言模型,中文块比只靠向量近邻稳一点;没有 Cohere key 就先拿掉 reranker_config,用默认检索。
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from quivr_core import Brain
from quivr_core.config import RetrievalConfig
brain = Brain.from_files(
name="my smart brain",
file_paths=["./my_first_doc.pdf", "./my_second_doc.txt"],
)
retrieval_config = RetrievalConfig.from_yaml("./basic_rag_workflow.yaml")
console = Console()
console.print(Panel.fit("Ask your brain !"))
while True:
question = Prompt.ask("Question")
if question.lower() == "exit":
break
answer = brain.ask(question, retrieval_config=retrieval_config)
console.print(answer.answer)切分策略同样可以外置。官方 ingestion 示例用 Megaparse + unstructured 处理 PDF:
parser_config:
megaparse_config:
strategy: "auto"
pdf_parser: "unstructured"
splitter_config:
chunk_size: 400
chunk_overlap: 100from quivr_core import Brain
from quivr_core.config import IngestionConfig
ingestion_config = IngestionConfig.from_yaml("./basic_ingestion_workflow.yaml")
processor_kwargs = {
"megaparse_config": ingestion_config.parser_config.megaparse_config,
"splitter_config": ingestion_config.parser_config.splitter_config,
}
brain = Brain.from_files(
name="pdf-brain",
file_paths=["./report.pdf"],
processor_kwargs=processor_kwargs,
)chunk_size 是 token 数。说明书、合同这类结构密的 PDF,400 / 100 是个能先跑的起点;代码仓库或短 FAQ 可以再调小。改 YAML 比改代码容易对照实验。
换模型和落盘
默认 LLM 看环境变量。要显式指定 Mistral,文档给的是 LLMEndpoint + LLMEndpointConfig:
from quivr_core import Brain
from quivr_core.llm.llm_endpoint import LLMEndpoint, LLMEndpointConfig
brain = Brain.from_files(
name="mistral-brain",
file_paths=["./notes.md"],
llm=LLMEndpoint(
llm_config=LLMEndpointConfig(
model="mistral-small-latest",
llm_base_url="https://api.mistral.ai/v1/chat/completions",
),
),
)本机 Ollama 也走同一套配置,把 llm_base_url 指到 Ollama 的 OpenAI 兼容口(本机常见是 http://127.0.0.1:11434/v1),model 写成你已经 ollama pull 过的名字。嵌入模型维度要和向量库一致,换本地 embedder 时先对一下维度,否则 FAISS 会直接报错。
brain 可以存到目录里,下次不用重新切分:
import asyncio
from quivr_core import Brain
brain = Brain.from_files(name="notes", file_paths=["./a.pdf", "./b.md"])
asyncio.run(brain.save("./brains/notes"))
loaded = Brain.load("./brains/notes")
print(loaded.ask("结论是什么?").answer)文件多、要反复问的时候,先 save 再 load,比每次 from_files 便宜。默认 FAISS 适合单机;数据要进 Postgres、跟业务表放一起,再换成 PGVector。
常见坑
- 还在找
docker-compose.yml和backend-base:latest。 那是旧全栈。现在自托管入口就是pip install quivr-core。GitHub Issue 里拉不到backend-base的,按官方说法就是别再走那条 compose。 - 装了
quivr而不是quivr-core。 导入Brain失败时先pip show quivr-core。 - key 没进环境。 没设
OPENAI_API_KEY(或你实际用的供应商 key)时,from_files往往在嵌入阶段就停。 - PDF 是扫描件。 默认识别对纯文本 PDF 友好。扫描件把 ingestion 里的
strategy改成ocr_only或hi_res,并确认本机 unstructured / OCR 依赖齐。 - 把 Quivr 当现成桌面客户端。 这条链没有官方一键 GUI。要开箱即用的窗口,去看 AnythingLLM;要把 RAG 嵌进自己的 API 或 Agent,用
quivr-core。
小结
现在的 Quivr 是给开发者用的 RAG 内核:pip install quivr-core,Brain.from_files 喂本地文件,brain.ask 提问,检索和切分用 YAML 改。仓库 https://github.com/QuivrHQ/quivr ,文档 https://core.quivr.com/ 。旧的 Docker 网页教程可以当历史,别跟当前包混着装。