前端到AI,LangChain.Js(五)

学习地址:
学习小册

实战

基于前面的RAG模块,可以通过构建本地存储向量数据库,本地存储聊天记录,部署成stream API,做一个chat bot。
Agents模块,可以通过tools进行数据标签和信息提取,通过RUnnableBranch构建复杂的chain等。

MBTI chat bot

做一个 MBTI 的 chatbot,让用户输入自己的 MBTI 类型和问题,然后由 LLM 根据这个性格去解答问题。

但不是使用传统的 GUI,而是让 LLM 去询问用户的 MBTI 和问题,多次对话,直到 LLM 认为收集到了足够的参数后,再调用对应的函数去回答用户的问题。

首先,先创建一个专业回答MBTI的chain

// 定义prompt
const prompt = ChatPromptTemplate.fromMessages([
  [
    "system",
    `你是一个共情能力非常强的心理医生,并且很了解MBTI(迈尔斯-布里格斯性格类型指标)的各种人格类型,
    你的任务是根据来访者的 MBTI 和问题,给出针对性的情感支持,你的回答要富有感情、有深度和充足的情感支持,引导来访者乐观积极面对问题`,
  ],
  [
    "human",
    "用户的 MBTI 类型是{type}, 这个类型的特点是{info}, 他的问题是{question}",
  ],
]);

//顺序调用
const mbtiChain = RunnableSequence.from([
  prompt,
  chatModel,
  new StringOutputParser(),
]);

这个chain主要就是根据用户的类型特点回答用户的问题

接着定义一个tools,这个tools负责调用mbtiChain

// 定义一个tools,里面调用mbtiChain去返回函数的内容
const mbtiTool = new DynamicStructuredTool({
  name: "get-mbti-chat",
  schema: z.object({
    type: z.enum(mbtiList).describe("用户的 MBTI 类型"),
    question: z.string().describe("用户的问题"),
  }),
  func: async ({ type, question }) => {
    const info = mbtiInfo[type];

    const res = await mbtiChain.invoke({ type, question, info });
    return res;
  },
  description: "根据用户的问题和 MBTI 类型,回答用户的问题",
});

const tools = [mbtiTool];

type和question是必填的信息,info可以直接给入每个类型的特点
在这里插入图片描述

接着创建一个agent,该智能体主要用来与用户的沟通,获取用户的信息,判断用户的类型,然后调用tool去调用mbtiChain来回答用户的问题。

 const agentPrompt = await ChatPromptTemplate.fromMessages([
    [
   // 有足够信息的时候就去调用get-mbti-chat,让专业的mbti-chain来回答问题,没有的话就反复询问
      "system",
      "你是一个用户接待的 agent,通过自然语言询问用户的 MBTI 类型和问题,直到你有足够的信息调用 get-mbti-chat 来回答用户的问题,如果是通过调用 get-mbti-chat回答的问题,返回内容请包括 “这是来自专业的MBTI导师提供的建议”",
    ],
    new MessagesPlaceholder("history_message"),
    ["human", "{input}"],
    new MessagesPlaceholder("agent_scratchpad"),
  ]);

  const agent = await createOpenAIToolsAgent({
    llm: chatModel,
    tools,
    prompt: agentPrompt,
  });

  const agentExecutor = new AgentExecutor({
    agent,
    tools,
  });

首先定义一个prompt,表明他的主要功能,并且强化对get-mbti-chat调用的指示。
然后还要加上历史记忆功能。直接用内存history,然后用RunnableWithMessageHistory将chain包裹起来。

 // 创建hisotry
  const messageHistory = new ChatMessageHistory();
  // 包裹,使chain具有历史记忆功能
  const agentWithChatHistory = new RunnableWithMessageHistory({
    runnable: agentExecutor,
    getMessageHistory: () => messageHistory,
    inputMessagesKey: "input",
    historyMessagesKey: "history_message",
  });

这样这个agent就具有了历史记忆功能。
接着可以通过readline来通过cli交互。

 // 创建一个cli交互功能
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  function chat() {
    rl.question("User: ", async (input) => {
      if (input.toLowerCase() === "exit") {
        rl.close();
        return;
      }

      // 调用agent回答去返回
      const response = await agentWithChatHistory.invoke(
        {
          input,
        },
        {
          configurable: {
            sessionId: "no-used",
          },
        }
      );

      console.log("Agent: ", response.output);

      chat();
    });
  }

  console.log("请输入问题。 输入 exit 退出聊天。");
  chat();

