你通过本篇文章可以快速了解 智能问答系统的主要组成部分。

然后可以在10分钟内的完成一个java版本的问答系统,来体会整个流程和环节。



智能问答系统介绍:

智能问答系统是一种先进的人类与计算机交互方式,它利用自然语言处理技术解析用户提出的问题,并从其知识库中查找相关信息以生成准确的答案。这种系统在在线客服、个人助手及教育等多个领域有着广泛应用,极大地提升了信息获取的速度和准确性。构成此类系统的几个核心组件包括:

自然语言处理(NLP):负责识别问题意图;

知识库:作为回答的基础数据源;高效的检索与匹配算法,确保快速找到最相关的答案;

对话生成:能够根据上下文合成易于理解的回答文本。

评估反馈:通过持续学习改善系统性能。这些部分协同工作,共同构建了一个高效且用户友好的问答平台。

随着大语言模型的落地,问答系统完全可以使用大语言模型来做,里面的自然语言处理,答案生成部分,就可以用大模型来做,而知识库和检索匹配算法,则可以用RAG检索增强技术来做。

后面的例子,我们使用 spring ai alibaba + 通义千问Qwen api 来构建这个智能问答系统 , qwen有100万免费Token额度,可以快速实现需求。同时,因为qwen 也是个开源的模型,我们可以自己搭建模型来实现免费使用

Spring AI Alibaba框架介绍

Spring AI Alibaba 是由Spring官方团队维护的一个框架,专为接入阿里云的AI服务设计。它提供了统一的接口,让开发者能够轻松对接不同AI供应商(如OpenAI、Azure、阿里云等)而无需更改大量代码,只需调整配置即可实现切换。这一特性极大简化了开发和迁移过程中的工作量。此外,该框架还融合了阿里云在AI领域的最佳实践,支持多种生成式任务,包括对话、文生图、文生语音等,并且具备RAG等功能,使Java开发者能更高效地构建智能应用。


通义千问大模型介绍:

通义千问大模型在MMLU、TheoremQA、GPQA等基准测评中表现出色,超越了Llama 3 70B。它在Hugging Face开源大模型排行榜Open LLM Leaderboard上荣登榜首。这一成就得益于其强大的语言理解和生成能力,能够准确回答各种问题,并提供高质量的文本生成。通义千问大模型在多个领域的知识广泛且深入,具备出色的推理和解决问题的能力。无论是学术研究还是实际应用,通义千问大模型都能为用户提供卓越的支持。

另外,在真人参与评测的arena里面,它不仅在思南平台 https://arena.opencompass.org.cn/ 上仅次于国际知名的GPT和Claude系列,还在 Hugging Face的视觉模型竞技场 https://huggingface.co/spaces/lmarena-ai/chatbot-arena-leaderboard 中暂居中国首位。

一文搞定:java构建AI问答系统-基于人工智能大模型-LLM-spring ai alibaba_App


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

检索增强生成(RAG)是一种结合了检索模型与生成模型的技术,通过从私有或专有的数据源中获取信息来辅助文本生成。它解决了使用大模型时常见的问题,如模型产生幻觉以及由于缺乏企业内部数据而导致的回答不够精准和泛化的问题。通过集成私有知识库,RAG能够利用特定领域的详尽资料,提供更准确、针对性更强的回复。


基于RAG技术的后端代码开发

为了通过检索增强 (RAG) 的方式读取一个名为“智能问答的问题集.docs”的PDF文件,并构建向量索引,然后提供对外服务,你需要遵循以下步骤来配置和编写后端代码。这些步骤将基于Spring AI Alibaba与阿里云百炼平台集成的知识来进行。

配置环境

首先确保你的开发环境满足以下要求:

  • JDK版本需在17(含)以上。
  • Spring Boot版本需在3.3.x以上。
  • 在阿里云申请通义千问的API key,并将其配置到你的项目中。

配置阿里云API Key

export AI_DASHSCOPE_API_KEY=your_valid_api_key_here

并在application.propertiesapplication.yml中添加如下配置项:

spring.ai.dashscope.api-key: ${AI_DASHSCOPE_API_KEY}

添加Spring仓库及依赖

确保你的pom.xml包含正确的仓库信息以及所需的依赖项。

<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>

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

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

    <version>1.0.0-M2</version>

  </dependency>

  <!-- 其他必要的依赖 -->
