军哥fastgpt教程-7-fastgpt源码解读之流程编排

大家好,这里是五彩石编程,我是军哥。上一篇文章中我们讲过了fastgpt中知识库相关的源码,这一篇文章中,我们将介绍流程编排相关的源码,一起来学习吧!

一、概述

我们在fastgpt中创建的应用,也被称为agent,一个agent通常是由多个组件按照用户的目的相互组合而成,我们编排一个agent的过程就是agent的流程编排,但在页面上进行流程编排只是创建一个agent的第一步,其输出为一个大的json,里面包含了我们用到的各个组件及组件间的关系。在用户开始会话时,fastgpt就会根据这个json中定义的流程,开始一步步的执行,并按照配置,向用户输出最终的结果。

由于页面上的流程编排最终只是产出了一个json,这部分不涉及后端的代码,所以不是我们关心的重点,完成编排后的流程调度,才是后端处理中的核心逻辑,所以我们关注的重点也是如何基于这个json,来进行流程调度。

二、会话入口

想要了解流程调度,需要先找到会话的入口,在fastgpt中,会话的入口通常有2个:

  1. 流程编排时的调试方法对应的入口,源码在:projects/app/src/pages/api/core/chat/chatTest.ts中
  2. 正常会话时的入口,源码在:projects/app/src/pages/api/v1/chat/completions.ts中

这两个会话的入口处理逻辑相差不大,在调试时,会话历史是不会保存进数据库的,而正常会话时,会话的历史会保存进数据库。其它的逻辑基本上一致。

三、整体流程

我们以正常会话时为例,打开projects/app/src/pages/api/v1/chat/completions.ts,可以看到会话处理的整体流程:

  1. 认证
  2. 处理会话历史
  3. 流程调度
  4. 保存会话结果到数据库中
  5. 记录token消耗

认证部分是对不同的会话渠道进行权限控制,由于fastgpt支持常规会话、分享为链接的形式、iframe嵌入、api调用等多种方式,不同的方式对登录也有不同的要求,所以第一步就是统一进行认证,以保证后续处理的都是合法的请求。

会话历史会为多轮对话提供强有力的支持,所以会话历史的处理也是放到的比较靠前的位置。然后就是核心的流程调度了,这里在下面会详细的讲到,这里先略过。

之后就是把流程调度的结果保存进数据库中,并纪录token的消耗等收尾的工作,这部分的代码相对比较简单,也非核心逻辑,就不再多讲了。下面就着重讲一下流程调度的源码

四、流程调度v1版

从源码中我们可以看到,流程调度目前有2个版本:v1和v2,对应的方法分别是:dispatchWorkFlowV1()和dispatchWorkFlow(),我们先看下v1版,其dispatchWorkFlowV1()方法在packages/service/core/workflow/dispatchV1/index.ts中,打开源码可以看到其先是调用了loadModules()方法,把流程编排时生成的json进行格式转换,转换为适合运行时的结构,然后定义了一系列的内部方法:

  1. pushStore(),收集各组件运行后的输出
  2. moduleInput(),把组件运行时需要的输入参数给注入进去
  3. moduleOutput(),把当前组件输出的内容传给下一个组件
  4. checkModulesCanRun(),检查组件是否可以运行
  5. moduleRun(),调用各组件的逻辑控制代码,来实现组件的运行,并调用上面几个方法来实现组件的调度

在上面几个方法之后,才是流程的起始代码,上面的几个方法是整个流程调度的核心,组件间的执行顺序主要由上面的这些方法来控制。

起始代码部分,先是过滤出来所有的入口,然后注入需要组件运行时需要的输入参数,然后调用checkModulesCanRun()方法来检查模块是否可以运行,如果可以运行,则会调用moduleRun()来运行模块。

checkModulesCanRun()方法主要是检查一个组件的input是否都赋过值了,如果都赋过值了,说明其相关的前组件都已经运行过了,那么当前组件也就可以运行了。

在moduleRun()方法内部,最重要的一行代码是关于callbackMap的,callbackMap中保存了各个组件实际的执行方法,它定义在文件的最上面,相当于当前文件只负责流程的调度,各个组件实际怎么去执行,就交给各个组件的具体实现了,这样的话,以后在添加新的组件时,只需要在callbackMap中添加一行就可以了,不会对流程调度过程的其它代码造成影响,而每个组件的实际执行代码通常是非常独立,功能相对来说比较单一的,实现起来就没有太大的难度了。所以好的架构在代码的扩展性上,一定是做得非常好的。

看懂了moduleRun()方法,基本上就了解了v1版本的流程调度的逻辑了。

五、流程调度v2版

接下来,我们再来看一下v2版本的代码,其方法dispatchWorkFlow()在packages/service/core/workflow/dispatch/index.ts中,在了解了v1版本的代码逻辑后,v2版本的逻辑相对来说就简单不少了。

v2版一上来就先定义了一堆的内部方法:

  1. pushStore(),收集各组件运行后的输出
  2. nodeOutput(),把组件运行时需要的输入参数给注入进去
  3. checkNodeCanRun(),检查组件是否可以运行
  4. nodeRunFinish(),组件运行的结束方法
  5. getNodeRunParams(),把组件运行时需要的输入参数给注入进去
  6. nodeRunWithActive(),运行一个组件
  7. nodeRunWithSkip(),跳过一个组件

在上面几个方法之后,才是流程调度的开始,先是过滤出会话的入口,然后通过checkNodeCanRun()来调起整个流程,最后是输出最终结果。

v2版本的内部方法和v1版本的有些相似,也有几个方法不太一样,主要的区别在于引入了边和组件的运行状态两个概念,把组件的调度控制转换为了对边和运行状态的控制。线分为了普通线和递归线,组件的状态被分为了:run、wait、skip三种,相较于版本1来说,流程调度的实现上变得更加了抽象了一点。

组件的运行方法虽然改为了nodeRunWithActive(),但其内部的核心依然是调用callbackMap()这个方法,从而实现调用各个组件的实际实现代码。

六、各组件的具体实现

在上一篇文章中,谈到了知识库的实现源码,它在所有的组件中,基本上算是最复杂的一个了,其它的组件像ai对话、指定回复、判断器、文本加工等,大多是调用大模型或简单的文本处理逻辑,只要找到callbackMap的定义处,再点进去就可以追踪到每个组件的具体实现代码了,由于都比较简单,这里就不再细说了,感兴趣的朋友们可以自行去查看

七、结语

到此为止,整个fastgpt系列就全部结束了,从一开始的概念了解,到后面的开发环境搭建、源码分析,虽然有很多的概念、代码量也比较大,但只要大家去实践一下,就会发现其实没有那么难。从fastgpt的版本迭代来看,整个项目也在经历着从最初的仅仅实现功能即可,到后期的架构上的不断优化,项目的易用性也得到了很大的提高。

最后期望大家能够随着军哥的文章一起进步,一起提升编程和项目理解能力,在编程的道路上,一同砥砺前行!


想了解更多编程的知识,请微信搜索并关注“五彩石编程”公众号,军哥的文章将会持续同步更新。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值