Java读取PDF后做知识库问答_SpringAI实现

​​​​​​​​​​​​​​

核心思路:

简单来说,就是把PDF文件读取并向量化,然后放到向量存储里面,再通过大模型,来实现问答。 

RAG(检索增强生成)介绍:

检索增强生成(RAG)是一种结合了信息检索和文本生成的技术,旨在提高大模型的响应准确性和相关性。通过将检索模型(用于搜索专有数据集或知识库)与生成模型(如大型语言模型LLM)相结合,RAG能够利用私有或专有的数据来辅助生成更精确的回答。这样不仅减少了由于缺乏特定背景知识导致的大模型“幻觉”现象,还使得生成的内容更加贴合用户的需求和上下文环境,特别适合于需要处理企业内部数据的应用场景。

Spring AI alibaba介绍

Spring AI Alibaba 是基于 Spring Ai 构建的,用于集成阿里云通义大模型服务的应用框架。它允许开发者通过简单的配置和少量代码,将强大的AI能力如对话、文生图等快速融入到 Java 应用程序中。其核心优势在于提供了一套标准化接口,使得应用程序能够轻松切换不同的AI提供商而无需大量修改代码;同时,该框架支持流式输出,并提供了Prompt模板等功能来简化开发流程,极大地提高了效率和灵活性。通过与Spring Boot生态系统的无缝集成,Spring AI Alibaba为开发者打造了一个既高效又便捷的AI应用开发环境。

详细例子:

1 后端代码编写

读PDF->向量化->向量存储->读取展现 

1. 环境准备

确保你的开发环境满足以下条件:

  • JDK版本在17或以上。
  • Spring Boot版本为3.3.x或更高。
  • 已经从阿里云申请到了通义千问API的api-key

2. 配置项目以使用Spring AI Alibaba

2.1 设置API Key

在启动应用之前,请设置环境变量AI_DASHSCOPE_API_KEY为你获得的API密钥值,并且在application.properties中正确引用它:

spring.ai.dashscope.api-key: ${AI_DASHSCOPE_API_KEY}
2.2 添加依赖

需要添加对spring-ai-alibaba-starter的依赖到你的pom.xml文件中,并且指定正确的Spring Boot父级依赖。同时不要忘记包含必要的仓库地址以便获取最新的快照版本。

<parent>
    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-staper-parent</artifactId>

    <version>3.3.4</version>

</parent>

<dependencies>
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>

        <artifactId>spring-ai-alibaba-starter</artifactId>

        <version>1.0.0-M2</version>

    </dependency>

</dependencies>

<repositories>
    <repository>
        <id>sonatype-snapshots</id>

        <url>https://oss.sonatype.org/content/repositories/snapshots</url>

        <snapshots><enabled>true</enabled></snapshots>

    </repository>

    <repository>
        <id>spring-milestones</id>

        <name>Spring Milestones</name>

        <url>https://repo.spring.io/milestone</url>

        <snapshots><enabled>false</enabled></snapshots>

    </repository>

    <repository>
        <id>spring-snapshots</id>

        <name>Spring Snapshots</name>

        <url>https://repo.spring.io/snapshot</url>

        <releases><enabled>false</enabled></releases>

    </repository>

</repositories>

3. 编写RAG服务代码

创建一个名为RagService的服务类,用于处理与向量存储、文档检索相关的逻辑。该服务还将负责初始化索引构建及查询操作。

public class RagService {
    private final ChatClient chatClient;
    private final VectorStore vectorStore;
    private final DashScopeApi dashscopeApi = new DashScopeApi("你的apiKey");
    DocumentRetriever retriever;

    public RagService(ChatClient chatClient, EmbeddingModel embeddingModel) {
        this.chatClient = chatClient;
        vectorStore = new DashScopeCloudStore(dashscopeApi, new DashScopeStoreOptions("spring-ai知识库"));
        retriever = new DashScopeDocumentRetriever(dashscopeApi, DashScopeDocumentRetrieverOptions.builder().withIndexName("spring-ai知识库").build());
    }

    public String buildIndex() {
        String filePath = "/path/to/阿里巴巴财报.pdf";
        DocumentReader reader = new DashScopeDocumentCloudReader(filePath, dashscopeApi, null);
        List<Document> documentList = reader.get();
        vectorStore.add(documentList);
        return "SUCCESS";
    }

