1.redis 可以作为内部资源的缓存数据库,把有效的数据放到redis时,当用户来调用,先优先从redis中进行匹配,来丰富请求内容。
2.然后把拼装好的内容,再发给LLM,这里使用deepseek。
准备好redis的环境。
第一步:读取文件,加载到redis中
java
package com.example.LLm03;
import com.fasterxml.jackson.databind.ObjectMapper;
import redis.clients.jedis.Jedis;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class FaqService {
private static final String REDIS_KEY_PREFIX = "faq:";
private static final ObjectMapper objectMapper = new ObjectMapper();
private final Jedis jedis;
public FaqService(Jedis jedis) {
this.jedis = jedis;
}
/**
* 把文件加载放到redis中
* 前缀:faq: 后缀拼接行数,
* 结果为 faq:0, faq:1 格式
* @throws IOException
*/
public void loadFaqDataToRedis() throws IOException {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("train_zh.txt");
if (inputStream == null) {
throw new FileNotFoundException("File not found in resources: data.json");
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String line;
int index = 0;
while ((line = reader.readLine()) != null) {
if (line.trim().isEmpty()) continue;
FaqItem item = objectMapper.readValue(line, FaqItem.class);
String key = REDIS_KEY_PREFIX + index++;
jedis.set(key, line); // 存储原始字符串,方便后续读取
}
}
}
public void loadFaqDataToRedis2() {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("train_zh.txt");
// JSON文件路径(替换为你的实际文件路径)
String jsonFilePath = "train_zh.txt";
// Jackson核心对象,用于反序列化
ObjectMapper objectMapper = new ObjectMapper();
// try-with-resources自动关闭流,避免资源泄漏
try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String line;
int lineNum = 1;
// 循环读取每一行
while ((line = br.readLine()) != null) {
System.out.println("第" + lineNum + "行读取内容:" + line);
// 将每行内容拼接到StringBuilder中
lineNum++;
// 1. 获取完整的JSON字符串
// 2. 将JSON字符串反序列化为Java对象
FaqItem rdmConfig = objectMapper.readValue(line, FaqItem.class);
String key = REDIS_KEY_PREFIX + lineNum++;
jedis.set(key, line); // 存储原始字符串,方便后续读取
// 3. 打印转换后的对象信息
System.out.println("\nJSON转换为Java对象结果:");
System.out.println(rdmConfig);
}
} catch (IOException e) {
System.err.println("读取JSON文件或反序列化失败:" + e.getMessage());
e.printStackTrace();
}
}
/**
* 用户查询时,先从redis进行精确匹配,
* @param keyword 用户输入关键字
* @param topNum 返回行数
* @return
* @throws IOException
*/
public List<FaqItem> searchInstructionByKeyword(String keyword,int topNum) throws IOException {
Set<String> keys = jedis.keys(REDIS_KEY_PREFIX + "*");
List<FaqItem> result = new ArrayList<>();
for (String key : keys) {
String json = jedis.get(key);
FaqItem item = objectMapper.readValue(json, FaqItem.class);
if (item.getInstruction().contains(keyword)) {
result.add(item);
}
if(result.size() >= topNum) {
break;
}
}
return result;
}
}
加载的对象结构体:
java
package com.example.LLm03;
public class FaqItem {
private String instruction;
private String input;
private String output;
// Getters and Setters
public String getInstruction() {
return instruction;
}
public void setInstruction(String instruction) {
this.instruction = instruction;
}
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
public String getOutput() {
return output;
}
public void setOutput(String output) {
this.output = output;
}
@Override
public String toString() {
return "FaqItem{" +
"instruction='" + instruction + '\'' +
", input='" + input + '\'' +
", output='" + output + '\'' +
'}';
}
}
java
package com.example.LLm03;
import com.example.llm01.LLMUtils;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import java.util.List;
import java.util.stream.Collectors;
/**
* 加载数据并存在到Redis中
* @throws Exception
*/
public class loadRedisFileData{
/**
* 加载数据并存在到Redis中
* @throws Exception
*/
@Test
public void loadRedisFileData() throws Exception{
Jedis jedis = new Jedis("localhost", 6379);
jedis.auth("000000");
FaqService faqService = new FaqService(jedis);
faqService.loadFaqDataToRedis();
// faqService.loadFaqDataToRedis2();
}
/**
* 1.从redis中取到关键字
* 2.拼接成有效的上下文,请求LLM
* @throws Exception
*/
@Test
public void rag1() throws Exception{
String prompt = "甲状腺囊肿如何治疗";
// 检索相关的内容
Jedis jedis = new Jedis("localhost", 6379);
jedis.auth("000000");
FaqService faqService = new FaqService(jedis);
List<FaqItem> list = faqService.searchInstructionByKeyword(prompt, 1);
// 把这个集合拼接为一个字符串
String result = list.stream()
.map(item -> "Q: " + item.getInstruction() + "\nA: " + item.getOutput())
.collect(Collectors.joining("\n"));
System.out.println(result);
String role="你是一个问答机器人。" +
"你的任务是根据下述给定的已知信息回答用户问题。" +
"根据已知信息的内容推理给出用户问题的解决方案。" +
"确保你的回复完全依据下述已知信息。不要编造答案。" +
"如果下述已知信息不足以回答用户的问题,请直接回复我无法回答您的问题。";
// 构建 Prompt
prompt = String.format("""
已知信息:
%s
用户问题:
%s
请用中文回答用户问题。
""", result, prompt);
// 然后把新的Prompt提交给大模型。看看对应的输出结果是怎么样的?
// String completion = LLMUtils.completion2("医生","感冒", "deepseek-chat");
//LLMUtils.completion2(role,prompt, "deepseek-chat");
String completion = LLMUtils.chatCompletion(role,prompt);
System.out.println(completion);
}
}
Redis 存储数据结果
调用 LLM 代码:
java
public static String chatCompletion(String systemPrompt, String userPrompt) throws Exception {
// 会话记忆
OkHttpClient client = new OkHttpClient().newBuilder(). build();
ObjectMapper mapper = new ObjectMapper();
// 使用ObjectNode构建请求体
ObjectNode requestBody = mapper.createObjectNode();
requestBody.put("model", "deepseek-chat");
ArrayNode messages = mapper.createArrayNode();
messages.addObject().put("role", "system").put("content", systemPrompt);
messages.addObject().put("role", "user").put("content", userPrompt);
requestBody.set("messages", messages);
String jsonBody = mapper.writeValueAsString(requestBody);
RequestBody body = RequestBody.create( MediaType.parse("application/json"),jsonBody);
Request request = new Request.Builder()
.url("https://api.deepseek.com/chat/completions")
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "Bearer " + API_KEY) // 从环境变量读取
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response + ", body: " + response.body().string());
}
String json= response.body().string(); // 返回原始JSON响应
// 解析返回的内容
JsonNode root = mapper.readTree(json);
JsonNode choices = root.get("choices");
if (choices != null && choices.isArray() && choices.size() > 0) {
return choices.get(0).get("message").get("content").asText();
}
return "No response content found.";
}
}
文件位置:

html
{"instruction": "1前几天体检时医生说我有甲状腺囊肿,我也没有什么感觉啊,为什么会长这个东西啊", "input": "","output": "1甲状腺囊肿是甲状腺疾病的一种,它是指甲状腺内出现的一个或多个液体囊肿。甲状腺囊肿的形成原因比较复杂,可能是由于甲状腺内的一些细胞发生异常增生,导致甲状腺组织在某些部位形成了囊肿,也可能是由于甲状腺内的一些细胞因为某种原因死亡,导致甲状腺组织在某些部位形成了囊肿。\n\n甲状腺囊肿一般不会有特别明显的症状,有的患者可能会出现颈部肿块或者轻微的不适感,但大部分患者是没有任何症状的。如果甲状腺囊肿较大或者压迫周围的组织或器官,可能会引起一些症状,如吞咽困难、呼吸困难、声音嘶哑等。\n\n如果您被诊断出有甲状腺囊肿,建议您定期复查,如果囊肿增大或引起症状,可能需要进行手术治疗。同时,保持良好的生活习惯,均衡饮食,避免过度疲劳和过度紧张,也有助于预防和治疗甲状腺囊肿。"}
{"instruction": "2前几天体检时医生说我有甲状腺囊肿,我也没有什么感觉啊,为什么会长这个东西啊", "input": "","output": "2甲状腺囊肿是甲状腺疾病的一种,它是指甲状腺内出现的一个或多个液体囊肿。甲状腺囊肿的形成原因比较复杂,可能是由于甲状腺内的一些细胞发生异常增生,导致甲状腺组织在某些部位形成了囊肿,也可能是由于甲状腺内的一些细胞因为某种原因死亡,导致甲状腺组织在某些部位形成了囊肿。\n\n甲状腺囊肿一般不会有特别明显的症状,有的患者可能会出现颈部肿块或者轻微的不适感,但大部分患者是没有任何症状的。如果甲状腺囊肿较大或者压迫周围的组织或器官,可能会引起一些症状,如吞咽困难、呼吸困难、声音嘶哑等。\n\n如果您被诊断出有甲状腺囊肿,建议您定期复查,如果囊肿增大或引起症状,可能需要进行手术治疗。同时,保持良好的生活习惯,均衡饮食,避免过度疲劳和过度紧张,也有助于预防和治疗甲状腺囊肿。"}