在本博客中,您将了解如何使用 Wea​​viate、LangChain4j 和 LocalAI 实现检索增强生成 (RAG)。此实现允许您使用自然语言询问有关文档的问题。享受吧!

1。简介

上一篇中post,Weaviate 被用作矢量数据库以执行语义搜索。使用的源文档是两个维基百科文档。 唱片目录Bruce Springsteen 录制的歌曲列表是使用的文档。这些文档的有趣之处在于它们包含事实并且主要采用表格格式。这些文档的部分内容被转换为 Markdown,以便更好地表示。 Markdown 文件嵌入到 Weaviate 的集合中。结果是惊人的:所有提出的问题都得到了正确的答案。也就是说,返回了正确的段。您仍然需要自己提取答案,但这很容易。

但是,可以通过创建正确的提示将 Weaviate 搜索结果提供给 LLM(大型语言模型)来解决这个问题吗? LLM 能够提取问题的正确答案吗?

该设置如下图所示:

  1. 文档嵌入并存储在 Weaviate 中;
  2. 嵌入问题并使用 Wea​​viate 执行语义搜索;
  3. Weaviate 返回语义搜索结果;
  4. 结果将添加到提示中并馈送到 LocalAI,后者使用 LangChain4j 运行 LLM;
  5. 法学硕士返回问题的答案。

weaviate 与 localAI

Weaviate 还支持 RAG,那么为什么还要使用 LocalAI和LangChain4j?遗憾的是,Weaviate 不支持与 LocalAI 集成,并且仅支持云 LLM可以使用。如果您的文档包含敏感信息或您不想发送到基于云的 LLM 的信息,您需要运行本地 LLM,这可以使用 LocalAI 和 LangChain4j 来完成。

如果您想运行本博客中的示例,则需要阅读上一篇博客

本博客中使用的来源可以在 GitHub 上找到。

2。先决条件

此博客的先决条件是:

  • 嵌入和向量存储的基本知识;
  • Java基础知识,使用Java 21;
  • Docker 基础知识;
  • LangChain4j基础知识;
  • 您需要 Weaviate 并且需要嵌入文档,请参阅上一篇博客介绍了如何执行此操作;
  • 如果您想运行示例,则需要 LocalAI,请参阅上一篇博客 了解如何利用 LocalAI。本博客使用的是 2.2.0 版本。
  • 如果您想了解有关 RAG 的更多信息,请阅读此博客.

3。创建设置

开始之前,需要进行一些设置。

3.1 设置 LocalAI

LocalAI 必须正在运行并配置。博客中解释了如何执行此操作本地运行LLM:分步-步骤指南

3.2 设置 Weaviate

Weaviate 必须启动。与 Weaviate 博客的唯一区别是您将在端口 8081 而不是端口 8080 上运行它。这是因为 LocalAI 已经在端口 8080 上运行。

从存储库的根目录启动撰写文件。

 

$ docker compose -f docker/compose-embed-8081.yaml

运行类 EmbedMarkdown 以嵌入文档(将端口更改为 8081!)。创建了三个集合:

  1. CompilationAlbum:布鲁斯·斯普林斯汀所有合辑专辑列表;
  2. 歌曲:布鲁斯·斯普林斯汀的所有歌曲列表;
  3. StudioAlbum:Bruce Springsteen 所有录音室专辑的列表。

4。实施RAG

4.1 语义搜索

实现的第一部分基于类 SearchCollectionNearText。这里假设您知道要在哪个集合(参数className)中搜索。

上一篇中发布后,您注意到严格来说,您不需要知道要搜索哪个集合。然而,此时,它使实现变得更容易一些,并且结果保持不变。

代码将接受问题,并在 NearTextArgument 的帮助下嵌入问题。 Weaviate 的 GraphQL API 用于执行搜索。

爪哇

 

private static String createPrompt(String Question, String inputData, String extraInstruction) {
    return "回答以下问题:" + 问题 + "\n" +
            额外指令 + "\n" +
            "使用以下数据回答问题:" + inputData;
}

4.3 使用法学硕士

最后要做的是将提示提供给 LLM 并将问题和答案打印到控制台。

爪哇

 

private static void AskQuestion(String className, Field[] fields, String Question, String extraInstruction) {
    ...
    ChatLanguageModel 模型 = LocalAiChatModel.builder()
            .baseUrl("http://localhost:8080")
            .modelName("lunademo")
            .温度(0.0)
            。建造();
 
    String Answer = model.generate(createPrompt(question, result.getResult().getData().toString(), extraInstruction));
 
    System.out.println(问题);
    System.out.println(答案);
}

4.4 问题

要问的问题与之前的帖子相同。他们将调用上面的代码。

爪哇

 

