当前位置: 首页 > news >正文

谈大语言模型动态思维流程编排

        尽管大语言模型已经呈现出了强大的威力,但是如何让它完美地完成一个大的问题,仍然是一个巨大的挑战。

    需要精心地给予大模型许多的提示(Prompt)。对于一个复杂的应用场景,编写一套完整的,准确无误的提示,并不容易。另一方面,尽管大模型已经具备了一些拆解问题,一步步解接的能力。但是就目前而言,这种分析,推理能力还是不能能准确地做出推理

  另一方面,对于大多数特定的问题而言,人类本身具有了成熟,有效的分析问题,解决问题的能力。我们出生起,就不断地学习如何一步步地拆解问题,通过步步地解决小问题,最终解决一个复杂的问题。

  许多的研究者提出了各种提示大模型拆解问题的方法。例如  计划和解题(Plan-and-Solve Prompting),反思 ReAct 等等。但是不同的问题,有不同的解决思路。我们从小在学校里解决应用题时,老师总是教我们解题思路。对于各种问题,大模型需要能够动态地做出解题方法。使用静态的提示来实现动态地计划是十分复杂,。在笔者看来,使用计算机语言来动态规划大模型解决问题的思路更加有效。

从实例谈起

     我们计划编写一个增强个人记忆力的大模型应用,该项目叫做 回忆(Recall)。在这个应用中,使用者要不断地告诉大模型一些关于个人的信息。例如:

  •       个人简历:包括姓名,性别,出身日期,出生地,家庭成员,教育和工作简历等等。
  •       个人爱好:自己的爱好,包括饮食,业余爱好,购物的品牌等等
  •      个人活动:比如一些主要的活动,比如逛街,朋友聚会,就医等等活动。
  •       备忘录:一些需要备忘的事情,例如 我的衣服放在哪里了。每天吃什么药等等。

      这个项目貌似比较简单,与windows AI PC 中的Recall ,开源项目Rewind 有相似之处。按照网络上的各种大模型架构的方法,主要使用如下方式

  •      使用大模型的Memory 功能实现对话的记忆
  •     将用户的个人信息,爱好,个人活动写入Vector 数据库中,使用RAG 技术在会话过程中读取相关信息
  •     构建ReAct Agent 进行 Action -Throught-Observation 的过程
  •    调用合适的工具(Agent Tools)

 vector 数据库 可以使用内存Memory  也可以使用永久VectorDB ,例如Croma VectorDB。

大模型我们测试了下列几种:

  1. openai
  2. 本地 llama-3
  3. 文心一言
  4. kimi
  5. 零一万物

但是结果并不令人满意,主要表现在如下几个方面

  •  并非所有的大模型都支持 Function Call,Agent,Memory ,RAG等功能的API。 
  • Vector 数据库要使用Embedding 功能实现text -splite .耗费的时间很长。
  • Momory 功能是将输入和回答都一股脑地存储了起来。会造成某些噪声混乱。
  • 简单的提问查询Vector数据库时,无法精切地匹配数据库的内容。
  • ReAct 的效果并不理想,有时后会乱想,反复地循环。明明得到了结果,却无法停止对话。
  • 延时长,耗费的token 多。

 实验下来,openai 效果最好,其它国内的大模型或多多少地出现问题。

观点

经过一段时间的实验之后,我们对大模型应用进行了新的思考,形成了下面几个观点:

  • 让大模型分层思考

         将复杂的问题分解为若干的小问题,通过解决小问题,最后解决大问题。这种方式具有如下的优点:

                -大模型回答简单的问题,有利于保证其确定性

                -使提示工程变得简单

                    提示也被分解成小提示,小问题的提示更具有针对性

                -不依赖具体的大模型API

                   简单地使用chat 就可以。 

                 -有利于采纳本地小模型与远程大模型相结合  ,降低使用大模型的成本,提高响应时间

  •    使用程序设计的方法动态地编排大模型的思维过程

          对于特定的一类问题,可以实现根据人类的经验,制定一套完整的思维过程。这样做的优点:

                -融入了人类的思维方式,更具有针对性。推理的速度更快

                -有利于对大模型的回答做确定性判断

                -有利于对大模型的回答做确定性验证

动态思维的流程

我们继续使用上面的实例来讨论动态思维流程。

  1. 判断语句是陈述句,还是询问句
  2. 如果是陈述句,内容要存储到数据库中,如果是提问句,那么要从数据库中获取相关的信息
  3. 为了对信息做分类,要判断陈述或者提问的内容的分类。
  4. 如果是其它类型的提问,就直接有大模型回答

思维流程的编排方法 

