首页 > 其他分享 >Langchain.js如何实现RAG

Langchain.js如何实现RAG

时间:2024-09-12 17:04:21浏览次数:12  
标签:检索 RAG const 模型 Langchain js 文档 文本 向量

前面介绍了Langchain的基本使用方法。仅仅是对GPT方法的封装还不足以让它赢得那么多的Start,以及获得融资。它还有另一个强大的功能-RAG(检索增强生成)。RAG是大模型跟企业内部业务落地的基石。是大模型的北斗导航,可以让大模型的结果更加精准。

一、RAG 的基本概念与实现流程

基于大语言模型(LLM)的应用已经随处可见,工作生活都去大模型问一问,对于很多人已经成为一种习惯,细心的你或许会发现LLM 存在的一个显著问题:它们的回答往往过于依赖训练数据,无法访问实时信息,导致出现“幻想问题”(即生成不符合实际情况的回答)。为了解决这个问题,业界提出了 RAG(Retrieval-Augmented Generation,检索增强生成)这一方案。

RAG 的核心思想是:在生成回答前,通过查询外部数据库或文档库检索相关信息,然后将这些检索到的内容嵌入到 LLM 的上下文中,从而提高生成的准确性和质量。通过这种方式,LLM 不仅可以从内部训练数据中进行生成,还能够结合实时数据做出更加符合实际的回答。

Langchain.js 也支持数据切割、向量化、存储到检索、生成的完整流程,可以很好地实现 RAG。

要实现 RAG,我们需要经历以下几个关键步骤:

  1. 切割(Chunking):由于大模型的上下文长度有限,长文档需要被合理切割成小块,方便向量化和检索。通常在 200 到 500 个字符之间是一个常见的选择。这种大小的片段既能保持较好的上下文完整性,又不会太大以至于超出模型的输入限制。

  2. 向量化(Embedding):将切割后的文档转化为向量表示,这样我们可以在向量空间中快速查找相关文档。也就是将文本表示为模型可以理解和处理的形式。不同模型对同一数据进行向量化后的结果通常是不同的。

  3. 存储(Storage):将文档和对应的向量存储到向量数据库中,便于后续的检索。

  4. 检索(Retrieval):根据用户的查询,将查询向量化后从数据库中检索出相关的文档。

  5. 增强与生成(Augmentation & Generation):将检索到的文档插入 LLM 的 prompt 中,从而生成高质量的回答。

RAG 的整个流程从输入用户的查询开始,经过嵌入模型向量化、数据库检索和增强,最后通过大模型生成符合实际需求的答案。

三、RAG具体实现

1. 文本切割

大模型的上下文长度是有限的,因此我们需要将长文档分成合理的小块,保证每个小块能够独立表达一定的语义。常见的切割策略包括按照句子、段落或固定字符数进行分割。Langchain.js 提供了多种文本切割策略,主要使用 TextSplitter 类来实现。

import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';

// 创建一个 RecursiveCharacterTextSplitter 实例
const splitter = new RecursiveCharacterTextSplitter({
  chunkSize: 500, // 每个文本块的最大字符数
  chunkOverlap: 50, // 各文本块之间的重叠字符数,防止信息丢失
});

// 需要进行切割的文本
const text = `
  Langchain.js 是一个用于构建语言模型应用的工具库。它可以处理多种类型的任务,包括语义搜索、问答、对话生成等。
  文本切割是 Langchain.js 中的重要功能之一,能够将大块文本分割成易于处理的小段。
`;

// 调用 createDocuments 方法进行文本分割
const documents = await splitter.createDocuments([text]);

console.log(documents);

chunkSize 是每个文本块的最大长度,chunkOverlap 用于控制文本块之间的重叠字符。输出的 documents 会是一个包含文本块的数组,每个文本块都不会超过 chunkSize 的限制,并且会在必要时增加重叠部分以保持上下文完整。

除此之外还支持 CharacterTextSplitter 按字符直接切割,MarkdownTextSplitter 进行基于 Markdown 语法的文本切割。通过 Langchain.js 的 TextSplitter 类,你可以灵活地选择不同的文本切割策略,根据具体的文本格式和处理需求,确保切割后的文本块适合进一步处理。

2. 文档向量化

切割后的文本块需要通过嵌入模型进行向量化。Langchain.js 提供了多种方法来实现文档的向量化,主要是通过将文本嵌入(embedding)到向量空间中,以便用于语义搜索、问答系统等自然语言处理任务。

