一款纯 js 实现的大模型应用服务 FastGPT 解读

背景介绍

最近被不同的人安利了 FastGPT 项目,实际上手体验了一下,使用流程类似之前调研过的 Dify, 包含的功能主要是:任务流的编排,知识库管理,另外还有一些外部工具的调用能力。使用页面如下所示:
请添加图片描述
实际去看了下项目的代码分布,结果发现如下所示:

请添加图片描述

难道后端 Python 只需要如此少的代码量就可以实现一个大模型应用了?深入了解了 FastGPT 的实现,发现其 Python 为测试代码,完整的项目实现都是基于前端语言 ts 和 js 实现。这篇文章就主要介绍下 FastGPT 知识库 RAG 设计的实现细节。

FastGPT 简介

FastGPT 被设计为基于 LLM 大语言模型的知识库问答系统,与常规的 RAG 相比增加了额外工作流编排的能力,这部分类似 Dify。但是相对 Dify 而言可调用的第三方应用更少一些。按照习惯先查看项目的架构图:

请添加图片描述
一般而言,从架构图中就可以看到项目的独特之处。之前 qanything 和 ragflow 同样从架构图看出 RAG 项目的设计差异。

对于常规的 RAG 架构图,这张图可以明显看到大模型模块被放大,而且文件入库的流程都会先调用大模型。从大模型的输出来看,存在 QA 拆分文本分段手动输入 三种情况:

  • 文本分段 是常规的 RAG 的处理方案
  • QA 拆分 看起来是基于原始文本生成问答对,这部分猜测应该是根据大模型生成问答对,之前 Dify 也有类似的功能,被称为 Q&A 模式
  • 手动输入 则是直接输入问答对,这部分应该是手工输入数据进行补充;

预计文件入库环节的大模型调用主要作用于 QA 拆分

技术选型

官方给出的技术栈为:NextJs + TS + ChakraUI + Mongo + Postgres (Vector 插件)

  • NextJs 用于构建前后端服务,可以在单个工程中同时构建前后端代码,熟悉 Flask 应该对这个玩法不陌生,只是 Flask 是后端想把前端的活干了,而 NextJs 则是前端把后端的活干了;
  • TS 用于编写具体的代码;
  • ChakraUI 是 UI 组件库;
  • MongoDB 是作为业务数据库使用,事实上 FastGPT 中的文件也是基于 MongoDB 的 GridFS 进行存储;
  • Postgres 用于存储向量数据;

核心模块解读

与常规的 Python 实现大模型应用不同,基于 TypeScript 没有类似 langchain 的框架,因此需要自行实现知识库构建的完整流程。

文件入库流程

实际文件的入库对应的接口为 api/core/dataset/collection/create/fileId, 因为是基于 NextJs 实现的,接口与文件的组织结构是一样的,对应的处理实现是在 projects/app/src/pages/api/core/dataset/collection/create/fileId.ts

文件入库会执行文件读取,切片,然后会依次写入知识库,实际会根据不同写入模式内容上有一些差异,具体的实现如下所示:

  // 1. 读取文件const { rawText, filename } = await readFileContentFromMongo({teamId,bucketName: BucketNameEnum.dataset,fileId});// 2. 切片,文本分段会保留 20% 的重叠,QA 拆分则没有重叠const chunks = rawText2Chunks({rawText,chunkLen: chunkSize,overlapRatio: trainingType === TrainingModeEnum.chunk ? 0.2 : 0,customReg: chunkSplitter ? [chunkSplitter] : []});// 3. 查询限制await checkDatasetLimit({teamId,insertLen: predictDataLimitLength(trainingType, chunks)});await mongoSessionRun(async (session) => {// 4. 构建知识库集合const { _id: collectionId } = await createOneCollection({...body,teamId,tmbId,type: DatasetCollectionTypeEnum.file,name: filename,fileId,metadata: {relatedImgId: fileId},// special metadatatrainingType,chunkSize,chunkSplitter,qaPrompt,hashRawText: hashStr(rawText),rawTextLength: rawText.length,session});// 5. 创建训练账单,确认消耗金额const { billId } = await createTrainingUsage({teamId,tmbId,appName: filename,billSource: UsageSourceEnum.training,vectorModel: getVectorModel(dataset.vectorModel)?.name,agentModel: getLLMModel(dataset.agentModel)?.name,session});// 6. 分片数据写入 MongoDB 数据库await pushDataListToTrainingQueue({teamId,tmbId,datasetId: dataset._id,collectionId,agentModel: dataset.agentModel,vectorModel: dataset.vectorModel,trainingMode: trainingType,prompt: qaPrompt,billId,data: chunks.map((item, index) => ({...item,chunkIndex: index})),session});

在目前的流程中只是写入业务数据库 MongoDB,之后再根据 MongoDB 数据库中内容进行向量化。

对于 QA 模式,可以查看对应的 prompt 设计:

标记中是一段文本,学习和分析它,并整理学习成果:\n
- 提出问题并给出每个问题的答案。\n
- 答案需详细完整,尽可能保留原文描述。\n
- 答案可以包含普通文字、链接、代码、表格、公示、媒体链接等 Markdown 元素。\n
- 最多提出 30 个问题。\n

