自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Spring?AI:如何采用Java編寫生成式人工智能應用程序 原創(chuàng)

發(fā)布于 2024-7-8 20:58
瀏覽
0收藏

譯者 | 李睿

審校 | 重樓

生成式人工智能(GenAI)是當今科技界的一個熱門話題。它是人工智能的一個子集,專注于創(chuàng)造新的內(nèi)容,例如文本、圖像或音樂。GenAI組件的一種流行類型是大型語言模型(LLM),它可以根據(jù)提示生成類似人類的文本。檢索增強生成(RAG)是一種基于外部知識來源來提高生成式人工智能模型準確性和可靠性的技術。雖然大多數(shù)GenAI應用程序和相關內(nèi)容都以Python及其生態(tài)系統(tǒng)為中心,但如果采用Java編寫GenAI應用程序應該怎么辦?

Spring?AI:如何采用Java編寫生成式人工智能應用程序-AI.x社區(qū)

本文將介紹如何使用Spring AI框架采用Java編寫GenAI應用程序,并利用RAG改進答案。

什么是Spring AI?

Spring AI是一個用于在Java中構建GenAI應用程序的框架。它提供了一組工具和實用程序,用于處理GenAI模型和架構,例如LLM和RAG。Spring AI構建在Spring框架之上,Spring框架是一個用于構建企業(yè)應用程序的流行Java框架,允許那些已經(jīng)熟悉或參與Spring生態(tài)系統(tǒng)的用戶將GenAI策略合并到他們已經(jīng)存在的應用程序和工作流中。

在Java中也有其他GenAI的選擇,例如Langchain4j,但是在這篇文章中將關注Spring AI。

創(chuàng)建項目

在開始使用Spring AI時,需要創(chuàng)建一個新項目或向現(xiàn)有項目添加適當?shù)囊蕾図?。可以使用Spring Initializr創(chuàng)建一個新項目,這是一個用于生成Spring Boot項目的基于Web的工具。

當創(chuàng)建一個新項目時,需要添加以下依賴項:

  • Spring Web?
  • OpenAI或其他LLM模型(例如Mistral、Ollama等)?
  • Neo4j Vector Database (其他矢量數(shù)據(jù)庫選項也可用)?
  • Spring Data Neo4j?

如果人工將這些依賴項添加到現(xiàn)有項目中,可以在相關的??GitHub存儲庫??中看到依賴項的詳細信息。?

Spring Web依賴項允許開發(fā)人員為GenAI應用程序創(chuàng)建REST API。需要OpenAI依賴來訪問OpenAI模型,這是一個流行的LLM。Neo4j Vector Database依賴項允許存儲和查詢用于相似性搜索的向量。最后,添加Spring Data Neo4j依賴項為在Spring應用程序中使用Neo4j數(shù)據(jù)庫提供了支持,允許在Neo4j中運行Cypher查詢并將實體映射到Java對象。

繼續(xù)生成項目,然后在喜歡的IDE中打開它。查看pom.xml文件,應該會看到里程碑存儲庫已包含在內(nèi)。由于Spring AI還不是一個通用版本,需要包含里程碑存儲庫來獲得依賴項的預發(fā)布版本。

一個樣板文件

構建Neo4j數(shù)據(jù)庫可以使用Neo4j Aura免費層,因為它管理了實例,當然還有Docker鏡像和其他方法。

根據(jù)選擇的LLM模型,還需要API密鑰。對于OpenAI,可以通過在OpenAI注冊獲得API密鑰。

一旦有了Neo4j數(shù)據(jù)庫和API密鑰,就可以在應用程序中設置application.properties文件。以下是一個可能的示例:

Properties files 
 spring.ai.openai.api-key=<YOUR API KEY HERE>
 spring.neo4j.uri=<NEO4J URI HERE>
 spring.neo4j.authentication.username=<NEO4J USERNAME HERE>
 spring.neo4j.authentication.password=<NEO4J PASSWORD HERE>
 spring.data.neo4j.database=<NEO4J DATABASE NAME HERE>

注意:將API密鑰和密碼等敏感信息保存在環(huán)境變量或應用程序外部的其他位置是一個很好的想法。要創(chuàng)建環(huán)境變量,可以在終端中使用export命令或在IDE中設置它們。

可以為OpenAI客戶端和Neo4j矢量存儲設置Spring Beans,這將允許在應用程序中需要的任何地方訪問必要的組件。

可以在SpringAiApplication類中添加以下代碼:

Java 
 @Bean
 public EmbeddingClient embeddingClient() {
 return new OpenAiEmbeddingClient(new OpenAiApi(System.getenv("SPRING_AI_OPENAI_API_KEY")));
 }

 @Bean
 public Neo4jVectorStore vectorStore(Driver driver, EmbeddingClient embeddingClient) {
 return new Neo4jVectorStore(driver, embeddingClient,
 Neo4jVectorStore.Neo4jVectorStoreConfig.builder()
 .withLabel("Review")
 .withIndexName("review-embedding-index")
 .build());
 }

EmbeddingClient bean為OpenAI API創(chuàng)建一個客戶端,并傳入API密鑰環(huán)境變量。最后,Neo4jVectorStore bean將Neo4j配置為嵌入(向量)的存儲。通過為存儲嵌入的節(jié)點指定標簽來定制配置,因為Spring的默認設置是查找Document實體。還為嵌入指定索引名(默認是spring-ai-document-index)。

數(shù)據(jù)集

對于這個例子,將使用來自Goodreads的書籍和評論數(shù)據(jù)集。可以從??這里??獲取數(shù)據(jù)集的精選版本。該數(shù)據(jù)集包含有關書籍的信息以及相關評論。?

已經(jīng)使用OpenAI的API生成了嵌入,所以用戶如果想生成自己的嵌入,需要在腳本中注釋掉最后的Cypher語句,而不是運行generate-embeddings.py腳本(或自定義版本)來生成和加載Neo4j的審查嵌入。

應用程序模型

接下來,需要在應用程序中創(chuàng)建一個域模型,以映射到數(shù)據(jù)庫模型。本例將創(chuàng)建一個表示圖書節(jié)點的Book實體。還將創(chuàng)建一個Review實體,它表示對某本書的評論。Review實體將有一個與之關聯(lián)的嵌入(向量),將使用它進行相似性搜索。

這些實體是標準的Spring Data Neo4j代碼,所以不會在這里展示代碼。但是,每個類的完整代碼都可以在GitHub存儲庫中獲得(Book類、Review類)。

此外,還需要定義一個存儲庫接口,以便與數(shù)據(jù)庫進行交互。雖然需要定義一個自定義查詢,但稍后將返回并添加它。

Java 
 public interface BookRepository extends Neo4jRepository<Book, String> {
 }

接下來,這個應用程序的核心是控制器類。這個類將包含獲取用戶提供的搜索短語并調(diào)用Neo4jVectorStore來計算和返回最相似短語的邏輯。然后,可以將這些類似的評論傳遞到Neo4j查詢中,以檢索連接的實體,在LLM的提示中提供額外的場景。它將使用提供的所有信息,為原始搜索短語提供一些類似的書籍推薦。

控制器

首先,控制器類包含兩個常見的注解。還將注入之前定義的Neo4jVectorStore和BookRepository bean,以及用于嵌入客戶端的OpenAiChatClient。

下一步是為提示符定義一個字符串。這是將傳遞給LLM以生成響應的文本,將使用用戶提供的搜索短語和在數(shù)據(jù)庫中找到的類似評論,在幾分鐘內(nèi)填充提示參數(shù)。接下來,定義控制器類的構造函數(shù),它將注入必要的bean。

Java 
 @RestController
 @RequestMapping("/")
 public class BookController {
 private final OpenAiChatClient client;
 private final Neo4jVectorStore vectorStore;
 private final BookRepository repo;

 String prompt = """
 You are a book expert with high-quality book information in the CONTEXT section.
 Answer with every book title provided in the CONTEXT.
 Do not add extra information from any outside sources.
 If you are unsure about a book, list the book and add that you are unsure.

 CONTEXT:
 {context}

 PHRASE:
 {searchPhrase}
 """;

 public BookController(OpenAiChatClient client, Neo4jVectorStore vectorStore, BookRepository repo) {
 this.client = client;
 this.vectorStore = vectorStore;
 this.repo = repo;
 }

 //Retrieval Augmented Generation with Neo4j - vector search + retrieval query for related context
 @GetMapping("/rag")
 public String generateResponseWithContext(@RequestParam String searchPhrase) {
 List<Document> results = vectorStore.similaritySearch(SearchRequest.query(searchPhrase).withTopK(5).withSimilarityThreshold(0.8));
 //more code shortly!
 }
 }

最后,定義了一個方法,當用戶向/rag端點發(fā)出GET請求時將調(diào)用該方法。該方法首先將搜索短語作為查詢參數(shù),并將其傳遞給向量存儲的similaritySearch()方法,以查找相似的評論。還通過限制前5個結(jié)果(. withtopk(5))并只提取最相似的結(jié)果(withSimilarityThreshold(0.8))向查詢添加了兩個自定義過濾器。

Spring AI的similaritySearch()方法的實際實現(xiàn)如下所示。