向量化后的文本可以通过距离度量(如余弦相似度)与其他向量进行对比,从而找到最相关的文档。

文档向量化通常包括以下步骤:

  1. 文本预处理:对文本进行基本的清洗、切割等操作。
  2. 文本嵌入:使用预训练的语言模型(如 OpenAI、Hugging Face 等)将文本转换为向量。
  3. 向量存储与检索:将生成的向量存储起来,以便在语义搜索或问答任务中进行高效检索。

在 Langchain.js 中可以直接集成 OpenAI 的嵌入模型来进行向量化处理。以下是一个使用 OpenAI 模型进行文档向量化的示例:

import { OpenAIEmbeddings } from 'langchain/embeddings/openai';
import { RecursiveCharacterTextSplitter } from 'langchain/text_splitter';

// 1. 创建文本切割器,确保长文本能够被处理
const textSplitter = new RecursiveCharacterTextSplitter({
  chunkSize: 500,
  chunkOverlap: 50,
});

// 2. 定义要向量化的文本
const text = `
  Langchain.js 是一个用于构建语言模型应用的工具库,支持多种文本处理功能。
  该库提供了文本切割、嵌入生成、文档存储等能力,方便开发者构建复杂的自然语言处理应用。
`;

// 3. 切割文本,生成文档块
const documents = await textSplitter.createDocuments([text]);

// 4. 使用 OpenAI 的 Embeddings API 对文档进行向量化
const embeddings = new OpenAIEmbeddings({
  openAIApiKey: 'your-openai-api-key', // 使用你的 API 密钥
});

const vectors = await embeddings.embedDocuments(documents.map(doc => doc.pageContent));

// 输出生成的向量
console.log(vectors);

Langchain.js 也支持集成 Hugging Face 模型,这允许你使用 Hugging Face 提供的各种预训练模型来处理文档向量化。此外也可以保存到向量数据库(如 Pinecone、Weaviate、Faiss 等)中,可以进行高效的相似度搜索。Langchain.js 也支持与这些向量数据库的集成。

import { PineconeClient } from 'pinecone-client';
import { OpenAIEmbeddings } from 'langchain/embeddings/openai';

// 初始化 Pinecone 客户端
const pinecone = new PineconeClient({
  apiKey: 'your-pinecone-api-key',
  environment: 'us-west1-gcp',
});

await pinecone.createIndex({
  indexName: 'document-embeddings',
  dimension: 1536, // 这里的维度要与 OpenAI 或其他模型生成的向量维度匹配
});

// 嵌入文档并存储到 Pinecone
const embeddings = new OpenAIEmbeddings({ openAIApiKey: 'your-openai-api-key' });
const vectors = await embeddings.embedDocuments(documents.map(doc => doc.pageContent));

await pinecone.upsert({
  indexName: 'document-embeddings',
  vectors: vectors.map((vector, idx) => ({
    id: `doc-${idx}`,
    values: vector,
  })),
});

// 在 Pinecone 中检索相似文档
const queryVector = await embeddings.embedQuery("查询文本...");
const results = await pinecone.query({
  indexName: 'document-embeddings',
  vector: queryVector,
  topK: 3,
});

console.log(results);

3、查询与检索

在 Langchain.js 中,查询与检索的核心是将输入的查询文本与已存储的向量化文档进行相似度匹配。这个过程通常称为语义搜索,通过向量化的方式找到与查询最相关的文档。

下面的流程可以帮助你理解如何在 Langchain.js 中进行查询与检索:

  1. 基本步骤
  • 向量化查询:将用户输入的查询文本通过嵌入模型转换为向量。
  • 相似度计算:使用向量数据库或本地存储计算查询向量与文档向量之间的相似度(通常使用余弦相似度)。
  • 检索最相关的文档:根据相似度返回最相关的文档或信息。
  1. 使用 OpenAI Embeddings 进行查询与检索

假设我们已经向量化并存储了一些文档,现在我们要对用户的查询进行向量化,并在文档库中查找最相似的文档。

import { OpenAIEmbeddings } from 'langchain/embeddings/openai';
import { PineconeClient } from 'pinecone-client';  // 假设我们使用 Pinecone 作为向量数据库

// 初始化 OpenAI Embeddings 模型
const embeddings = new OpenAIEmbeddings({
  openAIApiKey: 'your-openai-api-key',
});

// 初始化 Pinecone 客户端
const pinecone = new PineconeClient({
  apiKey: 'your-pinecone-api-key',
  environment: 'us-west1-gcp',
});