可以看到就是基于大模型直接生成不超过 30 个问答对。

知识库检索

FastGPT 的知识检索目前支持多种检索模式,主要关注下最复杂的混合检索。

FastGPT 实现的是基于向量检索 + 文本检索实现的混合检索,并基于 RRF 实现多种检索结果的融合。对应的实现在 packages/service/core/dataset/search/controller.ts ,具体的简化后如下所示:

  // 向量检索 + 文本检索召回const { embeddingRecallResults, fullTextRecallResults, tokens } = awaitmultiQueryRecall({embeddingLimit,fullTextLimit});// 重排序的支持const reRankResults = await (async () => {if (!usingReRank) return [];set = new Set<string>(embeddingRecallResults.map((item) => item.id));const concatRecallResults = embeddingRecallResults.concat(fullTextRecallResults.filter((item) => !set.has(item.id)));// remove same q and a dataset = new Set<string>();const filterSameDataResults = concatRecallResults.filter((item) => {// 删除所有的标点符号与空格等,只对文本进行比较const str = hashStr(`${item.q}${item.a}`.replace(/[^\p{L}\p{N}]/gu, ''));if (set.has(str)) return false;set.add(str);return true;});return reRankSearchResult({query: reRankQuery,data: filterSameDataResults});})();// 使用 rrf 合并向量检索和文本检索的结果const rrfConcatResults = datasetSearchResultConcat([{ k: 60, list: embeddingRecallResults },{ k: 60, list: fullTextRecallResults },{ k: 58, list: reRankResults }]);

可以看到基本上是目前比较中规中矩的混合检索方案,只是转换为 TypeScript 进行了实现。

总结

本文是对 FastGPT 现有知识库流程的解读,整体看起来 FastGPT 的处理流程中规中矩。

通过前后端使用相同的开发语言,可以解决前后端代码复用的问题,借助 NextJs 也可以简化框架设计与部署,同时对团队的技术栈要求也更低了。但是因为没有使用 Python 实现后端服务,导致无法使用大量现有的大模型应用框架,为未来的拓展能力带来了一些限制,有得有失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/41275.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端实现坐标系转换

一、地理坐标系和投影坐标系 地理坐标系和投影坐标系是地理信息系统&#xff08;GIS&#xff09;中常见的两种坐标系统&#xff0c;它们用于描述和定位地球表面上的点和区域&#xff0c;但在实现方式和应用场景上有所不同。 1. 地理坐标系&#xff08;Geographic Coordinate …

【CentOS 7.6】Linux版本 portainer本地镜像导入docker安装配置教程,不需要魔法拉取!(找不着镜像的来看我)

吐槽 我本来根本不想写这篇博客&#xff0c;但我很不解也有点生气&#xff0c;CSDN这么大没有人把现在需要魔法才能拉取的镜像放上来。 你们都不放&#xff0c;根本不方便。我来上传资源。 portainer-ce-latest.tar Linux/amd64 镜像下载地址&#xff1a; 链接&#xff1a;h…

Chapter11让画面动起来——Shader入门精要学习笔记

Chapter11让画面动起来 一、Unity Shader中的内置变量&#xff08;时间篇&#xff09;二、纹理动画1.序列帧动画2.滚动背景 三、顶点动画1.流动的河流2.广告牌3.注意事项①批处理问题②阴影投射问题 一、Unity Shader中的内置变量&#xff08;时间篇&#xff09; Unity Shader…

东北财税之星:董女士的家乡创业记

乐财业智慧财税赋能平台&#xff0c;是一个帮助财税机构专业提升、业务增长&#xff0c;让财税生意更好做的综合赋能平台。聚焦财税公司业绩增长&#xff0c;预计2027年帮助2000家财税合伙人利润增长300%&#xff0c;致力打造轻量化、批量化、智能化的”业财税“一体财税服务生…

ARCGIS PRO 要素标注

一、普通模式 1、标注&#xff1a;名称和面积&#xff08;无分数线&#xff09; 语言&#xff1a;Arcade $feature.QLR \nRound($feature.Shape_Area,2) 语言&#xff1a;vbscript [QLR] & " " & Round([Shape_Area],2) 2、标注&#xff1a;名称…

ChatGPT如何提升论文写作(附指令集合)

先讲前提&#xff1a; ChatGPT无论是3.5还是4.0都存在非常严重的幻觉问题&#xff0c;目前ChatGPT无法替代搜索引擎。 如果你希望得到更加优质的体验&#xff0c;请用GPT-4.0&#xff0c;幻觉问题上比3.5大幅降低 ChatGPT中文版&#xff0c;一站式AI创作平台​aibox365.com …

Python | Leetcode Python题解之第203题移除链表元素

题目&#xff1a; 题解&#xff1a; # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def removeElements(self, head: ListNode, val: int) -> Li…

因版本冲突导致logback的debug日志不打印

因框架调整&#xff0c;降级了logback的版本号&#xff0c;由1.3.12降级为1.2.11&#xff08;因框架限制&#xff0c;只能采用1.2版本&#xff09;&#xff0c;降级后发现debug日志无法打印出来&#xff0c;logback.xml配置文件不生效。后排查发现是与slf4j的版本兼容问题 依赖…

