Nota importante sulla costruzione del prompt
Il punto 6 – STEP 5, dedicato alla costruzione del prompt, è volutamente la parte più curata di tutta la stored procedure.
Tutte le istruzioni inviate al motore AI sono scritte in italiano, anche quando il risultato finale deve essere generato in un’altra lingua.
Questa scelta non è casuale. I modelli di linguaggio moderni comprendono perfettamente l’italiano e rispondono in modo molto affidabile quando viene loro chiesto esplicitamente in quale lingua produrre l’output.
Scrivere il prompt nella propria lingua rende il codice più leggibile, più facile da manutenere e soprattutto più immediato da comprendere durante la fase di test e sperimentazione.
L’aspetto davvero critico non è la lingua del prompt, ma la chiarezza delle istruzioni.
Per questo motivo l’indicazione sulla lingua di output viene ripetuta in modo esplicito e rafforzata (“IMPORTANTE”, “INTERO messaggio”, “completamente in…”), così da evitare risposte miste o parzialmente tradotte.
In altre parole:
è preferibile scrivere prompt chiari e ben strutturati nella propria lingua, piuttosto che prompt in inglese meno precisi.
Questo approccio si è rivelato particolarmente efficace nella demo multilingua della Fabbrica di Babbo Natale e rappresenta una buona pratica anche in contesti reali, soprattutto quando il team che lavora sul codice utilizza l’italiano come lingua principale.
CREATE OR ALTER PROCEDURE dbo.sp_GeneraEmailBambino
@IDBambino INT,
@TipoNotifica NVARCHAR(50) = N'ConfermaLetterina',
@Oggetto NVARCHAR(500) OUTPUT,
@CorpoEmail NVARCHAR(MAX) OUTPUT,
@Errore NVARCHAR(MAX) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
/* ============================================================
0) CONFIG AI (LAB / DEMO) - dichiarata inline per semplicità
============================================================ */
-- >>> Inserisci qui la tua API KEY (LAB). Non committare mai in repo pubblici.
DECLARE @ApiKey NVARCHAR(200) = N'YOUR_API_KEY_HERE';
-- Modello e versione API (Google AI / Gemini). Personalizza se necessario.
DECLARE @ModelName NVARCHAR(100) = N'gemini-2.5-flash';
DECLARE @ApiVersion NVARCHAR(10) = N'v1';
-- Parametri di generazione (tuning)
DECLARE @Temperature DECIMAL(3,2) = 0.90; -- creatività/variabilità
DECLARE @MaxOutputTokens INT = 8000; -- limite output
DECLARE @TopP DECIMAL(3,2) = 0.95;
DECLARE @TopK INT = 64;
-- Endpoint completo
DECLARE @url NVARCHAR(4000) =
N'https://generativelanguage.googleapis.com/' +
@ApiVersion + N'/models/' + @ModelName +
N':generateContent?key=' + @ApiKey;
/* ============================================================
1) Variabili di lavoro
============================================================ */
-- Variabili REST
DECLARE @payload NVARCHAR(MAX);
DECLARE @response NVARCHAR(MAX);
DECLARE @ret INT;
DECLARE @resultJSON NVARCHAR(MAX);
-- Dati bambino e contesto
DECLARE @Nome NVARCHAR(100), @Cognome NVARCHAR(100);
DECLARE @Email NVARCHAR(150), @Eta INT;
DECLARE @CodiceLingua CHAR(2), @NomeLingua NVARCHAR(50);
DECLARE @CodiceISO CHAR(5);
DECLARE @StatoLista NVARCHAR(20);
DECLARE @PunteggioComportamento INT;
DECLARE @IDLetterina INT;
DECLARE @ListaRegali NVARCHAR(MAX);
DECLARE @ComportamentiPositivi NVARCHAR(MAX);
-- Prompt finale
DECLARE @promptCompleto NVARCHAR(MAX);
BEGIN TRY
/* ============================================================
2) STEP 1 - Recupero dati bambino + lingua
============================================================ */
SELECT
@Nome = b.Nome,
@Cognome = b.Cognome,
@Email = b.Email,
@Eta = b.Eta,
@CodiceLingua = b.CodiceLingua,
@NomeLingua = l.NomeLingua,
@CodiceISO = l.CodiceISO639,
@StatoLista = b.StatoLista,
@PunteggioComportamento = b.PunteggioComportamento
FROM dbo.Bambini b
INNER JOIN dbo.Lingue l ON b.CodiceLingua = l.CodiceLingua
WHERE b.IDBambino = @IDBambino;
IF @Nome IS NULL
BEGIN
SET @Errore = N'Bambino non trovato con ID: ' + CAST(@IDBambino AS NVARCHAR(20));
RETURN -1;
END
/* ============================================================
3) STEP 2 - Recupero ultima letterina del bambino
============================================================ */
SELECT TOP (1)
@IDLetterina = IDLetterina
FROM dbo.Letterine
WHERE IDBambino = @IDBambino
ORDER BY DataRicezione DESC;
/* ============================================================
4) STEP 3 - Aggrego lista regali (se presenti)
============================================================ */
IF @IDLetterina IS NOT NULL
BEGIN
SELECT @ListaRegali = STRING_AGG(NomeRegalo, N', ')
FROM dbo.RegaliRichiesti
WHERE IDLetterina = @IDLetterina;
END
/* ============================================================
5) STEP 4 - Recupero comportamenti positivi (ultimi 5)
============================================================ */
SELECT @ComportamentiPositivi = STRING_AGG(DescrizioneAzione, N'; ')
FROM (
SELECT TOP (5) DescrizioneAzione
FROM dbo.RegistroComportamenti
WHERE IDBambino = @IDBambino
AND TipoComportamento = 'Positivo'
ORDER BY DataAzione DESC
) AS Pos;
/* ============================================================
6) STEP 5 - Costruzione PROMPT (la parte più importante)
============================================================ */
-- 6.1 Ruolo / tono (imposta lo “stile”)
SET @promptCompleto =
N'Sei un elfo simpatico e magico dell''officina di Babbo Natale al Polo Nord. ';
-- 6.2 Destinatario (età = linguaggio adeguato)
SET @promptCompleto +=
N'Scrivi una email natalizia calorosa e magica per ' + @Nome +
N' (età ' + CAST(@Eta AS NVARCHAR(10)) + N' anni). ';
-- 6.3 Contesto (stato e punteggio)
SET @promptCompleto +=
N'Il bambino è nella lista "' + ISNULL(@StatoLista, N'') +
N'" con un punteggio comportamento di ' +
CAST(ISNULL(@PunteggioComportamento, 0) AS NVARCHAR(10)) + N'/100. ';
-- 6.4 Dettagli personalizzati (opzionali)
IF @ListaRegali IS NOT NULL AND LEN(@ListaRegali) > 0
SET @promptCompleto += N'Regali richiesti: ' + @ListaRegali + N'. ';
IF @ComportamentiPositivi IS NOT NULL AND LEN(@ComportamentiPositivi) > 0
SET @promptCompleto += N'Buone azioni recenti: ' + @ComportamentiPositivi + N'. ';
-- 6.5 Vincoli formato (evita muri di testo)
SET @promptCompleto +=
N'Scrivi 2-3 paragrafi brevi, in tono gioioso. Usa 1-2 emoji natalizi. ';
-- 6.6 Istruzione CRITICA sulla lingua (per evitare mix)
SET @promptCompleto +=
N'IMPORTANTE: Scrivi l''INTERO messaggio in lingua ' + @NomeLingua +
N' (' + @CodiceISO + N'). ' +
N'Il messaggio deve essere completamente in ' + @NomeLingua +
N', inclusi saluti e firma.';
/* ============================================================
7) STEP 6 - Escape per JSON (evita payload non valido)
============================================================ */
-- Escape minimo per proteggere backslash e virgolette
SET @promptCompleto = REPLACE(@promptCompleto, N'\', N'\\');
SET @promptCompleto = REPLACE(@promptCompleto, N'"', N'\"');
SET @promptCompleto = REPLACE(@promptCompleto, CHAR(13), N'');
SET @promptCompleto = REPLACE(@promptCompleto, CHAR(10), N' ');
/* ============================================================
8) STEP 7 - Costruzione payload JSON per Google AI
============================================================ */
-- Nota: qui costruiamo un JSON “a mano” per semplicità (demo)
SET @payload =
N'{' +
N'"contents":[{"parts":[{"text":"' + @promptCompleto + N'"}]}],' +
N'"generationConfig":{' +
N'"temperature":' + CAST(@Temperature AS NVARCHAR(20)) + N',' +
N'"maxOutputTokens":' + CAST(@MaxOutputTokens AS NVARCHAR(20)) + N',' +
N'"topP":' + CAST(@TopP AS NVARCHAR(20)) + N',' +
N'"topK":' + CAST(@TopK AS NVARCHAR(20)) +
N'}' +
N'}';
/* ============================================================
9) STEP 8 - Chiamata REST al modello (sp_invoke_external_rest_endpoint)
============================================================ */
EXEC @ret = sys.sp_invoke_external_rest_endpoint
@url = @url,
@method = 'POST',
@payload = @payload,
@response = @response OUTPUT;
IF @ret <> 0
BEGIN
-- Prova a leggere il messaggio errore dal JSON (se presente)
SET @Errore =
N'Errore chiamata API (ret=' + CAST(@ret AS NVARCHAR(20)) + N'): ' +
ISNULL(JSON_VALUE(@response, '$.result.error.message'),
JSON_VALUE(@response, '$.error.message'));
IF @Errore IS NULL
SET @Errore = N'Errore chiamata API (ret=' + CAST(@ret AS NVARCHAR(20)) + N') - risposta non interpretabile';
RETURN -3;
END
/* ============================================================
10) STEP 9 - Parsing risposta JSON e composizione output
============================================================ */
-- Alcuni formati incapsulano la risposta sotto $.result
SET @resultJSON = JSON_QUERY(@response, '$.result');
-- Estrai il testo: prima da result, altrimenti fallback diretto
SET @CorpoEmail = COALESCE(
JSON_VALUE(@resultJSON, '$.candidates[0].content.parts[0].text'),
JSON_VALUE(@response, '$.candidates[0].content.parts[0].text')
);
IF @CorpoEmail IS NULL OR LEN(@CorpoEmail) = 0
BEGIN
SET @Errore = N'Impossibile estrarre il messaggio dalla risposta AI';
RETURN -2;
END
-- Oggetto localizzato
SET @Oggetto = CASE @CodiceLingua
WHEN 'IT' THEN N'🎅 Caro ' + @Nome + N', la tua letterina è arrivata!'
WHEN 'EN' THEN N'🎅 Dear ' + @Nome + N', your letter has arrived!'
WHEN 'FR' THEN N'🎅 Cher ' + @Nome + N', ta lettre est arrivée!'
WHEN 'ES' THEN N'🎅 Querido ' + @Nome + N', ¡tu carta ha llegado!'
WHEN 'DE' THEN N'🎅 Liebe/r ' + @Nome + N', dein Brief ist da!'
WHEN 'PT' THEN N'🎅 Querido ' + @Nome + N', a tua carta chegou!'
ELSE N'🎅 ' + @Nome + N' - Letter Received!'
END;
/* ============================================================
11) STEP 10 - Logging (audit: prompt + risposta raw)
============================================================ */
INSERT INTO dbo.LogNotifiche
(
IDBambino,
TipoNotifica,
Destinatario,
Oggetto,
CorpoMessaggio,
LinguaUtilizzata,
PromptUsato,
RispostaAI,
StatoInvio,
DataInvio
)
VALUES
(
@IDBambino,
@TipoNotifica,
@Email,
@Oggetto,
@CorpoEmail,
@CodiceLingua,
@promptCompleto,
@response,
'Generata',
GETDATE()
);
/* ============================================================
12) Fine: successo
============================================================ */
SET @Errore = NULL;
RETURN 0;
END TRY
BEGIN CATCH
-- Errore SQL “interno” (es. tabelle mancanti, conversioni, ecc.)
SET @Errore = N'Eccezione SQL: ' + ERROR_MESSAGE();
RETURN -999;
END CATCH
END;
GO
Dopo aver costruito la stored procedure principale per la generazione delle email, è utile avere uno strumento semplice e immediato per testare il risultato lingua per lingua, senza dover ogni volta selezionare manualmente un bambino o scrivere query di supporto.
Continua …