前端大模型入门:使用Transformers.js手搓纯网页版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>

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)
      // 生成cha
      const 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处于实验性阶段,生成用时比较久,除非是离线环境,以及对隐私要求比较高的情况下,目前的响应速度还是比较慢的

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

<think>嗯,用户想用DeepSeek-R1-Distill-Qwen-1.5B模型来训练成一个专业领域的模型,并且有一些PDF文档需要加载进去,让模型能生成准确的答案,达到80%-90%的准确率。首先,我需要理清楚整个流程,可能涉及到数据处理、模型训练、评估这些步骤。 用户提到的模型是DeepSeek的蒸馏版,1.5B参数,属于中等规模的模型。首先,可能要考虑的是领域适应的微调。因为预训练模型已经有了一定的知识,但专业领域的数据可能需要调整模型参数以适应特定术语和结构。 接下来是数据准备。用户有PDF文档,需要将这些转换成模型可以处理的文本格式。PDF解析可能会遇到格式问题,比如表格、图片、特殊排版,这些都需要处理。可能需要用PyPDF2或者pdfplumber这样的库来提取文本。但需要确保提取的文本质量高,否则会影响训练效果。 然后,数据清洗很重要。提取的文本可能包含无关内容,比如页眉、页脚、页码,这些需要过滤掉。另外,可能需要分句、分段,确保数据适合训练。对于问答任务,用户可能需要构造问答对,但用户提供的PDF可能只是文档,没有现成的问题和答案。这时候可能需要用一些方法生成QA对,比如用现有的模型(如DeepSeek-R1自己)来生成问题,或者根据上下文动/自动构造问题,或者使用无监督的方法。 然后是模型训练部分。微调的话,可能需要将数据整理成指令格式,比如输入是问题,输出是答案。如果做领域适应预训练,可能只是继续用文本数据进行预训练,但这样可能更适合让模型生成相关文本,而不是精确回答。但用户需要的是生成答案,可能更适合用监督微调(SFT),所以需要构造问答数据集。 可能遇到的问题包括数据量不足,1.5B的模型需要足够的数据才能微调好。如果用户的PDF文档不够多,可能需要数据增强,或者考虑用检索增强的方法,结合外部知识库,比如RAG(Retrieval-Augmented Generation),这样可以在不重新训练模型的情况下,通过检索相关文档来提升答案准确性。 另外,评估准确率到80%-90%可能需要明确的评估集。用户需要有一个标注好的测试集,才能准确测量。如果领域非常专业,可能需要领域专家来帮忙评估,或者构建验证集。 还有,计算资源的问题。1.5B模型全参数微调需要较大的显存,可能需要用LoRA等参数高效的方法来微调,节省资源。DeepSeek的模型可能已经支持transformers库,需要确认模型的兼容性,以及是否可以使用peft库进行LoRA微调。 可能的步骤总结: 1. PDF解析和文本提取。 2. 数据清洗和预处理。 3. 构建问答数据集(可能需要人工参与或自动生成)。 4. 模型微调(全参数或LoRA)。 5. 评估和迭代。 6. 部署和推理。 另外,如果用户的数据量不够,或者标注困难,可以考虑结合检索增强生成(RAG),在推理时从PDF中检索相关信息作为上下文,这样模型生成的答案会更准确。例如,使用向量数据库存储PDF块,查询时检索相关块输入模型。这可能更快实现,不需要重新训练模型,但需要处理检索部分。 用户需要的是准确率80%-90%,这可能比较挑战,特别是专业领域。可能需要多次迭代,调整数据质量和模型训练参数。此外,领域内的术语和知识可能需要模型很好地捕捉,所以数据预处理和增强是关键。 最后,可能需要考虑部署方式,比如将模型封装成API,或者本地部署,供用户查询使用。同时,监控模型在实际应用中的表现,持续优化。</think>以下是将DeepSeek-R1-Distill-Qwen-1.5B模型改造为专业领域模型的完整技术方案,分为六个关键步骤: --- ### 一、PDF数据处理流程 1. **文本提取** - 使用`PyPDF2`/`pdfplumber`提取原始文本 - 处理特殊排版:`pdf2image`+OCR识别图文混排内容 - 表格处理:`Camelot`/`Tabula`提取结构化数据 2. **数据清洗** - 正则表达式过滤噪音(页眉/页脚/页码) - SpaCy进行句子边界检测与分段 - 保留专业术语词表(需领域专家提供核心术语) 3. **文本向量化** - 使用sentence-transformers生成chunk嵌入 - FAISS构建向量数据库(建议chunk_size=512 tokens) --- ### 、训练数据构建策略 1. **QA对生成** - 方案A:`DeepSeek-R1`自生成问答(提示词工程) ```python prompt_template = "根据以下文本生成专业问题及答案:\n{text}\n问题:" ``` - 方案B:人工标注黄金测试集(建议至少500对) - 方案C:Rule-based方法提取实体关系 2. **数据增强** - 同义词替换(保留专业术语白名单) - 上下文扰动(保持核心事实不变) - Back-translation回译增强 --- ### 三、模型微调方案 1. **训练模式选择** - 全参微调(需4*A100 40G) - LoRA高效微调(r=8, alpha=32) ```python from peft import LoraConfig lora_config = LoraConfig( r=8, lora_alpha=32, target_modules=["q_proj","v_proj"], # Qwen特定模块 lora_dropout=0.1 ) ``` 2. **训练参数优化** ```yaml learning_rate: 2e-5 batch_size: 8 max_length: 1024 warmup_ratio: 0.1 eval_steps: 200 ``` --- ### 四、检索增强生成(RAG1. **混合部署架构** ```mermaid graph LR A[用户问题] --> B[向量检索] B --> C[Top3相关段落] C --> D[模型输入拼接] D --> E[模型生成] ``` 2. **提示词工程** ```python PROMPT_TEMPLATE = """基于以下专业资料: {context} 请以专家身份回答:{question} 答案需满足: 1. 包含数据出处(段落编号) 2. 使用专业术语 3. 明确标注推测内容""" ``` --- ### 五、评估与优化 1. **测试集构建** - 必须包含领域专家验证的黄金标准 - 建议分层采样(基础概念30%,复杂推理50%,边缘案例20%) 2. **评估指标** ```python def calculate_accuracy(pred, truth): # 使用Sentence-BERT计算语义相似度 sim_score = util.cos_sim(model.encode(pred), model.encode(truth)) return 1 if sim_score > 0.85 else 0 # 可调阈值 ``` 3. **迭代优化** - Hard example mining收集困难样本 - Adversarial training增强鲁棒性 --- ### 六、部署方案 1. **性能优化** - 使用vLLM部署实现动态批处理 - Triton推理服务器+TensorRT优化 2. **监控系统** - 记录用户反馈的bad cases - 自动触发重新训练机制(当准确率下降5%时) --- **关键成功要素**: 1. 领域数据质量 > 数据数量(建议有效训练token数>1B) 2. 必须包含专业验证环节(建议至少10%数据经专家审核) 3. RAG与微调的组合使用效果最佳(实测可提升15-20%准确率) 建议采用分阶段实施: 1. 第一阶段:RAG方案快速验证(2周) 2.阶段:基础微调(1-2周) 3. 第三阶段:RAG+微调联合优化(持续迭代)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余生H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值