// 1. 用户输入查询
const queryText = "如何使用 Langchain 进行向量化?";

// 2. 对查询文本进行向量化
const queryVector = await embeddings.embedQuery(queryText);

// 3. 在 Pinecone 中进行向量检索
const results = await pinecone.query({
  indexName: 'document-embeddings',
  vector: queryVector,
  topK: 3,  // 返回最相关的3个文档
});

console.log(results);

如果不使用外部向量数据库(如 Pinecone),你可以将向量存储在本地并使用本地算法进行检索。以下是一个使用余弦相似度在本地计算查询与文档相似度的示例。

import { cosineSimilarity } from 'vector-similarity';

// 模拟已存储的文档向量(通常从数据库加载)
const storedVectors = [
  { id: 'doc1', vector: [0.1, 0.2, 0.3] },
  { id: 'doc2', vector: [0.4, 0.5, 0.6] },
  { id: 'doc3', vector: [0.7, 0.8, 0.9] },
];

// 假设这是查询向量
const queryVector = [0.2, 0.3, 0.4];

// 计算每个文档与查询的相似度
const similarities = storedVectors.map(doc => ({
  id: doc.id,
  similarity: cosineSimilarity(queryVector, doc.vector),
}));

// 排序并输出最相似的文档
similarities.sort((a, b) => b.similarity - a.similarity);

console.log(similarities);

余弦相似度,即使用 cosineSimilarity 函数计算查询向量与每个文档向量的相似度。

查询与检索的核心流程是向量化查询和相似度检索。你可以通过集成 OpenAI、Hugging Face 等嵌入模型将查询文本转换为向量,再利用 Pinecone、Weaviate 等向量数据库,或者本地计算相似度来找到最相关的文档。选择合适的向量数据库和嵌入模型,可以提高语义搜索和问答系统的性能。

四、应用场景与扩展

一个典型的 RAG 案例如图所示。如果我们向 ChatGPT 询问 OpenAI CEO Sam Atlman 在短短几天内突然解雇随后又被复职的事情。由于受到预训练数据的限制,缺乏对最近事件的知识,ChatGPT 则表示无法回答。RAG 则通过从外部知识库检索最新的文档摘录来解决这一差距。在这个例子中,它获取了一系列与询问相关的新闻文章。这些文章,连同最初的问题,随后被合并成一个丰富的提示,使 ChatGPT 能够综合出一个有根据的回应。

RAG 就像给模型一本教科书,用于定制的信息检索,非常适合特定领域的查询。结合实际的应用场景,可以做如下的实践方向:

1. 企业内部知识库

对于大型企业来说,员工往往需要从大量文档中快速获取所需的信息。通过 RAG,员工可以输入查询,系统将从企业内部知识库中检索相关文档,并生成基于这些文档的回答。这样不仅提高了信息获取效率,还减少了员工手动查找文档的时间。

2. 实时搜索引擎

RAG 还可以用于构建结合大语言模型的实时搜索引擎。当用户提出查询时,系统可以从互联网或内部数据库中检索最新的相关信息,并生成准确的回答。这在新闻推送、市场行情分析等需要实时信息的场景下尤为重要。

3. 技术支持和客服

在技术支持或客服领域,RAG 可以帮助自动生成基于用户问题的回答,同时结合企业知识库中的相关文档,提供更加准确、专业的支持。这种方式不仅提高了客服效率,还减少了客户等待时间,提升了用户体验。

五、技术挑战与最佳实践

在实际应用 RAG 技术时,我们也需要注意一些可能的技术挑战:

1. 嵌入模型的选择

选嵌入模型就像挑工具,不同的模型有不同的表现。有的模型擅长处理文本,有的模型适合图像,如果你的项目需要同时处理多个类型的数据(比如文字和图片),你得确保模型能够稳定、准确地处理这些不同类型的数据。所以,开始项目之前,必须好好对比一下不同模型,看哪个最适合你的需求。而且不同模型由于架构、训练方法和目标不同,其向量也不一致,后期迁移的成本会非常大。

2. 向量数据库的扩展性

随着你存储的数据越来越多,你需要一个能够轻松扩展的数据库。如果选的数据库处理不了大规模的数据,就会卡壳。比如 LanceDB 就是个不错的选择,它可以处理多种类型的数据(比如图片、文本),查询速度也很快,适合长时间使用和数据量不断增长的项目。

3. 检索与生成之间的权衡

