乐于分享
好东西不私藏

从 0 到 1:用 AI 编程助手将 RagFlow 知识库集成到企业智能体平台

从 0 到 1:用 AI 编程助手将 RagFlow 知识库集成到企业智能体平台

本文记录了一次完整的 AI 辅助开发实践——从需求提出、技术调研、架构设计到代码实现与测试验证,全程由 AI 编程助手(Qoder)协同完成。


一、背景与需求

我正在构建一个企业级智能体平台,底层对接开源 AI Agent 框架,提供会话管理、流式对话、工具调用等能力。

平台已具备完整的对话功能,但缺少一个关键能力:让 AI 助手在回答问题时能够引用企业内部知识库

我们已经部署了 RagFlow(一款开源的 RAG 引擎),里面存放了架构设计文档、技术规范等企业知识。需求很明确:

在会话对话框中,允许用户主动开启知识库开关,选择要引用的知识库,AI 在回答时自动检索相关资料作为参考依据。


二、技术调研:RagFlow API 探秘

2.1 认证方式的抉择

RagFlow 提供两种认证方式:

方式
端点
特点
账号密码登录
POST /api/v1/auth/login
密码需 RSA 加密,实现复杂
API Key
Header: Authorization: Bearer ragflow-xxx
简单稳定,官方推荐

调研过程中发现,RagFlow 的 Web 登录接口要求对密码做 RSA 公钥加密(返回 "Fail to crypt password" 错误),这在前后端分离架构中实现成本过高。最终选择 API Key 认证——在 RagFlow 管理界面「头像 → 设置 → API → Create new key」一键生成。

2.2 核心 API 验证

通过 AI 助手操控浏览器登录 RagFlow 实例,创建 API Key 后,逐一验证了关键接口:

bash

# 知识库列表GET /api/v1/datasets?page=1&page_size=100→ 返回 "架构书籍"(19 分块 / 2 文档)# 语义检索POST /api/v1/retrievalBody: { "question""微服务架构""dataset_ids": ["726bb44a..."], ... }→ 返回带相似度分数的相关文本块

两个接口均验证通过,为后续集成奠定了基础。


三、架构设计:研读 QwenPaw 源码的启示

3.1 QwenPaw 内部的 RAG 机制

在动手之前,我让 AI 助手深入研读了 QwenPaw 源码,发现它有一套成熟的 RAG 架构——双通道检索

  1. 自动检索通道
    (Auto Memory Search):中间件在每次调用大模型前拦截,无条件执行语义检索,将结果伪装成 tool_call/tool_result 注入消息
  2. 主动检索通道
    (memory_search 工具):注册为 Agent 工具,由大模型自主判断是否需要检索

QwenPaw 的 RAG 哲学可以总结为一句话:

开关即意图,每轮自动检索,相关性交给检索引擎,取舍交给大模型。

3.2 我们的集成策略

QwenPaw 内部的 RAG 对接的是自己的长期记忆系统,并非外挂知识库。但它的设计思路给了我们重要启示:

  • 用户显式打开开关 = 明确的意图表达
    ,无需再做复杂的意图识别
  • 每轮提问前前置检索
    ,将资料注入上下文
  • 检索相关性由 RagFlow 保证
    ,最终取舍由大模型完成

考虑到我们的场景是通过 QwenPaw 的公开 HTTP API(/api/console/chat)通信,无法像内部中间件那样注入 tool_call 块,因此采用提示词注入方式——将检索结果拼接为用户消息的一部分。

3.3 整体架构

plaintext

┌─────────────────────────────────────────────────────┐                    前端 (Vue 3)                                                                            设置页:配置 RagFlow 地址 + API Key                   首页:知识库开关  选择知识库  发送时前置检索      └──────────────────────┬──────────────────────────────┘                        HTTP (localhost:8000)┌──────────────────────▼──────────────────────────────┐              后端代理 (FastAPI)                                                                            /api/ragflow/config    — 保存/获取配置               /api/ragflow/test      — 测试连接                    /api/ragflow/datasets  — 获取知识库列表              /api/ragflow/retrieval — 执行语义检索              └──────────────────────┬──────────────────────────────┘                        httpx (内网)         ┌─────────────┼─────────────┐                                    ┌─────────────────┐      ┌─────────────────────┐  RagFlow 服务            QwenPaw AI 服务       知识库 + 检索           对话 + 流式响应      └─────────────────┘      └─────────────────────┘

为什么用后端代理而非前端直连 RagFlow?

  1. 避免 CORS 问题
    ——RagFlow 服务未配置跨域头
  2. 保护 API Key
    ——密钥不暴露给浏览器
  3. 与现有架构一致
    ——QwenPaw 的 Token 管理也走后端代理

四、开发过程

