前端大模型入门:使用Transformers.js手搓纯网页版RAG(二)- qwen1.5-0.5B - 纯前端不调接口

server/2024/12/23 1:53:22/

书接上文,本文完了RAG的后半部分,在浏览器运行qwen1.5-0.5B实现了增强搜索全流程。但受限于浏览器和模型性能,仅适合于研究、离线和高隐私场景,但对前端小伙伴来说大模型也不是那么遥不可及了,附带全部代码,动手试试吧! 纯前端,不适用第三方接口

1 准备工作

1.1 前置知识

  • 读完前端大模型入门:使用Transformers.js实现纯网页版RAG(一)
  • 了解WebML 前端大模型入门:Transformer.js 和 Xenova
  • 基本的前端开发知识,esm和async/await

1.2页面代码框架

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><title>网页端侧增强搜索</title>
</head><body><div id="app"><div><input type="text" id="question" /><button id="search">提问</button></div><div id="info"></div></div><script type="module">import {pipeline,env,cos_sim,} from "https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2/dist/transformers.min.js";env.remoteHost = "https://hf-mirror.com";// 后续代码位置</script>
</body></html>

1.3 chrom/edge浏览器

目前测试firefox模型缓存有问题,建议用这两个,首次加载模型需要点时间,后续就不需要了,记住刷新时按F5不要清空缓存了。 

2 搜索代码实现 - R

2.1 准备好知识库和初始化向量库

前一篇文章已经介绍了相关内容,本文知识库有些不一样,因为是需要给大模型去生成回答,而不是直接给出答案,所以合并在了一起。

    const knowledges = ["问:洛基在征服地球的尝试中使用了什么神秘的物体?\n答:六角宝","问:复仇者联盟的哪两名成员创造了奥创?\n答:托尼·斯塔克(钢铁侠)和布鲁斯·班纳(绿巨人浩克)。","问:灭霸如何实现了他在宇宙中消灭一半生命的计划?\n答:通过使用六颗无限宝石","问:复仇者联盟用什么方法扭转了灭霸的行动?\n通过时间旅行收集宝石。","问:复仇者联盟的哪位成员牺牲了自己来打败灭霸?\n答:托尼·斯塔克(钢铁侠)",];const verctorStore = [];

2.2 定义打印输出和参数

topK控制送给大模型处理的最匹配的知识数量上下,越多的知识条数prompt越大会导致处理用时越长,一般三个最匹配的知识就差不多够用了,尤其是在网页中运行时

    const infoEl = document.getElementById("info");const print = text => infoEl.innerHTML = text;const knowEl = document.getElementById("knowEl");const topK = 3;

2.3 准备好嵌入和生成模型

嵌入使用 bge-base ,回答生成使用qwen1.5-0.5B

    const embedPipe = pipeline("feature-extraction", "Xenova/bge-base-zh-v1.5", {progress_callback: (d) => {infoEl.innerHTML = `embed:${JSON.stringify(d)}`;},});const chatPipe = pipeline('text-generation', 'Xenova/Qwen1.5-0.5B-Chat', {progress_callback: (d) => {infoEl.innerHTML = `chat:${JSON.stringify(d)}`;},});

2.4 定义向量库数据初始方法

这个不多赘述,和前一篇的类似

const buildVector = async () => {if (!verctorStore.size) {const embedding = await embedPipe;print(`构建向量库`)const output = await embedding(knowledges, {pooling: "mean",normalize: true,});knowledges.forEach((q, i) => {verctorStore[i] = output[i];});}};

2.5 定义问答主方法

 这里也不赘述过多,和上一篇不同之处在于:根据score从大到小排序,选出topK传入生成方法

  const search = async () => {const start = Date.now()const embedding = await embedPipe;const question = document.getElementById("question").value;const [qVector] = await embedding([question], {pooling: "mean",normalize: true,});await buildVector();const scores = verctorStore.map((q, i) => {return {score: cos_sim(qVector.data, verctorStore[i].data),knowledge: knowledges[i],index: i,};});scores.sort((a, b) => b.score - a.score);const picks = scores.slice(0, topK)const docs = picks.map(e => e.knowledge)const answer = await generateAnswer(question, docs.join('\n'))print(answer + `(用时:${Date.now()- start}ms)`)};document.querySelector("#search").onclick = search;

3 生成代码实现 - G

这一部分主要介绍generateAnser的实现

3.1 定义prompt

 这部分自己测试时可多调整下,prompt定义的越好效果越好

const prompt =`请根据【上下文】回答【问题】,当得不到较为准确的答案时,必须回答我不知道。【上下文】${context}【问题】${question}请给出你的答案:`

3.2 构建消息和输入

const messages = [{ role: 'system', content: '你是一个分析助手,根据上下文回答问题。必须生成更人性化的答案。' },{ role: 'user', content: prompt }]console.log(messages)// 生成chaconst text = generator.tokenizer.apply_chat_template(messages, {tokenize: false,add_generation_prompt: true,});console.log(text)

3.3 等待回答返回首个答案

      print(`思考中...`)const output = await generator(text, {max_new_tokens: 128,do_sample: false,return_full_text: false,});console.log(output)return output[0].generated_text;

