[LangChain] 14. 嵌入处理

news/2025/11/7 15:00:31/文章来源:https://www.cnblogs.com/Answer1215/p/19199685

回忆 RAG 关键步骤:

  1. 文本切割
  2. 嵌入处理
  3. 存储向量数据库

嵌入处理,又称之为向量化操作。核心就是将文本转为向量的形式,从而为下一步做数学运算做准备。

"今天的天气真好,万里无云"
[0.3297254741191864,   0.7386181354522705,    -3.342341899871826,-0.7811917066574097, -0.08536303788423538,   0.05086381733417511,... 668 more items  
]

该操作一般需要依赖专门做嵌入处理的模型。例如:

import { OpenAIEmbeddings } from "@langchain/openai";const embeddings = new OpenAIEmbeddings({apiKey: process.env.OPENAI_API_KEY,model: "text-embedding-3-large", // OpenAI 官方提供的专门用于做嵌入的模型
});const vectors = await embeddings.embedDocuments(documents.map((doc) => doc.pageContent)
);

在上面的代码中,使用的是 OpenAI 官方提供的专用嵌入模型。而 OpenAIEmbeddings 则是 Embeddings 的子类,关于 Embeddings 这个工具类,后面再来介绍。

快速上手

课堂练习:使用 nomic-embed-text 模型做嵌入操作

import { TextLoader } from "langchain/document_loaders/fs/text";
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";const loader = new TextLoader("data/kong.txt");const docs = await loader.load();const splitter = new RecursiveCharacterTextSplitter({chunkSize: 64,chunkOverlap: 0,
});const splittedDocs = await splitter.splitDocuments(docs);// console.log(splittedDocs)async function getEmbedding(text) {const res = await fetch("http://localhost:11434/api/embeddings", {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({model: "nomic-embed-text",prompt: text,}),});const result = await res.json();return result.embedding;
}const results = [];
for (const doc of splittedDocs) {const embedding = await getEmbedding(doc.pageContent);results.push({ ...doc, embedding });
}console.log(results);

不过目前这个例子,在进行嵌入操作时花费的时间是比较久的,这里我们可以做一个计时来测量一下花费的时间。

究其原因,是因为现在在做嵌入操作时,采用的是串行的形式。

所以,接下来一个工作重点,支持并发的嵌入操作。

自定义嵌入类

要实现并发的嵌入操作,我们可以自己来自定义一个嵌入类

不过在此之前,需要先了解 Embeddings 工具类。

Embeddings 是 LangChain 中抽象出来的嵌入操作基类,不同厂商的向量模型,都通过继承该基类实现暴露统一方法,从而能在向量库、检索器等组件里互换使用。

基类提供两组最核心的方法:

  • embedDocuments(texts: string[]) => Promise<number[][]>:批量嵌入用于索引的文本(返回二维向量数组)。
  • embedQuery(text: string) => Promise<number[]>:为查询文本生成向量(返回一维向量)。

文档地址:https://js.langchain.com/docs/concepts/embedding_models/?utm_source=chatgpt.com

使用并发工具方法:runWithConcurrency

export async function runWithConcurrency(items, worker, maxConcurrency) {if (!items?.length) return;let i = 0;const workers = [];async function spawn() {while (i < items.length) {const idx = i++;await worker(items[idx], idx);}}const n = Math.max(1, Math.min(maxConcurrency, items.length));for (let k = 0; k < n; k++) workers.push(spawn());await Promise.allSettled(workers);
}

课堂练习:自定义嵌入类

import { Embeddings } from "@langchain/core/embeddings";
import { runWithConcurrency } from "./concurrency.js";export class NomicEmbeddings extends Embeddings {constructor(concurrency = 3) {super();this.model = "nomic-embed-text";this.apiUrl = "http://localhost:11434/api/embeddings";this.concurrency = concurrency;}/*** 对单个文本做嵌入操作,这是一个内部方法* @param {*} text 单个文本*/async #fetchEmbedding(text) {const res = await fetch(this.apiUrl, {method: "POST",headers: { "Content-Type": "application/json" },body: JSON.stringify({model: this.model,prompt: text,}),});const result = await res.json();return result.embedding;}/*** 对单个文本做嵌入操作* @param {*} text*/async embedQuery(text) {return await this.#fetchEmbedding(text);}/*** 对一组文本做嵌入操作* @param {*} documents*/async embedDocuments(documents) {const results = Array.from({ length: documents.length }); // 存放结果的数组// 添加一个并发的探针let active = 0; // 并发数let maxActive = 0; // 最大并发数const t0 = performance.now();await runWithConcurrency(documents,async (text, idx) => {// 开始了一个任务,需要对并发数做一个计数active++;maxActive = Math.max(maxActive, active);console.log(`[start] #${idx} +${(performance.now() - t0).toFixed(0)}ms  active=${active}`);try {results[idx] = await this.#fetchEmbedding(text);} catch (err) {results[idx] = err;} finally {// 任务结束active--;console.log(`[end  ] #${idx} +${(performance.now() - t0).toFixed(0)}ms  active=${active}`);}},this.concurrency);return results;}
}

