example: add rag application example (#3743)
Signed-off-by: yuluo-yx <yuluo08290126@gmail.com>pull/3755/head
parent
fe7a28e6ec
commit
f0bb69b15b
Before Width: | Height: | Size: 861 KiB After Width: | Height: | Size: 861 KiB |
@ -0,0 +1,9 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis/redis-stack-server
|
||||
container_name: redis
|
||||
hostname: redis
|
||||
ports:
|
||||
- 6379:6379
|
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
Copyright 2023-2024 the original author or authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<parent>
|
||||
<artifactId>spring-cloud-alibaba-examples</artifactId>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-ai-rag-example</artifactId>
|
||||
<name>Spring Cloud Starter Alibaba AI RAG Example</name>
|
||||
<description>Example build RAG Application By Spring Cloud Alibaba AI</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<spring.ai.version>0.8.1</spring.ai.version>
|
||||
<redis.jedis.version>5.1.0</redis.jedis.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-ai</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.ai</groupId>
|
||||
<artifactId>spring-ai-redis-spring-boot-starter</artifactId>
|
||||
<version>${spring.ai.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${redis.jedis.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>${maven-deploy-plugin.version}</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<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>
|
||||
|
||||
</project>
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2013-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.ai.rag;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author yuluo
|
||||
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||
*/
|
||||
|
||||
@SpringBootApplication
|
||||
public class RAGApplication {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RAGApplication.class);
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
SpringApplication.run(RAGApplication.class, args);
|
||||
logger.info("RAGApplication started successfully.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.ai.rag.controller;
|
||||
|
||||
import com.alibaba.cloud.example.ai.rag.service.RAGService;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author yuluo
|
||||
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||
*/
|
||||
|
||||
@CrossOrigin
|
||||
@RestController
|
||||
@RequestMapping("/rag")
|
||||
public class RAGController {
|
||||
|
||||
@Autowired
|
||||
private RAGService ragService;
|
||||
|
||||
@GetMapping("/chat")
|
||||
public String chatMessage(@RequestParam(value = "prompt",
|
||||
defaultValue = "What ber pairs well with smoked meats?") String prompt) {
|
||||
|
||||
return ragService.retrieve(prompt)
|
||||
.getOutput()
|
||||
.getContent();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2013-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.ai.rag.loader;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
|
||||
import org.springframework.ai.reader.JsonReader;
|
||||
import org.springframework.ai.vectorstore.RedisVectorStore;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.core.io.InputStreamResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author yuluo
|
||||
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class RAGDataLoader implements ApplicationRunner {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RAGDataLoader.class);
|
||||
|
||||
private static final String[] KEYS = { "name", "abv", "ibu", "description" };
|
||||
|
||||
@Value("classpath:/data/beers.json.gz")
|
||||
private Resource data;
|
||||
|
||||
private final RedisVectorStore vectorStore;
|
||||
|
||||
private final RedisVectorStoreProperties properties;
|
||||
|
||||
public RAGDataLoader(RedisVectorStore vectorStore, RedisVectorStoreProperties properties) {
|
||||
|
||||
this.vectorStore = vectorStore;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
|
||||
Map<String, Object> indexInfo = vectorStore.getJedis().ftInfo(properties.getIndex());
|
||||
int numDocs = Integer.parseInt((String) indexInfo.getOrDefault("num_docs", "0"));
|
||||
if (numDocs > 20000) {
|
||||
logger.info("Embeddings already loaded. Skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
Resource file = data;
|
||||
if (Objects.requireNonNull(data.getFilename()).endsWith(".gz")) {
|
||||
GZIPInputStream inputStream = new GZIPInputStream(data.getInputStream());
|
||||
file = new InputStreamResource(inputStream, "beers.json.gz");
|
||||
}
|
||||
|
||||
logger.info("Creating Embeddings...");
|
||||
JsonReader loader = new JsonReader(file, KEYS);
|
||||
vectorStore.add(loader.get());
|
||||
logger.info("Embeddings created.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2013-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.cloud.example.ai.rag.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.ai.chat.ChatClient;
|
||||
import org.springframework.ai.chat.ChatResponse;
|
||||
import org.springframework.ai.chat.Generation;
|
||||
import org.springframework.ai.chat.messages.Message;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.chat.prompt.Prompt;
|
||||
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
|
||||
import org.springframework.ai.document.Document;
|
||||
import org.springframework.ai.vectorstore.SearchRequest;
|
||||
import org.springframework.ai.vectorstore.VectorStore;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author yuluo
|
||||
* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
|
||||
*/
|
||||
|
||||
@Service
|
||||
public class RAGService {
|
||||
|
||||
@Value("classpath:/prompts/system-qa.st")
|
||||
private Resource systemBeerPrompt;
|
||||
|
||||
@Value("${topk:10}")
|
||||
private int topK;
|
||||
|
||||
private final ChatClient client;
|
||||
|
||||
private final VectorStore store;
|
||||
|
||||
public RAGService(ChatClient client, VectorStore store) {
|
||||
|
||||
this.client = client;
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
public Generation retrieve(String message) {
|
||||
|
||||
SearchRequest request = SearchRequest.query(message).withTopK(topK);
|
||||
List<Document> docs = store.similaritySearch(request);
|
||||
|
||||
Message systemMessage = getSystemMessage(docs);
|
||||
UserMessage userMessage = new UserMessage(message);
|
||||
|
||||
Prompt prompt = new Prompt(List.of(systemMessage, userMessage));
|
||||
ChatResponse response = client.call(prompt);
|
||||
|
||||
return response.getResult();
|
||||
}
|
||||
|
||||
private Message getSystemMessage(List<Document> similarDocuments) {
|
||||
|
||||
String documents = similarDocuments.stream()
|
||||
.map(Document::getContent)
|
||||
.collect(Collectors.joining("\n"));
|
||||
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemBeerPrompt);
|
||||
|
||||
return systemPromptTemplate.createMessage(Map.of("documents", documents));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright 2023-2024 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: sca-ai-rag-example
|
||||
|
||||
ai:
|
||||
vectorstore:
|
||||
redis:
|
||||
index: peer
|
||||
prefix: peer
|
Binary file not shown.
@ -0,0 +1,7 @@
|
||||
You're assisting with questions about products in a beer catalog.
|
||||
Use the information from the DOCUMENTS section to provide accurate answers.
|
||||
The answer involves referring to the ABV or IBU of the beer, include the beer name in the response.
|
||||
If unsure, simply state that you don't know.
|
||||
|
||||
DOCUMENTS:
|
||||
{documents}
|
Loading…
Reference in New Issue