前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索

本文涉及的产品
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
OpenSearch LLM智能问答版免费试用套餐,存储1GB首月+计算资源100CU
推荐全链路深度定制开发平台,高级版 1个月
简介: 本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。

 本文将之前的文章,实现一个场景的实战应用,包含代码等内容。利用纯前端实现增强的列表搜索,抛弃字符串匹配,目标是使用番茄关键字可以搜索到西红柿

1 准备工作

1.1 了解llm和web开发

web端的ai开发参考 前端大模型入门:使用Transformers.js手搓纯网页版RAG(二)前端大模型入门:使用Transformers.js实现纯网页版RAG(一)

前端框架使用的vue3+antdv,最好是懂相关代码,读懂即可。

1.2 开发环境和工具

  • node20+
  • vite

1.3 工程准备

// init.sh
// 创建vite vue-ts项目
yarn create vite test-ra-list --template vue-ts
// 进入工程目录
cd test-ra-list
// 安装依赖
yarn add ant-design-vue @xenova/transformers

image.gif

1.4 本地模型目录准备

在public下面创建一个models目录,然后创建各个模型的子目录,以便后续将模型文件放入其中

image.gif

1.5 下载模型文件

在hf-mirror找到想用模型,本文用到的在Xenova/bge-base-zh-v1.5 at main (hf-mirror.com),点击各个文件的下载图标,然后存储在对应目录下

image.gif 编辑

下载模型文件,默认是quantized,除非你配置加载高精模型,也可以三个都下载,记得在1.4模型名的目录下新建一个onnx目录

image.gif 编辑

最后public目录如下图所示

image.gif

1.6  创建模拟数据

在public目录下创建一个data.json

[{"name":"PC1","id":"5F62AD98-9BAF-0B46-A506-D8EF3749D325"},{"name":"PC2","id":"58CE02BF-6F95-3F4C-9BF6-450E355BBD94"},{"name":"西红柿","id":"8FF8BC68-6BF3-0A4C-AD87-668C1CED3234"},{"name":"aaa11","id":"E6B61EFC-9730-4945-84C8-0C1FCF068AB6"},{"name":"地瓜-0","id":"3B26D363-6720-B241-AB1A-AE7C3BB1A989"},{"name":"地瓜-1","id":"A79DE23B-6A53-354A-90EA-3BAF90E43629"},{"name":"西红柿-10","id":"E3C781BF-F6ED-364E-923C-B9CA3C38BEA1"},{"name":"洋芋-100","id":"81E42720-3C18-9C4F-A302-D86C6AF51989"},{"name":"西红柿-101","id":"A98E902D-3ECB-A748-A3E6-2F4C2D36FD55"},{"name":"洋芋-102","id":"6B02AC77-55D4-7C40-98A3-383D52D72929"},{"name":"番茄-103","id":"D6E45494-BD47-5848-8492-287437155A3D"},{"name":"马铃薯-104","id":"7C4CB80B-6C0D-EC4A-A5BD-52E65D8EC2FF"},{"name":"土豆-104","id":"1C3829C0-8356-024E-AF90-9BC456A78E29"},{"name":"马铃薯-105","id":"5560C41C-46B2-BC44-9141-92E83B62D5C8"},{"name":"地瓜-106","id":"20598CEC-5E31-3F49-A578-A6F026018CC0"},{"name":"红薯-107","id":"E1061811-0886-0840-B387-A1321DA5212D"},{"name":"马铃薯-108","id":"D302EF74-0402-1F43-A4FD-FBF2CE852B5E"},{"name":"红薯-109","id":"608D7A1C-C265-9A4B-99D6-A08EBBDD08EF"},{"name":"番茄-11","id":"A19882CE-2B37-D64C-95E2-A8BC769D9A06"},{"name":"洋芋-110","id":"6D80D92B-540B-2A4D-AF2F-A15C8B04EB3F"},{"name":"番茄-111","id":"6F229077-AF25-D241-BEB4-0E53852EAF61"},{"name":"马铃薯-12","id":"A108EDCD-42D0-0B4E-9691-62FB8572ECF8"},{"name":"地瓜-13","id":"FB31B7D1-4CD3-F44C-9ED4-C659EDB58B25"}]

image.gif

2 实现方法

首先分析和分解任务:1 列表呈现数据;2 高级搜索功能

2.1 数据加载和列表数据展示

这部分使用antdv的table可以很快速的展示数据,数据加载就使用fetch即可

type RawInfo = {
  name: string;
  id: string;
};
const loading = ref(false);
const items = ref<RawInfo[]>([]);
onMounted(() => {
  fetch("data.json")
    .then((res) => res.json())
    .then((list) => (items.value = list));
});
const columns = [
  {
    title: "序号",
    dataIndex: "index",
    key: "index",
    customRender: (e: { index: number }) => {
      return h("span", {}, e.index + 1);
    },
    width: 84,
  },
  {
    title: "名称",
    dataIndex: "name",
    key: "name",
  }
] as ColumnsType<any>;

image.gif

<Table :loading="loading" :dataSource="items" :columns="columns" />

image.gif

2.2 搜索数据显示

为了动态显示搜索结果和原始结果,使用一个searchKey来切换显示的数据源。