第三方并发库

关于并发的控制,还可以使用一个第三方库:p-limit

该库是一个极小的工具,用来限制并发执行的 Promise 个数,可以用于 Node.js 和浏览器环境。

基本用法:

import pLimit from "p-limit";const limit = pLimit(3); // 同时最多跑 3 个const tasks = urls.map(url =>limit(() => fetchJson(url));
);
const results = await Promise.all(tasks);

下面是一个快速上手示例,添加并发探针,检测并发的数量:

import pLimit from "p-limit";const urls = ["https://jsonplaceholder.typicode.com/todos/1","https://jsonplaceholder.typicode.com/todos/2","https://jsonplaceholder.typicode.com/todos/3","https://jsonplaceholder.typicode.com/todos/4","https://jsonplaceholder.typicode.com/todos/5","https://jsonplaceholder.typicode.com/todos/6",
];// 基础请求函数:拿到 JSON,不是 2xx 则抛错
async function fetchJson(url) {const res = await fetch(url, { headers: { accept: "application/json" } });if (!res.ok) throw new Error(`HTTP ${res.status} for ${url}`);return res.json();
}async function main() {// 同时最多跑 3 个请求const limit = pLimit(3);// 并发探针let active = 0;let maxActive = 0;const t0 = performance.now();const tasks = urls.map((url, idx) =>limit(async () => {// 任务开始,并发探针检测并发数量active++;if (active > limit.concurrency) {console.warn(`并发超限: active=${active} > limit=${limit.concurrency}`);}maxActive = Math.max(maxActive, active);console.log(`[start] #${idx} +${(performance.now() - t0).toFixed(3)}ms  active=${active}`);try {return await fetchJson(url);} finally {// 任务结束active--;console.log(`[end  ] #${idx} +${(performance.now() - t0).toFixed(3)}ms  active=${active}`);}}));try {const results = await Promise.all(tasks);console.log("结果:", results);} catch (err) {console.error("至少有一个请求失败:", err);} finally {console.log(`并发观测:maxActive=${maxActive}, limit=${limit.concurrency}, ` +`activeCount=${limit.activeCount}, pendingCount=${limit.pendingCount}`);}
}main().catch((e) => console.error(e));

课堂练习:使用 p-limit 重构前面自定义的嵌入类。


-EOF-

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/958854.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年深圳ai优化公司权威推荐榜单:ai搜索优化/ai优化效果/geo优化推广源头公司精选

在当前人工智能技术重塑营销格局的背景下,深圳作为中国AI产业的重要创新中心,其AI优化服务市场呈现高速发展态势。据行业数据显示,2025年全球企业AI营销预算年增长率达45%,而AI搜索已占据43.7%的流量入口。深圳凭借…

损失函数之平均绝对误差MAE

平均绝对误差(Mean Absolute Error,简称 MAE)是回归模型中最常用的评估指标和损失函数之一。它衡量模型预测值与实际观测值之间的平均绝对差异,反映了预测误差的平均大小。 1. 定义与公式2.主要特点直观易懂:MAE …

2025年门窗铝合金型材实力厂家权威推荐榜单:工业铝型材/冰箱铝型材/交通轨道铝型材源头厂家精选

在建筑建材与工业制造持续升级的背景下,门窗铝合金型材作为关键基础材料,其质量性能与定制能力直接影响产品竞争力。行业数据显示,2024年中国铝型材市场规模已突破7500亿元,其中门窗铝型材在建筑领域需求占比达45%…

从零开始-使用three.Js实现沪深300股票热力图