    public StreamResponseSpec queryWithDocumentRetrieval(String message) {
        StreamResponseSpec response = chatClient.prompt().user(message)
            .advisors(new DocumentRetrievalAdvisor(retriever, DEFAULT_USER_TEXT_ADVISE)).stream();
        return response;
    }
}

4. 创建控制器暴露接口

接下来定义一个REST控制器,用来接收HTTP请求并将结果返回给客户端。

@RestController
@RequestMapping("/ai")
public class RagController {
    private final RagService ragService;

    public RagController(RagService ragService) {
        this.ragService = ragService;
    }

    @GetMapping("/steamChat")
    public Flux<String> generate(@RequestParam(value = "input", required = true) String input,
                                 HttpServletResponse httpResponse) {
        StreamResponseSpec chatResponse = ragService.queryWithDocumentRetrieval(input);
        httpResponse.setCharacterEncoding("UTF-8");
        return chatResponse.content();
    }

    @GetMapping("/buildIndex")
    public String buildIndex() {
        return ragService.buildIndex();
    }
}

5. 运行应用程序

在运行此应用程序之前,请确保已经完成了索引的构建(调用/buildIndex)。之后可以通过访问http://localhost:8080/ai/steamChat?input=你的问题来查询财务报告中的信息了。

通过上述步骤,你就可以成功地利用检索增强技术来处理阿里巴巴财务报表PDF文件,并通过一个简单的Web API提供交互式问答功能。这不仅能够帮助用户更高效地查找所需信息,同时也展示了如何结合现有技术和工具快速搭建起实用的服务。

检索增强的前端代码编写

构建项目并填写代码

首先,创建一个新的 React 应用并安装所需的依赖:

npx create-react-app ragChatFrontend
cd ragChatFrontend
npm install
public/index.html

public/index.html中不需要做特别的修改,保持默认即可。

src/index.js

确保你的src/index.js如下所示,它负责渲染应用的根组件App

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
src/App.js

这个文件定义了应用的主要布局。我们在这个例子中将只包含一个聊天组件:

import React from 'react';
import RAGChatComponent from './components/RAGChatComponent';

function App() {
  return (
    <div className="App">
      <RAGChatComponent />
    </div>

  );
}

export default App;
src/components/RAGChatComponent.js

这是主要的功能实现部分,我们将在这里处理用户输入、向后端发送请求以及展示返回的数据流。

import React, { useState } from 'react';

function RAGChatComponent() {
  const [input, setInput] = useState('');
  const [messages, setMessages] = useState('');

  const handleInputChange = (event) => {
    setInput(event.target.value);
  };

  const handleSendMessage = async () => {
    if (input.trim() === '') return;

    try {
      // 发送请求到后端的RAG Chat接口
      const response = await fetch(`http://localhost:8080/ai/streamChat?input=${encodeURIComponent(input)}`);
      const reader = response.body.getReader();
      const decoder = new TextDecoder('utf-8');
      let done = false;

      while (!done) {
        const { value, done: readerDone } = await reader.read();
        done = readerDone;
        const chunk = decoder.decode(value, { stream: true });
        setMessages((prevMessages) => prevMessages + chunk);
      }

      // 在每次请求完成后添加换行符以区分不同轮次的消息
      setMessages((prevMessages) => prevMessages + '\n\n=============================\n\n');
    } catch (error) {
      console.error('Failed to fetch', error);
    }
  };

  const handleClearMessages = () => {
    setMessages('');
  };

  return (
    <div>
      <input
        type="text"
        value={input}
        onChange={handleInputChange}
        placeholder="Enter your message"
      />
      <button onClick={handleSendMessage}>Send</button>

      <button onClick={handleClearMessages}>Clear</button>

      <div>
        <h3>Messages:</h3>

        <pre>{messages}</pre>

      </div>

    </div>

  );
}

export default RAGChatComponent;

运行项目

  1. 启动前端服务:
cd ragChatFrontend
npm start

