Ciao comunità!
Questo è il mio secondo articolo in una serie di presentazioni per l’IA di primavera. Potresti trovare il primo, in cui ho spiegato come generare immagini usando i modelli Spring AI e Openai Dall-E 3, Qui. Oggi creeremo semplici applicazioni utilizzando l’API di Embddings e l’IA Spring.
In questo articolo, salterò la spiegazione di alcuni concetti di base primaverili come la gestione dei fagioli, i principianti, ecc., Poiché l’obiettivo principale di questo articolo è scoprire Spring AI capacità. Per lo stesso motivo, non creerò istruzioni dettagliate sulla generazione della chiave API OpenAI. Nel caso in cui non ne hai uno, segui i hyperlink nel passaggio 0, che dovrebbe darti abbastanza contesto su come crearne uno.
Il codice che condividerò in questo articolo sarà disponibile anche in Il Repo di Github. Potresti trovare questo repository utile perché per rendere questo articolo più breve, non incollerò qui alcuni valori precalcolati e pojos semplici.
Cosa sono gli incorporati?
Prima di iniziare l’implementazione del codice, discutiamo di cosa sono gli incorporamenti.
Nella documentazione di AI di primavera, possiamo trovare la seguente definizione di incorporamenti:
Incorporamenti sono rappresentazioni numeriche di testo, immagini o video che acquisiscono relazioni tra enter.
Gli incorporamenti convertono testo, immagini e video in array di numeri a punta cell chiamati vettori. Questi vettori sono progettati per catturare il significato del testo, delle immagini e dei video. La lunghezza dell’array di incorporamento è chiamata dimensionalità del vettore.
Punti chiave a cui dovremmo prestare attenzione a:
- Rappresentazione numerica del testo (applicabile anche per immagini e video, ma concentriamoci solo sui testi in questo articolo)
- Incorporamenti sono vettori. E poiché ogni vettore ha coordinate per ogni dimensione che esiste, dovremmo pensare agli incorporamenti come una coordinata del nostro contributo in “Universo di testo”
Come per ogni altro vettore, possiamo trovare la distanza tra due incorporamenti. Più i due incorporamenti sono reciproci, più è simile il loro contesto. Useremo questo approccio nella nostra applicazione.
Determinare la portata della nostra futura applicazione
Immaginiamo di avere un negozio on-line con elettronica diversa. Ogni singolo elemento ha il suo ID e la sua descrizione. Dobbiamo creare un modulo che riceverà l’enter degli utenti che descrive l’articolo che l’utente desidera trovare o acquistare e restituire cinque dei prodotti più pertinenti a questa question.
Raggiungeremo questo obiettivo usando l’incorporamento. I seguenti sono i passaggi che dobbiamo implementare:
- Prenderemo incorporamenti (rappresentanza vettoriale) dei nostri prodotti esistenti e li conserveremo. Non mostrerò questo passaggio in questo articolo, perché sarà simile a quello che esploreremo in seguito. Ma puoi trovare incorporamenti precalcolati da utilizzare nel tuo codice nel Repo GitHub che ho precedentemente condiviso.
-
Chiameremo l’API di incorporamento per ogni enter dell’utente.
- Confronteremo gli incorporamenti dell’utente con gli incorporamenti precalcolati della descrizione del nostro articolo. Sfrutteremo l’approccio di somiglianza del coseno per trovare i vettori più vicini.
Implementazione
Passaggio 0: generare una chiave API aperta
Se non si dispone di una chiave API OpenAI attiva, eseguire i seguenti passaggi:
- Crea un account su Pagina di iscrizione aperta
- Generare il token sul Pagina API Keys
Passaggio 1: impostare un progetto
Per generare rapidamente un modello di progetto con tutte le dipendenze necessarie, si può usare https://begin.spring.io/.
Nel mio esempio, userò Java 17 e stivale a molla 3.4.1. Inoltre, dobbiamo includere la seguente dipendenza:
Aperto
Questa dipendenza ci fornisce una fluida integrazione con Openi solo scrivendo un paio di righe di codice e alcune righe di configurazioni.
Dopo aver fatto clic su Genera, apri i file scaricati nell’IDE in cui si sta lavorando e convalida che esistono tutte le dipendenze necessarie pom.xml
.
org.springframework.ai
spring-ai-openai-spring-boot-starter
org.springframework.ai
spring-ai-bom
1.0.0-M4
pom
import
Al momento della stesura di questo articolo, Spring AI versione 1.0.0-M4 non è stata ancora pubblicata nel repository di Maven Central ed è disponibile solo nel repository di primavera. Ecco perché dobbiamo aggiungere un hyperlink a quel repository nel nostro pom.xml
anche:
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
false
Passaggio 2: impostare il file di configurazione
Come passo successivo, dobbiamo configurare il nostro file di proprietà. Per impostazione predefinita, la primavera usa software.yaml
O software.properties
file. In questo esempio, sto usando il formato YAML. Puoi riformattare il codice in .properties
Se ti senti più a tuo agio a lavorare con questo formato.
Ecco tutte le configurazioni che dobbiamo aggiungere al software.yaml
file:
spring:
software:
identify: aiembeddings
ai:
openai:
api-key: (your OpenAI api key)
embedding:
choices:
mannequin: text-embedding-ada-002
Modello
Il modello da usare. Useremo text-embedding-ada-002
. Ci sono altre opzioni: text-embedding-3-large
, text-embedding-3-small
. Potresti saperne di più sulle differenze nei modelli in Documenti aperti.
Poiché lo scopo principale di questo articolo è quello di mostrare la facilità di integrazione dell’IA Spring con i modelli di incorporamento, non approfondiremo altre configurazioni. Potresti trovare più opzioni di configurazione in Documenti di primavera.
Passaggio 3: creare file di risorse
Creiamo due file nella cartella delle risorse.
Il primo è il “database” di articoli in formato JSON nel nostro negozio. Ogni elemento avrà i seguenti parametri: ID, nome e descrizione. Ho chiamato questo file samples.json e l’ho salvato nella cartella delle risorse.
(
{
"id": 1,
"identify": "Smartphone A",
"description": "5G smartphone with AMOLED show and 128GB storage."
},
{
"id": 2,
"identify": "Smartphone B",
"description": "4G smartphone with IPS display and 64GB storage."
},
{
"id": 3,
"identify": "Wi-fi Headphones",
"description": "Bluetooth headphones with lively noise cancellation."
},
{
"id": 4,
"identify": "Smartwatch X",
"description": "Health smartwatch with coronary heart price monitor and AMOLED show."
},
{
"id": 5,
"identify": "Pill Professional",
"description": "10-inch pill with 4GB RAM and 64GB storage."
},
{
"id": 6,
"identify": "Bluetooth Speaker",
"description": "Moveable speaker with 12-hour battery life and waterproof design."
},
{
"id": 7,
"identify": "Gaming Laptop computer",
"description": "Excessive-performance laptop computer with RTX 3060 GPU and 16GB RAM."
},
{
"id": 8,
"identify": "Exterior SSD",
"description": "1TB exterior SSD with USB-C for quick information switch."
},
{
"id": 9,
"identify": "4K Monitor",
"description": "27-inch monitor with 4K decision and HDR assist."
},
{
"id": 10,
"identify": "Wi-fi Mouse",
"description": "Ergonomic wi-fi mouse with adjustable DPI."
}
)
Il secondo è un elenco di incorporamenti della descrizione del prodotto. Ho eseguito l’API di incorporamento in un’applicazione separata e risparmiato per ogni singolo prodotto in un file separato, embeddings.json
. Non condividerò l’intero file qui, in quanto renderà l’articolo illeggibile, ma puoi ancora scaricarlo dal repository github di questo progetto che ho condiviso all’inizio dell’articolo.
Passaggio 4: creare un servizio di incorporamento
Ora, creiamo il servizio principale della nostra applicazione -> Incorporamento del servizio.
Per integrare la nostra applicazione con l’API di Embeddings, dobbiamo AutoWire EmbeddingModel
. Abbiamo già configurato gli incorporamenti aperti software.yaml
. Spring Boot creerà e configurerà automaticamente l’istanza (bean) di EmbeddingModel
.
Per recuperare l’incorporamento per una particolare stringa o testo, dobbiamo solo scrivere una riga di codice:
EmbeddingResponse embeddingResponse = embeddingModel.embedForResponse(Checklist.of(textual content));
Vediamo come appare l’intero servizio:
@Service
public class EmbeddingsService {
non-public static Checklist productList = new ArrayList();
non-public static Map embeddings = new HashMap();
@Autowired
non-public EmbeddingModel embeddingModel;
@Autowired
non-public SimilarityCalculator similarityCalculator;
@PostConstruct
public void initProducts() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("samples.json");
if (inputStream != null) {
// map JSON into Checklist
productList = objectMapper.readValue(inputStream, new TypeReference>() {
});
System.out.println("Merchandise loaded: Checklist dimension = " + productList.dimension());
} else {
System.out.println("File samples.json not present in sources.");
}
embeddings = loadEmbeddingsFromFile();
}
public Map loadEmbeddingsFromFile() {
attempt {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("embeddings.json");
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(inputStream, new TypeReference
Diventiamo profondamente in questo codice:
- Nel
@postconstruct
Metodo, stiamo caricando le nostre risorse in raccolte. L’elenco dei prodotti legge i nostri prodotti dasamples.json
. Il prodotto è un pojo con ID, nome e campi di descrizione. Cariciamo anche incorporamenti precalcolati dei nostri prodotti da un altro fileembeddings.json
. Avremo bisogno di questi incorporati più tardi quando cercheremo il prodotto più simile. - Il metodo più importante del nostro servizio è
getSimilarProducts
che riceverà question degli utenti, recupera i suoi incorporamenti utilizzando l’incorporamento e calcola somiglianze con i nostri prodotti esistenti. Dai un’occhiata più da vicinosimilarityCalculator.findTopSimilarProducts
Un po ‘più tardi in questo articolo. Dopo aver ricevuto un elenco di somiglianze, stamperemo i migliori prodotti simili nel seguente formato:- ID prodotto, nome, descrizione, somiglianza (un numero compreso tra 0 e 1)
Per calcolare le somiglianze, abbiamo introdotto SimilarityCalculator
Servizio. Diamo uno sguardo più profondo alla sua implementazione.
@Service
public class SimilarityCalculator {
public float calculateCosineSimilarity(float() vectorA, float() vectorB) {
float dotProduct = 0.0f;
float normA = 0.0f;
float normB = 0.0f;
for (int i = 0; i findTopSimilarProducts(
float() queryEmbedding,
Map embeddings,
Checklist merchandise,
int topN) {
Checklist similarities = new ArrayList();
for (Product product : merchandise) {
float() productEmbedding = embeddings.get(product.getId());
if (productEmbedding != null) {
float similarity = calculateCosineSimilarity(queryEmbedding, productEmbedding);
similarities.add(new ProductSimilarity(product, similarity));
}
}
return similarities.stream()
.sorted((p1, p2) -> Double.examine(p2.getSimilarity(), p1.getSimilarity()))
.restrict(topN)
.toList();
}
}
ProductSimilarity
è una classe Pojo contenenteProduct
Esimilarity
campi. Puoi trovare il codice per questa classe nel repository Github.calculateCosineSimilarity
è il metodo utilizzato per trovare le descrizioni più simili alle question degli utenti. La somiglianza del coseno è uno dei modi più popolari per misurare la somiglianza tra gli incorporamenti. Spiegare gli esatti meccanismi di somiglianza del coseno va oltre lo scopo di questo articolo.findTopSimilarProducts
è un metodo chiamato dal nostro servizio di incorporamento. Calcola le somiglianze con tutti i prodotti, li ordina e restituisce i migliori prodotti N con la massima somiglianza.
Passaggio 5: eseguire l’applicazione
Eseguiremo questa applicazione direttamente dal codice, senza utilizzare i controller di REST o effettuare chiamate API. Puoi usare un approccio simile a quello che ho usato nel primo articolo, quando ho creato un endpoint separato per rendere più fluida l’esecuzione.
@SpringBootApplication
public class AiEmbeddingsApplication {
public static void fundamental(String() args) {
ConfigurableApplicationContext run = new SpringApplicationBuilder(AiEmbeddingsApplication.class)
.internet(WebApplicationType.NONE)
.run(args);
run.getBean(EmbeddingsService.class).getSimilarProducts("5G Cellphone. IPS");
}
}
Stiamo eseguendo il nostro codice nell’ultima riga del metodo, prendendo il fagiolo dal contesto ed eseguendo il getSimilarProducts
Metodo con una question fornita.
Nella mia domanda, ho incluso tre parole chiave: 5g, TelefonoE IPS. Dovremmo ricevere una somiglianza piuttosto elevata con il prodotto 1 e il prodotto 2. Entrambi i prodotti sono smartphone, ma il prodotto 1 è uno smartphone 5G, mentre il prodotto 2 ha uno schermo IPS.
Per avviare la nostra applicazione, dobbiamo eseguire il seguente comando:
In un paio di secondi dopo l’esecuzione, potremmo vedere il seguente risultato nella console:
Product ID: 2, Title: Smartphone B, Description: 4G smartphone with IPS display and 64GB storage., Similarity: 0,9129
Product ID: 1, Title: Smartphone A, Description: 5G smartphone with AMOLED show and 128GB storage., Similarity: 0,8843
Product ID: 9, Title: 4K Monitor, Description: 27-inch monitor with 4K decision and HDR assist., Similarity: 0,8156
Product ID: 5, Title: Pill Professional, Description: 10-inch pill with 4GB RAM and 64GB storage., Similarity: 0,8156
Product ID: 4, Title: Smartwatch X, Description: Health smartwatch with coronary heart price monitor and AMOLED show., Similarity: 0,8037
Possiamo vedere che il prodotto 2 e il prodotto 1 hanno le maggiori somiglianze. Ciò che è anche interessante è che, come abbiamo incluso la parola chiave IPS, i nostri primi cinque prodotti simili sono tutti prodotti con show.
Conclusione
Spring AI è un ottimo strumento che aiuta gli sviluppatori a integrarsi senza intoppi con diversi modelli AI. Al momento della stesura di questo articolo, Spring AI supporta 10 modelli di incorporamento, inclusi ma non limitati a Ollama e Amazon Bedrock.
Spero che tu abbia trovato questo articolo utile e che ti ispirerà a esplorare la primavera AI più a fondo.