如何将检索增强生成(RAG)用于Go应用程序

智能真的很好说 2024-06-08 16:49:35
在本文中,学习如何实现 RAG(使用 LangChain 和 PostgreSQL)以提高 LLM 输出的准确性和相关性。

由于强大的机器学习模型(特别是大型语言模型,如 Claude、Meta 的 LLama 2 等)被托管平台/服务作为 API 调用公开,生成式 AI 开发已经民主化。这使开发人员摆脱了对基础设施的担忧,并让他们专注于核心业务问题。这也意味着开发人员可以自由使用最适合其解决方案的编程语言。Python 通常是 AI/ML 解决方案的首选语言,但该领域具有更大的灵活性。

在这篇文章中,您将看到如何利用 Go 编程语言将向量数据库和诸如检索增强生成 (RAG) 等技术与 langchaingo 一起使用。如果您是想要如何构建和学习生成式 AI 应用程序的 Go 开发人员,那么您来对地方了!

如果你正在寻找有关使用 Go for AI/ML 的介绍性内容,请随时查看我以前的博客和这个领域的开源项目。

首先,让我们退后一步,在深入了解本文的动手部分之前了解一些背景信息。

LLM的局限性

大型语言模型 (LLM) 和其他基础模型已经在大量数据语料库上进行了训练,使它们能够在许多自然语言处理 (NLP) 任务中表现出色。但最重要的限制之一是,大多数基础模型和 LLM 使用静态数据集,该数据集通常具有特定的知识截止点(例如,2022 年 1 月)。

例如,如果你要问一个发生在截止时间之后的事件,它要么无法回答(这很好),要么更糟,自信地回答不正确的回答——这通常被称为幻觉。

我们需要考虑这样一个事实,即 LLM 只根据他们接受训练的数据做出回应——这限制了他们准确回答有关专业或专有主题的问题的能力。例如,如果我要问一个关于特定AWS服务的问题,LLM可能会(也可能不会)给出准确的答案。如果 LLM 可以使用官方的 AWS 服务文档作为参考,那不是很好吗?

RAG(检索增强生成)有助于缓解这些问题

它通过在响应生成过程中动态检索外部信息来增强 LLM,从而将模型的知识库扩展到其原始训练数据之外。基于RAG的解决方案包含一个向量存储,可以对其进行索引和查询以检索最新和相关的信息,从而将LLM的知识扩展到其训练截止点之外。当配备 RAG 的 LLM 需要生成响应时,它首先查询向量存储以查找与查询相关的相关最新信息。这个过程确保模型的输出不仅基于其预先存在的知识,而且用最新信息进行扩充,从而提高其响应的准确性和相关性。

但是,RAG并不是唯一的方法

虽然这篇文章只关注 RAG,但还有其他方法可以解决这个问题,每种方法都有其优点和缺点:

特定于任务的调整:在特定任务或数据集上微调大型语言模型,以提高它们在这些领域的性能。提示工程: 仔细设计输入提示,以引导语言模型实现所需的输出,而无需进行重大的体系结构更改。少样本和零样本学习:使语言模型能够适应新任务的技术,而这些任务的训练数据有限或没有额外的训练数据。矢量存储和嵌入

我在上一段中多次提到向量存储。这些只不过是存储和索引向量嵌入的数据库,这些向量嵌入是文本、图像或实体等数据的数值表示。嵌入帮助我们超越基本搜索,因为它们代表了源数据的语义含义——因此有了语义搜索这个词,它是一种理解单词的含义和上下文以提高搜索准确性和相关性的技术。矢量数据库还可以存储元数据,包括对嵌入的原始数据源(例如,Web 文档的 URL)的引用。

得益于生成式人工智能技术,矢量数据库也出现了爆炸式增长。其中包括已建立的 SQL 和 NoSQL 数据库,您可能已经在体系结构的其他部分(例如 PostgreSQL、Redis、MongoDB 和 OpenSearch)中使用这些数据库。但也有为矢量存储定制的数据库。其中一些包括 Pinecone、Milvus、Weaviate 等。

好吧,让我们回到 RAG...

典型的 RAG 工作流程是什么样的?

概括地说,基于 RAG 的解决方案具有以下工作流。这些通常作为有凝聚力的管道执行:

