Fork me on GitHub

分类 RAGFlow 下的文章

学习 RAGFlow 的系统架构

昨天,我们学习了 RAGFlow 的安装配置和基本使用,通过创建一个知识库并上传文档,完整地体验了 RAGFlow 从数据处理到智能问答的基本工作流程。作为一个 RAG 系统,这套流程也是 RAGFlow 的核心流程,下面是 RAGFlow 的系统架构图:

ragflow-architecture.png

上面的架构图中省略了中间件部分,包括 ES、MySQL、Redis 和 Minio 等,仅展示了 RAGFlow 的两个核心服务:API 服务器(API Server)任务执行器(Task Executor),其中 API 服务器负责提供外部接口,包括知识库管理、文件管理、搜索、聊天等功能,而任务执行器则负责文件的解析和切片任务,正所谓 Quality in, quality out,它的深度文档理解和智能文本切片是 RAGFlow 的关键特性。

今天我们就从物理部署的角度来看看 RAGFlow 的这两个服务。

深入 entrypoint.sh 脚本

我们昨天学习了构建 RAGFlow 镜像的过程,感兴趣的同学可以研究下 Dockerfile 文件,它通过 多阶段构建(Multi-stage builds) 技巧,将构建过程分成基础(base)、构建(builder)、生产(production)三个阶段,大概的文件结构如下:

# --------
# 基础阶段
# --------
FROM ubuntu:22.04 AS base
USER root
WORKDIR /ragflow

# 从资源镜像拷贝模型资源
# 安装所需的系统类库
# 安装 Python Git Nginx 等软件 ...
# 安装 JDK、Node.js 等 ...

# --------
# 构建阶段
# --------
FROM base AS builder

# 安装 Python 依赖...
# 编译 Web 页面 ...

# --------
# 生产阶段
# --------
FROM base AS production

# 拷贝 Python 包
# 拷贝 Web 页面 ...

ENTRYPOINT ["./entrypoint.sh"]

从最后的生产阶段可以看出,RAGFlow 镜像的入口文件为 /ragflow/entrypoint.sh,它的用法如下:

function usage() {
  echo "Usage: $0 [--disable-webserver] [--disable-taskexecutor] [--consumer-no-beg=<num>] [--consumer-no-end=<num>] [--workers=<num>] [--host-id=<string>]"
  echo
  echo "  --disable-webserver             Disables the web server (nginx + ragflow_server)."
  echo "  --disable-taskexecutor          Disables task executor workers."
  echo "  --enable-mcpserver              Enables the MCP server."
  echo "  --consumer-no-beg=<num>         Start range for consumers (if using range-based)."
  echo "  --consumer-no-end=<num>         End range for consumers (if using range-based)."
  echo "  --workers=<num>                 Number of task executors to run (if range is not used)."
  echo "  --host-id=<string>              Unique ID for the host (defaults to \`hostname\`)."
  echo
  echo "Examples:"
  echo "  $0 --disable-taskexecutor"
  echo "  $0 --disable-webserver --consumer-no-beg=0 --consumer-no-end=5"
  echo "  $0 --disable-webserver --workers=2 --host-id=myhost123"
  echo "  $0 --enable-mcpserver"
  exit 1
}

可以看到这个镜像可以以多种方式启动:

  • --disable-taskexecutor 禁用任务执行器,仅启动 API 服务器
  • --disable-webserver 禁用 API 服务器,仅启动任务执行器
  • --enable-mcpserver 启动 MCP 服务器

RAGFlow 默认会在一个容器中同时启动 API 服务器和任务执行器,便于开发和测试,但是在生产环境中我们可以灵活地根据需要选择启动方式,将两者分开部署。

仅启动 API 服务器

我们可以修改 docker/docker-compose.yml 文件中的启动参数来做到这一点:

services:
  ragflow:
    image: ${RAGFLOW_IMAGE}
    command:
      - --disable-taskexecutor
    container_name: ragflow-server
    # 其他配置 ...

entrypoint.sh 文件中,启动 API 服务器的代码如下:

if [[ "${ENABLE_WEBSERVER}" -eq 1 ]]; then
  echo "Starting nginx..."
  /usr/sbin/nginx

  echo "Starting ragflow_server..."
  while true; do
    "$PY" api/ragflow_server.py
  done &
fi

首先启动 Nginx,然后执行 ragflow_server.py 脚本,它是一个基于 Flask 开发的 Web 服务,默认监听 9380 端口。这里的 while true; do ... done & 的写法挺有意思,while true 表示无限循环,& 表示将脚本放入后台执行,这样做可以确保服务进程在崩溃或异常退出后能够自动重启,通过这种纯 Shell 的方式实现自动恢复机制,不依赖任何第三方进程管理器(如 systemdsupervisor)。

Nginx 用于托管 Web 前端页面以及透传 API 服务器的 HTTP 请求,它的配置位于 ragflow.conf 文件中,内容如下:

server {
  listen 80;
  server_name _;
  root /ragflow/web/dist;

  gzip on;

  location ~ ^/(v1|api) {
    proxy_pass http://ragflow:9380;
    include proxy.conf;
  }

  location / {
    index index.html;
    try_files $uri $uri/ /index.html;
  }

  # Cache-Control: max-age~@~AExpires
  location ~ ^/static/(css|js|media)/ {
    expires 10y;
    access_log off;
  }
}

如果要对外提供 HTTPS 服务,可以将 docker/docker-compose.yml 文件中的 ragflow.conf 替换成 ragflow.https.conf,并将证书文件挂到容器中:

services:
  ragflow:
    volumes:
      # 证书文件
      - /path/to/fullchain.pem:/etc/nginx/ssl/fullchain.pem:ro
      - /path/to/privkey.pem:/etc/nginx/ssl/privkey.pem:ro
      # 使用 ragflow.https.conf 替换 ragflow.conf
      - ./nginx/ragflow.https.conf:/etc/nginx/conf.d/ragflow.conf
      # 其他配置 ...

同时编辑 nginx/ragflow.https.conf 文件,将 my_ragflow_domain.com 替换成你真实的域名。然后重启服务即可:

$ docker-compose down
$ docker-compose up -d

仅启动任务执行器

当处理的文档数量很多时,将任务执行器单独部署多个实例可以提高文档解析的速度。我们可以修改 docker/docker-compose.yml 文件,将 ragflow 配置复制一份出来,仅启动任务执行器:

services:
  ragflow_task_executor:
    image: ${RAGFLOW_IMAGE}
    command:
      - --disable-webserver
      - --workers=5
    container_name: ragflow-task-executor
    # 其他配置 ...

我们可以通过 --workers 参数来指定启动的 worker 数量。启动任务执行器的代码如下:

if [[ "${ENABLE_TASKEXECUTOR}" -eq 1 ]]; then
    echo "Starting ${WORKERS} task executor(s) on host '${HOST_ID}'..."
    for (( i=0; i<WORKERS; i++ ))
    do
        task_exe "${i}" "${HOST_ID}" &
    done
fi

每个 worker 都会启动一个独立的进程,其中 task_exe() 函数定义如下:

function task_exe() {
    local consumer_id="$1"
    local host_id="$2"

    JEMALLOC_PATH="$(pkg-config --variable=libdir jemalloc)/libjemalloc.so"
    while true; do
        LD_PRELOAD="$JEMALLOC_PATH" \
        "$PY" rag/svr/task_executor.py "${host_id}_${consumer_id}"
    done
}

这里也用了 while true 的技巧,防止 worker 进程异常退出,每个 worker 进程执行 task_executor.py 脚本,并将 ${host_id}_${consumer_id} 作为参数传入。任务执行器是一个基于 Trio 异步库开发的命令行程序,它通过监听 Redis 消息队列,对用户上传的文件进行解析处理。这里的 ${host_id} 是当前的主机名,${consumer_id} 是指 worker 的序号,拼接起来用于区分不同的消费者。

启动 MCP 服务器

RAGFlow 还支持 MCP 服务器,开启方法很简单,只需将 docker/docker-compose.yml 文件中 services.ragflow.command 部分的注释去掉即可:

services:
  ragflow:
    image: ${RAGFLOW_IMAGE}
    command:
      - --enable-mcpserver
      - --mcp-host=0.0.0.0
      - --mcp-port=9382
      - --mcp-base-url=http://127.0.0.1:9380
      - --mcp-script-path=/ragflow/mcp/server/server.py
      - --mcp-mode=self-host
      - --mcp-host-api-key=ragflow-xxxxxxx

关于 RAGFlow MCP 服务器的使用,我们今天暂且跳过,后面单开一篇介绍。

小结

通过今天的学习,我们了解了 RAGFlow 的系统架构,以及如何通过 entrypoint.sh 脚本启动不同的服务。接下来,我们将继续剖析 RAGFlow 的源码,探索 API 服务器和任务执行器的实现原理。


RAGFlow 快速入门

在构建高级 AI 应用时,检索增强生成(RAG)已成为一项关键技术,它能让大语言模型(LLM)利用外部知识库,提供更准确、更具上下文的回答。然而,如何高效地处理和理解格式各异的复杂文档(如 PDF、Word、PPT 等),并从中提取高质量信息,一直是 RAG 应用落地的一大挑战。

今天,我们将介绍一款强大的开源 RAG 引擎 —— RAGFlow,它专为解决这一难题而生。RAGFlow 基于深度文档理解技术,能够为企业和个人提供一套精简、高效的 RAG 工作流程,让 AI 应用能够从海量复杂数据中高质量地提取信息,真正做到 Quality in, quality out

ragflow-logo.png

RAGFlow 的核心特性如下:

  • 深度文档理解:不仅仅是提取文本,RAGFlow 能够深入理解各类复杂文档的布局和结构,确保从 PDF、Word、PPT 等文件中提取高质量、有价值的信息;
  • 智能文本切片:提供基于模板的文本切片方法,不仅智能,而且整个过程清晰可控,方便解释和调整;
  • 有理有据的回答:生成的回答都附带关键引用的快照,并支持追根溯源,最大限度地减少了 AI 幻觉;
  • 广泛的异构数据支持:兼容各类数据源,包括 Word 文档、PPT、Excel 表格、PDF、图片、网页,甚至是扫描件;
  • 自动化的 RAG 工作流:提供从数据处理、多路召回到融合重排序的全自动化 RAG 工作流,并支持灵活配置大语言模型和向量模型,提供易用的 API,方便与现有系统集成;

本文将带你快速入门 RAGFlow,学习如何安装、配置并使用它来构建你自己的 RAG 应用。

安装与上手

安装 RAGFlow 最简单的方法是使用 Docker 和 Docker Compose。首先检查我们的电脑上已经安装了它们:

$ docker --version
Docker version 24.0.2, build cb74dfc

$ docker compose version
Docker Compose version 2.38.1

确保 Docker 的版本在 24.0.0 以上,Docker Compose 的版本在 v2.26.1 以上。然后克隆 RAGFlow 仓库:

$ git clone https://github.com/infiniflow/ragflow.git

进入 docker 文件夹:

$ cd ragflow/docker

这个文件夹下有几个比较重要的文件:

  • docker-compose.yml - 定义了 RAGFlow 的镜像和配置,这个文件通过 Docker Compose 的 include 语法引用了 docker-compose-base.yml 文件,因此启动时只需指定这个入口文件即可
  • docker-compose-base.yml 定义了 RAGFlow 依赖的中间件的镜像和配置,包括 ES、MySQL、Redis 和 Minio 等
  • .env - 通过环境变量修改启动配置,比如调整各组件的端口,用户名和密码,默认镜像等,在 macOS 电脑上可以将 MACOS=1 打开,如果访问不了 huggingface.co 可以开启 HF_ENDPOINT=https://hf-mirror.com 参数

配置确认无误后,使用 Docker Compose 一键启动:

$ docker compose -f docker-compose.yml up -d

启动时默认会拉取官方构建好的 infiniflow/ragflow:v0.19.1-slim 镜像,该镜像比较大,下载要花点时间。启动成功后如下:

ragflow-containers.png

构建 ARM64 镜像