Java 
 @Override
 public List<Document> similaritySearch(SearchRequest request) {
 Assert.isTrue(request.getTopK() > 0, "The number of documents to returned must be greater than zero");
 Assert.isTrue(request.getSimilarityThreshold() >= 0 && request.getSimilarityThreshold() <= 1,
 "The similarity score is bounded between 0 and 1; least to most similar respectively.");

 var embedding = Values.value(toFloatArray(this.embeddingClient.embed(request.getQuery())));

 try (var session = this.driver.session(this.config.sessionConfig)) {
 StringBuilder condition = new StringBuilder("score >= $threshold");
 
 if (request.hasFilterExpression()) {
 condition.append(" AND ")
 .append(this.filterExpressionConverter.convertExpression(request.getFilterExpression()));
 }

 String query = """
 CALL db.index.vector.queryNodes($indexName, $numberOfNearestNeighbours, $embeddingValue)
 YIELD node, score
 WHERE %s
 RETURN node, score""".formatted(condition);
 
 return session
 .run(query,
 Map.of("indexName", this.config.indexName, "numberOfNearestNeighbours", request.getTopK(),
 "embeddingValue", embedding, "threshold", request.getSimilarityThreshold()))
 .list(Neo4jVectorStore::recordToDocument);
 }
 }

然后,將類似的Review節(jié)點映射回Document實體,因為Spring AI需要通用的文檔類型。Neo4jVectorStore類包含將Document轉(zhuǎn)換為自定義記錄的方法,以及將記錄反向轉(zhuǎn)換為Document的方法。以下將顯示這些方法的實際實現(xiàn)。

Java 
 private Map<String, Object> documentToRecord(Document document) {
 var embedding = this.embeddingClient.embed(document);
 document.setEmbedding(embedding);

 var row = new HashMap<String, Object>();
 row.put("id", document.getId());

 var properties = new HashMap<String, Object>();
 properties.put("text", document.getContent());

 document.getMetadata().forEach((k, v) -> properties.put("metadata." + k, Values.value(v)));
 row.put("properties", properties);
 row.put(this.config.embeddingProperty, Values.value(toFloatArray(embedding)));

 return row;
 }

 private static Document recordToDocument(org.neo4j.driver.Record neoRecord) {
 var node = neoRecord.get("node").asNode();
 var score = neoRecord.get("score").asFloat();
 var metaData = new HashMap<String, Object>();

 metaData.put("distance", 1 - score);

 node.keys().forEach(key -> {
 if (key.startsWith("metadata.")) {
 metaData.put(key.substring(key.indexOf(".") + 1), node.get(key).asObject());
 }
 });

 return new Document(node.get("id").asString(), node.get("text").asString(), Map.copyOf(metaData));
 }

回到圖書推薦的控制器方法,現(xiàn)在對用戶搜索的短語有類似的評論。但是評論(以及附帶的文字)并不能真正幫助推薦書籍。所以現(xiàn)在需要在Neo4j中運行一個查詢來檢索這些評論的相關書籍。這是應用程序的檢索增強生成(RAG)部分。

可以在BookRepository接口中編寫查詢,以查找與這些評論相關的圖書。

Java 
 public interface BookRepository extends Neo4jRepository<Book, String> {
 @Query("MATCH (b:Book)<-[rel:WRITTEN_FOR]-(r:Review) " +
 "WHERE r.id IN $reviewIds " +
 "AND r.text <> 'RTC' " +
 "RETURN b, collect(rel), collect(r);")
 List<Book> findBooks(List<String> reviewIds);

}

在查詢中,從相似性搜索($ reviews wids)中傳入評論的ID,并為這些評論提取Review -> Book模式。還過濾掉任何帶有文本“RTC”的評論(這是沒有文本的評論的占位符)。然后返回Book節(jié)點、關系和Review節(jié)點。

現(xiàn)在需要在控制器中調(diào)用該方法,并將結(jié)果傳遞給提示模板。將把它傳遞給LLM,以根據(jù)用戶的搜索短語生成一個帶有圖書推薦列表的響應。

Java 
 //Retrieval Augmented Generation with Neo4j - vector search + retrieval query for related context
 @GetMapping("/rag")
 public String generateResponseWithContext(@RequestParam String searchPhrase) {
 List<Document> results = vectorStore.similaritySearch(SearchRequest.query(searchPhrase).withTopK(5).withSimilarityThreshold(0.8));
 List<Book> bookList = repo.findBooks(results.stream().map(Document::getId).collect(Collectors.toList()));

 var template = new PromptTemplate(prompt, Map.of("context", bookList.stream().map(b -> b.toString()).collect(Collectors.joining("\n")), "searchPhrase", searchPhrase));
 System.out.println("----- PROMPT -----");
 System.out.println(template.render());

 return client.call(template.create().getContents());
 }