解释步骤

  • 我们创建了一个新的React应用,并构建了一个简单的界面来与支持检索增强(RAG)的聊天服务进行交互。
  • 用户可以在文本框内输入消息并通过点击“Send”按钮将其发送给后端。
  • 消息通过HTTP GET请求被发送到指定URL,即http://localhost:8080/ai/steamChat?input=...。这里使用了fetch API来发起异步请求,并且通过读取响应体中的数据流来逐步显示返回的内容。
  • 当接收到新数据块时,这些数据会被解码为字符串并追加到当前的消息列表中。
  • 最后,在每次请求完成之后都会插入一个分隔线,以便于清晰地区分不同的对话回合。
  • 提供了一个清除功能,允许用户清空消息历史记录以便开始新一轮对话。

此方案利用了浏览器内置的TextDecoderReadableStream API来高效地处理从服务器接收的数据流,非常适合于实时性要求较高的应用场景如在线聊天等。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构——树、二叉树和森林间的转换

前言 介绍 &#x1f343;数据结构专区&#xff1a;数据结构 参考 该部分知识参考于《数据结构&#xff08;C语言版 第2版&#xff09;》129~130页 &#x1f308;每一个清晨&#xff0c;都是世界对你说的最温柔的早安&#xff1a;ૢ(≧▽≦)و✨ 目录 前言 1、基础知识 2…

Qml-Button的使用

Qml-Button的使用 Button属性 Button的继承关系&#xff1a; Button – AbstractButton – Control – Item; Button的属性主要继承于AbstractButton。AbstractButton属性主要如下&#xff1a; a.action:是一个Action类型属性&#xff0c;与QAction类似&#xff0c;用于提供快…

【论文解读系列】EdgeNAT: 高效边缘检测的 Transformer

代码&#xff1a; https://github.com/jhjie/edgenat 论文&#xff1a; https://arxiv.org/abs/2408.10527v1 论文 EdgeNAT: Transformer for Efficient Edge Detection 介绍了一种名为EdgeNAT的基于Transformer的边缘检测方法。 1. 背景与动机 EdgeNAT预测结果示例。(a, b)…

c语言基础程序——经典100道实例。

c语言基础程序——经典100道实例 001&#xff0c; 组无重复数字的数002&#xff0c;企业发放的奖金根据利润提成003&#xff0c;完全平方数004&#xff0c;判断当天是这一年的第几天005&#xff0c;三个数由小到大输出006&#xff0c;输出字母C图案007&#xff0c;特殊图案008&…

【Petri网导论学习笔记】Petri网导论入门学习(七) —— 1.5 并发与冲突

导航 1.5 并发与冲突1.5.1 并发定义 1.14定义 1.15 1.5.2 冲突定义 1.17 1.5.3 一般Petri网系统中的并发与冲突定义 1.18一般网系统中无冲撞概念阻塞&#xff08;有容量函数K的P/T系统&#xff0c;类似于冲撞&#xff09;一般Petri网中并发与冲突共存情况 1.5 并发与冲突 Petr…

lstm基础知识

lstm前言 LSTM(Long short-term memory)通过刻意的设计来避免长期依赖问题&#xff0c;是一种特殊的RNN。长时间记住信息实际上是 LSTM 的默认行为&#xff0c;而不是需要努力学习的东西&#xff01; 在标准的RNN中&#xff0c;这个重复模块具有非常简单的结构&#xff0c;例…

路由器原理和静态路由配置

一、路由器的工作原理 根据路由表转发数据 接收数据包→查看目的地址→与路由表进行匹配找到转发端口→转发到该端口 二、路由表的形成 它是路由器中维护的路由条目的集合&#xff0c;路由器根据路由表做路径选择&#xff0c;里面记录了网段ip地址和对应下一跳接口的接口号。…

【C语言备课课件】(下)指针pointer

目录 定义type *var_name;初始化int *p &a; // p指向变量a的地址 空指针NULL,野指针&#xff0c;指针悬挂 解引用指针的算术运算指针与数组 数组名—首指针二维数组指针 行指针列指针 多级指针&#xff08;进阶&#xff09;数组指针,指针数组&#xff08;进阶&#xff09…

如何利用 Python抓取网页数据 其他方式抓取网页数据列举

在 Python 中可以使用多种方法抓取网页数据&#xff0c;以下是一种常见的方法&#xff0c;使用requests和BeautifulSoup库。 一、安装所需库 在命令提示符或终端中执行以下命令安装requests和BeautifulSoup库&#xff1a; pip install requests pip install beautifulsoup4二…

python——类

