前端RAG:使用Transformers.js手搓纯网页版RAG(二)- 基于qwen1.5-0.5B

本文涉及的产品
实时计算 Flink 版,5000CU*H 3个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 本文继续探讨了RAG的后半部分,通过在浏览器中运行qwen1.5-0.5B模型实现了增强搜索全流程。然而,由于浏览器与模型性能限制,该方案更适合研究、离线及高隐私场景。文章提供了完整的前端代码,让读者能够动手尝试。此外,详细介绍了代码框架、知识库准备、模型初始化及问答实现等步骤,并展示了实际运行效果。受限于当前技术,除非在离线或高隐私环境下,网页大模型的应用仍需进一步优化。

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

1 准备工作

1.1 前置知识

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>

image.gif

1.3 chrom/edge浏览器

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

2 搜索代码实现

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

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

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

image.gif

2.2 定义打印输出和参数

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

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

image.gif

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)}`;
      },
    });

image.gif

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];
        });
      }
    };

image.gif

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;

image.gif

3 生成代码实现 - G

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

3.1 定义prompt

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

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

image.gif

3.2 构建消息和输入

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

image.gif

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;

image.gif

4 运行测试

4.1 等待模型加载就绪

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

image.gif 编辑

4.2 输入提问

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

4.3 检查控制台输出的prompt

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

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

image.gif

4.4 等待回复

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

5 总结

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

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

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

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

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

相关文章
|
12天前
|
缓存 前端开发 JavaScript
前端开发的必修课:如何让你的网页在弱网环境下依然流畅运行?
【10月更文挑战第30天】随着移动互联网的普及,弱网环境下的网页性能优化变得尤为重要。本文详细介绍了如何通过了解网络状况、优化资源加载、减少HTTP请求、调整弱网参数和代码优化等方法,提升网页在弱网环境下的加载速度和流畅性,从而改善用户体验。
90 4
|
4天前
|
XML 前端开发 JavaScript
前端大神揭秘:如何让你的网页秒变炫酷,让用户欲罢不能的5大绝招!
前端开发不仅是技术活,更是艺术创作。本文揭秘五大前端开发技巧,包括合理运用CSS动画、SVG图形、现代JavaScript框架、优化网页性能及注重细节设计,助你打造炫酷网页,提升用户体验。
47 30
|
5天前
|
存储 编解码 前端开发
惊!前端新手也能秒懂的高级技巧,轻松提升网页颜值与性能!
本文针对前端新手,介绍了三个简单易学的高级技巧,帮助提升网页的颜值和性能。包括使用CSS框架快速美化网页、优化图片资源加快加载速度,以及利用ARIA属性和媒体查询提高网页的可访问性和响应性。示例代码清晰,适合初学者上手实践。
15 3
|
8天前
|
存储 前端开发 搜索推荐
(前端直接编辑CAD)网页CAD二次开发中线型表的使用方法
在DWG数据库中,线型样式存储在线型样式表 `McDbLinetypeTable` 中,每个线型表记录对象 `McDbLinetypeTableRecord` 对应一种线型样式。本文介绍了如何获取、添加、遍历、删除和修改线型样式,并提供了绘制不同线型的示例代码,包括虚线、点划线和带文字的线型。通过在线示例demo,用户可以实践修改CAD图纸中的实体线型及其样式。
|
11天前
|
搜索推荐 前端开发 开发者
前端开发的必修课:如何让你的网页在搜索引擎中脱颖而出?
【10月更文挑战第31天】前端开发不仅是构建网页与用户间桥梁的关键,还需注重搜索引擎优化(SEO)。优化网页结构、合理使用关键词、提升加载速度及整合社交媒体等技巧,能帮助网页在搜索引擎中脱颖而出,吸引更多用户。
22 5
|
11天前
|
机器学习/深度学习 前端开发 JavaScript
前端小白也能学会的高大上技巧:如何让你的网页支持语音控制?
【10月更文挑战第31天】你是否曾梦想过只需动动嘴皮子就能操控网页?现在,这个梦想触手可及。即使你是前端小白,也能轻松学会让网页支持语音控制的高大上技巧。本文将介绍语音控制的基本概念、实现方法和具体示例,带你走进语音控制的奇妙世界。通过Web Speech API,你只需掌握基本的HTML、CSS和JavaScript知识,就能实现语音识别和控制功能。快来尝试吧!
43 4
|
12天前
|
前端开发 JavaScript 搜索推荐
前端小白也能学会的高大上技巧:如何让你的网页支持暗黑模式?
【10月更文挑战第30天】随着现代网页设计的发展,暗黑模式已成为一种流行趋势,提升了用户的阅读体验并增强了网页的适应性。本文介绍了如何通过简单的HTML、CSS和JavaScript实现网页的暗黑模式。首先,定义两种主题的CSS样式;然后,使用JavaScript实现模式切换逻辑,并自动检测系统主题。通过这些步骤,前端小白也能轻松掌握暗黑模式的实现,提升网页的用户体验和个性化水平。
31 4
|
10天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
11天前
|
前端开发 JavaScript 数据处理
前端界的宝藏技术:掌握这些,让你的网页秒变交互神器!
【10月更文挑战第31天】前端开发藏有众多宝藏技术,如JavaScript异步编程和Web Components。异步编程通过Promise、async/await实现复杂的网络请求,提高代码可读性;Web Components则允许创建可重用、封装良好的自定义组件,提升代码复用性和独立性。此外,CSS动画、SVG绘图等技术也极大丰富了网页的视觉和交互体验。不断学习和实践,让网页秒变交互神器。
19 2
|
11天前
|
JavaScript
js实现简洁实用的网页计算器功能源码
这是一款使用js实现简洁实用的网页计算器功能源码。可实现比较基本的加减乘除四则运算功能,界面简洁实用,是一款比较基本的js运算功能源码。该源码可兼容目前最新的各类主流浏览器。
20 2