从各种外部来源(如文档、图像、Web URL、数据库、专有数据源等)检索数据。这包括子步骤,例如分块,它涉及将大型数据集(例如 100 MB PDF 文件)拆分为较小的部分(用于索引)。创建嵌入: 这涉及使用嵌入模型将数据转换为数值表示。矢量存储中的存储/索引嵌入

归根结底,这是作为更大应用程序的一部分的集成,其中上下文数据(语义搜索结果)提供给 LLM(以及提示)。

端到端 RAG 工作流的实际应用

每个工作流步骤都可以使用不同的组件执行。博客中使用的包括:

PostgreSQL: 由于 pgvector 扩展,它将用作向量数据库。为了简单起见,我们将在 Docker 中运行它。langchaingo: 它是 langchain 框架的 Go 端口。它为各种组件提供插件,包括矢量存储。我们将使用它从 Web URL 加载数据并在 PostgreSQL 中将其编入索引。文本和嵌入模型: 我们将使用 Amazon Bedrock Claude 和 Titan 模型(分别用于文本和嵌入)和 langchaingo。检索和应用集成:langchaingo vector store(用于语义搜索)和 chain(用于 RAG)。

您将了解这些单独的部分是如何工作的。我们将在随后的博客中介绍此体系结构的其他变体。

准备工作

确保您拥有:

安装了 Go、Docker 和 psql(例如,如果您在 Mac 上,则使用 Homebrew)。从本地计算机配置的 Amazon Bedrock 访问 - 有关详细信息,请参阅此博客文章。在 Docker 上启动 PostgreSQL

我们可以使用一个 Docker 镜像!

docker run --name pgvector --rm -it -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres ankane/pgvector

通过从其他终端登录 PostgreSQL(使用 )来激活扩展:pgvectorpsql

# enter postgres when prompted for passwordpsql -h localhost -U postgres -WCREATE EXTENSION IF NOT EXISTS vector;

将数据加载到 PostgreSQL (Vector Store)

克隆项目存储库:

git clone https://github.com/build-on-aws/rag-golang-postgresql-langchaincd rag-golang-postgresql-langchain

此时,我假设您的本地计算机已配置为使用 Amazon Bedrock

我们要做的第一件事是将数据加载到 PostgreSQL 中。在这种情况下,我们将使用现有的网页作为信息来源。我已经使用过这个开发人员指南——但请随意使用你自己的!请确保在后续步骤中相应地更改搜索查询。

export PG_HOST=localhostexport PG_USER=postgresexport PG_PASSWORD=postgresexport PG_DB=postgresgo run *.go -action=load -source=https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-nosql-design.html

应获得以下输出:

loading data from https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-nosql-design.htmlvector store ready - postgres://postgres:postgres@localhost:5432/postgres?sslmode=disableno. of documents to be loaded 23

给它几秒钟。最后,如果一切顺利,您应该会看到以下输出:

data successfully loaded into vector store

要进行验证,请返回终端并检查表:psql

\d