热力图能够直观看到大盘涨跌情况及股票和板块间相关性。平面热力图使用颜色来区分,使用echart报表组件容易实现。但使用3d形式比2D更直观,更有交互性可操作性。 HS300Sandbox: 使用Three.Js ,展示沪深300涨跌大盘云…

P4401 [IOI 2007] Miners 矿工配餐 题解

P4401 [IOI 2007] Miners 矿工配餐 题解大爬好啊!我最喜欢大爬了!P4401 [IOI 2007] Miners 矿工配餐 题解 题目传送门 我的博客 前言大爬好啊!我最喜欢大爬了!思路 这道题,当看到“以使得两个煤矿的产煤量的总和最…

第一周--2:Ubuntu24.04虚拟机环境准备与安装

1、开始准备Ubuntu24.04其余默认下一步其余默认下一步其余默认下一步至此Ubuntu24安装完成

代码重构 - 泛型继承与安全检查 - 泛型递归约束 - Curiously Recurring Template Pattern (CRTP)

Unity事件委托时,要设计事件类(类似Qt的信号类),实现基本一样就类型类名不一样,需要抽象[!tip] 重构技巧 两个类的实现代码完全一样, 就只有类名或类型不一样的时候, 而且还需要不断扩展 (未来会增加各种事件) 的…

2025.11.7——2蓝

提高/省选- P7322 「PMOI-4」排列变换 推不出数学式子,所以直接打表找规律 P3065 [USACO12DEC] First! G 字典树+拓扑排序,还挺简单的?

中小企业数字化转型中的常见陷阱及规避策略

中小企业数字化转型中的常见陷阱及规避策略$(".postTitle2").removeClass("postTitle2").addClass("singleposttitle");中小企业数字化转型不用贪大求全,找对方法选对工具,就能少走弯…

SMC串行传输系统通过Profinet转EtherCAT网关进行连接的配置案例

SMC串行传输系统通过Profinet转EtherCAT网关进行连接的配置案例 本案例是通过使用稳联技术研发的EtherCAT转Profinet网关将串行传输系统模块接入到西门子PLC的Profinet网络之中,具体配置如下配置过程: 网关配置: 打…

PHP检查和修复隐式可空类型的问题

PHP检查和修复隐式可空类型的问题PHP 隐式可空类型修复脚本 📋 功能说明 这个脚本用于解决 PHP 8.4 中废弃隐式可空类型的问题。根据 RFC: Deprecate implicitly nullable types,当函数参数有类型声明且默认值为 nu…

实用指南:零基础学AI大模型之解析器PydanticOutputParser

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

鸿蒙应用开发实战:从零构建往来记人情管理应用之回礼模块实现

引言:人情往来的智慧 在中国传统文化中,人情往来是一门深厚的学问。如何得体地回礼,既体现尊重又不失分寸,是每个人都面临的课题。今天,我们将通过鸿蒙应用开发,构建一个智能的人情管理应用"往来记",…

安装btop

https://github.com/aristocratos/btop/releases上下载btop-x86_64-linux-musl.tbz

AI应用开发新范式!基于 RDS Supabase 服务高效构建轻量级应用,赢取淘公仔、加湿器等好礼!

传统应用后端开发常面临搭建复杂、周期长等问题,本方案将基于阿里云 RDS Supabase 服务高效构建轻量级应用,通过深度融合 RDS PostgreSQL 的企业级能力,集成向量数据库、智能 API 调用与多层安全隔离机制,为企业和…

为什么不能使用均方差做为分类问题的损失函数?

1. MSE 是非凸函数,难以优化 对于分类问题(尤其是多分类问题),当使用 Sigmoid 或 Softmax 作为激活函数时,如果同时使用均方误差(MSE)作为损失函数,会导致整体的损失函数曲面是非凸的(Non-convex)。问题:非…

odoo18-半成品入线边库、成品入成品库-教程

1、配置自动化规则 路径:设置-》自动化规则 2、配置执行代码if record.product_id.categ_id.id == 5: # 替换为“半成品”类别的 IDrecord.write({picking_type_id: 13}) else:record.write({picking_type_id: 11})…

RK3588 上的 LLM(三):板端部署 RKLLM 并进行大模型推理(以 RK3588 为例)

本教程记录了如何在 RK3588 开发版上部署 RKLLM 并使用其进行大模型推理的过程,包含基于命令行的运行和服务端部署(本文以 Gradio 前后端为例) 注:运行 RKLLM 需要 RKNPU 驱动版本至少为 0.9.8,升级方法可以参考合…