Cosa è Spring AI framework

Cosa è Spring AI framework

  1. Panoramica Spring AI framework
    Spring Framework ha ufficialmente abilitato la potenza dei prompt generativi AI con il progetto Spring AI. In questo articolo, forniremo una solida panoramica all’integrazione dell’AI generativa nelle applicazioni Spring Boot e ci familiarizzeremo con i concetti essenziali dell’AI.

Acquisiremo inoltre una comprensione del modo in cui Spring AI interagisce con i modelli e creeremo un’applicazione per dimostrarne le capacità.

  1. Concetti principali di Spring AI framework
    Prima di iniziare, rivediamo alcuni termini e concetti chiave del settore.

Spring AI inizialmente si è concentrata su modelli progettati per gestire l’input linguistico e generare l’output linguistico. L’idea alla base del progetto era quella di fornire agli sviluppatori un’interfaccia astratta, la base per abilitare le API AI generative nell’applicazione come componente isolato.

Una di queste astrazioni è l’interfaccia AiClient, che ha due implementazioni di base, OpenAI e Azure OpenAI:

public interface AiClient {
default String generate(String message);
AiResponse generate(Prompt prompt);
}

AiClient fornisce due opzioni per la funzione generativa. Quella semplificata, generate(String message), usa String come input e output, e potrebbe essere usata per evitare la complessità extra delle classi Promt e AiResponse .

Ora diamo un’occhiata più da vicino alle loro differenze.

2.1. Prompt avanzato e AiResponse
Nel dominio dell’IA, prompt si riferisce a un messaggio di testo fornito all’IA. È costituito dal contesto e dalla domanda, e quel modello viene utilizzato per la generazione della risposta.

Dal punto di vista del progetto Spring AI, il Prompt è un elenco di messaggi parametrizzati :

public class Prompt {
private final List messages;
// constructors and utility methods
}

public interface Message {
String getContent();
Map getProperties();
MessageType getMessageType();
}

Prompt consente agli sviluppatori di avere più controllo sull’input di testo . Un buon esempio sono i modelli di prompt, costruiti con un testo predefinito e un set di segnaposto. Quindi possiamo popolarli con i valori Map passati al costruttore Message :

Tell me a {adjective} joke about {content}.

L’ interfaccia Message contiene anche informazioni avanzate sulle categorie di messaggi che un modello AI può elaborare. Ad esempio, l’implementazione di OpenAI distingue tra ruoli conversazionali, mappati in modo efficace da MessageType . In altri modelli, potrebbe riflettere il formato del messaggio o altre proprietà personalizzate. Per maggiori dettagli, fare riferimento alla documentazione ufficiale :

public class AiResponse {
private final List generations;
// getters and setters
}

public class Generation {
private final String text;
private Map info;
}

L’ AiResponse è costituito dall’elenco degli oggetti Generation , ognuno contenente l’output del prompt corrispondente. Inoltre, l’ oggetto Generation fornisce le informazioni sui metadati della risposta AI.

Tuttavia, mentre il progetto Spring AI è ancora in versione beta, non tutte le funzionalità sono finite e documentate. Possiamo seguire i progressi con i problemi sul repository GitHub .

  1. Introduzione al progetto Spring AI framework
    Innanzitutto, AiClient richiede la chiave API per tutte le comunicazioni con la piattaforma OpenAI . Per questo, creeremo un token nella pagina API Keys.

Il progetto Spring AI definisce la proprietà di configurazione spring.ai.openai.api-key . Possiamo impostarla nel file application.yml :

spring:
ai:
openai.api-key: ${OPEN_AI_KEY}

Il passo successivo è configurare un repository di dipendenza. Il progetto Spring AI fornisce artefatti nel repository Spring Milestone .

Pertanto, dovremo aggiungere la definizione del repository:

<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <releases>
            <enabled>false</enabled>
        </releases>
    </repository>
</repositories>

Dopodiché siamo pronti per importare open-ai-spring-boot-starter :

<dependency>
    <groupId>org.springframework.experimental.ai</groupId>
    <artifactId>spring-ai-openai-spring-boot-starter</artifactId>
    <version>1.0.0-M1</version>
</dependency>

Tieni presente che il progetto Spring AI è in continua evoluzione, quindi controlla la pagina ufficiale GitHub per la versione più recente.