4 运行测试

4.1 等待模型加载就绪

嵌入和千问整体有接近1G的数据下载,需要稍微等待下,直到看到下图所示结果 

4.2 输入提问

我的问题是“他是怎么实现计划的”,点击提问

4.3 检查控制台输出的prompt

可以看到匹配到的三个答案和问题

<|im_start|>system
你是一个分析助手,根据上下文回答问题。必须生成更人性化的答案。<|im_end|>
<|im_start|>user
请根据【上下文】回答【问题】,当得不到较为准确的答案时,必须回答我不知道。【上下文】问:灭霸如何实现了他在宇宙中消灭一半生命的计划?
答:通过使用六颗无限宝石
问:复仇者联盟用什么方法扭转了灭霸的行动?
通过时间旅行收集宝石。
问:洛基在征服地球的尝试中使用了什么神秘的物体?
答:六角宝【问题】他是怎么实现计划的请给出你的答案:<|im_end|>
<|im_start|>assistant

 4.4 等待回复

耗时25s,有点长,但考虑到这是可以离线在端侧运行的非gpu版本,用于做一些后台任务还是可以的,结果如下

5 总结

5.1 qwen1.5-0.5B比预期效果好

 结果比续期要好一些,因为比较新的web版本大模型就找到qwen1.5-0.5B的,后续有时间我会出一期试试llama3.2-1B,但整个过程会比较长 - 因为还涉及到模型迁移

5.2 除非离线和高隐私环境网页大模型暂不适用

受限于网页性能和WebGPU的支持在transformer.js处于实验性阶段,生成用时比较久,除非是离线环境,以及对隐私要求比较高的情况下,目前的响应速度还是比较慢的

最近眼睛肿了,今天就一篇吧,剩下时间休息了,明天又得上班 ~ 啊啊啊


http://www.ppmy.cn/server/126526.html

相关文章

Elasticsearch学习笔记(2)

索引库操作 在Elasticsearch中&#xff0c;Mapping是定义文档字段及其属性的重要机制。 Mapping映射属性 type&#xff1a;字段数据类型 1、字符串&#xff1a; text&#xff1a;可分词的文本&#xff0c;适用于需要全文检索的情况。keyword&#xff1a;用于存储精确值&am…

数据特征工程:如何计算块熵?| 基于SQL实现

目录 0 信息量定义 1 块熵定义 2 问题描述 ​3 数据准备 4 问题分析 5 小结 0 信息量定义 信息量是指从N 个相等可能事件中选出一个事件所需要的信息度量或含量,也就是在辩识N 个事件中特定的一个事件的过程中所需要提问是或否的最少次数。 在一个系统中,等可能事件的数…

Vue3项目开发——新闻发布管理系统(九)(完结篇)

文章目录 十一、用户信息管理1、用户基本资料管理1.1 页面设计1.2 封装接口,更新信息2、更换头像2.1 静态结构2.2 选择图片预览2.3 上传头像3、重置密码3.1 页面设计3.2 封装接口,更新密码十二、项目打包十三、系统全部源码下载十一、用户信息管理 用户信息管理包括功能:基…

UML中类和类之间关系和各种图

文章目录 1.UML概述2.UML建模工具3.常见UML图_类图4.类图之类和类之间的关系5.用例图1.用例图是什么2.用例图所包含的元素3.用例图所包含的关系 6.状态图1.状态图是什么&#xff1f;2.状态图所包含的元素 7.活动图1.活动图的元素 8.时序图1.时序图是什么&#xff1f;2.时序图的…

【Git原理与使用】Git初识基本操作

Git初识&&基本操作 1.初识Git2.Git安装3.Git基本操作3.1创建Git本地仓库3.2配置Git3.3认识工作区、暂存区、版本库3.4添加文件3.5修改文件3.6版本回退3.7撤销修改3.8删除文件 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f…

基于微信的乐室预约小程序+ssm(lw+演示+源码+运行)

摘 要 随着社会的发展&#xff0c;社会的方方面面都在利用信息化时代的优势。互联网的优势和普及使得各种系统的开发成为必需。 本文以实际运用为开发背景&#xff0c;运用软件工程原理和开发方法&#xff0c;它主要是采用java语言技术和mysql数据库来完成对系统的设计。整个…

Springboot + netty + rabbitmq + myBatis

目录 0.为什么用消息队列1.代码文件创建结构2.pom.xml文件3.三个配置文件开发和生产环境4.Rabbitmq 基础配置类 TtlQueueConfig5.建立netty服务器 rabbitmq消息生产者6.建立常规队列的消费者 Consumer7.建立死信队列的消费者 DeadLetterConsumer8.建立mapper.xml文件9.建立map…

MongoDB 快速入门+单机部署(附带脚本)

目录 介绍 体系结构 数据模型 BSON BSON 数据类型 特点 高性能 高可用 高扩展 丰富的查询支持 其他特点 部署 单机部署 普通安装 脚本安装 Docker Compose 安装 卸载 停止 MongoDB 删除包 删除数据目录 参考&#xff1a; https://docs.mongoing.com/ 介绍…