上传文档即可提问。文档解析、结构感知分块、上下文检索、混合检索(向量 + BM25)、MMR 去冗余、多查询检索全部在你的电脑本地完成 —— 文档内容与向量数据不出设备一步,零嵌入 API 成本。回答支持任意 OpenAI 兼容模型:DeepSeek / GLM / Kimi 云端,或 Ollama 本地模型实现全离线;支持推理模型思考过程展示、引用可信度自检、嵌入模型版本管理与一键重新嵌入、数据备份/恢复。
市面上文档问答工具(如 NotebookLM、Dify)都要把文档上传到云端。敏感资料(合同、论文、内部手册)越少离开本机越好。DocRAG 做一件事:文档不离机。
- 嵌入模型本地推理(transformers.js + 多语言 MiniLM,约 112MB,支持中英 50+ 语言)
- 向量与原文一张 SQLite 文件(Node 内置
node:sqlite,零原生依赖) - BYOK:自己的 API Key 自己管,只存在浏览器 localStorage,随请求头发给所选服务商
- 可选 Ollama 接入:嵌入 + 回答全离线,断网可用
- 拖拽上传 txt / md / pdf / docx / html / csv / tsv,多文件批量入库(带内容哈希去重、单文件大小/数量限制)
- 结构感知分块:Markdown 标题层级切分并记录章节路径(600 字/块、120 字重叠,超长段落硬切兜底)
- 上下文检索(Contextual Retrieval):嵌入前为每块拼接「文档名 · 章节 · 位置」上下文头,向量携带结构信息,语义召回更准
- 混合检索:向量语义 + BM25 关键词(中文 bigram 分词)RRF 融合 —— 专有名词/精确术语不再漏检,前端标注双分数
- 多查询检索(Multi-Query):可选,先把问题改写成多条检索查询并合并召回,复杂问题命中率更高(失败自动回退单查询)
- MMR 多样性重排:融合结果去冗余(同段落近似块只留信息量最大者),检索更全面
- 邻块上下文扩展:命中块自动并入同文档相邻块,回答更完整、少断章取义
- 流式回答(NDJSON over fetch stream,带超时保护),回答标注 [n] 引用,点击查看原文出处段落
- 多轮对话会话:上下文随问答自动保存(SQLite),可随时回来继续;会话标题从首问自动生成(≤24 字);支持重命名、置顶、搜索与 Markdown 导出
- 按文档筛选检索范围:每个会话可限定仅在指定文档内问答,多主题资料互不干扰
- 文档库管理:全文搜索(命中段落高亮切片)、批量删除、查看原文、自动标签 + LLM 摘要 + 一键重新嵌入
- 数据安全:
GET/POST /api/backup一致性备份与安全恢复;嵌入模型信息随文档落库,换模型后旧块自动降级仅关键词召回并预警 - CLI 批量导入:
npm run import -- 目录/递归扫描本地文档入库,不经 HTTP,自动跳过重复文档 - REST API + 健康检查 + OpenAPI 文档:
/api/openapi机器可读,/api/health供探活/容器健康检查 - 模型预设:DeepSeek / GLM / Kimi / Ollama / 自定义 OpenAI 兼容端点
- 可选访问密码(
APP_PASSWORD环境变量,适合部署到局域网) - Docker 一键部署(多阶段构建 + 数据卷持久化 + 构建期预下载嵌入模型 + 健康检查)
要求:Node.js ≥ 22.5(使用内置 node:sqlite)
npm install
cp .env.example .env.local # 国内网络必须设置 HF_ENDPOINT=https://hf-mirror.com
npm run dev # http://localhost:3000- 打开首页,拖入文档(首次上传会自动下载嵌入模型,约 30 秒~2 分钟)
- 打开「问答」页,点「模型设置」,选服务商并填入 API Key(Ollama 本地模型可留空)
- 输入问题,回答会标注 [n] 引用,点击可查看文档原文段落
验证安装:
npm test # 168 项单元测试(含路由层集成测试)
npm run build && npm start # 生产构建
node scripts/verify-embed.mjs # 验证本地嵌入模型
node scripts/verify-api.mjs # 端到端验收(需服务已启动)
npx tsx scripts/eval-retrieval.ts # 检索质量离线评估(Recall/Precision/MRR)无需打开网页,把本地目录整个倒入:
npm run import -- ./docs/ 论文.pdf 随手记.md # 目录 + 文件混用,递归扫描
DATA_DIR=/path/to/data npm run import -- ./docs/ # 指定数据目录docker compose up -d --build
# 打开 http://localhost:3000- 构建期自动预下载嵌入模型(约 112MB),运行时零等待
- 数据卷
./data持久化文档与向量库,重建容器数据不丢 - 环境变量在
docker-compose.yml中配置(服务端兜底 Key / 访问密码)
注:本机未安装 Docker 时无法在仓库内直接验证,构建命令已验证至 Node 环境,镜像需在安装 Docker 的机器上构建。
┌────────┐ 解析 ┌──────┐ 分块 ┌──────┐ 本地嵌入 ┌────────┐ 入库 ┌──────────┐
│ 拖拽上传 ├─────────►│ txt ├────────►│ 600字 ├───────────►│ MiniLM ├────────►│ SQLite │
└────────┘ pdf/docx └──────┘ 重叠120 └──────┘ 384 维归一化 └────────┘ BLOB │ + WAL │
CLI 导入 ────────────────────────────────► 同一管道 ────────────────────────► │ sessions │
│ messages │
└──────────┘
提问 ──► 本地嵌入 ──► 余弦 top-k 检索(按会话范围过滤)──► 历史注入 ──► 流式 LLM ──► 回答 [n] + 原文出处
▲ │
└──── 问答自动存档 ────┘
| 层 | 技术 | 说明 |
|---|---|---|
| 前端 | Next.js 16 (App Router) + Tailwind 4 | 浅色极简,无组件库,会话侧栏双栏布局 |
| 解析 | pdf-parse / mammoth / 内置 | 纯 JS 本地解析,支持 txt/md/pdf/docx/html/csv/tsv |
| 嵌入 | @huggingface/transformers | 本地 ONNX 推理,q8 量化 |
| 存储 | node:sqlite (内置) | 零原生依赖,单文件数据库,WAL 模式;文档/分块/会话/消息四表,分块带上下文头,文档带嵌入模型元信息 |
| 检索 | 混合检索 + 上下文检索 + 多查询 + MMR + ANN | 余弦 + BM25 经 RRF 融合(BM25 倒排 posting、大库 IVF 近似加速);块嵌入带章节上下文;多查询增强召回,MMR 去冗余 |
| LLM | OpenAI 兼容 chat/completions | BYOK 透传(x-api-key 请求头),多轮上下文注入 |
| 部署 | Docker 多阶段 / CLI 批量导入 | 构建期预下载模型,数据卷持久化 |
| 变量 | 默认 | 说明 |
|---|---|---|
HF_ENDPOINT |
https://hf-mirror.com |
嵌入模型下载镜像(国内网络必需) |
LLM_API_KEY |
- | 服务端兜底 Key(前端填写的 Key 优先) |
LLM_BASE_URL |
https://api.deepseek.com/v1 |
服务端兜底端点 |
LLM_MODEL |
deepseek-chat |
服务端兜底模型 |
LLM_TEMPERATURE |
- | 默认采样温度 |
LLM_MAX_TOKENS |
- | 默认最大生成 token |
LLM_TIMEOUT_MS |
120000 |
单次调用超时(毫秒) |
EMBED_MODEL |
Xenova/paraphrase-multilingual-MiniLM-L12-v2 |
可换其他 transformers.js 兼容模型 |
EMBED_DTYPE |
q8 |
量化精度 |
EMBED_CONCURRENCY |
2 |
嵌入并发上限(上传/重嵌入共享) |
ANN_MIN_CHUNKS |
2000 |
块数达到该值启用 IVF 近似向量检索;0 禁用 |
DATA_DIR |
./data |
SQLite 数据目录 |
MAX_UPLOAD_MB |
50 |
单文件上传大小上限 |
MAX_FILES |
20 |
单次上传文件数上限 |
APP_PASSWORD |
- | 设置后启用访问密码门 |
- 文档解析、分块、嵌入、检索全部在服务端进程本地完成,不经过任何第三方
- API Key 仅存于浏览器 localStorage,通过 HTTPS 请求头直达所选服务商,服务端不落盘(
.env.local兜底 Key 可选配) - 数据库为单文件
data/app.db,删除即彻底清除 - 部署到局域网/公网时设置
APP_PASSWORD即可设访问门槛:cookie 由密码单向派生、不可伪造,且页面与全部 API 同步受保护(未认证 API 返回 401) - 防 SSRF:LLM 端点地址经校验,仅允许 http/https,阻断云元数据/保留地址
- 登录接口限流(默认 60s 内 10 次),防暴力枚举
- 备份/恢复安全:恢复前校验 SQLite 文件头,自动保留
app.db.pre-restore回退快照 - 依赖审计:CI 对 critical 级漏洞设门槛;
@huggingface/transformers传递依赖(adm-zip / sharp)存在 high 级公告且上游暂无修复,仅在本机解析模型文件时触发
app/
page.tsx # 首页:上传 + 文档库(搜索 / 批量删除 / 标签 / 摘要 / 查看原文)
chat/page.tsx # 问答页:会话侧栏 + 流式对话(reasoning)+ 引用 + 设置 + 导出
lock/page.tsx # 可选密码门
error.tsx / not-found.tsx / loading.tsx # 全局错误与加载边界
api/upload/ # 上传解析入库(限制 + 去重 + 标签 + 并发闸)
api/documents/ # 文档列表 / 单个或批量删除
api/documents/content/ # 文档原文内容
api/documents/summarize/ # 文档摘要(可选 LLM)
api/documents/reembed/ # 文档重新嵌入(换模型后重建向量)
api/search/ # 全文搜索
api/chat/ # RAG 流式问答(多轮历史 + 自动存档, NDJSON)
api/sessions/ # 会话管理(列表/新建/重命名/置顶/删除)
api/sessions/export/ # 会话导出 Markdown
api/messages/ # 会话消息恢复(含引用重放)
api/lock/ # 密码校验(限流)
api/backup/ # 数据备份下载 / 恢复上传
api/health/ # 健康检查(含嵌入队列状态)
api/openapi/ # OpenAPI 3.1 文档
components/
session-sidebar.tsx # 会话列表 + 置顶/搜索/重命名 + 文档范围筛选
doc-browser.tsx # 文档浏览器(搜索/批量删除/标签/摘要/原文查看)
upload.tsx # 拖拽上传(去重/跳过展示)
message-bubble.tsx # 消息气泡(引用芯片/思考过程/越界引用提示)
model-settings.tsx # 模型设置弹窗(温度/查询增强/BYOK)
locale.tsx # 基础 i18n(中/英)+ 本地化 Provider
nav.tsx # 顶部导航(含深色模式/语言切换)
proxy.ts # 可选密码门(Next 16 proxy 约定)
.github/workflows/ci.yml # CI:lint / test / build / audit
lib/
parse.ts # txt/md/pdf/docx/html/csv/tsv 解析
chunk.ts # 段落感知分块 + 结构感知分块(标题层级)
embed.ts # 本地嵌入(transformers.js 单例) + 嵌入元信息
vector.ts # 余弦检索 + BLOB 转换
bm25.ts # BM25 关键词检索(中文 bigram + 倒排 posting)
search.ts # 混合检索(RRF 融合)+ 多查询合并 + null 向量兼容
ann.ts # IVF-Lite 近似向量索引(大库加速)
rerank.ts # MMR 多样性重排
context.ts # 邻块上下文扩展
contextualize.ts # 上下文检索(context head 拼接)
multiQuery.ts # 查询改写提示 + 结果解析
eval.ts # 检索评估指标(Recall/Precision/MRR)
citations.ts # 引用可信度校验(越界编号)
validate.ts # 请求体参数校验
semaphore.ts # 嵌入并发闸
hash.ts # 内容哈希(重复检测)
keywords.ts # 文档关键词提取(词频加权)
summarize.ts # 文档摘要 prompt 组装
llm-config.ts # LLM 配置集中解析(BYOK/环境变量 + SSRF 校验)
auth.ts # 密码门鉴权(cookie 密码派生 + 恒定时间比较)
ssrf.ts # LLM 端点校验(防 SSRF)
rateLimit.ts # 内存滑动窗口限流
export.ts # 会话 Markdown 导出
db.ts # node:sqlite 惰性初始化(WAL + 迁移 + 备份/恢复 + 检索缓存)
llm.ts # OpenAI 兼容流式/非流式调用(超时/温度/推理内容)
rag.ts # prompt 组装(历史注入)+ 引用提取
tests/ # node --test(168 项,含路由层集成测试)
scripts/
import-cli.ts # CLI 批量导入(目录递归 + 去重)
verify-embed.mjs # 嵌入模型验证
verify-api.mjs # 端到端验收(上传→检索→会话全流程)
eval-retrieval.ts # 检索质量离线评估(Recall/Precision/MRR)
Dockerfile # 多阶段构建(构建期预下载模型)
docker-compose.yml # 一键部署 + 数据卷 + 健康检查
- 全文搜索、批量删除与文档原文查看
- 会话重命名与 Markdown 导出
- MMR 多样性重排与邻块上下文(检索质量)
- 上下文检索 + 结构感知分块 + 多查询检索 + 检索评估
- 文档自动标签 + LLM 摘要
- 会话置顶 / 搜索
- REST API 文档(OpenAPI)与健康检查接口
- 嵌入模型版本管理与重新嵌入
- 数据备份 / 恢复
- BM25 倒排加速 + IVF 近似检索(大库)
- LLM 参数化与推理模型支持(temperature/max_tokens/reasoning)
- 引用可信度自检、输入校验、CI、路由集成测试、深色模式、基础 i18n
- 扫描件 PDF 的 OCR 支持
- 重排序模型(cross-encoder)接入
- PDF 导出分享
MIT