const searchKey = ref("");
const showItems = computed(() => {
  return searchKey.value ? result.value : items.value;
});
const search = async (e: string) => {
  searchKey.value = e || "";
  if (!e) {
    return;
  }
  // 待完成搜索
};

image.gif

<InputSearch placeholder="请输入搜索内容" @search="search" />
<Table :loading="loading" :dataSource="showItems" :columns="columns" />

image.gif

2.3 模型参数准备

  • 模型加载路径即为之前创建的public下的/models目录
  • topK表示结果最多显示10个
  • 使用minScore指定最低的相似度
import { cos_sim, env, pipeline } from "@xenova/transformers";
env.remoteHost = "/models/";
const topK = 10;
const minScore = 0.6;
const pipe = pipeline("feature-extraction", "bge-base-zh-v1.5", {
  progress_callback: (d: any) => {
    console.log(d);
  },
});

image.gif

2.4 向量数组构建

深度搜索的核心就是高位空间的相似度(距离)匹配,所以需要将数据全部进行Emebdding

const buildVector = async () => {
  if (!items.value.length) return;
  const list = items.value;
  loading.value = true;
  vectors.length = list.length;
  await nextTick();
  const embedding = await pipe;
  const questions = list.map((item) => item.name);
  const output = (await embedding(questions, {
    pooling: "mean",
    normalize: true,
  })) as any;
  console.log(output);
  questions.forEach((q, i) => {
    vectors[i] = output[i];
  });
  loading.value = false;
};

image.gif

2.5 相似度计算

将关键词/字进行向量化,然后依次计算相似度,而不是使用子字符串/包含关系的匹配。

const embedding = await pipe;
  const [vector] = await embedding([e], {
    pooling: "mean",
    normalize: true,
  });
  if (!vectors.length) {
    await buildVector();
  }
  const scores = vectors.map((q, i) => {
    return {
      score: cos_sim(vector.data, vectors[i].data),
      index: i,
    };
  });

image.gif

2.6 结果筛选

最后,根据匹配度排序,过滤掉相似度过低的,再取相似度最高的topK项

scores.sort((a, b) => b.score - a.score);
  console.log(scores);
  result.value = scores
    .filter((e) => e.score > minScore)
    .slice(0, topK)
    .map((s) => items.value[s.index]);
  console.log(
    `搜索到${result.value.length}条记录:topK=${topK} minScore=${minScore}`
  );

image.gif

3 实际效果

3.1 番茄 - 可搜索到西红柿

image.gif 编辑

3.2 红薯-可搜索到地瓜

image.gif 编辑

4 待改进点

4.1 模型精度

目前使用的是最小的模型,以便于都能体验,效果会有一点差,但整体结果还算理想

4.2 最低相似度和topK控制

这两个参数对结果的影响也不小,实际上我想去掉相似度过滤,而是直接选出topK可能好一点

4.3 嵌入改进 - 非阻塞

目前在初次计算向量组(列表元素向量)是比较耗资源的,会造成页面卡顿,这部分可考虑在worker或者做成单条异步运算,而不是一次性计算出所有条目的嵌入向量



相关文章
|
2月前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
44 0
|
2月前
|
前端开发 程序员 API
前端|基于 Layui 实现动态搜索选择框
网页端实现动态搜索选择框,要求下拉选项列表能根据用户输入内容动态刷新,最终提交的值必须是由选项列表中点选的。
43 3
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
2月前
|
前端开发 算法 测试技术
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
本文对比测试了通义千文、文心一言、智谱和讯飞等多个国产大模型在处理基础计数问题上的表现,特别是通过链式推理(COT)提示的效果。结果显示,GPTo1-mini、文心一言3.5和讯飞4.0Ultra在首轮测试中表现优秀,而其他模型在COT提示后也能显著提升正确率,唯有讯飞4.0-Lite表现不佳。测试强调了COT在提升模型逻辑推理能力中的重要性,并指出免费版本中智谱GLM较为可靠。
前端大模型应用笔记(五):大模型基础能力大比拼-计数篇-通义千文 vs 文心一言 vs 智谱 vs 讯飞vsGPT
|
2月前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
2月前
|
机器学习/深度学习 弹性计算 自然语言处理
前端大模型应用笔记(二):最新llama3.2小参数版本1B的古董机测试 - 支持128K上下文,表现优异,和移动端更配
llama3.1支持128K上下文,6万字+输入,适用于多种场景。模型能力超出预期,但处理中文时需加中英翻译。测试显示,其英文支持较好,中文则需改进。llama3.2 1B参数量小,适合移动端和资源受限环境,可在阿里云2vCPU和4G ECS上运行。
|
3月前
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
|
4月前
|
存储 前端开发 JavaScript
前端语言串讲 | 青训营笔记
前端语言串讲 | 青训营笔记
43 0
|
6月前
|
JSON 前端开发 JavaScript
前端Ajax、Axios和Fetch的用法和区别笔记
前端Ajax、Axios和Fetch的用法和区别笔记
99 2
|
6月前
|
前端开发 JavaScript 数据库
如何实现前后端分离-----前端笔记
如何实现前后端分离-----前端笔记