Resposta rápida: para receber uma resposta de LLM em streaming no Delphi com o sgcWebSockets, atribua o evento OnHTTPAPISSE do componente e, em seguida, chame o método de streaming — _CreateChatCompletion com Stream := True para a OpenAI, _CreateMessageStream para a Anthropic Claude e o Ollama, _CreateContentStream para a Gemini. Cada delta chega no handler como um Server-Sent Event; acrescente aData a um Memo e a resposta se digita sozinha conforme o modelo a gera.
Uma chamada de LLM sem streaming bloqueia até que toda a resposta esteja pronta. Para uma resposta de um parágrafo, tudo bem, mas para uma conclusão longa o usuário fica olhando para uma janela congelada por vários segundos sem nenhum feedback. O streaming resolve isso: o modelo retorna a saída como uma sequência de pequenos blocos por uma única conexão HTTP, e você renderiza cada bloco no instante em que ele chega. O resultado é o familiar efeito de "digitação" que você vê no ChatGPT, e uma interface que parece responsiva mesmo quando a resposta completa demora um pouco.
Como o streaming funciona: OnHTTPAPISSE
Por baixo dos panos, todo componente de IA do sgcWebSockets faz streaming usando Server-Sent Events (SSE). O provedor mantém a resposta aberta e envia eventos conforme os tokens são produzidos. O componente analisa esses eventos e dispara um evento por bloco através de um único handler com a mesma assinatura em todos os componentes:
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;
Esse é todo o contrato. aData carrega o conteúdo incremental, aEvent informa qual é o tipo de evento (útil com provedores que emitem vários tipos de evento), e definir Cancel := True interrompe o stream, por exemplo quando o usuário clica em um botão Parar. O mesmo formato de handler funciona para OpenAI, Anthropic, Gemini e Ollama, então, uma vez que você o tenha escrito, pode reutilizá-lo entre os provedores.
OpenAI: Stream := True
Com o TsgcHTTP_API_OpenAI, você opta pelo streaming na requisição e conecta o evento. Defina OpenAIOptions.ApiKey, atribua OnHTTPAPISSE e a conclusão do chat é entregue bloco a bloco em vez de em um único pedaço:
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;
A requisição tipada expõe uma propriedade Stream, então, quando você constrói o objeto da requisição você mesmo, define Stream := True antes de enviar. Os tokens então aparecem através de OnHTTPAPISSE conforme são gerados, e você acrescenta cada um ao seu Memo.
Anthropic Claude: _CreateMessageStream
O Claude expõe um helper de streaming dedicado, então não há nenhum flag separado para acionar: chamar _CreateMessageStream no TsgcHTTP_API_Anthropic ativa o SSE para aquela requisição. Defina a chave de API e a versão, atribua o handler e chame-o:
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;
O Claude emite vários tipos de evento SSE enquanto faz streaming (início de blocos de conteúdo, deltas e depois parada). O argumento aEvent permite distingui-los se você precisar; para uma interface simples de "mostrar o texto conforme chega", acrescentar aData é suficiente.
Gemini e Ollama: o mesmo formato
A Google Gemini segue o padrão idêntico com o seu próprio método de streaming, _CreateContentStream no TsgcHTTP_API_Gemini:
Gemini.OnHTTPAPISSE := HandleSSE;
Gemini._CreateContentStream(
'gemini-2.0-flash',
'Explain quantum entanglement',
1024);
Modelos locais funcionam exatamente da mesma forma. O TsgcHTTP_API_Ollama não precisa de chave de API — aponte OllamaOptions.BaseUrl para http://localhost:11434/api e chame _CreateMessageStream, e o modelo aberto no seu próprio hardware faz streaming de volta pelo mesmo handler OnHTTPAPISSE:
Ollama.OllamaOptions.BaseUrl := 'http://localhost:11434/api';
Ollama.OnHTTPAPISSE := HandleSSE;
Ollama._CreateMessageStream('llama3', 'Summarise RFC 6455');
Quatro provedores, um evento, uma chamada de método cada. Trocar o backend de streaming é uma edição localizada, não uma reescrita.
Atualizando a interface com segurança
Algumas notas práticas para o handler. Primeiro, mantenha o trabalho dentro de OnHTTPAPISSE pequeno — acrescente o delta e retorne. Processamento pesado por token deixará o stream com aparência irregular, então acumule o texto e faça a formatação custosa quando o stream terminar. Segundo, atente-se ao contexto de thread. Se você iniciar a requisição a partir de uma thread em segundo plano, o evento SSE dispara nessa thread, e tocar em controles VCL ou FMX fora da thread principal não é seguro. Nesse caso, encaminhe a atualização de volta com TThread.Synchronize (ou TThread.Queue para um acréscimo não bloqueante):
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;
Acrescentar com SelText em vez de Lines.Add evita reorganizar todo o Memo a cada token, o que mantém um stream longo suave. Se você chamar a API a partir da thread principal, pode dispensar o wrapper TThread.Queue e atualizar o controle diretamente.
Primeiros passos
Todos esses componentes vêm no sgcWebSockets. Baixe a versão de avaliação gratuita, adicione o componente do provedor que você quiser, atribua OnHTTPAPISSE e chame o método de streaming — você terá uma interface token a token em poucas linhas. Veja a página do componente OpenAI e a página do componente Anthropic para a referência completa dos métodos, ou explore todos os modelos no hub de componentes de IA & LLM.
Dúvidas ou comentários? Entre em contato — você receberá uma resposta das pessoas que escreveram o código.
