스트리밍은 모델을 더 빠르게 만들지 않는다. 대기 시간을 더 짧게 느껴지게 만들 뿐이다. 응답을 생성하는 총 시간은 스트리밍을 하든 안 하든 거의 동일하다. 스트리밍이 바꾸는 것은 사용자가 첫 토큰을 언제 보느냐이며, 바로 그 숫자, 즉 첫 토큰까지의 시간(time to first token)이 속도에 대한 전체적인 인상을 좌우한다. 스트리밍을 있는 그대로 UX 결정으로 다뤄야, 언제 써야 하고 언제 실제로 해가 되는지 더 나은 판단을 내릴 수 있다.

반사적으로 InvokeModelWithResponseStream이나 ConverseStream을 떠올리는 이유는 스트리밍이 성능적인 선택처럼 느껴지기 때문이다. 하지만 모델은 어느 쪽이든 같은 총 시간에 같은 토큰을 생성한다. 여러분은 처리량을 최적화하는 것이 아니다. 사람이 6초 동안 빈 화면을 바라볼지, 300밀리초 후에 텍스트가 나타나는 것을 지켜볼지를 결정하는 것이다.

첫 토큰까지의 시간이 중요한 숫자인 이유

스트리밍하지 않은 응답에는 사용자가 체감하는 지연이 하나뿐이다: 시작부터 끝까지 전체 생성 과정이다. 세 문단을 요청하면 사용자는 아무것도 나타나기 전에 그 전체를 기다린다. 총 시간이 괜찮더라도 그 대기는 시스템이 느리다는 인상으로 읽힌다.

스트리밍은 이것을 두 개의 숫자로 나눈다. 첫 토큰까지의 시간은 무언가가 나타나기까지 걸리는 시간이다. 그다음 토큰은 계속해서 도착하는데, 사람은 모델이 생성하는 속도보다 느리게 읽기 때문에 텍스트가 독자보다 앞서 있는 경향이 있다. 체감 경험은 "즉각적이고 물 흐르듯 이어지는" 느낌이지만, 실제 총 생성 시간은 전혀 변하지 않았다. 이것은 진행률 표시줄과 같은 심리다: 움직임은 진행으로 읽히고, 빈 화면은 멈춤으로 읽힌다. 사람이 산문으로 출력을 읽는 대화형 상황에서는 이 이유 하나만으로도 스트리밍이 거의 필수에 가깝다.

스트리밍이 조용히 상황을 악화시키는 지점

스트리밍은 기본값이지 법칙이 아니다. 몇 가지 흔한 경우는 완전한 응답을 기다리는 편이 더 낫다.

클라이언트가 파싱해야 하는 구조화된 출력

응답이 프론트엔드가 역직렬화하는 JSON이라면, 부분적인 스트림은 쓸모없거나 오히려 해롭다. JSON 객체의 절반을 파싱할 수는 없고, 반쯤 만들어진 구조체를 사용자에게 보여주는 것은 스피너를 보여주는 것보다 나쁘다. 출력의 소비자가 사람이 아니라 코드라면, 전체를 기다렸다가 한 번에 파싱하라. 스트리밍은 아무것도 얻지 못하면서 잘못된 부분 상태를 렌더링할 위험만 추가한다.

에이전트 내부의 도구 사용

모델이 도구 호출 결정을 스트리밍할 때, 사용자가 읽을 것은 아무것도 없다: "출력"은 산문이 아니라 도구 호출이기 때문이다. 함수 호출의 토큰을 UI로 스트리밍하는 것은 사용자가 보고 싶어 하지 않은 내부 기계장치를 보여주는 것이다. 올바른 패턴은 최종적으로 사용자에게 보여줄 답변만 스트리밍하고, 중간의 도구 호출 추론은 화면 밖에 두거나 "주문을 확인하는 중입니다" 같은 상태 표시로 표현하는 것이지, 원시 스트리밍 토큰으로 표현하는 것이 아니다.

짧은 응답

답이 한 문장이라면, 스트리밍은 체감할 수 있는 이득 없이 프로토콜 복잡도만 추가한다. 어느 쪽이든 전체가 수백 밀리초 안에 도착한다. 스트리밍 배관은 그렇지 않으면 대기가 체감될 만큼 긴 응답을 위해 아껴두라.

스트리밍할 때 짊어지는 비용

스트리밍은 공짜 엔지니어링이 아니다. 지속 시간 동안 연결을 열어두어야 하고, 이는 타임아웃, 재시도, 로드 밸런싱을 생각하는 방식을 바꾼다. 오류 처리도 더 어려워진다: 스트림 중간의 실패는 사용자에게 잘린 답변을 남기고, 여러분은 그것을 감지하고 복구해야 한다. 버퍼링된 호출에서의 깔끔한 전부-아니면-전무 실패와는 다르다. 그리고 이미 토큰 단위로 사용자에게 보여준 응답에 대해서는 Guardrails 출력 검사나 JSON 검증을 실행할 수 없다. 검증이 중요하다면 버퍼링을 하거나, 스트리밍하면서 검증하고 철회할 준비를 해야 하는데, 이는 실제로 상당한 작업이다. 스트리밍이 무조건 더 낫다고 가정하지 말고 이것을 UX 이득과 견주어라.

때로는 숫자 자체를 낮춰라

문제가 정말로 첫 토큰이 너무 오래 걸린다는 것이라면, 스트리밍은 그것을 감출 뿐 고치지 못한다. 프롬프트 캐싱은 고친다: 긴 프롬프트의 안정적인 접두부를 캐싱하면 생성이 시작되기 전 시간이 줄어들어 첫 토큰까지의 시간이 직접적으로 낮아진다. 프롬프트가 무거운 에이전트에서는 프롬프트를 다듬고 캐싱하는 것이 스트리밍보다 체감 속도에 더 큰 효과를 낼 수 있고, 스트리밍하지 않는 경우와 구조화된 출력 경우에도 함께 도움이 된다.

핵심 요약

스트리밍은 모델이 얼마나 빨리 실행되는지를 바꾸지 않는다. 첫 토큰까지의 시간을 바꾸고, 그것이 시스템이 얼마나 빠르게 느껴지는지를 바꾸므로, 이것은 UX 결정이다. 사람이 읽는 대화형 산문은 스트리밍하라. 클라이언트가 파싱해야 하는 구조화된 출력, 원시 도구 호출 추론, 한 줄짜리 답변은 스트리밍하지 마라. 그리고 첫 토큰 지연이 진짜 불만이라면, 스트리밍으로 감추기보다 프롬프트를 캐싱해서 숫자 자체를 낮춰라.

다음으로 읽을 글

지속 연결과 엣지에서의 지연 시간을 뒷받침하는 인프라는 ercan.cloud의 클라우드 필드 노트에 있고, 허브는 ercanermis.com이다.