在用大模型生成内容时,虽然你可以通过检索获得更准确的信息,但如果检索出来的信息太多,反而会让生成的内容变得杂乱,影响效果。所以你得平衡好,检索的信息要足够,但不能过多,确保生成的内容既准确又简洁。

六、总结与未来展望

RAG 的核心在于将外部信息与大语言模型的生成能力结合起来,利用嵌入模型和向量数据库,实现更高质量、更可信的生成结果。通过这种方式,LLM 不仅能够从自身的训练数据中生成答案,还能结合实时信息做出更加合理的推断。

未来,随着向量数据库和嵌入技术的不断发展,RAG 有望在更多领域得到应用。例如,在医学、法律等需要高度精准和实时信息的场景中,RAG 可以帮助自动生成权威且符合现实需求的回答,为各行业带来更加智能化的解决方案。

本文由mdnice多平台发布

标签:检索,RAG,const,模型,Langchain,js,文档,文本,向量
From: https://www.cnblogs.com/miniwa/p/18410621

相关文章

  • 基于Node.js+vue中心医院药品管理系统的设计与实现(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着医疗技术的不断进步和人们对健康需求的日益增长,中心医院作为医疗服务的重要载体,其运营效率和管理水平直接影响到患者的治疗效果与满意度。药品作为医疗......
  • 基于Node.js+vue基于springboot的影视资讯管理系统(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着互联网的飞速发展,影视行业迎来了前所未有的繁荣期。海量影视资源的涌现,使得用户对于高效、便捷地获取影视资讯的需求日益增长。传统的影视资讯管理方式......
  • 基于Node.js+vue在线新闻网站系统的设计与实现(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景在信息爆炸的时代,新闻资讯的获取与传播速度成为了衡量一个社会信息化水平的重要指标。随着互联网技术的飞速发展,传统新闻媒体逐渐向数字化、网络化转型,在线......
  • Vue.js应用程序容器化部署
    为什么要对Vue.js应用程序进行容器化?      在当今快节奏的开发环境中,容器化已成为一种必不可少的做法。Docker提供了一个标准化的软件单元,确保的应用程序无论部署在哪里,都能以相同的方式运行。对Vue.js应用程序进行Docker化有以下几个好处:一致性:确保应用程序在所......
  • 面试-JS Web API-事件绑定和事件代理
    编写一个通用的事件监听函数描述事件冒泡的流程无线下拉的图片列表,如何监听每个图片的点击?---事件代理用e.target获取触发元素用matches判断是否是触发元素事件绑定addEventListenerfunctionbindEvent(elem,type,fn){elem.addEventListener(type,fn)}const......
  • json数据解析
    Stringdata="{json}";ObjectMapperobjectMapper=newObjectMapper();JsonNoderootNode=null;try{rootNode=objectMapper.readTree(data);//通过将String类型的json数据转化为JsonNode对象}catch(JsonPr......
  • js 变量提升
    JavaScript中的变量提升(hoisting)是指在代码执行之前,变量和函数的声明会被提升到作用域的顶部。这意味着你可以在声明之前使用变量和函数,而不会引发错误。变量提升的规则如下:变量声明(使用var关键字)会被提升到其所在作用域的顶部,并初始化为undefined。函数声明会被提升到其所在......
  • Chainlit集成Langchain并使用通义千问和智谱AI实现AI知识库检索网页对话应用
    LangChain简介LangChain是一个开源框架,设计用于开发和部署与语言模型(如大型语言模型LLM)交互的应用程序。它提供了一种简便的方法来构建基于自然语言处理(NLP)的系统,这些系统可以执行各种任务,例如问答、文本生成、文档检索等。LangChain的主要目标是简化开发过程,使开发者能......
  • Mybatis读取和存储json类型的数据
    目录一、测试使用JSONObject来获取json二、设置@TableName的autoResultMap为true,@TableField的typeHandler为JacksonTypeHandler.class三、设置xml当中的resultMap四、JacksonTypeHandler讲解五、新增假如是JSONObject异常问题六、遇到转义的问题不管数据库当中是以json还是longte......
  • SolidJS-每日小知识(9/12)
    知识介绍对SVG元素实现拖拽视图的功能代码分析对于SVG元素的viewBox属性(x,y,w,h),我们设置x,y作为信号量const[boxLocation,setboxLocation]=createSignal({x:0,y:0});添加拖拽所需的变量和事件letisDragging=false;letstartX:number;letst......