# docpilot **Repository Path**: xzs-ctrl/docpilot ## Basic Information - **Project Name**: docpilot - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-30 - **Last Updated**: 2026-09-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # DocPilot · AI 知识库 > 一个把「写文档、搜文档、问文档、一起编辑文档」串起来的全栈 AI 知识库:当前已实现用户体系、空间权限、Markdown 文档管理、空间内全文检索、文档入库管道(分块 + 向量化)与 RAG 问答(SSE 流式输出、带可点击引用、可中断);多人实时协作仍在路线图规划中。 --- ## ✨ 功能特性 **已实现** - **📝 Markdown 文档管理**:TipTap 富文本编辑器 + 自动保存、软删除、列表按更新时间排序 - **🔍 空间内全文搜索**:基于 PostgreSQL `pg_trgm`,对中文友好,标题 + 正文命中并按相关度排序,命中词高亮、正文片段预览 - **🧩 文档入库管道**:保存后按 Markdown 标题层级分块(默认约 1000 字符、相邻块重叠 12%)→ 调用 Embedding 接口向量化(OpenAI 兼容)→ 写入 `doc_chunks`(pgvector,HNSW 索引)。异步触发不阻塞保存、失败只告警不影响编辑;以 `ingested_version` 版本号判断增量;并发重建用 PostgreSQL 咨询锁串行化。手动重建:`POST /api/spaces/:spaceId/documents/:documentId/reindex`(owner / member) - **🤖 RAG 文档问答**:对空间提问 → 问题向量化 → pgvector 余弦相似度检索 top-8 块 → 交给 DeepSeek 生成带 `[1][2]` 引用的回答,引用可点击跳转原文。检索严格限定空间并排除软删文档;空间内没有可检索资料时**不调用模型**、直接返回提示(不编造);上游(embedding / LLM)失败统一降级 503,且每人限 **10 次/分钟**(提问会真实调用付费接口)。问答与来源落库 `chat_messages`,空间成员可回看历史 - **⚡ 流式输出与中断**:回答走 SSE(`POST /api/spaces/:spaceId/qa/stream`)逐 token 推送,前端打字机式渲染;先发 `sources` 再发正文,引用列表不必等模型。点「停止」、切换空间或离开页面都会**透传 AbortSignal 取消上游 LLM 请求**(剩下的 token 不再计费),已生成的部分照常落库,回来还能接着读。回答被中断、上游中途失败或撞到模型长度上限时会在回答气泡里明确标注(不把半截正文当完整回答);「开流前」的失败(检索 / embedding / 首字节 503)仍是普通的 503 JSON - **👥 用户体系**:注册 / 登录 / JWT + 刷新 token - **🔐 空间与成员权限**:空间为数据隔离最小单位,三档角色权限(owner / member / viewer) **规划中(见下方路线图)** - **👥 多人实时协作**:基于 Yjs CRDT 实现同文档协同编辑、实时光标、在线成员列表 --- ## 🛠 技术栈 | 层 | 技术 | |---|---| | 前端 | Next.js (App Router) · TypeScript · Tailwind CSS · TipTap(Markdown) | | 后端 | NestJS · TypeScript · Prisma(pgvector / pg_trgm) | | 数据库 | PostgreSQL 16 · Redis | | AI | Embedding API(百炼 / SiliconFlow,OpenAI 兼容,已接入入库与检索)· DeepSeek Chat(RAG 问答,SSE 流式) | | 实时(规划中) | Socket.IO · Yjs | | 工程化 | pnpm workspace · Docker Compose · Vitest + Supertest | --- ## 🏗 架构 ``` Browser (Next.js) │ └── REST /api/* ──► NestJS API ──► PostgreSQL (pgvector / pg_trgm) │ │ │ │ │ ├──► Embedding API(保存文档后异步分块 + 向量化;问答时向量化问题) │ │ └──► LLM API(RAG 问答:余弦检索 top-8 块 → 生成带引用的回答) │ ▼ │ Redis (缓存/限流/refresh-token 黑名单) │ └── SSE /api/spaces/:id/qa/stream ──► 逐 token 转发 LLM 输出(可 AbortSignal 中断) ``` 当前实现的是 REST 业务链路 + Embedding 调用(入库与问答检索)+ SSE 流式 LLM 问答(含中断与半截回答落库);Socket.IO 实时协作属于规划中的路线图。完整技术设计见 [`ai-knowledge-base-design.md`](./ai-knowledge-base-design.md)。 --- ## 🚀 快速开始 ### 方式一:Windows 一键脚本 > 下面两个脚本仅在 Windows 下可用(行尾固定为 CRLF,见 [`.gitattributes`](./.gitattributes))。**Linux / macOS 请直接用「方式三:手动命令」**,或使用「方式二:VS Code Tasks」。 前置:Node.js 20+、pnpm、Docker Desktop(WSL2)。根目录 [package.json](./package.json) 固定 `pnpm@11.7.0`,先 `corepack enable pnpm` 让 pnpm 自动切换到对应版本。 ```bat install-deps.bat :: 首次或依赖变更后运行:安装依赖、补齐缺失的 .env、生成 Prisma Client start-dev.bat :: 日常启动:拉起 PostgreSQL/Redis、应用迁移并分别启动前后端 ``` ### 方式二:VS Code Tasks 用 VS Code 打开仓库根目录后,执行 `Terminal → Run Task…`: - `DocPilot: 一键启动前后端`:并行启动后端 API 与前端 Web - `DocPilot: 启动依赖服务 (PostgreSQL/Redis)`、`DocPilot: 应用数据库迁移`:首次启动前先执行 ### 方式三:手动命令 前置要求:Node.js 20+、pnpm、Docker ```bash # 0. 在仓库根目录一次性安装依赖(pnpm workspace 会同时装好 apps/api 与 apps/web) pnpm install # 1. 准备环境变量(Windows PowerShell 可用 Copy-Item 代替 cp),并填入 API Key cp apps/api/.env.example apps/api/.env cp apps/web/.env.example apps/web/.env.local # 2. 启动依赖服务(docker compose 只包含 PostgreSQL 与 Redis,不含应用服务) docker compose up -d # 3. 应用数据库迁移(首次用 dev 建迁移;日常启动只需 deploy) pnpm --filter api exec prisma migrate dev # 4. 开两个终端分别启动前后端 pnpm --filter api start:dev # 后端 http://localhost:8080(api 没有 dev 脚本) pnpm --filter web dev # 前端 http://localhost:3000 ``` ### 环境变量 **apps/api/.env** | 变量 | 说明 | |---|---| | `DATABASE_URL` | PostgreSQL 连接串 | | `REDIS_URL` | Redis 连接串 | | `JWT_ACCESS_SECRET` / `JWT_REFRESH_SECRET` | JWT 签名密钥(生成:`openssl rand -hex 32`) | | `LLM_API_KEY` / `LLM_BASE_URL` / `LLM_MODEL` | LLM 接口(DeepSeek,OpenAI 兼容格式) | | `EMBEDDING_API_KEY` / `EMBEDDING_BASE_URL` / `EMBEDDING_MODEL` / `EMBEDDING_DIM` | Embedding 接口(百炼 / SiliconFlow) | | `CORS_ORIGIN` | 允许的前端来源 | > `EMBEDDING_*` 未配置或配置错误时,保存文档本身不受影响,只是文档不会产生向量(入库失败仅打告警日志,旧块保持可用);`EMBEDDING_DIM` 必须与 `doc_chunks.embedding` 的 `vector(1024)` 一致,换模型后需要手动触发一次 reindex 重建全部块。 **apps/web/.env.local** | 变量 | 说明 | |---|---| | `NEXT_PUBLIC_API_BASE_URL` | 后端 REST 地址 | | `NEXT_PUBLIC_WS_URL` | WebSocket 地址 | | `ALLOWED_DEV_ORIGINS` | 允许访问 dev 服务器的额外来源(局域网 IP / 域名,逗号分隔,可留空)。从手机等其他设备访问 `next dev` 时必填,**不要把它硬编码进 `next.config.ts`** | > `LLM_*` 未配置或调用失败时,问答接口返回 503(其余功能不受影响);`EMBEDDING_*` 没配好时问答同样会 503——检索不到块就没法组织上下文。流式接口只在**开流前**失败时返回 503(embedding / 检索 / LLM 首字节,此时还没写响应头);已经开流之后才失败,HTTP 状态码就改不了了,只能发一条 SSE `error` 事件,前端提示重试并保留已收到的正文。 ### 测试 ```bash pnpm --filter api test # 单测(vitest,不需要数据库) pnpm --filter api test:e2e # e2e(需要 PostgreSQL;串行跑在开发库上,结束会清理数据) ``` > `test/ingestion.e2e-spec.ts` 会**真实调用 Embedding 接口(可能计费)**,`test/qa.e2e-spec.ts` 还会**真实调用 LLM**;对应 key 缺失或仍是占位符 `sk-...` 时整组自动跳过。 --- ## 📁 项目结构 ``` docpilot/ ├─ apps/ │ ├─ web/ # Next.js 前端 │ │ └─ src/app/ # App Router 页面(/login、/space/[id]...) │ └─ api/ # NestJS 后端 │ └─ src/modules/ # auth / users / spaces / documents / search / ingestion / qa ├─ .vscode/ │ └─ tasks.json # VS Code 任务:一键启动前后端等 ├─ .gitattributes # 统一 LF 入库,*.bat 例外为 CRLF ├─ .gitignore ├─ AGENTS.md # AI 编码助手与协作者开发约定 ├─ ai-knowledge-base-design.md # 技术设计文档(含数据库设计与面试准备) ├─ docker-compose.yml # 仅编排 PostgreSQL / Redis ├─ install-deps.bat # Windows:安装前后端依赖 ├─ package.json # workspace 根,固定 pnpm 版本 ├─ pnpm-lock.yaml ├─ pnpm-workspace.yaml ├─ README.md └─ start-dev.bat # Windows:一键启动前后端 ``` --- ## 🗺 路线图 **MVP(进行中)** - [x] 用户体系:注册 / 登录 / JWT + 刷新 token - [x] 空间与成员权限:owner / member / viewer,非成员 403 - [x] 文档 CRUD + 自动保存(乐观锁)+ TipTap 富文本编辑器 - [x] 空间内全文搜索 - [x] 文档入库管道:按标题分块 + Embedding 向量化写 `doc_chunks`(异步触发 + 手动 reindex) - [x] RAG 问答:向量检索 top-8 → 带 `[1][2]` 引用的回答,问答落库 `chat_messages` - [x] RAG 流式输出(SSE + 中断,中断后保留已生成内容) - [ ] 多人实时协作(Yjs + Socket.IO) - [ ] Docker Compose 部署 + GitHub Actions CI **v2(候选,MVP 完成后再考虑)** - [ ] 文档历史版本与 diff 对比 - [ ] Word / PDF 导入导出 - [ ] @提及、评论、通知 - [ ] 移动端适配 --- ## 📸 截图 --- ## 📄 License [MIT](./LICENSE)