빠른 답변: sgcWebSockets로 Delphi에서 LLM 응답을 스트리밍하려면, 컴포넌트의 OnHTTPAPISSE 이벤트를 할당한 다음 스트리밍 메서드를 호출하세요 — OpenAI는 Stream := True를 지정한 _CreateChatCompletion, Anthropic Claude와 Ollama는 _CreateMessageStream, Gemini는 _CreateContentStream입니다. 각 델타는 Server-Sent Event로 핸들러에 도착합니다. aData를 Memo에 덧붙이면 모델이 생성하는 대로 답변이 스스로 타이핑되어 나옵니다.
스트리밍하지 않는 LLM 호출은 전체 답변이 준비될 때까지 블록됩니다. 한 문단짜리 응답에는 괜찮지만, 긴 완성에는 사용자가 아무런 피드백 없이 몇 초간 멈춘 창을 바라보게 됩니다. 스트리밍이 이를 해결합니다. 모델은 출력을 하나의 HTTP 연결을 통해 작은 청크의 연속으로 반환하고, 당신은 각 청크가 도착하는 순간 렌더링합니다. 그 결과가 ChatGPT에서 보는 익숙한 "타이핑" 효과이며, 전체 답변에 시간이 걸려도 반응이 빠르게 느껴지는 UI입니다.
스트리밍이 작동하는 방식: OnHTTPAPISSE
내부적으로 모든 sgcWebSockets AI 컴포넌트는 Server-Sent Events(SSE)를 사용해 스트리밍합니다. 제공자는 응답을 열어 두고 토큰이 생성되는 대로 이벤트를 푸시합니다. 컴포넌트는 그 이벤트를 파싱하여, 모든 컴포넌트에서 동일한 시그니처를 갖는 하나의 핸들러를 통해 청크마다 하나의 이벤트를 발생시킵니다.
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;
그것이 전체 계약입니다. aData는 증분 페이로드를 담고, aEvent는 어떤 종류의 이벤트인지 알려주며(여러 이벤트 유형을 내보내는 제공자에 유용), Cancel := True를 설정하면 스트림을 멈춥니다. 예를 들어 사용자가 Stop 버튼을 클릭할 때입니다. 같은 핸들러 형태가 OpenAI, Anthropic, Gemini, Ollama에 모두 작동하므로, 한 번 작성하면 제공자 간에 재사용할 수 있습니다.
OpenAI: Stream := True
TsgcHTTP_API_OpenAI에서는 요청에서 스트리밍을 선택하고 이벤트를 연결합니다. OpenAIOptions.ApiKey를 설정하고, OnHTTPAPISSE를 할당하면, 채팅 완성이 하나의 블록 대신 청크 단위로 전달됩니다.
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;
타입이 지정된 요청은 Stream 속성을 노출하므로, 요청 객체를 직접 구성할 때 전송하기 전에 Stream := True를 설정합니다. 그러면 토큰이 생성되는 대로 OnHTTPAPISSE를 통해 나타나고, 각 토큰을 Memo에 덧붙이면 됩니다.
Anthropic Claude: _CreateMessageStream
Claude는 전용 스트리밍 헬퍼를 노출하므로 따로 켤 플래그가 없습니다. TsgcHTTP_API_Anthropic에서 _CreateMessageStream을 호출하면 그 요청에 SSE가 켜집니다. API 키와 버전을 설정하고, 핸들러를 할당한 다음 호출하세요.
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는 스트리밍하면서 여러 SSE 이벤트 유형을 내보냅니다(콘텐츠 블록 시작, 델타, 그다음 정지). 필요하다면 aEvent 인자로 이들을 구분할 수 있습니다. 단순히 "도착하는 대로 텍스트를 보여주는" UI에는 aData를 덧붙이는 것으로 충분합니다.
Gemini와 Ollama: 같은 형태
Google Gemini는 자체 스트리밍 메서드인 TsgcHTTP_API_Gemini의 _CreateContentStream으로 동일한 패턴을 따릅니다.
Gemini.OnHTTPAPISSE := HandleSSE;
Gemini._CreateContentStream(
'gemini-2.0-flash',
'Explain quantum entanglement',
1024);
로컬 모델도 정확히 같은 방식으로 동작합니다. TsgcHTTP_API_Ollama는 API 키가 필요 없습니다 — OllamaOptions.BaseUrl을 http://localhost:11434/api로 가리키고 _CreateMessageStream을 호출하면, 자신의 하드웨어에서 실행되는 오픈 모델이 같은 OnHTTPAPISSE 핸들러를 통해 스트리밍되어 돌아옵니다.
Ollama.OllamaOptions.BaseUrl := 'http://localhost:11434/api';
Ollama.OnHTTPAPISSE := HandleSSE;
Ollama._CreateMessageStream('llama3', 'Summarise RFC 6455');
네 개의 제공자, 하나의 이벤트, 각각 하나의 메서드 호출. 스트리밍 백엔드를 전환하는 것은 재작성이 아니라 국소적인 편집입니다.
UI를 안전하게 업데이트하기
핸들러에 대한 몇 가지 실용적인 메모가 있습니다. 첫째, OnHTTPAPISSE 안의 작업은 작게 유지하세요 — 델타를 덧붙이고 반환하세요. 토큰마다 무거운 처리를 하면 스트림이 끊기는 느낌을 주므로, 텍스트를 누적해 두고 비용이 큰 서식 처리는 스트림이 끝난 뒤 한 번에 하세요. 둘째, 스레드 컨텍스트에 유의하세요. 백그라운드 스레드에서 요청을 시작하면 SSE 이벤트가 그 스레드에서 발생하며, 메인 스레드가 아닌 곳에서 VCL이나 FMX 컨트롤을 건드리는 것은 안전하지 않습니다. 그런 경우 TThread.Synchronize(또는 논블로킹 덧붙임에는 TThread.Queue)로 업데이트를 되돌려 마샬링하세요.
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;
Lines.Add 대신 SelText로 덧붙이면 토큰마다 전체 Memo를 다시 흐르게 하는 것을 피할 수 있어, 긴 스트림이 매끄럽게 유지됩니다. 메인 스레드에서 API를 호출한다면 TThread.Queue 래퍼를 빼고 컨트롤을 직접 업데이트할 수 있습니다.
시작하기
이 컴포넌트들은 모두 sgcWebSockets에 포함되어 있습니다. 무료 평가판을 받아서, 원하는 제공자의 컴포넌트를 놓고, OnHTTPAPISSE를 할당하고 스트리밍 메서드를 호출하세요 — 몇 줄로 토큰 단위 UI를 갖게 됩니다. 전체 메서드 레퍼런스는 OpenAI 컴포넌트 페이지와 Anthropic 컴포넌트 페이지를 보거나, 모든 모델은 AI & LLM 컴포넌트 허브에서 둘러보세요.
질문이나 피드백이 있나요? 문의하기 — 코드를 작성한 사람들로부터 답변을 받게 됩니다.