</dependencies>

编写RAG服务类

接下来,我们需要定义一个RAG服务类来处理文档的读取、向量存储以及查询逻辑。

public class RagService {

  private final ChatClient chatClient;
  private final VectorStore vectorStore;
  private final DashScopeApi dashscopeApi = new DashScopeApi("your_valid_api_key_here");

  DocumentRetriever retriever;

  public RagService(ChatClient chatClient, EmbeddingModel embeddingModel) {
    this.chatClient = chatClient;
    vectorStore = new DashScopeCloudStore(dashscopeApi, new DashScopeStoreOptions("intelligent_qa"));
    retriever = new DashScopeDocumentRetriever(dashscopeApi,
            DashScopeDocumentRetrieverOptions.builder().withIndexName("intelligent_qa").build());
  }

  // 构建索引的方法
  public String buildIndex() {
    String filePath = "/path/to/智能问答的问题集.docs";
    DocumentReader reader = new DashScopeDocumentCloudReader(filePath, dashscopeApi, null);
    List<Document> documentList = reader.get();
    vectorStore.add(documentList);
    return "SUCCESS";
  }

  // 查询方法
  public StreamResponseSpec queryWithDocumentRetrieval(String message) {
    return chatClient.prompt().user(message)
            .advisors(new DocumentRetrievalAdvisor(retriever, DEFAULT_USER_TEXT_ADVISE)).stream();
  }
}

提供RESTful API接口

最后一步是创建一个控制器类来暴露两个端点:一个用于构建索引,另一个用于根据用户输入生成响应。

@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", defaultValue = "") String input,
                               HttpServletResponse httpResponse) {
    StreamResponseSpec chatResponse = ragService.queryWithDocumentRetrieval(input);
    httpResponse.setCharacterEncoding("UTF-8");
    return chatResponse.content();
  }

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

上述步骤详细介绍了如何设置Spring AI Alibaba应用程序以使用RAG技术处理特定格式的文档,并通过HTTP请求提供交互式聊天功能。请确保按照指示正确配置项目,并替换示例中的路径和密钥等具体值。


增强前端代码的检索功能

在构建一个基于React的支持流输出的前端项目时,首先需要确保你的开发环境已经安装了Node.js和npm。这个项目将通过HTTP请求与后端通信,以获取流式数据。下面根据提供的知识详细说明如何实现这样一个应用程序。

创建并配置React应用

开始前,请先创建一个新的React应用,并进入该目录安装必要的依赖项:

npx create-react-app stream-chat-app
cd stream-chat-app
npm install

这会为你设置好基本的React项目结构。接下来,我们将调整一些默认文件以适应我们的需求。

修改 public/index.html

保持此文件内容不变,因为它定义了一个简单的HTML文档结构,其中包含一个用于挂载React组件的<div id="root"></div>元素。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Chat App</title>

</head>

<body>
  <div id="root"></div>

</body>

</html>

更新 src/index.js

这里也不需要做太多更改,它主要是用来渲染<App />组件到DOM上。

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

App.js将是主组件,负责展示聊天界面以及管理其状态。

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

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

  );
}

export default App;

实现聊天组件

主要的功能将在ChatComponent中实现,包括处理用户输入、发送消息给服务器并通过流接收响应。

新建 src/components/ChatComponent.js

这里定义了聊天的主要逻辑:捕获用户输入、发送请求、读取返回的数据流并显示它们。

import React, { useState } from 'react';

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

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

  const handleSendMessage = async () => {
    try {
      const response = await fetch(`http://localhost:8080/ai/steamChat?input=${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((preMessages) => preMessages + chunk);
      }

      // 添加分隔符
      setMessages((preMessages) => preMessages + '\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 ChatComponent;

这段代码展示了如何使用React Hooks(特别是useState)来管理本地状态,同时利用fetch API连接至指定的后端URL,通过读取响应体中的字节流实时更新UI上的消息列表。

启动并测试项目

最后,你可以运行以下命令启动你的React应用,并访问http://localhost:3000查看效果:

npm start

以上步骤提供了从零开始构建一个支持流式数据传输的简单聊天应用的方法。需要注意的是,为了使该示例正常工作,你需要保证后端服务正在运行并且允许来自前端应用的CORS(跨源资源共享)请求。