☰
RuoYi 集成 RAGFlow:构建私有化企业知识库问答系统
2026/11/2 22:44:49 网站建设 项目流程

1. 为什么要在 RuoYi 里塞进一套 RAGFlow

很多团队做企业级后台,第一反应就是拿 RuoYi 起手。权限、菜单、部门、数据字典、代码生成器,一套下来省掉至少两周的脚手架工作量。但真到了"让系统能回答业务问题"这一步,RuoYi 本身是给不了答案的——它是个优秀的后台管理框架,不是一个知识检索系统。

于是就有了两条路:一条是自己在 RuoYi 里手搓向量检索,从文档切分、embedding、向量库到 prompt 拼装全自己写;另一条是找一个成熟的知识库引擎,把它当成一个"外挂大脑"接进来。RAGFlow 属于后者,它把文档解析、分块、向量化、检索、重排、引用溯源这一整条链路都封装好了,尤其是对 PDF、Word、Excel 这类复杂版式的解析能力,比大多数自研方案要扎实得多。

这篇要聊的就是第二条路:用 RuoYi 做业务外壳和权限中枢,用 RAGFlow 做知识检索内核,两者通过 API 打通,搭出一套能私有化部署、数据不出内网的知识库问答系统。适合谁看?适合手里已经有一套 RuoYi 项目、被业务方追着要"智能问答"功能、又不想把公司文档传到外部服务的后端同学。整套东西跑通之后,你在 RuoYi 的页面上传文档、建知识库、发起提问,答案带着原文出处返回,全程数据都在自己的服务器上。

需要先说明一点:RuoYi 有多个版本分支,RAGFlow 也在持续迭代,下面的接口路径和字段名以我实际跑通的版本为准,你那边如果版本不同,对着官方接口文档微调即可,思路是一致的。

2. 先把两边的角色边界划清楚

动手之前必须想明白一件事:谁负责什么。这个边界如果一开始没划清,后面会陷入"到底该在 RuoYi 存文档还是该在 RAGFlow 存文档"的反复纠结。

2.1 RuoYi 负责的那一半

RuoYi 在这套架构里承担的是"业务与权限层",具体包括:

  • 用户与登录态:谁在提问、属于哪个部门、能看到哪些知识库,这些都由 RuoYi 的sys_user、sys_dept、sys_role体系来管。RAGFlow 自己那套账号体系在企业内网里其实用不上,我们只需要它提供一个稳定的 API Key。
  • 知识库的业务归属:一个知识库属于哪个部门、哪些角色可见、谁有上传权限,这些元数据存在 RuoYi 的 MySQL 里,RAGFlow 那边只存"知识库实体"本身。
  • 文件上传入口:用户从 RuoYi 页面上传文件,RuoYi 负责接收、落盘、记录业务信息,然后再转发给 RAGFlow 做解析。
  • 对话界面与会话记录:前端聊天窗口、历史会话列表、消息落库,都在 RuoYi 侧完成。

2.2 RAGFlow 负责的那一半

RAGFlow 是"检索与生成层",它管的是:

  • 文档解析:把 PDF、Word、PPT、Excel、TXT、Markdown 等格式拆成可检索的文本块,这一步是它的核心价值,尤其是带表格、带多栏排版的 PDF。
  • 向量化与索引:调用 embedding 模型把文本块转成向量,存进它内置的向量库。
  • 检索与重排:根据用户问题召回相关文本块,做重排后拼成上下文。
  • 调用大模型生成答案:把上下文和问题一起送给 LLM,返回带引用的回答。

2.3 为什么不让 RuoYi 直接调大模型

有人会问:既然 RuoYi 都能调 API,为什么不干脆跳过 RAGFlow,自己拼 prompt 调大模型?原因在于检索质量。自己手搓的方案,文档切分策略往往很粗糙,PDF 里的表格会被切得七零八落,检索出来的上下文驴唇不对马嘴,大模型再强也答不对。RAGFlow 在文档解析和分块上投入了大量工程,这是它值得被引入的理由。把专业的事交给专业的组件,RuoYi 专注它擅长的权限和业务编排,这才是合理的分工。

提示:如果你的文档全是结构规整的纯文本,自研检索也不是不行;但只要涉及扫描件、复杂表格、多栏 PDF,RAGFlow 的解析优势会非常明显。

3. 部署 RAGFlow 时那些文档没写清楚的细节

