当前位置: 首页 > news >正文

微信公众号网页授权登录wordpress厦门seo全网营销

微信公众号网页授权登录wordpress,厦门seo全网营销,广州网站建设设计公司,linux系统网站空间Spring AI之Java经典面试题智能小助手 前言一、准备面试题二、搭建工程三、文件读取与解析四、Markdown文件解析五、问题搜索六、自定义EmbeddingClient七、定义请求Controller 前言 通过Ollama在本地部署了Llama3大模型,这篇来基于Llama3和Spring AI,以…

Spring AI之Java经典面试题智能小助手

  • 前言
  • 一、准备面试题
  • 二、搭建工程
  • 三、文件读取与解析
  • 四、Markdown文件解析
  • 五、问题搜索
  • 六、自定义EmbeddingClient
  • 七、定义请求Controller

前言

通过Ollama在本地部署了Llama3大模型,这篇来基于Llama3和Spring AI,以及ChatGPT Web来实现一个Java经典面试题智能小助手。
私有化部署大模型最佳解决方案 Ollama

一、准备面试题

建议优先使用marddown或txt等文本格式,因为经过尝试,如果导出为PDF格式,会出现格式错乱。

ThreadLocal和InheritableThreadLocal的区别
ThreadLocal和InheritableThreadLocal都可以用通过线程来共享数据,区别在于当前线程在InheritableThreadLocal中设置的值可以被子线程继承,并且是复制(也就是子线程和父线程一开始InheritableThreadLocal中的值时一致的,但是后续的修改互不影响),而当前线程在ThreadLocal中设置的值不会被子线程所继承。

如何理解Java中的装箱与拆箱
装箱,就是int类型包装为Integer类型,拆箱,就是反过来,因为Java中支持8种基本数据类型,每种基本类型都有对应的包装类型,装箱会调用valueOf()方法,传入基本类型,返回包装类型,这个方法中通常会有一个缓存,比如用来缓存数字1对应的Integer对象,拆箱会调用intValue()方法,返回基本类型,不要过多的进行装箱和拆箱,毕竟是在调方法,是消耗性能的。

Java中为什么要有基础类型
Java是面向对象的,一切都是对象,但是像字符、数字这些常用类型,每次用的时候也去new对象,就会比较费性能和内存了,所以Java设计了8种基础类型,在使用基础类型时,对应的内存空间是直接分配在栈上的,而不是分配在堆上,这样性能也更好。

说说进程和线程的区别
一个操作系统上会运行很多个程序,这些程序都有自己的代码,以及都要用内存来存代码,和代码运行过程中产生的数据,进程就是用来隔离各个程序的内存空间的,使得程序之间互不干扰,还是这多个程序,为了让它们能同时运行,CPU就需要先执行这个程序的几条指令,然后切换到另外一个程序去执行,然后再切回来,就像同时在运行多条指令流水线,而这个流水线就是线程,是CPU调度的最小单位

为什么Java不支持多继承?
首先,思考这么一种场景,假如现在A类继承了B类和C类,并且B类和C类中,都存在test()方法,那么当A类对象调用test()方法时,该调用B类的test()呢?还是C类的test()呢?是没有答案的,所以Java中不允许多继承。

String、StringBuffer、StringBuilder的区别

  1. String是不可变的,如果尝试去修改,会新生成一个字符串对象,StringBuffer和StringBuilder是可变的
  2. StringBuffer是线程安全的,StringBuilder是线程不安全的,所以在单线程环境下StringBuilder效率会更高

二、搭建工程

引入SpringBoot:

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.1</version>
</parent>

引入Spring AI

<dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>0.8.1-SNAPSHOT</version><type>pom</type><scope>import</scope></dependency></dependencies>
</dependencyManagement>

引入spring web

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

引入Ollama

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>

引入Markdown解析器

<dependency><groupId>com.vladsch.flexmark</groupId><artifactId>flexmark</artifactId><version>0.42.14</version>
</dependency>

引入Redis向量数据库相关

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-redis</artifactId>
</dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>5.1.0</version>
</dependency>

指定仓库

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

三、文件读取与解析

新建InterviewService,提供向量存储、向量搜索功能:

@Bean
public RedisVectorStore vectorStore(EmbeddingClient embeddingClient) {RedisVectorStore.RedisVectorStoreConfig config = RedisVectorStore.RedisVectorStoreConfig.builder().withURI("redis://localhost:6379").withIndexName("interview-assistant-index").withMetadataFields(RedisVectorStore.MetadataField.text("filename")).build();return new RedisVectorStore(config, embeddingClient);
}
package com.qjc.demo.service;import org.springframework.ai.document.Document;
import org.springframework.ai.reader.TextReader;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;import java.util.List;/**** @projectName spring-ollama-demo* @packageName com.qjc.demo.service* @author qjc* @description TODO* @Email qjc1024@aliyun.com* @date 2024-10-18 10:23**/@Component
public class InterviewService {@Value("classpath:Java基础面试题.md")private Resource resource;@Autowiredprivate VectorStore vectorStore;public List<Document> loadText() {// 读取文件内容TextReader textReader = new TextReader(resource);List<Document> documents = textReader.get();// 解析文件内容MarkdownSplitter textSplitter = new MarkdownSplitter();List<Document> list = textSplitter.apply(documents);// 将问题提取出来存入Metadatalist.forEach(document -> {String title = document.getContent().split("==title==")[0];String replace = title.replace("##", "");document.getMetadata().put("question", replace.trim());});// 向量化以及向量存储vectorStore.add(list);return list;}public List<Document> search(String message){// ...}
}

四、Markdown文件解析

思路是:通过解析文件中的二级标题和标题下的内容,得到一个Document,标题和内容直接用"title"分割。

package com.com.qjc.demo.utils;import com.vladsch.flexmark.ast.Heading;
import com.vladsch.flexmark.parser.Parser;
import com.vladsch.flexmark.util.ast.Document;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.collection.iteration.ReversiblePeekingIterator;
import org.springframework.ai.transformer.splitter.TextSplitter;import java.util.ArrayList;
import java.util.List;
/**** @projectName spring-ollama-demo* @packageName com.qjc.demo.utils* @author qjc* @description TODO* @Email qjc1024@aliyun.com* @date 2024-10-18 10:23**/
public class MarkdownSplitter extends TextSplitter {@Overrideprotected List<String> splitText(String text) {Parser parser = Parser.builder().build();Document markdownDocument = parser.parse(text);List<String> result = new ArrayList<>();ReversiblePeekingIterator<Node> iterator = markdownDocument.getChildren().iterator();StringBuilder builder = new StringBuilder();while (iterator.hasNext()) {Node node = iterator.next();// 如果是二级标题if (node instanceof Heading && ((Heading) node).getLevel() == 2) {if (!builder.isEmpty()) {result.add(builder.toString());}builder.delete(0, builder.length());builder.append(node.getChars());builder.append("==title==");} else {builder.append(node.getChars());}}if (!builder.isEmpty()) {result.add(builder.toString());}return result;}
}

五、问题搜索

public List<Document> search(String question){// 先查元数据SearchRequest metaSearchRequest = SearchRequest.query(question).withTopK(3).withSimilarityThreshold(0.9).withFilterExpression(String.format("question in ['%s']", question));List<Document> metaDocuments = vectorStore.similaritySearch(metaSearchRequest);if (!CollectionUtils.isEmpty(metaDocuments)) {return metaDocuments;}// 元数据没查到在相似搜索SearchRequest searchRequest = SearchRequest.query(question).withTopK(3).withSimilarityThreshold(0.9);return vectorStore.similaritySearch(searchRequest);}

六、自定义EmbeddingClient

默认情况下是对问题和答案同时进行向量化,如果只想对问题进行向量化,则需要自定义EmbeddingClient:

package com.qjc.demo.config;import org.springframework.ai.document.Document;
import org.springframework.ai.ollama.OllamaEmbeddingClient;
import org.springframework.ai.ollama.api.OllamaApi;import java.util.List;/**** @projectName spring-ollama-demo* @packageName com.qjc.demo.config* @author qjc* @description TODO* @Email qjc1024@aliyun.com* @date 2024-10-18 10:23**/
public class QjcOllamaEmbeddingClient extends OllamaEmbeddingClient {public QjcOllamaEmbeddingClient (OllamaApi ollamaApi) {super(ollamaApi);}@Overridepublic List<Double> embed(Document document) // 单独对问题进行向量化String question = (String) document.getMetadata().get("question");return this.embed(question);}
}
@Beanpublic QjcOllamaEmbeddingClient ollamaEmbeddingClient(OllamaApi ollamaApi, OllamaEmbeddingProperties properties) {QjcOllamaEmbeddingClient qjcOllamaEmbeddingClient = new QjcOllamaEmbeddingClient (ollamaApi);qjcOllamaEmbeddingClient.withModel("nomic-embed-text:v1.5");return qjcOllamaEmbeddingClient;}

七、定义请求Controller

package com.qjc.demo.controller;import org.springframework.ai.chat.ChatClient;
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.StreamingChatClient;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.openai.api.OpenAiApi;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/**** @projectName spring-ollama-demo* @packageName com.qjc.demo.controller* @author qjc* @description TODO* @Email qjc1024@aliyun.com* @date 2024-10-18 10:23**/
@RestController
public class ChatController {@Autowiredprivate StreamingChatClient chatClient;@Autowiredprivate InterviewService interviewService;@GetMapping("/document")public List<Document> document() {return interviewService.loadText();}@GetMapping("/documentSearch")public List<Document> documentSearch(@RequestParam String message) {return interviewService.search(message);}@PostMapping(value = "/v1/chat/completions", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<OpenAiApi.ChatCompletionChunk> interview(@RequestBody OpenAiApi.ChatCompletionRequest request) {String question = request.messages().get(1).content();// 向量搜索List<Document> documentList = interviewService.search(question);// 提示词模板PromptTemplate promptTemplate = new PromptTemplate("{userMessage}\n\n 用中文,并根据以下信息回答问题:\n {contents}");// 组装提示词Prompt prompt = promptTemplate.create(Map.of("userMessage", question, "contents", documentList));// 调用大模型Flux<ChatResponse> stream = chatClient.stream(prompt);return stream.map(chatResponse -> {String content = chatResponse.getResult().getOutput().getContent();// 需要优化OpenAiApi.ChatCompletionChunk chatCompletionChunk = new OpenAiApi.ChatCompletionChunk("1",List.of(new OpenAiApi.ChatCompletionChunk.ChunkChoice(OpenAiApi.ChatCompletionFinishReason.STOP,1,new OpenAiApi.ChatCompletionMessage(content,OpenAiApi.ChatCompletionMessage.Role.ASSISTANT), new OpenAiApi.LogProbs(null))),null, null, null, null);return chatCompletionChunk;});}
}

文章转载自:
http://dinncoramate.tqpr.cn
http://dinncolepidolite.tqpr.cn
http://dinncostitch.tqpr.cn
http://dinncodescription.tqpr.cn
http://dinncowolfbane.tqpr.cn
http://dinncoappro.tqpr.cn
http://dinncolossmaker.tqpr.cn
http://dinncoallocatee.tqpr.cn
http://dinncoeponymy.tqpr.cn
http://dinncodurkheimian.tqpr.cn
http://dinncolasable.tqpr.cn
http://dinncomanometry.tqpr.cn
http://dinncopredatory.tqpr.cn
http://dinncoskatol.tqpr.cn
http://dinncoasepsis.tqpr.cn
http://dinncoaerobacter.tqpr.cn
http://dinncostalactic.tqpr.cn
http://dinncospleeny.tqpr.cn
http://dinncocaesalpiniaceous.tqpr.cn
http://dinncosiamese.tqpr.cn
http://dinncogilbertese.tqpr.cn
http://dinncoasymptomatic.tqpr.cn
http://dinncokabul.tqpr.cn
http://dinncococcidiosis.tqpr.cn
http://dinncocineole.tqpr.cn
http://dinncohypercorrectness.tqpr.cn
http://dinncosaccharize.tqpr.cn
http://dinncosneer.tqpr.cn
http://dinncoukase.tqpr.cn
http://dinncoortolan.tqpr.cn
http://dinncofowl.tqpr.cn
http://dinncopolydymite.tqpr.cn
http://dinncomerger.tqpr.cn
http://dinncogymnastic.tqpr.cn
http://dinncoelbert.tqpr.cn
http://dinncosapan.tqpr.cn
http://dinncooversimple.tqpr.cn
http://dinncoveterinarian.tqpr.cn
http://dinnconfc.tqpr.cn
http://dinncosentence.tqpr.cn
http://dinncosalability.tqpr.cn
http://dinncoedaphic.tqpr.cn
http://dinncochook.tqpr.cn
http://dinncophysoclistous.tqpr.cn
http://dinncoscaldingteass.tqpr.cn
http://dinncoreceivership.tqpr.cn
http://dinncoearpick.tqpr.cn
http://dinncolacedaemonian.tqpr.cn
http://dinncocosecant.tqpr.cn
http://dinncogloat.tqpr.cn
http://dinncopitiably.tqpr.cn
http://dinncomonostomous.tqpr.cn
http://dinncogibblegabble.tqpr.cn
http://dinncoconform.tqpr.cn
http://dinncolaryngitis.tqpr.cn
http://dinncojeans.tqpr.cn
http://dinncoincense.tqpr.cn
http://dinncocardioid.tqpr.cn
http://dinncolutestring.tqpr.cn
http://dinncodisaster.tqpr.cn
http://dinncoupswept.tqpr.cn
http://dinncochabuk.tqpr.cn
http://dinncoparegoric.tqpr.cn
http://dinncocanis.tqpr.cn
http://dinncounicode.tqpr.cn
http://dinncohypolimnion.tqpr.cn
http://dinncodisbar.tqpr.cn
http://dinncovinyl.tqpr.cn
http://dinncohatchery.tqpr.cn
http://dinncometastasize.tqpr.cn
http://dinncoaffluence.tqpr.cn
http://dinncoteknonymy.tqpr.cn
http://dinncoer.tqpr.cn
http://dinncoinfirmarian.tqpr.cn
http://dinncosacrilege.tqpr.cn
http://dinncoannulose.tqpr.cn
http://dinncohockshop.tqpr.cn
http://dinncotrochometer.tqpr.cn
http://dinncobleacherite.tqpr.cn
http://dinncocgt.tqpr.cn
http://dinncotile.tqpr.cn
http://dinncohematozoon.tqpr.cn
http://dinncosagacity.tqpr.cn
http://dinncoaspectant.tqpr.cn
http://dinncoalgonkin.tqpr.cn
http://dinncowoofter.tqpr.cn
http://dinncocurtail.tqpr.cn
http://dinncoflaringly.tqpr.cn
http://dinncocalorimetry.tqpr.cn
http://dinncocyclostomatous.tqpr.cn
http://dinncoimpi.tqpr.cn
http://dinncovestibule.tqpr.cn
http://dinncogallophobia.tqpr.cn
http://dinncolwv.tqpr.cn
http://dinncoaeropause.tqpr.cn
http://dinncohyperboloidal.tqpr.cn
http://dinncoforefeel.tqpr.cn
http://dinncodestain.tqpr.cn
http://dinncouncivilized.tqpr.cn
http://dinncosixte.tqpr.cn
http://www.dinnco.com/news/120134.html

相关文章:

  • 口碑好的黄石网站建设电商最好卖的十大产品
  • 北京网站建设著名公司宁波怎么优化seo关键词
  • 企业网站开发用什么成都seo培训班
  • 品牌建设实施纲要黑帽seo排名
  • 精英学校老师给学生做的网站百度搜索推广创意方案
  • 石家庄企业网站开发今日新闻简报
  • 网站建设详细设计新闻联播今日新闻
  • 找外包公司做网站价钱成人职业技能培训学校
  • 毕业设计网站可以做什么免费建站建站abc网站
  • 廊坊seo排名霸屏网站优化基本技巧
  • 外宣做网站宣传国家职业技能培训平台
  • 天津微信网站开发整站优化 mail
  • 律师网站建设 优帮云软件推广的渠道是哪里找的
  • 海外如何 淘宝网站建设人民日报新闻
  • 高清做网站插图mac923水蜜桃923色号
  • 企业官方网站建设的流程大庆建站公司
  • 做a的网站有哪些seo网站推广方案策划书
  • 罗湖平台网站建设费用上海全网推广
  • php做的购物网站系统下载推广软件赚钱的平台
  • 珠海市网站网络营销方案总结
  • 做公司网站别人能看到吗6seo站长工具平台
  • dw可以用来做网站吗seo策略有哪些
  • jsp做网站网络营销与直播电商专业就业前景
  • 北京好的网站建设网络营销服务企业有哪些
  • 免费做外贸的网站建设优化优化
  • 网站建设教程书籍seo的范畴是什么
  • 公司网页免费制作北京网站优化方案
  • 摄影网站设计代码成都网站制作
  • 建筑设计师要学什么专业网站排名seo
  • 易趣网官网北京seo排名公司