至此,我们可以来跟agent进行交互了。

在这里插入图片描述

在传统的编程里,我们需要控制用户的输入方式,输入顺序,输入格式等,比如很多MBTI问卷,就是GUI的方式。
而在llm中,这些不受限制,由LLM支持的基于语义理解推理引擎,用自然语言一步一步引导用户说出需求,通过自己对任务理解来创造流程引导用户。也就是LLM_UIZ

算命 bot

llm 本质上是一个语言模型,其基于预训练的模型,根据用户输入的 prompt 去生成最大概率的下一个字符(token)。换句话说,其最擅长的是“把话说圆”。 在前面的章节中,我们讲解了 llm 展现出来的是涌现的智能,他并不理解输出内容的意义,而是一个根据概率吐出 token 的机器。

六爻算卦

初爻 为 背字背 为 阴
二爻 为 字背字 为 阳
三爻 为 背背背 为 阴
您的首卦为 坎
四爻 为 字字字 为 阳
五爻 为 背背背 为 阴
六爻 为 字字背 为 阳
您的次卦为 震

六爻结果: 震坎  
卦名为:屯卦   
水雷屯(屯卦)起始维艰   
卦辞为:风刮乱丝不见头,颠三倒四犯忧愁,慢从款来左顺遂,急促反惹不自由   
算卦流程实现

八卦和八卦对应的信息是有真实答案的类别,一般不要让LLm自己生成,否则会出现一些不存在的卦象和解读。

所以,类似于 RAG 的思路,我们把标准的算卦流程和真实的八卦信息,由我们代码生成,并在后续 chat 中,直接嵌入到 llm 上下文中。

具体的实现过程就是把算卦流程编码化,写起来比较繁琐,但逻辑很简单。

模拟算卦流程

 const yaoName = ["初爻", "二爻", "三爻", "四爻", "五爻", "六爻"];

const guaDict = {
  阳阳阳: "乾",
  阴阴阴: "坤",
  阴阳阳: "兑",
  阳阴阳: "震",
  阳阳阴: "巽",
  阴阳阴: "坎",
  阳阴阴: "艮",
  阴阴阳: "离",
};
// 模拟算卦流程
function generateGua(): string[] {
  let yaoCount = 0;
  const messageList = [];

  const genYao = () => {
    const coinRes = Array.from({ length: 3 }, () =>
      Math.random() > 0.5 ? 1 : 0
    );
    const yinYang = coinRes.reduce((a, b) => a + b, 0) > 1.5 ? "阳" : "阴";
    const message = `${yaoName[yaoCount]}${coinRes
      .map((i) => (i > 0.5 ? "字" : "背"))
      .join("")}${yinYang}`;

    return {
      yinYang,
      message,
    };
  };

  const firstGuaYinYang = Array.from({ length: 3 }, () => {
    const { yinYang, message } = genYao();
    yaoCount++;

    messageList.push(message);
    return yinYang;
  });
  const firstGua = guaDict[firstGuaYinYang.join("")];
  messageList.push(`您的首卦为 ${firstGua}`);

  const secondGuaYinYang = Array.from({ length: 3 }, () => {
    const { yinYang, message } = genYao();
    yaoCount++;

    messageList.push(message);
    return yinYang;
  });
  const secondGua = guaDict[secondGuaYinYang.join("")];
  messageList.push(`您的次卦为 ${secondGua}`);

  const gua = secondGua + firstGua;
  const guaDesc = guaInfo[gua];

  const guaRes = `
  六爻结果: ${gua}  
  卦名为:${guaDesc.name}   
  ${guaDesc.des}   
  卦辞为:${guaDesc.sentence}   
    `;

  messageList.push(guaRes);

  return messageList;
}

// 生成一次算卦结果
const messageList = generateGua();


用Math.random模拟丢硬币
在这里插入图片描述
然后将这个信息作为上下文交给LLM。
定义prompt

const guaMessage = messageList.map((message): ["ai", string] => [
    "ai",
    message,
  ]);

  // 成prompt
  const prompt = await ChatPromptTemplate.fromMessages([
    [
      "system",
      `你是一位出自中华六爻世家的卜卦专家,你的任务是根据卜卦者的问题和得到的卦象,为他们提供有益的建议。
你的解答应基于卦象的理解,同时也要尽可能地展现出乐观和积极的态度,引导卜卦者朝着积极的方向发展。
你的语言应该具有仙风道骨、雅致高贵的气质,以此来展现你的卜卦专家身份。`,
    ],
    ...guaMessage,
    new MessagesPlaceholder("history_message"), //方便插入聊天记录
    ["human", "{input}"],
  ]);