從相似性搜索之后開始,調(diào)用新的findBooks()方法,并傳入相似性搜索中的評論ID列表。檢索查詢返回一個名為bookList的圖書列表。接下來,使用提示字符串、圖中的場景數(shù)據(jù)和用戶的搜索短語創(chuàng)建提示模板,并將場景和searchPhrase提示參數(shù)分別映射到圖數(shù)據(jù)(每個項目位于新行上的列表)和用戶的搜索短語。還添加了System.out.println()來將提示打印到控制臺,以便可以看到傳遞給LLM的內(nèi)容。

最后,調(diào)用模板的create()方法從LLM生成響應。返回的JSON對象有一個內(nèi)容鍵,其中包含響應字符串,基于用戶搜索短語的圖書推薦列表。

以下測試一下!

運行應用程序

要運行Goodreads AI應用程序,可以在終端中使用./mvnw spring-boot:run命令。一旦應用程序開始運行,就可以使用搜索短語作為查詢參數(shù)向/rag端點發(fā)出GET請求。下面包括一些示例。

Shell 
 http ":8080/rag?searchPhrase=happy%20ending"
 http ":8080/rag?searchPhrase=encouragement"
 http ":8080/rag?searchPhrase=high%tech"

示例調(diào)用和輸出+完整提示符

電話和退貨書推薦:

Shell 
 jenniferreif@elf-lord springai-goodreads % http ":8080/rag?searchPhrase=encouragement"

 The Cross and the Switchblade
 The Art of Recklessness: Poetry as Assertive Force and Contradiction
 I am unsure about 90 Minutes in Heaven: A True Story of Death and Life
 The Greatest Gift: The Original Story That Inspired the Christmas Classic It's a Wonderful Life
 I am unsure about Aligned: Volume 1 (Aligned, #1)

應用程序日志輸出:

Shell 
 ----- PROMPT -----
 You are a book expert with high-quality book information in the CONTEXT section.
 Answer with every book title provided in the CONTEXT.
 Do not add extra information from any outside sources.
 If you are unsure about a book, list the book and add that you are unsure.

 CONTEXT:
 Book[book_id=772852, title=The Cross and the Switchblade, isbn=0515090255, isbn13=9780515090253, reviewList=[Review[id=f70c68721a0654462bcc6cd68e3259bd, text=encouraging, rating=4]]]
 Book[book_id=89375, title=90 Minutes in Heaven: A True Story of Death and Life, isbn=0800759494, isbn13=9780800759490, reviewList=[Review[id=85ef80e09c64ebd013aeebdb7292eda9, text=inspiring & hope filled, rating=5]]]
 Book[book_id=1488663, title=The Greatest Gift: The Original Story That Inspired the Christmas Classic It's a Wonderful Life, isbn=0670862045, isbn13=9780670862047, reviewList=[Review[id=b74851666f2ec1841ca5876d977da872, text=Inspiring, rating=4]]]
 Book[book_id=7517330, title=The Art of Recklessness: Poetry as Assertive Force and Contradiction, isbn=1555975623, isbn13=9781555975623, reviewList=[Review[id=2df3600d488e182a3ef06bff7fc82eb8, text=Great insight, great encouragement, and great company., rating=4]]]
 Book[book_id=27802572, title=Aligned: Volume 1 (Aligned, #1), isbn=1519114796, isbn13=9781519114792, reviewList=[Review[id=60b9aa083733e751ddd471fa1a77535b, text=healing, rating=3]]]

 PHRASE:
 encouragement

可以看到,LLM生成了一個響應,其中包含基于數(shù)據(jù)庫中找到的圖書推薦列表(提示的CONTEXT部分)。用戶搜索短語的相似度搜索+圖形檢索查詢的結(jié)果在提示符中,LLM的回答使用該數(shù)據(jù)作為響應。

結(jié)語

本文學習了如何在Java中使用Spring AI構建GenAI應用程序。使用OpenAI模型根據(jù)用戶的搜索短語生成圖書推薦。以及使用Neo4j Vector Database來存儲和查詢用于相似性搜索的向量。還將域模型映射到數(shù)據(jù)庫模型,編寫與數(shù)據(jù)庫交互的存儲庫接口,并創(chuàng)建控制器類來處理用戶請求和生成響應。

希望這篇文章能幫助人們使用Spring AI。

資源

文檔:??Spring AI???

網(wǎng)頁:??Spring AI project???

API:Spring AI - Neo4jVectorStore

原文標題:Spring AI: How To Write GenAI Applications With Java,作者:Jennifer Reif

鏈接:https://dzone.com/articles/spring-ai-how-to-write-genai-applications-with-jav


?著作權歸作者所有,如需轉(zhuǎn)載,請注明出處,否則將追究法律責任
收藏
回復
舉報
回復
相關推薦