4.1 后端:5 个代理端点

在 FastAPI 后端新增 RagFlowConfig 数据模型和 5 个 API 端点:

classRagFlowConfig(Base):    __tablename__ ="ragflow_config"id= Column(Integer, primary_key=True)    base_url = Column(String(500), nullable=False)    api_key = Column(String(500), default="")    updated_at = Column(DateTime, default=datetime.utcnow)

端点设计:

端点
方法
功能
/api/ragflow/config
POST
保存配置(同时验证连通性)
/api/ragflow/config
GET
获取配置(API Key 脱敏)
/api/ragflow/test
POST
测试连接
/api/ragflow/datasets
GET
获取知识库列表
/api/ragflow/retrieval
POST
执行语义检索

关键设计细节:

  • 保存即验证
    POST /config 保存前会先调 RagFlow 列知识库,连通失败直接拒绝保存
  • API Key 脱敏
    GET 返回时只显示末 4 位(****dpc
  • 超时控制
    检索接口 30s 超时,列表接口 15s 超时

4.2 前端 API 层:ragflow.js

新建 ragflow.js,封装 8 个函数,其中最核心的是提示词拼接历史还原

// 将检索结果拼接为注入给大模型的提示词exportfunctionbuildRagPrompt(question, chunks, datasetNames){const refs = chunks.map((c, i)=>{const src = c.document?`(来源:${c.document})`:''return`[${i +1}]${src}\n${c.content.trim()}`}).join('\n\n')return(`【知识库参考资料】\n`+`以下为从知识库「${datasetNames}」检索到的相关资料,`+`请优先结合这些资料回答用户问题。`+`若资料与问题无关请忽略,不要编造资料中不存在的内容:\n\n`+`${refs}\n\n`+`【用户问题】\n${question}`)}// 历史回显时还原干净的用户问题exportfunctionstripRagPrompt(text){const idx = text.indexOf('【用户问题】')if(idx ===-1)return textreturn text.slice(idx +'【用户问题】'.length).trim()}

  为什么需要 stripRagPrompt 因为注入的提示词会被 QwenPaw 存入会话历史。当用户回看历史消息时,不应看到那一大段注入的参考资料,而应只看到自己原始的提问。通过标记包裹(【知识库参考资料】...【用户问题】...),前端可以在展示时精准剥离。

4.3 设置页:RagFlow 配置卡片

在设置页新增第三张配置卡片(前两张是 QwenPaw 连接和企业 Branding):

  • 服务地址
    输入框
  • API Key
     密码输入框(附创建指引提示)
  • 测试连接
    按钮 → 调后端验证
  • 保存配置
    按钮 → 保存并自动列出知识库
  • 知识库预览区
     → 显示已配置的知识库名称、分块数、文档数

4.4 首页:知识库开关与检索注入

这是用户体验的核心。在输入框上方添加了一个知识库工具条

<divclass="kb-toolbar"><!-- 开关按钮 --><buttonclass="kb-toggle":class="{ active: kbEnabled }"@click="toggleKb">    📚 知识库<spanv-if="kbEnabled">:开</span></button><!-- 知识库多选下拉 --><divv-if="kbEnabled"class="kb-dropdown-wrap"><buttonclass="kb-select-btn"@click="kbDropdownOpen = !kbDropdownOpen">      {{ kbSelectedIds.length ? `已选 ${kbSelectedIds.length} 个` : '选择知识库' }} ▾</button><divv-if="kbDropdownOpen"class="kb-dropdown"><labelv-for="ds in kbDatasets":key="ds.id"class="kb-option"><inputtype="checkbox":value="ds.id"v-model="kbSelectedIds"/><span>{{ ds.name }}</span><span>{{ ds.chunk_count }} 分块</span></label></div></div><!-- 检索状态提示 --><spanv-if="kbRetrieving"class="kb-retrieving">📚 检索知识库中...</span></div>

发送消息时的检索注入流程:

asyncsendMessage(){let sendText = displayText// 开启知识库时:先检索 RagFlow,将资料注入发给大模型的文本if(this.kbEnabled&&this.kbSelectedIds.length){this.kbRetrieving=truetry{const result =awaitretrieveRagFlow(displayText,this.kbSelectedIds,5)if(result.chunks&& result.chunks.length){        sendText =buildRagPrompt(displayText, result.chunks,this.kbSelectedNames)}}catch(e){console.warn('RagFlow 检索失败,降级为普通提问:', e)}this.kbRetrieving=false}// 将(可能注入了知识库资料的)文本发给 QwenPawawaitsendChatMessage(sendText, sessionId, callbacks, signal, attachments)}

优雅降级:如果 RagFlow 检索失败(网络超时、服务宕机等),不会阻断对话,而是静默降级为普通提问,仅在控制台输出警告。


五、测试验证

5.1 后端接口测试

5 个端点逐一通过 curl 验证:

POST /api/ragflow/config  → 200 "配置已保存,连通正常(1 个知识库)"GET  /api/ragflow/config  → 200 {"configured"true"api_key_masked""****dpc"}POST /api/ragflow/test    → 200 {"success"true"message""连接成功,共 1 个知识库"}GET  /api/ragflow/datasets → 200 {"datasets": [{"name""架构书籍""chunk_count": 19}]}POST /api/ragflow/retrieval → 200 {"total": 3, "chunks": [...]}

5.2 浏览器端到端测试

通过 AI 助手操控浏览器完成全流程实测:

  1. ✅ 设置页 RagFlow 卡片正确渲染,状态显示"已配置"
  2. ✅ 知识库预览显示"📚 架构书籍 19分块/2文档"
  3. ✅ 首页"📚 知识库"开关按钮可点击切换
  4. ✅ 下拉选择器正确列出知识库并支持多选
  5. ✅ 发送问题时显示"📚 检索知识库中..."状态
  6. ✅ 用户气泡标注"📚 引用知识库:架构书籍"
  7. ✅ 大模型基于检索资料流式作答(内容包含微服务架构定义、核心特征等)
  8. ✅ 控制台零报错,所有网络请求 HTTP 200
在ragflow看到的知识库信息:
选一个架构书籍进去,可以看到文档 :
随意选一个文档,可以看到分片信息:
对话框可以选择知识库:
在上面的内容可以看到,已成功通过 知识库获取到了内容。


六、技术亮点与思考

6.1 "简单版"的哲学

最初考虑过两种方案:

方案
描述
复杂度
A(采用)
用户手动开关 + 选择知识库,前端前置检索注入
B(放弃)
将 RagFlow 注册为 QwenPaw 的 MCP 工具,由 Agent 自主决定何时检索

选择方案 A 的理由:

  • 用户意图明确
    ——开关本身就是意图表达,无需复杂的意图识别
  • 可控性强
    ——用户知道什么时候在用知识库,什么时候没有
  • 实现轻量
    ——不需要改动 QwenPaw 侧配置
  • 可渐进升级
    ——后续如需更智能的触发,可在此基础上叠加

6.2 提示词注入 vs 工具注入

QwenPaw 内部用 tool_call/tool_result 伪装注入检索结果(模型更重视工具返回),但我们通过公开 API 只能传用户文本。提示词注入的效果如何?

实测表明,只要提示词结构清晰(用标记分隔参考资料和用户问题,并明确指示"优先结合资料回答"),大模型能很好地利用注入的知识库内容,且不会在资料无关时强行引用。

6.3 后端代理模式的价值

整个项目中,QwenPaw 和 RagFlow 的所有敏感操作都通过 FastAPI 后端代理:

  • Token 管理
    :后端自动登录 QwenPaw、5 天轮换 Token
  • API Key 保护
    :RagFlow 密钥只存后端数据库,前端永远看不到明文
  • 统一错误处理
    :后端将各种异常统一转换为友好的中文提示
  • CORS 无忧
    :前端只与同源后端通信

七、代码规模与交付

模块
文件
新增代码量
后端代理
backend/main.py
~180 行
前端 API 层
frontend/src/api/ragflow.js
121 行(新建)
设置页
frontend/src/views/Settings.vue
~80 行
首页交互
frontend/src/views/Home.vue
~120 行
合计4 个文件~500 行

从需求提出到功能上线(含调研、设计、编码、测试),AI 辅助开发总耗时约 2 小时


八、总结

这次 RagFlow 知识库集成的实践,验证了一个完整的 AI 辅助开发工作流:

  1. 需求描述
     → 用自然语言向 AI 表达意图
  2. 技术调研
     → AI 操控浏览器登录 RagFlow、验证 API、研读 QwenPaw 源码
  3. 架构设计
     → AI 分析现有代码结构,提出集成方案并给出理由
  4. 方案审批
     → 人类决策"先做简单版",AI 立即调整执行
  5. 代码实现
     → AI 逐模块编码,人类审查关键逻辑
  6. 自动测试
     → AI 操控浏览器完成端到端验证

最终交付的功能虽然"简单",但架构合理、体验流畅、可维护可扩展。用户只需在设置页配一次 API Key,之后在对话中一键开启知识库,AI 就能结合企业内部资料给出有据可依的回答。

这就是 AI 时代软件开发的缩影——人类负责决策和审美,AI 负责调研和实现


我是AI易用君,我在此公众号分享探索、学习、使用AI的经验,让我们一起来学AI,用AI,AI(爱)让生活更美好。如果你觉得我说的对,欢迎点赞收藏。

相关学习资料