问&#xff1a;小编为什么突然开始发python&#xff1f;难道C语言你不行了&#xff1f; 废话少说&#xff0c;让我们进入python中的类的学习&#xff01;&#xff01; &#xff08;一&#xff09;基本知识 &#xff08;1&#xff09;掌握类的概念 1、类的定义&#xff1a; 即…

python安装transformer教程

本章教程,记录在Windows中如何使用python安装transformer。 一、安装依赖 pip install transformers推荐使用国内镜像源,速度会快很多。 二、测试代码 from transformers import pipeline# 加载一个文本生成模型 text_generator = pipe

LCWLAN设备的实际使用案例

我们的LCWLAN设备在实际使用中以裸板的形式放在客户的智能总线控制器中&#xff0c;客户的 智能总线刀片灯&#xff0c;柔性灯货架&#xff0c;柔性感应钢网柜以及智能电子料架等设备都是接到总线控制 器中&#xff0c;然后总控制器通过CAN总线和我们的LCWLAN设备连接&#xff…

Linux DEADLINE调度算法详解

介绍 在实时系统中&#xff0c;调度算法的选择对于任务的及时执行至关重要。为了满足实时性需求&#xff0c;Linux内核引入了不同的调度算法&#xff0c;其中 DEADLINE 调度算法是为硬实时任务而设计的。DEADLINE 调度算法的目标是在多任务的情况下确保任务在其指定的最后期限…

Cpp::STL—容器适配器Stack和Queue的讲解和模拟实现(15)

文章目录 前言一、适配器模式概念分类 二、Stack核心作用代码实现 三、Queue核心作用代码实现 四、deque双端队列貌似兼收并蓄&#xff1f;实则也难以兼得~ 总结 前言 适配器也是STL六大组件之一&#xff0c;请跟我一起领悟它的智慧&#xff01;   正文开始&#xff01; 一、…

如何实现简单的 WinCC 项目分屏?

说明&#xff1a; 本文主要介绍了在不使用分屏器的情况下&#xff0c;通过 WinCC 项目中的设置&#xff0c;实现简单的分屏操作。两台显示器分别显示不同的 WinCC 画面&#xff0c;独自操作&#xff0c;互不影响。 试验环境 &#xff1a; 本文试验时所用硬件及软件环境…

案例分享—国外优秀UI设计作品赏析

国外UI界面设计之所以出色&#xff0c;首要原因在于其注重用户体验。设计师们深入洞察用户需求&#xff0c;通过细致的用户调研和数据分析&#xff0c;确保界面布局、色彩搭配及交互方式都能贴合用户习惯&#xff0c;从而提供流畅、直观的操作体验&#xff0c;增强用户满意度和…

【MySQL】数据库基础、库的操作、表的操作、数据类型

目录 1. 数据库基础1.1 MySQL是什么1.2 使用案例1.3 服务器&#xff0c;数据库&#xff0c;表关系 2. 库的操作2.1 字符集和校验规则2.1.1 查看系统默认字符集以及校验规则2.1.2 查看数据库的字符集和校验规则2.1.3 修改数据库的字符集和校验规则 2.2 库的操作2.2.1 创建数据库…

c++算法第4天

本篇文章包含三道算法题&#xff0c;难度由浅入深&#xff0c;适合新手练习哟 第一题 题目链接 牛牛的快递_牛客题霸_牛客网 题目解析 <1kg -------> 20元 大于1kg&#xff1a;超出部分每千克1元 加急 5元 代码原理 代码编写 #include …

QT 实现自定义水波进度条

1.界面实现效果 以下是具体的项目需要用到的效果展示。 2.简介 原理:随着进度的改变,在我们的绘制图像void paintEvent(QPaintEvent *) override;事件中绘制图形。 使用QPainter来绘制正弦波,通过定时器,不断的更新我们绘制的图形,动态改变正弦波的参数来创建动画效果…

【从零开始的LeetCode-算法】3099. 哈沙德数

如果一个整数能够被其各个数位上的数字之和整除&#xff0c;则称之为 哈沙德数&#xff08;Harshad number&#xff09;。给你一个整数 x 。如果 x 是 哈沙德数 &#xff0c;则返回 x 各个数位上的数字之和&#xff0c;否则&#xff0c;返回 -1 。 示例 1&#xff1a; 输入&am…