将上述算卦的流程转为AI:xxx,传入prompt里面
创建一个简单的chain,有历史记忆功能

//创建一个简单的chain
  const chain = prompt.pipe(chatModel).pipe(new StringOutputParser());
  const history = new ChatMessageHistory();
  const chainWithHistory = new RunnableWithMessageHistory({
    runnable: chain,
    getMessageHistory: (_sessionId) => history,
    inputMessagesKey: "input",
    historyMessagesKey: "history_message",
  });

最后通过cli直接交互

 const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  const question = util.promisify(rl.question).bind(rl);

// 等待用户输入
  const input = await question("告诉我你的疑问: ");

  let index = 0;
 // 一秒打印一次messageList的结果,模拟算卦
  const printMessagesPromise = new Promise<void>((resolve) => {
    const intervalId = setInterval(() => {
      if (index < messageList.length) {
        console.log(messageList[index]);
        index++;
      } else {
        clearInterval(intervalId);
        resolve();
      }
    }, 1000);
  });

// 调用chain
  const llmResPromise = chainWithHistory.invoke(
    { input: "用户的问题是:" + input },
    { configurable: { sessionId: "no-used" } }
  );
  const [_, firstRes] = await Promise.all([printMessagesPromise, llmResPromise]);

// 输出占卦结果
  console.log('firstRes===', firstRes);

输出占卦结果后,用户可能还有疑问,我们需要开启新的一轮聊天

 // 开启新的一轮聊天
  async function chat() {
    const input = await question("User: ");

    if (input.toLowerCase() === "exit") {
      rl.close();
      return;
    }

    const response = await chainWithHistory.invoke(
      { input },
      { configurable: { sessionId: "no-used" } }
    );

    console.log("AI: ", response);
    chat();
  }

  chat();

这样就完成了一个基础的算命bot。
测试:
在这里插入图片描述

在这基础上提问
在这里插入图片描述
这是完整的流程,可以看到因为我们加入了 chat history,llm 可以根据用户问题持续解读卦象。

从输出结果来看,llm 把话说圆的能力非常适合算卦的场景,他能有效的把用户的问题和随机生成的卦象挂钩,进行解读。并且我们在 prompt 指定其语言风格是 “仙风道骨、雅致高贵的气质”,只使用这简单的指令,就能控制 llm 的语言风格。

从代码量上看,LLm相关的代码只占很小一部分。所以LLM应用的核心不是LLM,而是用户场景和idea。

AI辅助编程基础

模型是什么?

“模型” 是指一个通过大量数据训练出来的智能系统,能够理解和生成自然语言,并完成多种任务
举个通俗易懂的例子,小孩学说话
1 数据收集:小孩从周围的人听到各种各样的句子和话语,相当于模型在训练过程中接受大量文本数据。
2 模式学习:小孩逐渐理解语言的结构,比如如何组成句子,单词的意思是什么,这就类似模型在训练过程中,识别语言模式和语义的过程。
3 生成语言:当小孩学会了足够多的单词和句子结构后,他可以尝试自己说话,表达想法,类似模型在接受输入后,输出一个合理的响应。

模型训练是什么?

通过海量的人类数据,让模型学会人类文字表达中的概率信息。

  • 1 数据收集 :收集大量的文本或代码数据,这些数据可以来自书籍、文章、代码库等多种来源
  • 2 数据预处理: 对收集到的数据进行清洗和整理,确保数据的质量和一致性。
  • 3 模型训练:利用高性能的计算资源(如 GPU),通过复杂的算法(如梯度下降)调整模型内部的参数,使其能够更准确地预测下一个词或代码片段,从而实现更接近人类语言的表达效果。
    通过这样的训练过程,模型逐渐掌握了语言和编程语言中的各种模式和规则。
大模型是什么?

LLM(large language Model)大型语言模型。
在前面描述的模型原理中,模型只能在部分场景下展现出出色的补全能力,无法发挥更高级别的价值。
而LLM就是模型的各个维度进行扩大,比如更大的数据集,更大的模型参数量,在“大力出奇迹”的思路下,大模型展现出相当的智能程度,称为“涌现的智能”,当数据和模型达到一定规模后,它表现出了类似智能的表象。