RAGFlow 官方推荐用 Docker Compose 部署,命令看起来很简单,但实际跑起来有几个坑,我一个个说。

3.1 硬件与系统前提

RAGFlow 对资源的要求不低,尤其是内存。它内部跑着 Elasticsearch(或 Infinity)、MySQL、Redis、MinIO 等一堆组件,最低建议 16GB 内存,低于这个数容器会频繁被 OOM Killer 干掉。CPU 建议 4 核以上,磁盘留出至少 50GB,因为向量索引和原始文件都占空间。

如果你是在 Windows 11 上做本地验证,最省事的做法是装 Docker Desktop 并开启 WSL2 后端,把项目放在 WSL 的文件系统里而不是 Windows 挂载盘里——放在/mnt/c/...下会因为跨文件系统 IO 导致容器启动慢得离谱,这个坑我踩过,换成 WSL 内部路径后启动时间从几分钟降到几十秒。

3.2 部署命令与关键配置

拉取代码后进入 docker 目录,核心是改.env文件。几个必须关注的参数:

# .env 中需要重点确认的项 # 对外暴露的 HTTP 端口,默认 80,如果被占用改成别的 SVR_HTTP_PORT=9380 # 镜像源,国内环境建议换成可访问的镜像仓库 RAGFLOW_IMAGE=infiniflow/ragflow:v0.15.0 # 时区,避免日志时间对不上 TZ=Asia/Shanghai

改完之后:

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

启动完成后用docker logs -f ragflow-server看日志,等到出现类似 "Running on all addresses" 的字样,说明服务起来了。第一次启动会拉取镜像并初始化数据库,耐心等几分钟。

3.3 模型接入的两种选择

RAGFlow 需要两类模型:embedding 模型和对话模型。这里有个关键决策——用云端 API 还是本地部署。

方案优点缺点适用场景
云端 API接入快、效果好、不占本地资源数据要出内网、按量计费对数据敏感度不高的场景
本地模型数据完全不出内网需要 GPU、效果依赖模型选型强合规要求的企业内网

如果走本地路线,embedding 可以用 BGE 系列,对话模型可以用 Qwen 系列的开源版本,通过 Ollama 或 vLLM 起服务,然后在 RAGFlow 的模型设置里填本地推理服务的地址。注意 embedding 模型一旦选定,中途不要换,因为换模型意味着所有已索引的向量都要重新生成,代价很大。

注意:RAGFlow 里配置模型时,base_url 要填容器能访问到的地址。如果模型服务跑在宿主机上,容器里不能用localhost,得用宿主机的内网 IP 或者 Docker 的host.docker.internal。

4. 打通 RuoYi 与 RAGFlow 的接口层

这一节是整篇的核心。RuoYi 要调 RAGFlow,本质就是发 HTTP 请求,但里面有几个容易翻车的点。

4.1 认证方式:API Key 怎么拿怎么用

RAGFlow 的 API 认证用的是 Bearer Token。登录 RAGFlow 的 Web 界面,在右上角头像菜单里找到 API 设置,生成一个 API Key。这个 Key 要配置到 RuoYi 的配置文件里,绝对不要硬编码在 Java 代码里,也不要提交到 Git 仓库。

在 RuoYi 的application.yml里加一段:

ragflow: base-url: http://192.168.1.100:9380 api-key: ragflow-xxxxxxxxxxxxxxxx connect-timeout: 10000 read-timeout: 120000

read-timeout 要设得大一点,因为文档解析和问答生成都是耗时操作,默认的几秒根本不够,会直接超时。

4.2 用 RestTemplate 还是 OkHttp

RuoYi 默认集成了 RestTemplate 的封装,但说实话,处理 RAGFlow 这种长耗时、大响应体的接口,我更推荐用 OkHttp 或者 Hutool 的 HttpUtil。原因有两个:一是连接池管理更灵活,二是超时控制更细粒度。

下面是一个基于 OkHttp 的调用封装示例:

@Component public class RagFlowClient { private final OkHttpClient client; private final String baseUrl; private final String apiKey; public RagFlowClient(@Value("${ragflow.base-url}") String baseUrl, @Value("${ragflow.api-key}") String apiKey, @Value("${ragflow.read-timeout}") long readTimeout) { this.baseUrl = baseUrl; this.apiKey = apiKey; this.client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(readTimeout, TimeUnit.MILLISECONDS) .build(); } public String post(String path, String jsonBody) throws IOException { RequestBody body = RequestBody.create( jsonBody, MediaType.parse("application/json")); Request request = new Request.Builder() .url(baseUrl + path) .addHeader("Authorization", "Bearer " + apiKey) .addHeader("Content-Type", "application/json") .post(body) .build(); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException("RAGFlow 调用失败: " + response.code()); } return response.body().string(); } } }

