Risposta rapida: per trasmettere in streaming una risposta LLM in Delphi con sgcWebSockets, assegna l'evento OnHTTPAPISSE del componente, poi chiama il metodo di streaming — _CreateChatCompletion con Stream := True per OpenAI, _CreateMessageStream per Anthropic Claude e Ollama, _CreateContentStream per Gemini. Ogni delta arriva nel gestore come un Server-Sent Event; aggiungi aData a una Memo e la risposta si digita da sola man mano che il modello la genera.
Una chiamata LLM non in streaming si blocca finché l'intera risposta non è pronta. Per una risposta di un paragrafo va bene, ma per un completamento lungo l'utente fissa una finestra bloccata per diversi secondi senza alcun riscontro. Lo streaming risolve questo: il modello restituisce il suo output come una sequenza di piccoli chunk su un'unica connessione HTTP, e tu visualizzi ogni chunk nel momento in cui arriva. Il risultato è il familiare effetto di "digitazione" che vedi in ChatGPT, e una UI che sembra reattiva anche quando la risposta completa richiede un po' di tempo.
Come funziona lo streaming: OnHTTPAPISSE
Sotto il cofano ogni componente AI di sgcWebSockets trasmette in streaming usando i Server-Sent Events (SSE). Il provider mantiene la risposta aperta e invia eventi man mano che i token vengono prodotti. Il componente analizza quegli eventi e solleva un evento per ogni chunk attraverso un unico gestore con la stessa firma su ogni componente:
procedure TForm1.HandleSSE(Sender: TObject;
const aEvent, aData: string; var Cancel: Boolean);
begin
// aEvent -> the SSE event name (provider-specific)
// aData -> the payload for this chunk (the token delta)
// Cancel -> set True to abort the stream early
Memo1.Lines.Add(aData);
end;
Questo è l'intero contratto. aData trasporta il payload incrementale, aEvent ti dice di quale tipo di evento si tratta (utile con i provider che emettono diversi tipi di evento), e impostare Cancel := True arresta lo stream, ad esempio quando l'utente fa clic su un pulsante Stop. La stessa forma del gestore funziona per OpenAI, Anthropic, Gemini e Ollama, quindi una volta scritta puoi riutilizzarla tra i vari provider.
OpenAI: Stream := True
Con TsgcHTTP_API_OpenAI abiliti lo streaming sulla richiesta e agganci l'evento. Imposta OpenAIOptions.ApiKey, assegna OnHTTPAPISSE, e il completamento della chat viene consegnato chunk per chunk invece che in un unico blocco:
uses
sgcHTTP_API_OpenAI;
var
OpenAI: TsgcHTTP_API_OpenAI;
begin
OpenAI := TsgcHTTP_API_OpenAI.Create(nil);
OpenAI.OpenAIOptions.ApiKey := 'sk-...';
// Each token delta arrives in HandleSSE
OpenAI.OnHTTPAPISSE := HandleSSE;
// Build a typed request, set Stream := True, then call
OpenAI._CreateChatCompletion('gpt-4o-mini', 'Explain WebSockets in detail.');
end;
La richiesta tipizzata espone una proprietà Stream, quindi quando costruisci tu stesso l'oggetto richiesta imposti Stream := True prima dell'invio. I token affiorano poi attraverso OnHTTPAPISSE man mano che vengono generati, e tu aggiungi ciascuno alla tua Memo.
Anthropic Claude: _CreateMessageStream
Claude espone un helper di streaming dedicato, quindi non c'è alcun flag separato da attivare: chiamare _CreateMessageStream su TsgcHTTP_API_Anthropic attiva SSE per quella richiesta. Imposta la chiave API e la versione, assegna il gestore e chiamalo:
uses
sgcHTTP_API_Anthropic;
var
Anthropic: TsgcHTTP_API_Anthropic;
begin
Anthropic := TsgcHTTP_API_Anthropic.Create(nil);
Anthropic.AnthropicOptions.ApiKey := 'sk-ant-...';
Anthropic.AnthropicOptions.AnthropicVersion := '2023-06-01';
Anthropic.OnHTTPAPISSE := HandleSSE;
Anthropic._CreateMessageStream(
'claude-3-5-sonnet-latest',
'Summarise RFC 6455',
1024);
end;
Claude emette diversi tipi di evento SSE durante lo streaming (inizio dei blocchi di contenuto, delta, poi stop). L'argomento aEvent ti permette di distinguerli se ne hai bisogno; per una semplice UI "mostra il testo man mano che arriva", aggiungere aData è sufficiente.
Gemini e Ollama: la stessa forma
Google Gemini segue lo schema identico con il proprio metodo di streaming, _CreateContentStream su TsgcHTTP_API_Gemini:
Gemini.OnHTTPAPISSE := HandleSSE;
Gemini._CreateContentStream(
'gemini-2.0-flash',
'Explain quantum entanglement',
1024);
I modelli locali funzionano esattamente allo stesso modo. TsgcHTTP_API_Ollama non richiede alcuna chiave API — punta OllamaOptions.BaseUrl su http://localhost:11434/api e chiama _CreateMessageStream, e il modello aperto sul tuo hardware viene trasmesso in streaming attraverso lo stesso gestore OnHTTPAPISSE:
Ollama.OllamaOptions.BaseUrl := 'http://localhost:11434/api';
Ollama.OnHTTPAPISSE := HandleSSE;
Ollama._CreateMessageStream('llama3', 'Summarise RFC 6455');
Quattro provider, un evento, una chiamata di metodo ciascuno. Cambiare il backend di streaming è una modifica localizzata, non una riscrittura.
Aggiornare la UI in sicurezza
Un paio di note pratiche per il gestore. Primo, mantieni piccolo il lavoro all'interno di OnHTTPAPISSE — aggiungi il delta e ritorna. Un'elaborazione pesante per ogni token renderà lo stream a scatti, quindi accumula il testo ed esegui la formattazione costosa una volta che lo stream è terminato. Secondo, fai attenzione al contesto del thread. Se avvii la richiesta da un thread in background, l'evento SSE viene generato su quel thread, e toccare i controlli VCL o FMX al di fuori del thread principale non è sicuro. In tal caso reindirizza l'aggiornamento con TThread.Synchronize (o TThread.Queue per un'aggiunta non bloccante):
procedure TForm1.HandleSSE(Sender: TObject;
const aEvent, aData: string; var Cancel: Boolean);
begin
TThread.Queue(nil,
procedure
begin
Memo1.SelStart := Length(Memo1.Text);
Memo1.SelText := aData; // append at the caret, no full repaint
end);
end;
Aggiungere con SelText invece di Lines.Add evita di ricomporre l'intera Memo a ogni token, il che mantiene fluido uno stream lungo. Se chiami l'API dal thread principale, puoi eliminare il wrapper TThread.Queue e aggiornare il controllo direttamente.
Come iniziare
Tutti questi componenti sono inclusi in sgcWebSockets. Scarica la prova gratuita, inserisci il componente per il provider che desideri, assegna OnHTTPAPISSE e chiama il metodo di streaming — avrai una UI token per token in poche righe. Consulta la pagina del componente OpenAI e la pagina del componente Anthropic per il riferimento completo dei metodi, oppure esplora ogni modello nell'hub dei componenti AI & LLM.
Domande o feedback? Contattaci — riceverai una risposta dalle persone che hanno scritto il codice.
