我将使用两篇文章的篇幅,教大家如何实现一个在网页中运行的RAG系统。本文将其前一半功能:深度搜索。
通过这篇文章,你可以了解如何在网页中利用模型实现文本相似度计算、问答匹配功能,所有的推理都在浏览器端本地执行,无需依赖服务器。
RAG搜索与传统搜索的不同之处在于:它不再是关键字匹配,而且基于高维向量(768至数千维)空间的距离,所以匹配时不需要全词命中等。对一些说法不一样但意思一样的搜索有奇效,例如RAG搜索土豆可以得出马铃薯、洋芋相关的结果,因为它们的高纬空间距离很近
1 测试页面概述
以下是我创建的一个简单测试的HTML页面,核心功能包括用户输入问题,系统会基于预定义的问答库进行向量检索,并返回最相关的问题和答案:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>网页RAG</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>
2 核心功能解析
2.1 知识库
我们首先定义了一组预先设置好的问题和对应的正确答案,分别存储在questions
和ground_truth
数组中。这个系统的工作原理是:用户输入的问题将与这些已知问题进行相似度匹配,找到最相似的问题,然后返回对应的答案。
const questions = [ "洛基在征服地球的尝试中使用了什么神秘的物体?", "复仇者联盟的哪两名成员创造了奥创?", "灭霸如何实现了他在宇宙中消灭一半生命的计划?", "复仇者联盟用什么方法扭转了灭霸的行动?", "复仇者联盟的哪位成员牺牲了自己来打败灭霸?", ]; const ground_truth = [ "六角宝", "托尼·斯塔克(钢铁侠)和布鲁斯·班纳(绿巨人浩克)。", "通过使用六颗无限宝石", "通过时间旅行收集宝石。", "托尼·斯塔克(钢铁侠)", ];
2.2 初始化配置-向量库+查询管道
const verctorStore = []; const task = "feature-extraction"; const model = "Xenova/bge-base-zh-v1.5"; const infoEl = document.getElementById("info"); const pipe = pipeline(task, model, { progress_callback: (d) => { infoEl.innerHTML = JSON.stringify(d); }, });
transformers.js
我已经在上一篇文章前端大模型入门:Transformer.js 和 Xenova进行了介绍,此次使用了Xenova/bge-base-zh-v1.5
模型进行特征提取-词嵌入。
2.3 向量存储与构建
为了提高性能,我们在用户第一次查询时,将所有预定义问题的特征向量一次性生成并存储在verctorStore
中。后续查询时,直接基于这些预生成的向量进行相似度计算。
const buildVector = async () => { if (!verctorStore.length) { const embedding = await pipe; const output = await embedding(questions, { pooling: "mean", normalize: true, }); questions.forEach((q, i) => { verctorStore[i] = output[i]; }); } };
2.4 相似度计算与答案匹配
当用户输入问题时,系统将问题向量化,并与存储的预定义问题向量进行余弦相似度(cosine similarity)计算。最后,返回得分最高的问题及其对应的答案。
const search = async () => { const embedding = await pipe; 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), question: questions[i], index: i, }; }); const max = scores.reduce((a, b) => (a.score > b.score ? a : b)); infoEl.innerHTML = JSON.stringify(`最相似问题:${max.question} - 答案:${ground_truth[max.index]}`); }; document.querySelector("#search").onclick = search;
2.5 效果测试
编辑
3 网页端 RAG 应用场景
在浏览器内直接运行基于 RAG,能够大幅提高用户的交互体验,我们可以在用户的浏览器中实时执行自然语言处理任务,而不必依赖外部 API 或服务器。以下是一些适合网页端 RAG 模型应用的场景:
3.1 列表搜索和过滤
在许多现代网页应用中,用户往往需要在庞大的列表数据中找到自己感兴趣的条目。传统的搜索方式可能是基于关键词的匹配,但这对于一些复杂查询或上下文相关的搜索可能效果不佳。通过在浏览器中使用 RAG 模型,用户可以直接输入自然语言问题,系统可以检索并生成更符合语义的答案。例如:
- 电商平台商品列表搜索:用户可以用自然语言提出复杂查询,比如“价格低于100美元的蓝色连衣裙”,RAG 模型能够根据查询生成符合条件的商品列表,并准确筛选出符合条件的商品。
- 文件或文章列表的智能检索:在教育或工作环境中,用户可能需要从大量文件中找到特定信息,例如“找到包含人工智能技术应用的文章”。RAG 可以快速检索列表并为用户生成最相关的结果。
3.2 网页功能搜索和导航
对于复杂的网页或应用,用户在寻找某一特定功能时,可能很难记住具体的按钮位置或操作流程。通过使用 RAG,用户可以直接在搜索框中输入自然语言命令,模型会根据查询生成详细的功能位置或直接执行相应操作。例如:
- 设置页面的功能搜索:用户可以在设置页面内输入“如何更改密码”或“开启暗黑模式”,RAG 模型可以快速定位到相关设置选项,甚至生成具体的操作步骤或自动跳转到对应功能页面。
- 复杂 SaaS 系统的导航:在企业级 SaaS 系统中,功能模块繁多且设置复杂。用户可以通过自然语言查询,快速找到如何执行某个任务,例如“如何导出销售报告”或“查看上月的财务报表”,提高用户的操作效率。
3.3 文档或产品说明的智能查询
对于一些技术文档、产品说明书或者服务条款等长篇文字内容,用户通常需要花费较多时间来查找具体的信息。而通过在网页端集成 RAG 模型,用户可以直接提出问题,模型会从相关文档中检索出最相关的内容并生成精确的回答。例如:
- 技术文档的问答:在开发者平台或在线帮助文档中,用户可以输入自然语言问题,如“如何在项目中集成 API”,RAG 模型可以立即生成与该问题相关的文档片段,并提供详细的操作指引。
- 产品说明的快速解答:对于电子产品或软件产品的用户,可能会有具体功能或使用上的疑问。用户可以直接在产品页面输入问题,如“如何启用手写识别功能”,RAG 可以从产品说明书中检索并生成详细的使用说明。
3.4 智能表单填写助手
在许多应用场景中,用户需要填写复杂的表单,如申请表、注册表或调查问卷。通过 RAG 模型,可以为用户提供智能化的表单填写建议。用户可以输入自然语言描述,模型生成相应的表单字段内容,自动填充或提供填写建议。例如:
- 在线申请表单:用户可以输入“我住在纽约,我的邮政编码是10001”,RAG 模型可以自动填写地址相关的表单字段,减少用户的手动操作。
- 复杂调查问卷:在调查问卷中,RAG 模型可以根据用户提供的信息生成智能化建议,如“我想投资科技领域”,模型可以根据此生成相关的问卷选项或建议答案。
4 小结
通过阅读本文,相信你已经学会在浏览器端实现一个深度搜索功能,让用户不必严格按照某些格式等输入内容便能实现搜索、过滤等,尤其是文本多,大列表的场景。接下来的一章,我将会教你如何实现后部分的生成功能。
代码比较粗糙,但可以跑起来的,希望看完的你能够下载页面,自己修改一些内容参数等跑一跑哈~