4.3 创建知识库与上传文档的完整链路

RAGFlow 的接口大致分这么几类:数据集(dataset,也就是知识库)管理、文档管理、检索、对话。RuoYi 侧要做的编排是:

  1. 用户在 RuoYi 页面点"新建知识库",RuoYi 调 RAGFlow 的创建数据集接口,拿到返回的dataset_id,存进 RuoYi 自己的业务表。
  2. 用户上传文件,RuoYi 先把文件存到本地或对象存储,记录业务信息,然后调 RAGFlow 的上传接口把文件传过去。
  3. 上传后要手动触发解析,RAGFlow 不会自动解析,这一步很多人会漏掉,导致文档传上去了但检索不到。
  4. 解析是异步的,RuoYi 侧要么轮询解析状态,要么用回调,解析完成后文档才真正可检索。

这里有个实操细节:RAGFlow 上传文档的接口用的是multipart/form-data,不是 JSON。用 OkHttp 构造的时候要换成MultipartBody,别用上面那个 JSON 方法。而且文件流要重新读,如果同一个InputStream被读两次会报错,建议先落盘再读文件。

4.4 检索与问答接口的调用姿势

问答接口是用户感知最直接的。RAGFlow 提供两种模式:一种是纯检索(返回召回的文本块),一种是带生成的对话(返回答案和引用)。企业知识库问答一般用后者。

调用对话接口时,关键参数有:

  • question:用户问题
  • dataset_ids:限定在哪些知识库里检索,这个由 RuoYi 根据用户权限动态传入
  • stream:是否流式返回,前端要打字机效果就设 true

权限控制就卡在dataset_ids这一步。RuoYi 在调用前先查当前用户能访问哪些知识库,把对应的dataset_id列表传进去,这样即使用户绕过前端直接调接口,也拿不到没权限的知识库内容。这是把权限做在 RuoYi 侧的核心价值。

5. 权限模型怎么和知识库对齐

这是 RuoYi 集成 RAGFlow 时最需要动脑子的地方,也是很多教程一笔带过的地方。

5.1 知识库的可见性设计

我建议在 RuoYi 里建一张知识库业务表,字段大致如下:

字段类型说明
idbigint主键
kb_namevarchar知识库名称
ragflow_dataset_idvarchar对应 RAGFlow 的数据集 ID
dept_idbigint归属部门
visibilitytinyint0 私有 1 部门可见 2 全公司可见
create_byvarchar创建人
statustinyint启用状态

可见性判断逻辑放在 Service 层:私有库只有创建人可见,部门库同部门可见,全公司库所有人可见。查询用户可访问的知识库时,把这三个条件用 OR 拼起来。

5.2 为什么不在 RAGFlow 里做权限

RAGFlow 本身也有团队和权限的概念,但它的权限模型是围绕它自己的账号体系设计的,跟 RuoYi 的部门、角色、数据权限对不上。硬要在两边做映射,维护成本极高,而且一旦 RuoYi 的组织架构调整,两边就不同步了。正确做法是:RAGFlow 只当它是一个无状态的检索服务,所有权限判断都在 RuoYi 侧完成,通过 dataset_ids 参数来收口。这样 RuoYi 的组织架构怎么变,权限逻辑都只在一处维护。

5.3 会话记录的归属

用户和知识库的对话历史,存在 RuoYi 的 MySQL 里,而不是依赖 RAGFlow 的会话管理。原因很简单:RAGFlow 的会话数据是跟它的账号绑定的,而我们的用户体系在 RuoYi。自己存会话记录,还能顺便做审计、做敏感词过滤、做问答质量分析。

会话表设计上,一条会话关联一个用户和一个知识库,会话下面挂多条消息,每条消息记录角色(用户/助手)、内容、引用的文档块 ID、耗时等信息。引用信息很重要,前端要展示"答案来自哪份文档的哪一段",这个数据从 RAGFlow 的响应里取。

6. 实测中冒出来的那些坑