可以用程序或者图形方式来编排大模型的思维流程,在我们的实验中,采取了工业控制领域中功能块的编排方法。

      基于我们的经验,决定借用IEC61499 事件功能块的概念和方法,这样做的另一个意图是实现语言功能块和IEC61499 功能块的融合。

IEC61499 的基本概念包括:

  • 基本功能块
  • 复合功能块
  • 功能块网络

       IEC61499 功能块由事件输入,事件输出,数据输入和数据输出。事件用来控制程序执行 的流程,数据用来表示数据的流动。

 

大语言功能块内部由大语言模型来回答一个特定的问题。 其内部结构如下:

大模型思维流程

       大语言思维流程由大语言功能块网络组成,通过功能块网络运行时解释执行。功能块共享环境信息,环境信息包含了基本信息(对话者的姓名, 今天几号,星期几等等)和功能块通过数据库中提取的信息。一个功能块系统的结构如下

实验平台

   为了实验langFunctionblock 的想法,我们简单地搭建列一个实验平台:

  • 基于Nodejs/Javascript
  • 基于langchain库
  • 一个Javascript 实现的功能块运行时
  • 一组基于大模型的功能块
  • 不依赖大模型的API
App架构

实例的功能块网络 

功能块

InputMessage

输入用户提问的功能块,当用户输入消息时。该功能块产生:

  • Output 事件
  • OutMessage 数据

应用程序通过 WriteData 和Execution  调用该功能块。

设置InputMessage和OutMessage功能块的主要目的是使功能块具有一个统一的入口和出口。

Check

主要判断输入语句是询问句还是陈述句。

Memory

该功能块判断陈数句内容的类型:个人信息,事件,备忘录,然后将语句的类型,语句和时间标签存储到MongoDB 数据库中。

Recall

该功能块判断陈数句内容的类型:个人信息,事件,备忘录,然后从数据库中读出相应类型的数据,添加在环境信息中。

Basic

  这是一个基本大模型的功能块,将InMessage 结合环境信息一起构成Prompt 询问大模型,回答输出到OutMessage

OutMessage

 该模块将信息返回给对话者。

程序的实例

Check功能块

class Check {constructor(Parameters) {this.Name = Parameters.Name;this.Type = "CheckType";this.model = Parameters.Modelthis.ModelType = Parameters.ModelType}async Executive(runtime, EventType) {if (EventType == "Invoke") {console.log("Invoke:" + this.ModelType)console.log(this.InMessage)const Prefix = `请将下列语句分为下列几类:询问,陈述,请求。`const Suffix = `。请以JSON形式输出语句的类型 :JSON的格式为:{class:"语句的类型"}如果无法判断语句的类型,直接输出 {class:"其它"}`const Prompt = Prefix + this.InMessage + Suffixconst completion = await this.model.chat.completions.create({messages: [{"role": "user","content": Prompt,}],model: this.ModelType,});const Content = await completion.choices[0].message.contentconst JSonContent = JSON.parse(Content.replace("```json\n", "").replace("```", ""))console.log(JSonContent.class)if (JSonContent.class == "询问") {this.OutMessage = this.InMessageawait runtime.WriteOutputData({ FBName: this.Name, DataName: "OutMessage", Value: this.OutMessage })await runtime.EventNotify({ FBName: this.Name, EventName: "Ask" })}else if (JSonContent.class == "陈述") {this.OutMessage = this.InMessageawait runtime.WriteOutputData({ FBName: this.Name, DataName: "OutMessage", Value: this.OutMessage })await runtime.EventNotify({ FBName: this.Name, EventName: "Statment" })} else if (JSonContent.class == "请求") {this.OutMessage = this.InMessage;await runtime.WriteOutputData({ FBName: this.Name, DataName: "OutMessage", Value: this.OutMessage })await runtime.EventNotify({ FBName: this.Name, EventName: "Request" })}else {this.OutMessage = this.InMessageawait runtime.WriteOutputData({ FBName: this.Name, DataName: "OutMessage", Value: this.OutMessage })await runtime.EventNotify({ FBName: this.Name, EventName: "Ask" })}}}async WriteData(Name, Value) {if (Name == "InMessage") {this.InMessage = Value;}}async ReadData(Name) {if (Name == "OutMessage")return this.OutputMessage;}
}

主程序