有一个哲学实验可以帮助理解

一个只说英语、对中文一窍不通的人被关在一间只有一个开口的封闭房间中。房间里有一本用英文写成的手册,指示该如何处理收到的中文信息及如何用中文作出相应回复。房外的人不断向房间内递进用中文写成的问题,房内的人便按照手册的说明,查找合适的指示,将相应的中文字符组合、形成答案,并将答案递出房间。 如果房内的人查询手册的速度飞快,手册涉及中文的所有应用情形,那么对于房间外的人来说,是否可以认为这个房间里的人懂中文?

这个思维实验,与大模型十分相似。大模型基于概率原理,依靠巨大的模型规模和训练数据,展现出智能的表象。

Fine-tune(微调)是什么?

微调是指,在一个已经预训练的大模型基础上,针对特定任务或领域的进一步训练。例如,一个通用的语言模型可以通过微调,变成专门用于代码生成或特定编程语言的辅助编程。

Fine-tune的核心在于,针对某个特殊场景,比如编程,应用在巨大通用数据集上训练的模型,再针对新的较小数据集(比如编程语言数据集,肯定小于人类通识),进行二次训练(fine-tune),其表现出的智能效果更好。目前大多数代码辅助编程工具,都是基于通用大模型,使用大量的代码训练数据,微调而成。

如果用一句话粗略地总结大模型:
它是一个基于概率和海量数据训练的模型,能够在部分任务中表现出近似甚至超越人类的智能,但这只是“涌现的智能”,而不是真正的智能。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 Arduino 和 Wi-Fi 控制 RGB LED

通过 WiFi 的 Arduino RGb LED 控制器 &#xff0c;在本文中&#xff0c;我们将介绍下一个基于 IOT 的项目 - 使用 Wi-Fi 的 RGB LED 闪光灯。在这里&#xff0c;我们使用 Arduino 和 ESP8266 Wi-Fi 模块通过 Android 手机通过 Wi-Fi 控制 RGB LED 的颜色。 在这个 RGB Flash…

C# 开发工具Visual Studio下载和安装

开发环境与工具 C#的主要开发环境是Visual Studio&#xff0c;这是一个功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;集成了代码编辑、调试、项目管理、版本控制等功能。此外&#xff0c;Visual Studio Code也是一个轻量级的跨平台代码编辑器&#xff0c;支…

HTML + CSS 题目

1.说说你对盒子模型的理解? 一、是什么 对一个文档进行布局的时候&#xff0c;浏览器渲染引擎会根据标准之一的css基础盒模型&#xff0c;将所有元素表示为一个个矩形的盒子。 一个盒子由四个部分组成: content&#xff0c;padding&#xff0c;border&#xff0c;margin 下…

数据结构–栈

数据结构–栈 什么是栈&#xff1f; 首先先给大家讲一下栈是什么&#xff1a;栈是一种特殊的线性表。特殊之处就在于对栈的操作的特殊。对于栈&#xff0c;只允许其在固定的一端进行插入和删除元素操作。不像普通的顺序表&#xff0c;链表&#xff0c;可以在任意位置进行删除插…

通过Docker搭个游戏——疯狂大陆(Pkland)

最近在研究我的服务器&#xff0c;在服务器上搭了很多docker的项目&#xff0c;然后找着找着发现一个能用Docker配置环境的游戏叫Pkland。 项目地址&#xff1a;GitHub - popkarthb/pkland: 疯狂大陆是一款多人在线的战略游戏。 游戏操作简捷,您仅需要使用浏览器就可以在任何时…

03.06 QT

一、使用QSlider设计一个进度条&#xff0c;并让其通过线程自己动起来 程序代码&#xff1a; <1> Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QThread> #include "mythread.h"QT_BEGIN_NAMESPACE namespace Ui {…

【LeetCode 热题 100】3. 无重复字符的最长子串 | python 【中等】

美美超过管解 题目&#xff1a; 3. 无重复字符的最长子串 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长的长度。 示例 1: 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"&#xff0c;所以其长度为 3。 注…

微服务拆分-拆分商品服务

复制hm-service模块pom.xml文件里面的依赖到item-service模块pom.xml文件。 需要准备的依赖 <dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</v…

父进程和子进程

