系列文章用 FastAPI RAG 多模型路由独立开发一个可商用的学术 PDF 知识库 SaaS 平台 DocMind。一、为什么做这个项目读研期间最痛苦的事情之一桌面上堆了几十篇 PDF想找某个知识点只能靠 CtrlF 关键词搜索看到一半又跳到另一篇上下文完全割裂。市面上有 ChatPDF、Elicit 这类工具但ChatPDF免费版只能传一篇不支持跨文献对比Elicit主要做文献发现不做深度问答Notion AI导入 PDF 体验很差本地部署方案Ollama AnythingLLM配置复杂非技术用户用不了决定自己做一个上传论文 → 自动解析章节 → AI 问答 精读 写综述 降率一站搞定。二、最终实现的功能模块经过迭代DocMind 最终实现了 6 个核心模块模块功能 文档库PDF 上传、管理、批量删除 知识库问答多文献 RAG 问答支持章节定向检索 PDF 精读对话三栏布局目录 PDF 原文 AI 对话支持框选截图分析 文献综述多文献一键生成综述✍️ 论文撰写按章节框架 AI 辅助写作✂️ 降率工具英文降 AI 率 / 降重复率分块流式处理附加功能引用格式导出10 种格式、联网检索增强。三、整体架构┌─────────────────────────────────────────────────────┐ │ 用户浏览器 │ │ index.html落地页 app.htmlSPA │ └──────────────────────┬──────────────────────────────┘ │ HTTPS / SSE ┌──────────────────────▼──────────────────────────────┐ │ FastAPI 后端Railway │ │ │ │ routers/ │ │ ├── auth.py 注册/登录/JWT │ │ ├── upload.py PDF上传 异步处理入库 │ │ ├── query.py RAG问答 / 综述 / 撰写 / 引用 │ │ ├── reduce.py 英文降率 │ │ └── vision.py 图像分析Gemini │ │ │ │ services/ │ │ ├── pdf_processor.py PyMuPDF章节解析 │ │ ├── embedder.py Jina AI向量化 Chroma存储 │ │ └── retriever.py RAG检索 LLM调用 │ └─────┬────────────────┬───────────────────────────────┘ │ │ ▼ ▼ Supabase Chroma DB PostgreSQL Railway 本地卷 用户/文档元数据 向量索引 │ └──── 调用外部 API ────┐ ▼ ┌─────────────────┐ │ LLM / Embedding │ │ DeepSeek v4 │主力问答 │ Groq Llama 3 │限流降级 │ Gemini 2.5 Flash│视觉分析 │ Jina AI │向量化 └─────────────────┘四、关键技术选型理由4.1 为什么不用 LangChainLangChain 是 RAG 场景的常见选择但我最终没有用原因过度抽象LangChain 把检索、提示、输出解析全包了出了问题很难定位是哪一层的锅升级频繁0.1 → 0.2 → 0.3 接口变化很大文档跟不上我的场景简单RAG 核心逻辑不过 200 行自己写反而清晰最终选择直接用openaiSDK 自写检索逻辑所有 LLM 调用一目了然。4.2 向量库Chroma 而非 Pinecone / WeaviateChromaPineconeWeaviate部署本地/嵌入云服务自托管/云免费完全免费有免费额度开源免费Railway 适配✅ 直接挂卷✅ 但需联网⚠️ 较重中文支持✅✅✅选 Chroma 的关键原因可以直接挂 Railway 持久卷零额外费用嵌入式运行无需独立服务。⚠️ 注意Railway 免费套餐文件系统是临时的每次重启数据清空。需要升级到有持久卷的套餐或迁移到 Supabase pgvector。4.3 EmbeddingJina AI 而非 OpenAIOpenAItext-embedding-3-small$0.02/1M token但对中英混合文本效果一般Jina AIjina-embeddings-v3免费额度 100万 token/月中英双语语义对齐好对学术场景特别有价值用中文提问「注意力机制」能命中英文文本中的「Attention」不需要额外翻译。4.4 LLM 路由DeepSeek 主力 Groq 降级DeepSeek v4-flash 性价比极高官方定价约 $0.07/1M 输入 token但 Groq 免费版每日有 Token 上限约 14400 token/分钟。解决方案设计MODEL_ROUTESMODEL_FALLBACK双表路由遇到 429 自动切换对用户完全透明。具体实现见第三篇。4.5 部署平台Railway 而非 VercelVercel适合 Node.js/Next.jsPython 支持通过 Serverless Functions有执行时间限制10sPDF 处理会超时Railway完整 Linux 环境可以跑任意 Python 进程支持后台线程持久卷Dockerfile 部署五、数据库设计使用 Supabase PostgreSQL核心表-- 用户表 CREATE TABLE users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), email TEXT UNIQUE NOT NULL, password TEXT NOT NULL, -- SHA256 salt plan TEXT DEFAULT free, -- free / pro pdf_count INTEGER DEFAULT 0, query_today INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT now() ); -- 文档表 CREATE TABLE documents ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), filename TEXT, -- 服务器存储名uuid.pdf original_name TEXT, -- 用户上传的原始文件名 size_bytes INTEGER, page_count INTEGER, chunk_count INTEGER, status TEXT DEFAULT pending, -- pending/processing/ready/error error_msg TEXT, created_at TIMESTAMP DEFAULT now() );向量块单独存在 PostgreSQLdoc_chunks表通过 pgvector 扩展或 Chroma 本地库。六、项目目录结构kb_project/ ├── main.py # FastAPI 入口挂载路由 ├── config.py # 所有配置API Key、模型路由、分块参数 ├── requirements.txt │ ├── db/ │ └── database.py # SQLAlchemy 模型 连接池 │ ├── routers/ │ ├── auth.py # 注册/登录/JWT 验证 │ ├── upload.py # PDF 上传 文件下载接口 │ ├── query.py # 问答/综述/撰写/引用 │ ├── reduce.py # 英文降率 │ └── vision.py # 图像分析 │ ├── services/ │ ├── pdf_processor.py # PDF 解析 → chunks │ ├── embedder.py # 向量化 Chroma 存取 │ └── retriever.py # RAG 检索 LLM 调用 │ ├── uploads/ # 上传的 PDF 文件 └── frontend/ ├── index.html # 落地页 └── app.html # 工作台 SPA单文件约3000行七、开发与部署流程# 本地开发 pip install -r requirements.txt uvicorn main:app --reload --port 8000 # Railway 部署Dockerfile FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD [uvicorn, main:app, --host, 0.0.0.0, --port, 8000]Railway 环境变量不写死在代码里GROQ_API_KEY... DEEPSEEK_API_KEY... GEMINI_API_KEY... JINA_API_KEY... DATABASE_URLpostgresql://......supabase.co:5432/postgres SECRET_KEYyour-jwt-secret八、小结本篇覆盖了 DocMind 的整体架构与核心选型。关键决策回顾不用 LangChain自写 RAG 逻辑更可控Chroma做向量库Railway 本地挂卷Jina AI做 Embedding中英双语对齐DeepSeek 主力 Groq 降级兼顾成本与稳定性单文件 SPA 前端零构建步骤Railway 直接静态服务下一篇PDF 解析与 RAG 检索核心实现——如何让 AI 真正读懂论文章节结构。