import express from 'express';
import path from 'path'
import url from 'url'
//import fs from 'fs'
import OpenAI from 'openai';
import {RunTime} from "./RunTime/RunTime.mjs"
const API_BASE = "https://api.lingyiwanwu.com/v1"
const API_KEY = "xxxxxxxxxxxxxxxxxxx"
const openai = new OpenAI({apiKey: API_KEY,baseURL:API_BASE,model: "yi-large",temperature: 0});const router = express.Router();const app = express();const __filename = url.fileURLToPath(import.meta.url);const __dirname = path.dirname(__filename);
// var upload = multer({ dest: './documents' })app.use(express.static(path.join(__dirname, 'public')));app.use(express.json())router.get('/index', function (req, res) {res.sendFile(path.join(__dirname + '/views/indexB.html'));});router.post('/Request', async function (req, res) {Request = req.body;console.log(Request)const Method = Request.Method;const Message = Request.Message;console.log(Method);console.log(Message);const result = await RunFBNetwork(Message)res.send(JSON.stringify({Method: "SendMessage",Message: result}))
})
app.use('/', router);//RunTime Initialize 
console.log("llm FunctionBlock Runtime Ver 1.0")
const runtime=new RunTime();
runtime.InitializeFunctionBlickList();
runtime.LoadFBNetwork(openai); 
app.listen(process.env.port || 3000);
console.log('Running at Port 3000');async function RunFBNetwork(InputMessage){console.log("llm FunctionBlock Runtime Ver 1.0")//RunTime Initialize runtime.InitializeMongoDB()runtime.InitializeEnvironment()await runtime.WriteInputData({FBName:"InMessage",DataName:"InMessage",Value:InputMessage})await runtime.Executive({FBName:"InMessage",EventType:"Request"})//Running....await runtime.run()const Output=await runtime.ReadFBData({FBName:"OutMessage",DataName:"OutMessage"})console.log(Output)return (Output)
}

结果

        经过我们的初步测试,结果要比采用大模型的memory,RAG,ReAct Agent等方式要好。主要表现为准确率高,速度快。

  •   将复杂的问题拆解成为小问题更有效
  • 对于特定的应用场景,能够利用人类分析问题的经验,动态地编写思维流程要比简单的将复杂任务交给大模型更好。效果远远超过ReAct Agent
  • 功能块及其功能块网络适合大模型思维流程的编排。

 感兴趣的读者可以进一步共同探讨。

相关文章:

  • ELK日志系统和Filebeat采集器的学习总结
  • 中国网络安全审查认证和市场监管大数据中心数据合规官CCRC-DCO
  • 搭建vue3+vite+pinia项目步骤
  • JAVA基础(8) 面向对象编程3
  • 「植物大战僵尸杂交版」保姆级攻略大全以及下载指南
  • 【ARMv8/v9 GIC 系列 5.3 -- 系统寄存器对中断的处理】
  • Pytest--安装与入门
  • Firewalld 防火墙基础
  • Flask-Session使用Redis
  • 蓝桥杯web组国三选手题纲解析和备赛技巧--经验分享
  • c++之旅第十一弹——顺序表
  • 常见网络攻击方式及防御方法
  • 图像处理中的二维傅里叶变换
  • 鸿蒙:1.入门
  • 十大排序:插入/希尔/选择/堆/冒泡/快速/归并/计数/基数/桶排序 汇总(C语言)
  • fetch 从初识到应用
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Java超时控制的实现
  • Js基础——数据类型之Null和Undefined
  • mysql中InnoDB引擎中页的概念
  • Node项目之评分系统(二)- 数据库设计
  • php面试题 汇集2
  • TypeScript迭代器
  • 从零开始在ubuntu上搭建node开发环境
  • 聚类分析——Kmeans
  • 日剧·日综资源集合(建议收藏)
  • 协程
  • 异步
  • 带你开发类似Pokemon Go的AR游戏
  • ​渐进式Web应用PWA的未来
  • $.ajax,axios,fetch三种ajax请求的区别
  • (1)SpringCloud 整合Python
  • (顺序)容器的好伴侣 --- 容器适配器
  • (一)硬件制作--从零开始自制linux掌上电脑(F1C200S) <嵌入式项目>
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (转)fock函数详解
  • (转)Scala的“=”符号简介
  • (转)一些感悟
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .net MVC中使用angularJs刷新页面数据列表
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET(C#、VB)APP开发——Smobiler平台控件介绍:Bluetooth组件
  • .net开发时的诡异问题,button的onclick事件无效
  • .NET面试题解析(11)-SQL语言基础及数据库基本原理
  • .net专家(高海东的专栏)
  • @EventListener注解使用说明
  • @Transactional 竟也能解决分布式事务?
  • [ C++ ] STL---string类的模拟实现
  • [] 与 [[]], -gt 与 > 的比较
  • [1]-基于图搜索的路径规划基础
  • [23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution
  • [BUG]Datax写入数据到psql报不能序列化特殊字符