Snel antwoord: om een LLM-antwoord in Delphi te streamen met sgcWebSockets, wijs je de OnHTTPAPISSE-gebeurtenis van het component toe, en roep je vervolgens de streamingmethode aan — _CreateChatCompletion met Stream := True voor OpenAI, _CreateMessageStream voor Anthropic Claude en Ollama, _CreateContentStream voor Gemini. Elke delta arriveert in de handler als een Server-Sent Event; voeg aData toe aan een Memo en het antwoord typt zichzelf uit terwijl het model het genereert.
Een niet-streamende LLM-aanroep blokkeert totdat het hele antwoord klaar is. Voor een antwoord van één alinea is dat prima, maar bij een lange completion staart de gebruiker enkele seconden naar een bevroren venster zonder enige feedback. Streaming lost dat op: het model geeft zijn uitvoer terug als een reeks kleine fragmenten over een enkele HTTP-verbinding, en je rendert elk fragment op het moment dat het binnenkomt. Het resultaat is het vertrouwde "typ"-effect dat je in ChatGPT ziet, en een UI die responsief aanvoelt zelfs wanneer het volledige antwoord even duurt.
Hoe streaming werkt: OnHTTPAPISSE
Onder de motorkap streamt elk sgcWebSockets AI-component met Server-Sent Events (SSE). De provider houdt het antwoord open en duwt gebeurtenissen door zodra tokens worden geproduceerd. Het component parseert die gebeurtenissen en triggert één gebeurtenis per fragment via een enkele handler met dezelfde signatuur op elk component:
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;
Dat is het hele contract. aData draagt de incrementele payload, aEvent vertelt je om welk soort gebeurtenis het gaat (handig bij providers die meerdere gebeurtenistypen uitzenden), en het instellen van Cancel := True stopt de stream, bijvoorbeeld wanneer de gebruiker op een Stop-knop klikt. Dezelfde handlervorm werkt voor OpenAI, Anthropic, Gemini en Ollama, dus zodra je hem één keer hebt geschreven, kun je hem hergebruiken over providers heen.
OpenAI: Stream := True
Met TsgcHTTP_API_OpenAI kies je op de aanvraag voor streaming en koppel je de gebeurtenis. Stel OpenAIOptions.ApiKey in, wijs OnHTTPAPISSE toe, en de chat completion wordt fragment voor fragment geleverd in plaats van in één blok:
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;
De getypeerde aanvraag stelt een Stream-eigenschap beschikbaar, dus wanneer je het aanvraagobject zelf opbouwt, stel je Stream := True in voordat je verstuurt. Tokens komen dan tevoorschijn via OnHTTPAPISSE zodra ze worden gegenereerd, en je voegt elke token toe aan je Memo.
Anthropic Claude: _CreateMessageStream
Claude biedt een aparte streaminghelper, dus er is geen aparte vlag om om te zetten: het aanroepen van _CreateMessageStream op TsgcHTTP_API_Anthropic schakelt SSE in voor die aanvraag. Stel de API-sleutel en versie in, wijs de handler toe, en roep hem aan:
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 zendt verschillende SSE-gebeurtenistypen uit terwijl het streamt (start van contentblokken, delta's, dan stop). Het argument aEvent laat je ze uit elkaar houden als dat nodig is; voor een eenvoudige "toon de tekst zoals hij binnenkomt"-UI volstaat het toevoegen van aData.
Gemini en Ollama: dezelfde vorm
Google Gemini volgt het identieke patroon met zijn eigen streamingmethode, _CreateContentStream op TsgcHTTP_API_Gemini:
Gemini.OnHTTPAPISSE := HandleSSE;
Gemini._CreateContentStream(
'gemini-2.0-flash',
'Explain quantum entanglement',
1024);
Lokale modellen werken precies hetzelfde. TsgcHTTP_API_Ollama heeft geen API-sleutel nodig — wijs OllamaOptions.BaseUrl naar http://localhost:11434/api en roep _CreateMessageStream aan, en het open model op je eigen hardware streamt terug via dezelfde OnHTTPAPISSE-handler:
Ollama.OllamaOptions.BaseUrl := 'http://localhost:11434/api';
Ollama.OnHTTPAPISSE := HandleSSE;
Ollama._CreateMessageStream('llama3', 'Summarise RFC 6455');
Vier providers, één gebeurtenis, één methodeaanroep elk. Het wisselen van de streamingbackend is een lokale aanpassing, geen herschrijving.
De UI veilig bijwerken
Een paar praktische opmerkingen voor de handler. Houd ten eerste het werk binnen OnHTTPAPISSE klein — voeg de delta toe en keer terug. Zware verwerking per token maakt de stream schokkerig, dus verzamel de tekst en doe dure formattering pas zodra de stream is voltooid. Let ten tweede op de threadcontext. Als je de aanvraag vanuit een achtergrondthread start, vuurt de SSE-gebeurtenis op die thread af, en het aanraken van VCL- of FMX-controls buiten de hoofdthread is niet veilig. Marshall in dat geval de update terug met TThread.Synchronize (of TThread.Queue voor een niet-blokkerende toevoeging):
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;
Toevoegen met SelText in plaats van Lines.Add voorkomt dat de hele Memo bij elke token opnieuw wordt opgemaakt, wat een lange stream soepel houdt. Als je de API vanuit de hoofdthread aanroept, kun je de TThread.Queue-wrapper weglaten en de control rechtstreeks bijwerken.
Aan de slag
Al deze componenten zitten in sgcWebSockets. Pak de gratis proefversie, voeg het component toe voor de provider die je wilt, wijs OnHTTPAPISSE toe en roep de streamingmethode aan — je hebt een token-voor-token UI in een paar regels. Zie de pagina van het OpenAI-component en de pagina van het Anthropic-component voor de volledige methodereferentie, of bekijk elk model op de hub met AI & LLM-componenten.
Vragen of feedback? Neem contact op — je krijgt antwoord van de mensen die de code geschreven hebben.