一种频偏估计与补偿方法

一种简易的频偏估计补偿方法&#xff0c;使用QAM等信号。估计精度受FFT长度限制&#xff0c;可以作为粗频偏估计。 Nfft 1024; % FFT长度 N 10*Nfft; % 仿真符号数 M 16; % 调制QAM16 freq 1e…

如何选择视频号矩阵系统源码:关键要素与决策指南

在短视频和直播内容迅速崛起的今天&#xff0c;视频号矩阵系统源码成为了企业和个人创作者高效管理视频内容的重要工具。选择合适的视频号矩阵系统源码&#xff0c;可以极大提升内容发布的效率和质量&#xff0c;同时优化用户体验。本文将提供一套选择视频号矩阵系统源码的指南…

MYSQL篇二:数据库的操作

文章目录 1. 创建数据库1.1 查看数据库列表1.2 创建与删除数据库 2. 数据的编码问题3. 字符集和校验规则3.1 查看系统默认字符集以及校验规则3.2 查看数据库支持的字符集3.3 查看数据库支持的字符集校验规则3.4 校验规则对数据库的影响 4. 操纵数据库4.1 查看当前是哪一个数据库…

小程序渗透测试的两种方法——burpsuite、yakit

首先呢主要是配置proxifier&#xff0c;找到小程序的流量&#xff0c;然后使用burpsuite或者yakit去抓包。 一、使用burpsuiteproxifier的抓包测试 1、先配置proxifier&#xff0c;开启http流量转发 勾选确定 2、配置burp对应代理端口&#xff0c;选择profile&#xff0c;点…

《梦醒蝶飞:释放Excel函数与公式的力量》8.7 STDEV函数

8.7 STDEV函数 STDEV函数是Excel中用于计算一组数值的标准偏差的函数。标准偏差是统计学中的一个重要指标&#xff0c;用于衡量数据集中各数值偏离平均值的程度。它反映了数据的离散程度或波动大小。 8.7.1 函数简介 STDEV函数用于返回样本数据的标准偏差&#xff0c;标准偏…

软件测试面试1000问(含答案)

1、自动化代码中,用到了哪些设计模式? 单例设计模式工厂模式PO设计模式数据驱动模式面向接口编程设计模式 2、什么是断言( Assert) ? 断言Assert用于在代码中验证实际结果是不是符合预期结果&#xff0c;如果测试用例执行失败会抛出异常并提供断言日志 3、什么是web自动化…

地图下载工具

1 概述 做仿真的&#xff0c;一般都要用到地图。各大地图厂商&#xff0c;都提供了地图测试接口。只不过&#xff0c;这些接口有限制&#xff0c;用多了就容易被封IP。于是我写了一个瓦片地图下载工具&#xff0c;把地图下载到本地&#xff0c;就可以愉快的玩耍了。 2 操作 …

文字识别技术升级:Airtest与PaddleOCR模型的协作小技巧

一、前言 在进行自动化测试的过程中&#xff0c;ocr文字识别一直是大家最想要实现以及最需要的能力&#xff0c;今天就来介绍一个由百度飞浆提供的一个免费的ocr识别库——PaddleOCR&#xff0c;以及探讨一下&#xff0c;PaddleOCR与Airtest协作能擦出怎么样的火花~ 二、Padd…

打包 最新血液净化器制作技术和资料

网盘 https://pan.baidu.com/s/1fm3LF20dCvy4iSMQklHpug?pwd4je2 便携可穿戴可血液净化用器件及其制备方法和应用.pdf 基于贻贝仿生化学的血液净化材料及其制备方法.pdf 膜分离式一体化血液净化系统.pdf 血液净化器固定夹.pdf 血液净化膜及其制备方法和应用.pdf 评估血液净化…

【手机取证】如何使用360加固助手给apk加固

文章关键词&#xff1a;手机取证、电子数据取证、数据恢复 一、前言 APP加固是对APP代码逻辑的一种保护。原理是将应用文件进行某种形式的转换&#xff0c;包括不限于隐藏&#xff0c;混淆&#xff0c;加密等操作&#xff0c;进一步保护软件的利益不受损坏&#xff0c;下面给…

生成式人工智能如何改变软件开发:助手还是取代者?

生成式人工智能如何改变软件开发&#xff1a;助手还是取代者&#xff1f; 生成式人工智能&#xff08;AIGC&#xff09;正在引领软件开发领域的技术变革。从代码生成、错误检测到自动化测试&#xff0c;AI工具在提高开发效率的同时&#xff0c;也引发了对开发者职业前景的讨论…

Java面试八股之MySQL的pconenct和connect有什么区别

MySQL的pconenct和connect有什么区别 在PHP中&#xff0c;mysql_pconnect() 和 mysql_connect() 是用来建立与MySQL数据库服务器连接的两个函数&#xff0c;它们的主要区别在于连接的持久性。 mysql_connect(): 这个函数每次调用都会尝试创建一个新的数据库连接。 当PHP脚本…