您应该会看到几个表 — 和 .这些是创建的,因为我们没有明确指定它们(没关系,方便入门! 包含集合名称,同时存储实际的嵌入。langchain_pg_collectionlangchain_pg_embeddinglangchaingolangchain_pg_collectionlangchain_pg_embedding

| Schema | Name | Type | Owner ||--------|-------------------------|-------|----------|| public | langchain_pg_collection | table | postgres || public | langchain_pg_embedding | table | postgres |

您可以自省这些表:

select * from langchain_pg_collection;select count(*) from langchain_pg_embedding;select collection_id, document, uuid from langchain_pg_embedding LIMIT 1;

您将在langchain_pg_embedding表中看到 23 行,因为这是我们的网页源被拆分为 langchain 文档的数量(当您加载数据时,请参阅上面的应用程序日志)

快速绕道了解其工作原理......

数据加载实现在 load.go 中,但让我们看看我们如何访问向量存储实例(在 common.go 中):

brc := bedrockruntime.NewFromConfig(cfg) embeddingModel, err := bedrock.NewBedrock(bedrock.WithClient(brc), bedrock.WithModel(bedrock.ModelTitanEmbedG1)) //... store, err = pgvector.New( context.Background(), pgvector.WithConnectionURL(pgConnURL), pgvector.WithEmbedder(embeddingModel), )

pgvector.WithConnectionURL是提供 PostgreSQL 实例连接信息的位置pgvector.WithEmbedder是有趣的部分,因为这是我们可以插入我们选择的嵌入模型的地方。 支持 Amazon Bedrock 嵌入。在本例中,我使用了 Amazon Bedrock Titan 嵌入模型。langchaingo

回到 load.go 中的加载过程。为此,我们首先使用内置的 HTML 加载器以 ( 函数) 切片的形式获取数据。schema.DocumentgetDocslangchaingo

docs, err := documentloaders.NewHTML(resp.Body).LoadAndSplit(context.Background(), textsplitter.NewRecursiveCharacter())

然后,我们将其加载到 PostgreSQL 中。与其自己写所有东西,不如使用向量存储抽象,使用高级函数:langchaingoAddDocuments

_, err = store.AddDocuments(context.Background(), docs)

伟大。我们设置了一个简单的管道来获取数据并将其摄取到 PostgreSQL 中。让我们好好利用吧!

执行语义搜索

让我们问一个问题。我将使用“我可以使用哪些工具来设计 dynamodb 数据模型?”,这与我用作数据源的文档相关 - 请根据您的场景随意调整它。

export PG_HOST=localhostexport PG_USER=postgresexport PG_PASSWORD=postgresexport PG_DB=postgresgo run *.go -action=semantic_search -query="what tools can I use to design dynamodb data models?" -maxResults=3

您应该会看到类似的输出 — 请注意,我们选择最多输出三个结果(您可以更改它):

vector store ready============== similarity search results ==============similarity search info - can build new data models from, or design models based on, existing data models that satisfy your application's data access patterns. You can also import and export the designed data model at the end of the process. For more information, see Building data models with NoSQL Workbenchsimilarity search score - 0.3141409============================similarity search info - NoSQL Workbench for DynamoDB is a cross-platform, client-side GUI application that you can use for modern database development and operations. It's available for Windows, macOS, and Linux. NoSQL Workbench is a visual development tool that provides data modeling, data visualization, sample data generation, and query development features to help you design, create, query, and manage DynamoDB tables. With NoSQL Workbench for DynamoDB, yousimilarity search score - 0.3186116============================similarity search info - key-value pairs or document storage. When you switch from a relational database management system to a NoSQL database system like DynamoDB, it's important to understand the key differences and specific design approaches.TopicsDifferences between relational data design and NoSQLTwo key concepts for NoSQL designApproaching NoSQL designNoSQL Workbench for DynamoDB Differences between relational data design and NoSQLsimilarity search score - 0.3275382============================

现在你在这里看到的是前三个结果(感谢)。-maxResults=3

请注意,这不是我们问题的答案。这些是来自我们的向量存储的结果,它们在语义上接近查询——这里的关键字是语义。多亏了 中的向量存储抽象,我们能够轻松地将源数据摄取到 PostgreSQL 中,并使用该函数获得与我们的查询相对应的顶级结果(参见 query.go 中的函数):langchaingoSimilaritySearchNsemanticSearch

请注意,(在撰写本文时)langchaingo 中的 pgvector 实现使用余弦距离向量运算,但 pgvector 也支持 L2 和内积 - 有关详细信息,请参阅 pgvector 文档。

好的,到目前为止,我们有:

加载的矢量数据已执行的语义搜索

这是 RAG(检索增强生成)的垫脚石 - 让我们看看它的实际效果!

使用 RAG 进行智能搜索

为了执行基于 RAG 的搜索,我们运行与上面相同的命令(几乎),只是 () 略有变化:actionrag_search

export PG_HOST=localhostexport PG_USER=postgresexport PG_PASSWORD=postgresexport PG_DB=postgresgo run *.go -action=rag_search -query="what tools can I use to design dynamodb data models?" -maxResults=3

这是我得到的输出(在您的情况下可能略有不同):

Based on the context provided, the NoSQL Workbench for DynamoDB is a tool that can be used to design DynamoDB data models. Some key points about NoSQL Workbench for DynamoDB:- It is a cross-platform GUI application available for Windows, macOS, and Linux.- It provides data modeling capabilities to help design and create DynamoDB tables.- It allows you to build new data models or design models based on existing data models.- It provides features like data visualization, sample data generation, and query development to manage DynamoDB tables.- It helps in understanding the key differences and design approaches when moving from a relational database to a NoSQL database like DynamoDB.

因此,总而言之,NoSQL Workbench for DynamoDB 似乎是一个专门为建模和使用 DynamoDB 数据模型而设计的有用工具。

正如你所看到的,结果不仅仅是“这是你的查询的前 X 个响应”。相反,这是对这个问题的精心设计的回答。让我们再次窥探幕后花絮,看看它是如何工作的。

与摄取和语义搜索不同,基于 RAG 的搜索不会直接由向量存储实现公开。为此,我们使用一条链来处理以下事项:langchaingolangchaingo

调用语义搜索将语义搜索与提示相结合将其发送到大型语言模型 (LLM),在本例中,该模型恰好是 Amazon Bedrock 上的 Claude。

这是链的样子(参考 query.go 中的函数):ragSearch

result, err := chains.Run( context.Background(), chains.NewRetrievalQAFromLLM( llm, vectorstores.ToRetriever(store, numOfResults), ), question, chains.WithMaxTokens(2048), )

让我们再试一个

这只是一个例子。我尝试了一个不同的问题,并将 maxResults 增加到 10,这意味着将使用向量数据库中的前 10 个结果来制定答案。

go run *.go -action=rag_search -query="how is NoSQL different from SQL?" -maxResults=10

结果(同样,对你来说可能不同):

Based on the provided context, there are a few key differences between NoSQL databases like DynamoDB and relational database management systems (RDBMS):1. Data Modeling: - In RDBMS, data modeling is focused on flexibility and normalization without worrying much about performance implications. Query optimization doesn't significantly affect schema design. - In NoSQL, data modeling is driven by the specific queries and access patterns required by the application. The data schema is designed to optimize the most common and important queries for speed and scalability.2. Data Organization: - RDBMS organizes data into tables with rows and columns, allowing flexible querying. - NoSQL databases like DynamoDB use key-value pairs or document storage, where data is organized in a way that matches the queried data shape, improving query performance.3. Query Patterns: - In RDBMS, data can be queried flexibly, but queries can be relatively expensive and don't scale well for high-traffic situations. - In NoSQL, data can be queried efficiently in a limited number of ways defined by the data model, while other queries may be expensive and slow.4. Data Distribution: - NoSQL databases like DynamoDB distribute data across partitions to scale horizontally, and the data keys are designed to evenly distribute the traffic across partitions, avoiding hot spots. - The concept of "locality of reference," keeping related data together, is crucial for improving performance and reducing costs in NoSQL databases.In summary, NoSQL databases prioritize specific query patterns and scalability over flexible querying, and the data modeling is tailored to these requirements, in contrast with RDBMS where data modeling focuses on normalization and flexibility.

从这里“去”哪里?

边做边学是一个很好的方法。如果您到目前为止已经遵循并执行了该应用程序,那就太好了!我建议您尝试以下方法:

langchaingo支持许多不同的模型,包括 Amazon Bedrock 中的模型(例如 Meta LLama 2、Cohere 等)——尝试调整模型,看看它是否有所作为。输出更好吗?矢量数据库呢?我演示了 PostgreSQL,但也支持其他(包括 OpenSearch、Chroma 等) - 尝试交换 Vector 存储,看看搜索结果如何/是否不同。langchaingo您可能了解要点,但您也可以尝试不同的嵌入模型。我们使用了 Amazon Titan,但也支持许多其他模型,包括 Amazon Bedrock 中的 Cohere 嵌入模型。langchaingo㯱

这是一个简单示例,可让您更好地了解构建基于 RAG 的解决方案的各个步骤。这些可能会根据实现而略有变化,但高级想法保持不变。

我用作框架。但这并不总是意味着你必须使用一个。如果您需要在应用程序中进行精细控制或框架不符合您的要求,您还可以删除抽象并直接调用 LLM 平台 API。与大多数生成式 AI 一样,这个领域正在迅速发展,我对 Go 开发人员有更多选择来构建生成式 AI 解决方案持乐观态度。langchaingo

如果您有任何反馈或问题,或者您希望我围绕此主题介绍其他内容,请随时在下面发表评论!

祝您建造愉快!

原文标题:How To Use Retrieval Augmented Generation (RAG) for Go Applications

原文链接:https://dzone.com/articles/how-to-use-retrieval-augmented-generation-rag-for

作者:Abhishek Gupta

编译:LCR

0 阅读:0

智能真的很好说

简介:感谢大家的关注