DevTurtle logo DevTurtle

Spring AI – Come integrare il Function Calling con OpenAI

guide/ Guida Spring AI

Spring AI, il potente framework per lo sviluppo di applicazioni di Intelligenza Artificiale, offre un'interessante funzionalità chiamata "Function Calling", che consente di integrare facilmente funzioni personalizzate all'interno delle conversazioni con l'IA. In questo articolo, esploreremo come funziona il meccanismo del "function calling" di Spring AI e come è possibile sfruttarlo per arricchire le conversazioni con l'IA.

Cos’è il Function Calling?

Il Function Calling è una funzionalità di Spring AI che consente di registrare funzioni Java personalizzate e consentire all’IA di scegliere intelligentemente di chiamarle durante una conversazione. Questo significa che è possibile collegare le capacità del modello di linguaggio con strumenti esterni e API, consentendo un’integrazione più profonda e potente delle funzionalità dell’IA con altre parti del sistema.

Il Function Calling offre diversi vantaggi significativi:

  • Flessibilità: Consente di integrare facilmente funzioni personalizzate con l’IA, consentendo una maggiore flessibilità e personalizzazione delle conversazioni.
  • Semplicità: Grazie all’integrazione diretta con Spring AI e al supporto fornito dal framework, l’implementazione delle funzioni personalizzate è semplice e intuitiva.
  • Risparmio di codice: Spring AI si occupa di gran parte del codice boilerplate necessario per supportare l’invocazione delle funzioni, consentendo agli sviluppatori di concentrarsi sulla logica di business.

Function Calling con OpenAI

Prima di iniziare questo tutorial vi consigliamo di leggere l’articolo precedente di questa guida che spiega come creare un progetto Spring AI con OpenAI.

Partiamo dunque dal nostro progetto Spring Boot base e definiamo un nuovo Service che implementi una funzione a nostra scelta. Nel caso di questo esempio creeremo una funzione che calcola l’area di un rettangolo data la base e l’altezza:

Java
package com.example.aidemo.service;

import java.util.function.Function;

import com.example.aidemo.service.RectangleAreaService.Request;
import com.example.aidemo.service.RectangleAreaService.Response;

public class RectangleAreaService implements Function<Request, Response> {

	// Request for RectangleAreaService
	public record Request(double base, double height) {}
	public record Response(double area) {}

	@Override
	public Response apply(Request r) {
		return new Response(r.base()*r.height());
	}
	
}

Dopo aver implementato la logica del servizio, è necessario definire la funzione che poi potrà essere invocata dall’IA. A tal proposito è necessario definire un bean come segue:

Java
package com.example.aidemo.config;

import java.util.function.Function;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Description;

import com.example.aidemo.service.RectangleAreaService;

@Configuration
public class Functions {
	
	@Bean
	@Description("Calculate the area of a rectangle from its base and height")
	public Function<RectangleAreaService.Request, RectangleAreaService.Response> rectangeleAreaFunction() {
		return new RectangleAreaService();
	}

}

Rispetto alla definizione di un generico Bean di Spring, abbiamo inserito l’annotazione @Description che fornisce al modello una descrizione di cosa fa la funzione.

A questo punto, possiamo aggiungere un nuovo endpoint al RestController che risponda ai prompt utilizzando la funzione appena definita:

Java
@GetMapping("/ai/function")
public Generation functionCalling(@RequestParam(value = "message") String message) {
	Prompt prompt = new Prompt(message,
			OpenAiChatOptions.builder().withFunction("rectangeleAreaFunction").build());
	ChatResponse response = chatModel.call(prompt);
	return response.getResult();
}

Sarà possibile testare l’applicazione invocando l’endpoint:

Plaintext
localhost:8080/ai/function?message=Can you calculate the area of a rectangle with base 10 and height 4?

La risposta avrà il seguente formato:

JSON
{
  "metadata": {
    "finishReason": "STOP",
    "contentFilterMetadata": null
  },
  "output": {
    "messageType": "ASSISTANT",
    "properties": {
      "role": "ASSISTANT",
      "finishReason": "STOP",
      "id": "chatcmpl-9GTohEE6TtLVMhYPA6ZMF4oOUD633"
    },
    "content": "The area of a rectangle with a base of 10 and height of 4 is 40.",
    "media": [
      
    ]
  }
}
git icon
Git RepositoryScarica il codice sorgente

Conclusioni

L’esempio ci deve far riflettere sulle grandi potenzialità che ha questo strumento in quanto ci permette di integrare il modello di AI con parti di codice personalizzato. Si potrebbe ad esempio invocare un’API esterna o accedere ad un database per recuperare informazioni utili.