前言:

6月的时候,基于Dolphin实现了一个轻量级的RAG,支持文档上传,构建知识库,检索问答。

一些实现细节放在了下边。

本项目的git地址:[email protected]:zuka1129/dolphin-rag.git

官方的dolphin git地址:github.com/bytedance/Do

轻量 RAG 服务技术文档(基于 FastAPI + Celery + ChromaDB + Ollama + Dolphin)

下面介绍如何搭建一个轻量级的 RAG(Retrieval-Augmented Generation)服务,包括整体架构、核心流程、接口设计、关键实现细节、部署配置与优化建议。适合希望快速落地“私有文档问答/摘要/提取”等能力的开发者。最终落地还需要根据业务进行调整。


项目简介

  • 目标:支持文档上传 → 异步解析 → 向量化入库 → 语义检索 → 流式对话(含总结、提取、检索问答)。
  • 核心文件
  • main.py:FastAPI 服务与路由
  • services/document_service.py:业务核心(文档解析、分块、向量化、检索、流式对话)
  • tasks/document_tasks.py:Celery 异步解析任务
  • utils/sqlite_utils.py:SQLite 元数据存取
  • utils/chat_stream_utils.py:流式会话终止管理
  • config/settings.py:配置项(Ollama/Redis/Chroma 等)

整体架构

  • 入口层:FastAPI 提供 HTTP API 与 SSE 流。
  • 任务层:Celery + Redis 作为异步任务队列,后台解析文档。
  • 存储层
  • SQLite:文档元数据与任务状态
  • ChromaDB:向量化文档块的持久化存储与相似度检索
  • 本地文件:原始上传文件
  • 模型层
  • Dolphin 文档感知模型(图像页解析)
  • Ollama:Embedding 与 Chat(LLM、流式输出)

技术栈与依赖

  • FastAPI、Uvicorn、Starlette(SSE)
  • Celery、Redis(Broker/Backend)
  • ChromaDB(持久化路径 ./chroma_db
  • SQLite(dolphin.db
  • Transformers BertTokenizer(上下文裁剪)
  • Dolphin(demo_page_hf.pyDOLPHIN/process_page
  • Ollama(/api/embeddings/api/chat

配置要点

  • 文件上传限制:MAX_FILE_SIZE 默认 10MB
  • 用户文档数上限:MAX_DOCUMENTS_PER_USER 默认 50(超出删除最旧)
  • 向量库持久化:CHROMA_PERSIST_DIR=./chroma_db
  • LLM 与 Embedding:
  • OLLAMA_BASE_URL(默认 http://192.168.4.20:11434
  • DEFAULT_EMBEDDING_MODEL=mxbai-embed-large:latest
  • DEFAULT_CHAT_MODEL=qwen3:latest
  • Token 管控:TOKENIZER_MODELMAX_TOKENBUFFER_TOKEN
  • Celery/Redis:通过环境变量 .env 配置

数据表结构(SQLite)

表名:documents – 字段:iduser_idfilenamefile_pathstatuscontentcreated_atprocessed_timesizetask_idresulterror – 列表接口按 created_at DESC 排序


核心流程(RAG 数据流)

1) 文档上传与入队(/upload) – 保存文件 → 记录 documents(status=pending)→ 派发 Celery 任务并记录 task_id

2) 异步解析(Celery 任务) – 加载 Dolphin 模型,按文档类型: – .txt 直接读取全文 – 其他(PDF/图片/Word/Excel)→ 转图片 → process_page → 聚合识别为 content – 更新 SQLite(status=completed、content、结构化识别结果 result)。

3) 向量化与入库(ChromaDB) – 对 content 按段落/句法边界分块(默认块长约 1000 字符) – 调用 Ollama /api/embeddings 生成向量 – 写入 ChromaDB(documents/embeddings/metadatas/ids)

4) 语义检索(/search) – 生成查询向量 → ChromaDB collection.query → 返回命中文档块(内容+元数据)

5) 流式对话(/chat) – 先做意图识别(总结/提取/检索/通用),再按意图选择上下文: – 检索类:检索若干块拼接上下文 – 总结/提取:整篇全文上下文 – 清洗文本 → Token 预算裁剪 → 构造 messages → 调用 /api/chat(stream=true) – 以 SSE 输出;/chat/stop 可终止同一 session_id 的流


API 设计与示例

  • 上传文档
curl -F "file=@/path/to/a.pdf" "http://localhost:15001/upload?user_id=alice"
  • 查询任务状态
curl "http://localhost:15001/task_status/<task_id>"
  • 获取用户文档列表
curl "http://localhost:15001/documents?user_id=alice"
  • 获取文档详情
curl "http://localhost:15001/document/<document_id>?user_id=alice"
  • 语义检索
curl "http://localhost:15001/search?user_id=alice&query=关键术语"
  • 流式对话(SSE)
curl -N -H "Content-Type: application/json" \
  -d '{"query":"帮我总结","user_id":"alice","document_id":"alice_20240910120000"}' \
  http://localhost:15001/chat
  • 终止流
curl -X POST -H "Content-Type: application/json" \
  -d '{"session_id":"<从流响应 data.id 获取>"}' \
  http://localhost:15001/chat/stop

关键实现细节

  • 文档解析
  • DocumentProcessor 支持 PDF/图片/Excel/Word → 图片
  • Dolphin process_page 针对每页返回结构化识别结果,最终 _extract_content 汇总为可检索文本
  • 分块策略(面向向量化)
  • 先段落后句子,尽量保持语义边界
  • 默认块长约 1000 字符,日志可见每块长度与数量
  • 意图理解与 Prompt 组装
  • 小调用:/api/generate 输出 JSON(意图/目标/格式),包含鲁棒清洗与回退
  • 动态构建 system_prompt 与 messages,引导总结/提取/检索
  • BertTokenizer 计算 token,严格预算,预留 BUFFER_TOKEN 防溢出
  • 流式输出与终止
  • SSE 输出 text/error 类型数据块
  • 全局 StreamSessionManager 支持多会话并发与按 session_id 停止
  • 数据一致性
  • 超出配额删除最旧文档与其文件
  • 向量化失败不影响文档已完成状态(容错记录日志)

部署与运行

  • 前置
  • 准备 Redis,并配置 .env 的 REDIS_HOST/REDIS_PSD/REDIS_PORT/REDIS_DB_NUM
  • 准备 Ollama 服务,并确保加载 DEFAULT_CHAT_MODEL 与 DEFAULT_EMBEDDING_MODEL
  • 确保 TOKENIZER_MODEL 路径可用
  • 启动(直接运行)
python main.py
  • 启动过程会初始化 SQLite、启动 Celery worker(通过 start_celery_worker())、再启动 FastAPI(0.0.0.0:15001)
  • Docker/Compose
  • 项目包含 Dockerfile 与 docker-compose.yml,可按实际环境调整网络与卷

性能优化建议

  • 追求并发的话可以替换成vLLM
  • 提升召回:可尝试 BM25 + Embedding 融合(RRF)与相似度阈值过滤
  • 分块与检索窗口:结合 LLM 上下文大小调整块长与 n_results
  • 对于长文本总结的话,建议构建一个

结语

以上基本就是全部实现流程,提供了一个“可直接落地”的轻量 RAG 实现,稳定的异步解析与入库、可靠的向量检索、可终止的流式对话。可以在此基础上按场景增强召回、改进分块、扩展多模态能力,快速支撑各类私有知识问答与文档处理应用。