目前官方提供的 Docker 镜像均基于 x86 架构构建,并不提供基于 ARM64 的 Docker 镜像,比如在我的 macOS 上启动后,容器的下面会显示一个 AMD64 的标签。如果你的 Docker 和我一样,开启了 QEMU 或 Apple 的 Virtualization Framework 虚拟化技术,在 ARM64 机器上也可以跑 x86 的镜像,就是速度有点慢。

docker-desktop-setting.png

当然你也可以自行构建 ARM64 架构的镜像,顺便也能看看镜像中隐藏的一些细节,参考这篇文档:

首先,下载构建镜像所需的资源:

$ uv run download_deps.py

下载的资源包括:

  • 几个库文件

    • libssl
    • tika-server-standard.jar
    • cl100k_base.tiktoken
    • chrome 和 chromedriver
  • 几个 nltk_data 资源

    • wordnet
    • punkt,
    • punkt_tab
  • 几个 huggingface 模型

    • InfiniFlow/text_concat_xgb_v1.0
    • InfiniFlow/deepdoc
    • InfiniFlow/huqie
    • BAAI/bge-large-zh-v1.5
    • maidalun1020/bce-embedding-base_v1

然后构建资源镜像(就是将刚刚下载的资源拷贝到基础镜像里):

$ docker build -f Dockerfile.deps -t infiniflow/ragflow_deps .

然后基于资源镜像构建 RAGFlow 镜像:

$ docker build --build-arg LIGHTEN=1 -f Dockerfile -t infiniflow/ragflow:nightly-slim .

构建完成后,打开 docker/.env 文件,找到 RAGFLOW_IMAGE 配置,将其修改为 infiniflow/ragflow:nightly-slim。最后,使用 Docker Compose 一键启动:

$ cd docker
$ docker compose -f docker-compose-macos.yml up -d

RAGFlow 登录

启动后,查看 RAGFlow 容器的日志,当显示如下的文字 LOGO 时,说明启动成功:

ragflow-start-log.png

RAGFlow 默认监听本地 80 端口,直接用浏览器打开 http://localhost 即可,进入 RAGFlow 的登录页面:

ragflow-login.jpg

吐槽下 RAGFlow 的登录页面,这背景图选的,文字都看不清。

第一次使用需要注册一个新账号,注册完成后使用新账号登录即可:

ragflow-login-success.png

RAGFlow 初体验

进入 RAGFlow 的第一件事是配置模型,点击右上角的头像,然后进入 “模型供应商” 页面:

ragflow-model-setting.png

从下面的列表中选择并添加自己的模型,根据不同的模型,需要配置 API Key 等不同的参数。然后设置默认模型:

ragflow-model-setting-default.png

RAGFlow 支持大量的模型供应商,这些模型按功能被划分成几类:

  • 聊天模型
  • 嵌入模型
  • Img2txt模型
  • Speech2txt模型
  • Rerank模型
  • TTS模型

根据需要配置这些模型,一般来讲,除了聊天模型和嵌入模型是必填的,其他的可以不填;配置完默认模型后,就可以体验 RAGFlow 的功能了。进入 “知识库” 页面,创建一个新知识库:

ragflow-new-kb.png

然后点击 “新增文件” 按钮,从本地上传一个文件,上传后点击解析按钮,只有解析成功后的文件才可以对其问答,文件解析完成后如下所示:

ragflow-kb-files.png

我们再进入 “聊天” 页面,点击 “新建助理” 创建一个聊天助手:

ragflow-new-chat.png

下面的知识库选择我们刚刚创建的知识库,创建成功后,就可以和它进行对话了:

ragflow-kb-chat.png

小结

在本文中,我们对 RAGFlow 进行了快速入门。我们学习了 RAGFlow 的核心特性,讲解了如何通过 Docker Compose 进行安装部署,并为 ARM64 用户提供了详细的镜像构建指南。在完成模型供应商的配置后,我们通过创建一个知识库并上传文档,完整地体验了 RAGFlow 从数据处理到智能问答的基本工作流程。

通过今天的学习,我们对 RAGFlow 已经有了初步的了解。在后续的文章中,我们将结合源码深入其核心,探索更多高级功能,例如深度文档理解、智能文本切片、自动化 RAG 工作流等。