J-LangChain - RAG - PDF问答

embedded/2025/2/27 14:27:48/

系列文章索引
J-LangChain 入门

在现代自然语言处理(NLP)中,基于文档内容的问答系统变得愈发重要,尤其是当我们需要从大量文档中提取信息时。通过结合文档检索和生成模型(如RAG,Retrieval-Augmented Generation),我们可以构建强大的问答系统。在处理大量文本数据时,PDF 文件常常是最常见的格式之一。很多时候,我们需要从这些文档中提取信息并利用现代自然语言处理(NLP)技术进行问答。本文将通过一个完整的实例,展示如何使用 J-LangChain 来处理 PDF 文件并通过问答接口获取回答。

J-LangChain 简介

J-LangChain 是一个基于 Java 的链式模型开发框架,旨在帮助开发者利用现代语言模型(如 ChatGPT、Ollama 等)进行多步骤的推理和数据处理。它特别适合用于构建编排复杂的应用程序,这些应用程序涉及到多个步骤的转换、文档处理、模型推理等。

github:https://github.com/flower-trees/j-langchain

本文的目标

我们将展示如何:

  1. 使用 PdfboxLoader 加载 PDF 文档。
  2. 使用 StanfordNLPTextSplitter 对文档进行切分。
  3. 使用 OllamaEmbeddings 对文本进行向量化。
  4. 将文档转换为向量并使用 Milvus 向量存储。
  5. 构建一个多步骤的问答流程来处理用户问题。

项目依赖

为了使用 J-LangChain,你需要在你的 pom.xml 中添加相关的依赖项。这些依赖包括:

  • J-LangChain 大模型编排框架
  • Ollama 模型支持
  • Milvus 向量存储
  • Pdfbox 用于加载 PDF 文件

代码实现步骤

1. 加载 PDF 文档

首先,我们需要加载 PDF 文件并解析其中的文本。J-LangChain 提供了一个名为 PdfboxLoader 的类来帮助我们完成这一任务。你只需指定 PDF 文件的路径,它就会返回一个包含文档内容的 List<Document>

java">PdfboxLoader loader = PdfboxLoader.builder().filePath("./files/pdf/en/Transformer.pdf").extractImages(false) //不处理图片.build();
List<Document> documents = loader.load();
System.out.println("Load documents count:" + documents.size());
2. 切分文档

由于 PDF 文档可能很长,直接将整个文档传递给语言模型会导致性能问题。因此,我们需要将文档切分成较小的部分。J-LangChain 提供了一个 StanfordNLPTextSplitter,它可以根据指定的 chunk 大小和重叠量来切分文档。

java">StanfordNLPTextSplitter splitter = StanfordNLPTextSplitter.builder().chunkSize(1000).chunkOverlap(100).build();
List<Document> splits = splitter.splitDocument(documents);
System.out.println("Splits count:" + splits.size());
3. 将文档转为向量存储

接下来,我们需要将文本信息转化为向量表示,这样可以进行快速的相似性检索。J-LangChain 提供了与 Milvus 向量存储集成的功能。首先,我们需要通过 OllamaEmbeddings 来生成文档的向量表示,然后使用 Milvus 保存这些向量。

java">VectorStore vectorStore = Milvus.fromDocuments(splits,OllamaEmbeddings.builder().model("nomic-embed-text").vectorSize(768).build(),"JLangChain");
System.out.println("Save success");
4. 构建问答流程

现在我们已经将文档切分并存储在向量数据库中,接下来就是通过用户输入的问题来进行检索和回答。我们需要一个 BaseRetriever 来从向量存储中检索相关文档,然后将检索到的文档与问题一起传递给语言模型进行处理。

首先,定义一个 promptTemplate,它包含了需要回答的问题和相关的文档内容:

java">String promptTemplate = """Please provide the following text content:${text}Answer the question:${question}""";

然后,我们通过 J-LangChain 构建一个包含多个步骤的流程。首先,我们从向量存储中检索与问题相关的文档,然后将文档和问题传递给 PromptTemplateChatOllama 进行处理,最后解析模型的输出。

java">BaseRunnable<StringPromptValue, ?> prompt = PromptTemplate.fromTemplate(promptTemplate);
ChatOllama llm = ChatOllama.builder().model("deepseek-r1:7b").build();FlowInstance chain = chainActor.builder().next(baseRetriever).next(input -> { System.out.println("Query content:" + JsonUtil.toJson(input)); return input; }).next(formatDocs).next(input -> Map.of("text", input, "question", ContextBus.get().getFlowParam())).next(prompt).next(llm).next(new StrOutputParser()).build();

最后,调用 chainActor.invoke 执行流程,并打印出结果:

java">ChatGeneration result = chainActor.invoke(chain, "Why is masking necessary in the decoder’s self-attention mechanism?");
System.out.println("Chat Result:" + result);

代码完整实现

代码下载地址:https://github.com/flower-trees/j-langchain-example/blob/master/src/main/java/org/salt/jlangchain/demo/rag/pdf/PdfChatExample.java

java">@Component
public class PdfChatExample {@AutowiredChainActor chainActor;public void pdfChat() {PdfboxLoader loader = PdfboxLoader.builder().filePath("./files/pdf/en/Transformer.pdf").build();List<Document> documents = loader.load();System.out.println("Load documents count:" + documents.size());StanfordNLPTextSplitter splitter = StanfordNLPTextSplitter.builder().chunkSize(1000).chunkOverlap(100).build();List<Document> splits = splitter.splitDocument(documents);System.out.println("Splits count:" + splits.size());VectorStore vectorStore = Milvus.fromDocuments(splits,OllamaEmbeddings.builder().model("nomic-embed-text").vectorSize(768).build(),"JLangChain");System.out.println("Save success");BaseRetriever baseRetriever = vectorStore.asRetriever();String promptTemplate = """Please provide the following text content:${text}Answer the question:${question}""";BaseRunnable<StringPromptValue, ?> prompt = PromptTemplate.fromTemplate(promptTemplate);ChatOllama llm = ChatOllama.builder().model("deepseek-r1:7b").build();Function<Object, String> formatDocs = input -> {if (input == null) {return "";}List<Document> docs = (List<Document>) input;StringBuilder sb = new StringBuilder();for (Document doc : docs) {sb.append(doc.getPageContent()).append("\n");}return sb.toString();};FlowInstance chain = chainActor.builder().next(baseRetriever).next(input -> { System.out.println("Query content:" + JsonUtil.toJson(input)); return input; }).next(formatDocs).next(input -> Map.of("text", input, "question", ContextBus.get().getFlowParam())).next(prompt).next(llm).next(new StrOutputParser()).build();ChatGeneration result = chainActor.invoke(chain, "Why is masking necessary in the decoder’s self-attention mechanism?");System.out.println("Chat Result:" + result);}
}

代码执行

java">@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
@SpringBootConfiguration
public class PdfExampleTest {@AutowiredPdfChatExample pdfChatExample;@Testpublic void PdfChatExample() {pdfChatExample.pdfChat();}
}

总结

本文展示了如何使用 J-LangChain 框架从 PDF 文件中提取信息并进行基于问题的回答。我们通过加载 PDF 文档、切分文档、向量化文档内容并存储到 Milvus 中,然后构建问答流程,最终利用语言模型来回答用户的问题。

通过这种方式,开发者可以轻松地将自然语言处理模型应用到 PDF 文档中,进行信息提取、问答等操作。

参考文档
LangChain教程 - RAG - PDF问答
使用 Apache PDFBox 提取 PDF 中的文本和图像
详细介绍Tess4J的使用:从PDF到图像的OCR技术实现
全面了解 Stanford NLP:强大自然语言处理工具的使用与案例
使用 Milvus 与 Ollama 进行文本向量存储与检索


http://www.ppmy.cn/embedded/167547.html

相关文章

idea中或pycharm中编写Markdown文件

参考 ltjt_aiseek: seek_backend_py 项目 数智科技ai探索API接口开发 1. 安装 Django 框架 在开始创建 Django 项目之前&#xff0c;需要先安装 Django 框架。可以通过 PyCharm 的终端或者系统的命令行工具来完成安装。 使用 PyCharm 终端安装 打开 PyCharm&#xff0c;如果…

华为交换机堆叠方法

堆叠配置&#xff1a; 先把接口shutdown 第一台&#xff1a; int stack-port 0/1 port interface XGigabitEthernet0/0/3 enable y qu int stack-port 0/2 port interface XGigabitEthernet0/0/4 enable y qu stack slot 0 priority 200 y 第二台&#xff1a; int stack…

一键部署DeepSeek

腾讯Cloud Studio提供DeepSeek一键部署功能&#xff0c;0行代码&#xff0c;秒级部署使用&#xff01; 重点是每月免费提供10000分钟&#xff01; 不用等待模型下载&#xff0c;创建即可使用。 内置 Ollama、DeepSeek-R1 1.5B、7B、8B、14B 及 32B 模型。 热门模板 AI模板 前…

【奥卡姆剃刀原理-如何理解云计算和边缘计算 关键字摘取】

云计算可能还是你相对熟悉的概念。通俗来说&#xff0c;就是把计算任务从本地挪到远程&#xff0c;往往是挪到一个大的计算中心。在那里完成计算之后&#xff0c;再把计算结果返回本地。这样本地就不用部署很强的硬件搞计算了。 而边缘计算的介绍大都说&#xff0c;这是把一部…

MySQL--索引的优化--ORDER BY

在MySQL中&#xff0c;ORDER BY语句的性能优化是一个重要的课题&#xff0c;尤其是在处理大数据集时&#xff0c;如果ORDER BY没有正确使用索引&#xff0c;可能会导致全表扫描或文件排序&#xff08;Using filesort&#xff09;&#xff0c;从而严重影响查询性能。以下是一些详…

2025系统架构师(一考就过):案例之三:架构风格总结

软件架构风格是描述某一特定应用领域中系统组织方式的惯用模式&#xff0c;按照软件架构风格&#xff0c;物联网系统属于&#xff08; &#xff09;软件架构风格。 A:层次型 B:事件系统 C:数据线 D:C2 答案&#xff1a;A 解析&#xff1a; 物联网分为多个层次&#xff0…

火语言RPA--Word打开文档

【组件功能】&#xff1a;打开已有或者新建Word文档&#xff0c;并实例化初始化操作 配置预览 配置说明 打开方式 打开已存在Word文档或者新建Word文档。 Word文件路径 支持T或# 设置打开或者新建Word文件的文件路径。 对象修改操作保存模式 word文件被改变时每一步自动…

2025.2.26总结

工作 今日终于完成了Core Common的遗留问题的闭环&#xff0c;整个项目版本下来&#xff0c;还是挺磨练人的&#xff0c;如今已经不记得熬了多少个夜&#xff0c;不记得有多少个焦虑的周末。收获也是挺大的&#xff0c;最主要的还是工作方法的总结。 学习 ilearnming平台学习…