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

news/2024/7/10 3:41:17 标签: 语言模型, 人工智能, 自然语言处理

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

    需要精心地给予大模型许多的提示(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

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

 工具的使用

         零一万物大模型目前还不支持Agent Tools,FunctionCall 的API ,但是通过我们功能块的方法也能够实现工具的调用。下面是调用打开空调和电灯的功能块网络。

再一次说明了基于功能块网络方式的动态思维编排方法的灵活性。 

程序的实例

Check功能块

class Check {

  constructor(Parameters) {

    this.Name = Parameters.Name;
    this.Type = "CheckType";
    this.model = Parameters.Model
    this.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 + Suffix
      const completion = await this.model.chat.completions.create({
        messages: [
          {
            "role": "user",
            "content": Prompt,
          }],
        model: this.ModelType,
      });

      const Content = await completion.choices[0].message.content
      const JSonContent = JSON.parse(Content.replace("```json\n", "").replace("```", ""))
      console.log(JSonContent.class)
      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: "Ask" })

      }
      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: "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.InMessage
        await 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
  • 功能块及其功能块网络适合大模型思维流程的编排。

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


http://www.niftyadmin.cn/n/5539237.html

相关文章

超过GPT-4V,国产开源多模态大模型来了!支持视频理解/超高分辨率图片理解/多轮对话...

扫码领取享50优惠!随时可用,先到先得! 大家好,开源多模态大模型真的是每天都在疯狂的涌现,今天分享一个国产大模型 InternLM-XComposer-2.5 中文名:浦语灵笔2.5 仅使用 7B LLM 后端就达到了 GPT-4V 级别的能…

全面掌握 Postman 数据导入与导出:详细指南

Postman 是一款广泛使用的 API 开发工具,它提供了丰富的功能来帮助开发者测试、开发和维护 API。其中,数据导入和导出是 Postman 中非常重要的功能之一,它们允许用户将工作从一个环境迁移到另一个环境,或者与团队成员共享配置。本…

Typescript window.localStorage 存储 Obj Value区别

window.localStorage.setItem(UserC, JSON.stringify(userC)) const userC JSON.parse(window.localStorage.getItem(UserC) || {}) 不能获得UserC,所有保存的时候需要存储value,而不是对象。 {"__v_isShallow":false, "__v_isRef&quo…

Selenium 切换窗口

环境: Python 3.8 selenium3.141.0 urllib31.26.19说明: driver.current_window_handle # 返回当前窗口的句柄 driver.window_handles # 返回当前由driver启动所有窗口句柄,是个列表 driver.switch_to.window(handle) # 根据 handle 切换窗口…

记一次使用“try-with-resources“的语法导致的BUG

背景描述 最近使用try-catch的时候遇到了一个问题,背景是这样的:当第一次与数据库建立连接以后执行查询完毕并没有手动关闭连接,但是当我第二次获取连接的时候报错了,显示数据库连接失败,连接已经关闭。 org.postgres…

Linux下的Vim编辑器

一、绪论 1.1 Linux Vim的概述 1.2 Vim在Linux操作系统中的重要性 二、Linux Vim基础知识 2.1 Vim的起源和发展历史 2.2 Vim编辑器的安装与配置 2.3 Vim的基本操作命令 一、绪论 1.1 Linux Vim的概述 vi ( visual editor )编辑器通常被简称为vi,它是Linux和Unix系统上最…

disql使用

进入bin目录:cd /opt/dmdbms/bin 启动disql:./disql,然后输入用户名、密码 sh文件直接使用disql: 临时添加路径到PATH环境变量:在当前会话中临时使用disql命令而无需每次都写完整路径,可以在执行脚本之前…

聚焦云技术,探讨 AGI 时代的云原生数据计算系统

6月22日,开源中国社区在上海举办了 OSC 源创会活动,本期活动以「云技术」为主题,邀请了来自华为 openEuler、字节跳动、AutoMQ 等厂商的技术大咖进行分享,拓数派作为云原生数据计算领域的引领者,受邀参与了本次活动&am…