public static void main(String[] args) {
    AskQuestion(Song.NAME, Song.getFields(), "最初发行的《亚当举起凯恩》是在哪张专辑上?", "");
    AskQuestion(StudioAlbum.NAME, StudioAlbum.getFields(), "《来自新泽西州阿斯伯里帕克的问候》在美国的最高排行榜位置是多少?", "");
    AskQuestion(CompilationAlbum.NAME, CompilationAlbum.getFields(), "专辑\"tracks\"在加拿大的最高排行榜位置是多少?", "");
    AskQuestion(Song.NAME, Song.getFields(), "《公路巡警》是哪一年发行的?", "");
    AskQuestion(Song.NAME, Song.getFields(), "谁创作了\"全有或全无?\"", "");
}

完整源码可查看此处

5。结果

运行代码,结果如下:

  1. 《Adam Raising a Cain》最初发行于哪张专辑?
    专辑《Darkness on the Edge of Town》最初发行于 1978 年,歌曲“ Adam Raising a Cain”收录在该专辑中。
  2. “来自新泽西州阿斯伯里帕克的问候”的最高排行榜位置是多少?在美国?
    排行榜最高位置是“来自新泽西州阿斯伯里帕克的问候”在美国是 60。
  3. 专辑《Tracks》在加拿大的最高排行榜位置是多少?
    根据提供的数据,专辑《Tracks》在加拿大的最高排行榜位置是 -。这是因为数据不包括该专辑的任何加拿大排行榜位置。
  4. 《Highway Patrolman》是哪一年发行的?
    歌曲《Highway Patrolman》于 1982 年发行。
  5. 谁制作了“all or nothin’ at all?”
    歌曲“All or Nothingth’ at All”由 Bruce Springsteen、Roy Bittan、Jon Landau 制作,和查克·普洛特金。

问题的所有答案都是正确的。最重要的工作已在 上一篇文章,以正确的方式嵌入文档,导致找到正确的段。当提供正确的数据时,法学硕士能够提取问题的答案。

6。注意事项

在实现过程中,我遇到了一些奇怪的行为,了解这些行为对于您何时开始实现用例非常重要。

6.1 Weaviate结果格式

Weaviate 响应包含一个 GraphQLResponse 对象,如下所示:

JSON

 

GraphQLResponse(
  数据={
    获取={
      歌曲=[
        {_additional={确定性=0.7534831166267395,距离=0.49303377},
         OriginalRelease=城镇边缘的黑暗,
         制片人=乔恩·兰道、布鲁斯·斯普林斯汀、史蒂文·范·赞特(助理)、
         歌曲=“亚当养育了该隐”,作者=布鲁斯·斯普林斯汀,年份=1978}
      ]
     }
  },
错误=空)

在代码中,数据部分用于添加到提示中。

爪哇

 

字符串答案 = model.generate(createPrompt(question, result.getResult().getData().toString(), extraInstruction));


当您将响应按原样添加到提示时会发生什么?

爪哇
 
字符串答案 = model.generate(createPrompt(question, result.getResult().toString(), extraInstruction));

运行代码会返回问题 3 的以下错误答案以及问题 4 的一些不必要的附加信息。其他问题均已正确回答。

  • 专辑《Tracks》在加拿大的最高排行榜位置是多少?
    根据提供的数据,专辑《Tracks》在加拿大的最高排行榜位置是 50。
  • 《高速公路巡警》是哪一年发布的?
    根据提供的 GraphQLResponse,《高速公路巡警》于 1982 年发布。
    谁制作了“所有或者什么都没有?”

6.2 提示格式

该代码包含向提示添加额外指令的功能。您可能已经注意到,没有使用此功能。让我们看看当您从提示中删除此内容时会发生什么。 createPrompt 方法如下(我没有删除所有内容,因此只需要进行较小的代码更改)。

爪哇

 

private static String createPrompt(String Question, String inputData, String extraInstruction) {
    return "回答以下问题:" + 问题 + "\n" +
             "使用以下数据回答问题:" + inputData;
}

运行代码会为问题 3 的答案添加一些额外的信息,这并不完全正确。这张专辑在美国、英国、德国和瑞典的排行榜上的位置是正确的。说这张专辑进入英国和美国排行榜前十名是不正确的。所有其他问题均已正确回答。

  • 专辑《Tracks》在加拿大的最高排行榜位置是多少?
    根据提供的数据,专辑《Tracks》在加拿大的最高排行榜位置没有指定。该数据仅包括美国、英国、德国和瑞典等其他国家的图表位置。不过,这张专辑确实进入了英国和美国排行榜前十名。

使用法学硕士时它仍然有点脆弱。你不能总是相信它给出的答案。相应地改变提示似乎可以最大限度地减少法学硕士的幻觉。因此,收集用户的反馈非常重要,以便确定法学硕士何时出现幻觉。这样,您将能够改善对用户的响应。一个有趣的 博客是由 Fiddler 编写的,它解决了此类问题。

7。结论

在本博客中,您学习了如何使用 Wea​​viate、LangChain4j 和 LocalAI 实现 RAG。结果是相当惊人的。以正确的方式嵌入文档、过滤结果并将其提供给法学硕士是一个非常强大的组合,可用于许多用例。

Comments are closed.