Ora mettiamo in pratica il concetto.

  1. Spring AI in azione
    Scriviamo una semplice API REST a scopo dimostrativo. Sarà composta da due endpoint che restituiscono poesie su qualsiasi tema e genere desideriamo:
  • /ai/cathaiku — implementerà il metodo di base generate() e restituirà un valore stringa semplice con Haiku sui gatti
  • /ai/poetry?theme={{theme}}&genre={{genre}} — dimostrerà le capacità delle classi PromtTemplate e AiResponse


4.1. Iniezione di AiClient nell’applicazione Spring Boot
Per semplificare le cose, iniziamo con l’endpoint cat haiku. Con l’ annotazione @RestController , imposteremo PoetryController e aggiungeremo il mapping del metodo GET :

@RestController
@RequestMapping("ai")
public class PoetryController {
private final PoetryService poetryService;

// constructor

@GetMapping("/cathaiku")
public ResponseEntity<String> generateHaiku(){
    return ResponseEntity.ok(poetryService.getCatHaiku());
}

}

Successivamente, seguendo il concetto DDD, il livello di servizio definirà tutta la logica di dominio. Tutto ciò che dobbiamo fare per chiamare il metodo generate () è iniettare AiClient in PoetryService . Ora possiamo definire il prompt String, dove specificheremo la nostra richiesta per generare Haiku:

@Service
public class PoetryServiceImpl implements PoetryService {
public static final String WRITE_ME_HAIKU_ABOUT_CAT = """
Write me Haiku about cat,
haiku should start with the word cat obligatory""";

private final AiClient aiClient;

// constructor

@Override
public String getCatHaiku() {
    return aiClient.generate(WRITE_ME_HAIKU_ABOUT_CAT);
}

}

L’endpoint è attivo e pronto a ricevere le richieste. La risposta conterrà una stringa semplice:

Cat prowls in the night,
Whiskers twitch with keen delight,
Silent hunter's might.

Finora sembra buono; tuttavia, la soluzione attuale ha qualche insidia. La risposta di una stringa semplice non è la soluzione migliore per i contratti REST in primo luogo.

Inoltre, non ha molto senso interrogare ChatGPT con lo stesso vecchio prompt ogni volta. Quindi il nostro prossimo passo è aggiungere i valori parametrizzati: theme e genre. Ecco quando PromtTemplate ci sarà più utile.

4.2. Query configurabili con PromptTemplate
Nella sua natura, PromptTemplate funziona in modo abbastanza simile a una combinazione di StringBuilder e dictionary . Similmente all’endpoint /cathaiku , definiremo prima la stringa di base per il prompt. Al contrario, questa volta definiremo i segnaposto popolati con valori effettivi tramite i loro nomi:

String promptString = """
Write me {genre} poetry about {theme}
""";
PromptTemplate promptTemplate = new PromptTemplate(promptString);
promptTemplate.add("genre", genre);
promptTemplate.add("theme", theme);

Successivamente, potremmo voler standardizzare l’output dell’endpoint. Per questo, introdurremo la semplice classe record , PoetryDto , che conterrà il titolo, il nome e il genere della poesia:

public record PoetryDto (String title, String poetry, String genre, String theme){}

Un ulteriore passaggio consiste nel registrare PoetryDto nella classe BeanOutputParser ; ciò fornisce funzionalità per serializzare e deserializzare l’output dell’API OpenAI.

Forniremo quindi questo parser al promtTemple e da ora in poi i nostri messaggi verranno serializzati negli oggetti DTO.

Alla fine, la nostra funzione generativa apparirà così:

@Override
public PoetryDto getPoetryByGenreAndTheme(String genre, String theme) {
BeanOutputParser poetryDtoBeanOutputParser = new BeanOutputParser<>(PoetryDto.class);

String promptString = """
    Write me {genre} poetry about {theme}
    {format}
""";

PromptTemplate promptTemplate = new PromptTemplate(promptString);
promptTemplate.add("genre", genre);
promptTemplate.add("theme", theme);
promptTemplate.add("format", poetryDtoBeanOutputParser.getFormat());
promptTemplate.setOutputParser(poetryDtoBeanOutputParser);

AiResponse response = aiClient.generate(promptTemplate.create());

return poetryDtoBeanOutputParser.parse(response.getGeneration().getText());

}