前面讲的是"应该怎么做",这一节讲"实际做的时候会怎么翻车"。这些都是我在真实项目里踩出来的。

6.1 文档解析卡在"未解析"状态

最常见的问题:文件上传成功,但状态一直是未解析。排查链路是这样的:

先看 RAGFlow 的容器日志,docker logs ragflow-server,如果看到 embedding 相关的报错,多半是模型配置有问题——要么 API Key 失效,要么本地模型服务没起来。如果日志里是解析超时,那可能是文件太大或者格式太复杂,PDF 里的扫描件需要 OCR,而 OCR 模型没配置好。

还有一个隐蔽的坑:RAGFlow 的解析任务是有并发限制的,一次传几十个文件,后面的会排队,看起来像卡住了,其实是在等。这种情况耐心等或者分批传就行。

6.2 中文检索召回不准

如果发现问中文问题召回的相关文档很少,检查两个地方:一是 embedding 模型是不是对中文友好的,有些英文模型对中文语义的捕捉很差;二是分块大小,RAGFlow 默认的 chunk size 对中文来说可能偏大,一个块里塞了太多内容,向量表达反而模糊。可以适当调小分块大小,或者开启它的自动分块优化。

6.3 跨域与前端直连的诱惑

前端同学可能会想:能不能让浏览器直接调 RAGFlow 的接口,省得 RuoYi 后端转发?千万别这么干。一是 API Key 会暴露在前端,二是权限控制就彻底失效了,三是跨域配置会很麻烦。所有对 RAGFlow 的调用必须经过 RuoYi 后端,这是安全底线。

6.4 大文件上传超时

RuoYi 默认的上传大小限制和 Nginx 的client_max_body_size都可能拦住大文件。一个几十兆的 PDF 传不上去,先查这两个配置。另外 RAGFlow 侧对单文件大小也有限制,超大文件建议先拆分。

7. 让问答效果再上一个台阶的几个调优点

系统跑通只是及格线,真正让业务方满意的是回答质量。分享几个我实测有效的调优点。

7.1 检索参数不是越大越好

RAGFlow 检索时有top_k、similarity_threshold这些参数。很多人以为召回越多越好,把 top_k 调到几十,结果上下文里塞了一堆不相关的内容,大模型反而被干扰,答案质量下降。我的经验是 top_k 控制在 3 到 8 之间,配合相似度阈值过滤掉低分块,效果比无脑调大要好。

7.2 给知识库分门别类

不要把所有文档都堆进一个知识库。按业务线、按文档类型分开建库,检索时根据问题意图路由到对应的库,召回精度会明显提升。比如"报销制度"的问题就只在行政制度库里检索,不要去财务库里捞。

7.3 引用溯源要展示到位

用户对 AI 答案天然有戒心,把引用来源展示清楚能极大提升信任度。前端在答案下面列出引用的文档名和片段,用户点开能看原文,这个体验比单纯给一段答案强太多。RAGFlow 的响应里带了引用信息,RuoYi 侧解析出来存好、传给前端就行。

7.4 定期重建索引

文档更新后,旧索引不会自动失效。如果知识库内容变动频繁,要建立定期重建索引的机制,或者在文档更新时触发对应块的重新解析。否则用户会问出"为什么答案还是老版本的"这种问题。

8. 关于选型的一点个人看法

最后聊聊选型。市面上做知识库问答的开源方案不止 RAGFlow 一家,各有各的定位。RAGFlow 的优势在于文档解析扎实、部署相对独立、API 清晰,适合把它当成一个纯粹的检索后端来接。它的短板是自带的界面偏工程化,直接给业务用户用体验一般,所以拿 RuoYi 做一层业务外壳是合理的搭配。

至于大模型选云端还是本地,我的建议是分阶段:验证阶段用云端 API 快速跑通链路,确认业务价值后再评估是否迁移到本地模型。一上来就折腾本地部署,很容易在环境问题上耗掉大量时间,还没看到效果就先泄气了。

这套 RuoYi + RAGFlow 的组合,我前后在几个项目里落地过,最深的体会是:集成的难点从来不在技术本身,而在于把权限、数据归属、用户体验这几件事想清楚。接口调通可能一天就够了,但把权限模型设计对、把引用溯源做扎实、把解析失败的兜底处理好,才是真正花时间的地方。如果你正准备动手,建议先把第 5 节的权限模型想明白再写代码,能省掉后面大量的返工。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询