思维导图&#xff1a; 1.使用父子进程实现一个图片的拷贝 要求父进程拷贝前一部分 子进程拷贝后一部分 使用diff查看两个文件是否相同 #include <head.h> int main(int argc, const char *argv[]) {int fd1open("/home/ubuntu/3.6/xiaoxin.bmp",O_RDONLY);…

3.2、对称加密算法

目录 对称加密算法总结国产加密算法 - SM系列 对称加密算法总结 首先看一下第一个它的全称叫数据加密标准&#xff0c;英文单词是DES&#xff0c;它是一种分组加密算法&#xff0c;就是比如说&#xff0c;我有10t的数据&#xff0c;我先给你做一下分组&#xff0c;比如说就是64…

let、const和var的区别是什么?

文章目录 一、概述二、var 的特点2.1、作用域2.2、提升&#xff08;Hoisting&#xff09;2.3、全局变量2.4、重复声明‌ 三、let 的特点3.1、作用域3.2、提升&#xff08;Hoisting&#xff09;3.3、不允许重复声明 四、const 的特点4.1、作用域4.2、不可变性4.3、提升&#xff…

数一考研复习之拉格朗日中值定理在求解函数极限中的应用,

最近在复习考研数学,只是简单做题过于乏味,因此便总结了一些笔记,后续若有空,也会将自己的复习笔记分享出来。本篇&#xff0c;我们将重点讲解拉格朗日中值定理在求解函数极限中的应用。同时,作者本人作为python领域创作者&#xff0c;还将在本文分享使用sympy求解高数中函数极…

Devart dbForge Studio for MySQL Enterprise 9.0.338高效数据库管理工具

Devart dbForge Studio for MySQL Enterprise 9.0.338 是一款功能强大的 MySQL 数据库管理工具&#xff0c;专为数据库开发人员和管理员设计。它提供了丰富的功能&#xff0c;帮助用户更高效地管理、开发和维护 MySQL 数据库 Devart dbForge Studio for MySQL Enterprise 9.0.…

Android15使用FFmpeg解码并播放MP4视频完整示例

效果: 1.编译FFmpeg库: 下载FFmpeg-kit的源码并编译生成安装平台库 2.复制生成的FFmpeg库so文件与包含目录到自己的Android下 如果没有prebuiltLibs目录,创建一个,然后复制 包含目录只复制arm64-v8a下

DeepSeek大模型 —— 全维度技术解析

DeepSeek大模型 —— 全维度技术解析 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff01;点我试试&#xff01;&#xff01; 文章目录 DeepSeek大模型 —— 全维度技术解析一、模型架构全景解析1.1…

Spring Boot 与 MyBatis 版本兼容性

初接触Spring Boot&#xff0c;本次使用Spring Boot版本为3.4.3&#xff0c;mybatis的起步依赖版本为3.0.0&#xff0c;在启动时报错&#xff0c;报错代码如下 org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name userMapper…

JavaWeb6、Servlet

6.1Servlet简介 Servlet就是sun公司开发动态web的一门技术 sun公司在这些API中提供一个接口叫做Servlet&#xff0c;如果想开发一个Servlet程序&#xff0c;只需要完成两个小步骤&#xff1a; 编写一个类&#xff0c;实现Servlet接口 把开发好的Java类部署到web服务器中 把…

论文粗读——Isometric 3D Adversarial Examples in the Physical World

论文地址:Isometric 3D Adversarial Examples in the Physical World 动机 现有的3D点云攻击方法远远不够隐蔽,并且在物理世界中性能严重下降。 已有方法及其不足 基于梯度的攻击->仅限于数字世界攻击;KNN攻击和GeoA3攻击->点云重建引入了较大的噪声和错误,导致攻…

AI视频领域的DeepSeek—阿里万相2.1图生视频

让我们一同深入探索万相 2.1 &#xff0c;本文不仅介绍其文生图和文生视频的使用秘籍&#xff0c;还将手把手教你如何利用它实现图生视频。 如下为生成的视频效果&#xff08;我录制的GIF动图&#xff09; 如下为输入的图片 目录 1.阿里巴巴全面开源旗下视频生成模型万相2.1模…

微电网协调控制器ACCU-100 分布式光伏 光储充一本化

安科瑞 华楠 18706163979 应用范围&#xff1a; 分布式光伏、微型风力发电、工商业储能、光储充一体化电站、微电网等领域。 主要功能&#xff1a; 数据采集&#xff1a;支持串口、以太网等多通道实时运行&#xff0c;满足各类风电与光伏逆变器、储能等 设备接入&#xff…