La risposta che riceve il nostro cliente ora sembra molto migliore e, cosa ancora più importante, è conforme agli standard e alle best practice della REST API :

{
"title": "Dancing Flames",
"poetry": "In the depths of night, flames dance with grace,
Their golden tongues lick the air with fiery embrace.
A symphony of warmth, a mesmerizing sight,
In their flickering glow, shadows take flight.
Oh, flames so vibrant, so full of life,
Burning with passion, banishing all strife.
They consume with ardor, yet do not destroy,
A paradox of power, a delicate ploy.
They whisper secrets, untold and untamed,
Their radiant hues, a kaleidoscope unnamed.
In their gentle crackling, stories unfold,
Of ancient tales and legends untold.
Flames ignite the heart, awakening desire,
They fuel the soul, setting it on fire.
With every flicker, they kindle a spark,
Guiding us through the darkness, lighting up the dark.
So let us gather 'round, bask in their warm embrace,
For in the realm of flames, magic finds its place.
In their ethereal dance, we find solace and release,
And in their eternal glow, our spirits find peace.",
"genre": "Liric",
"theme": "Flames"
}
  1. Gestione degli errori
    Il progetto Spring AI fornisce un’astrazione sugli errori OpenAPI con la classe OpenAiHttpException . Sfortunatamente, non fornisce una mappatura individuale delle classi per tipo di errore. Tuttavia, grazie a tale astrazione, possiamo gestire tutte le eccezioni con RestControllerAdvice in un unico gestore.

Il codice sottostante utilizza lo standard ProblemDetail del Framework Spring 6. Per familiarizzarsi con esso, consultare la documentazione ufficiale :

@RestControllerAdvice
public class ExceptionTranslator extends ResponseEntityExceptionHandler {
public static final String OPEN_AI_CLIENT_RAISED_EXCEPTION = "Open AI client raised exception";

@ExceptionHandler(OpenAiHttpException.class)
ProblemDetail handleOpenAiHttpException(OpenAiHttpException ex) {
    HttpStatus status = Optional
      .ofNullable(HttpStatus.resolve(ex.statusCode))
      .orElse(HttpStatus.BAD_REQUEST);
    ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, ex.getMessage());
    problemDetail.setTitle(OPEN_AI_CLIENT_RAISED_EXCEPTION);
    return problemDetail;
}

}

Ora, se la risposta OpenAPI contiene errori, li gestiremo:

{
"type": "about:blank",
"title": "Open AI client raised exception",
"status": 401,
"detail": "Incorrect API key provided: sk-XG6GW***wlmi.
You can find your API key at https://platform.openai.com/account/api-keys.",
"instance": "/ai/cathaiku"
}

L’elenco completo dei possibili stati di eccezione si trova nella pagina della documentazione ufficiale .

  1. Conclusione
    In questo articolo, abbiamo familiarizzato con il progetto Spring AI e le sue capacità nel contesto delle API REST. Nonostante il fatto che, al momento in cui è stato scritto questo articolo, spring-ai-starter fosse ancora in fase di sviluppo attivo e fosse accessibile in una versione snapshot, forniva un’interfaccia affidabile per l’integrazione dell’IA generativa nell’applicazione Spring Boot.

Nel contesto di questo articolo, abbiamo trattato sia le integrazioni di base che quelle avanzate con Spring AI , incluso il funzionamento di AiClient sotto il cofano. Come esercizio, abbiamo implementato un’applicazione REST di base che genera una poesia. Insieme a un esempio di base di un endpoint generativo, abbiamo fornito un campione che utilizza le funzionalità avanzate di Spring AI: PromtTemplate, AiResponse e BeanOutputParser . Inoltre, abbiamo implementato la funzionalità di gestione degli errori.

(fonte)

Innovaformazione, scuola informatica specialistica segue costantemente i trend del mercato e promuove la formazione continua del team di sviluppatori delle aziende. Nell’offerta formativa trovate il Corso Spring framework.

INFO: info@innovaformazione.net – tel. 3471012275 (Dario Carrassi)

Vuoi essere ricontattato? Lasciaci il tuo numero telefonico e la tua email, ti richiameremo nelle 24h:

    Ti potrebbe interessare

    Articoli correlati