`finish_reason=length`가 빈 콘텐츠를 반환함 — 그리고 에러 메시지는 나를 속였다
요약
멀티 에이전트 파이프라인 구축 중 발생한 '빈 콘텐츠 반환' 에러의 원인을 분석합니다. DeepSeek-V4와 같은 추론 모델 사용 시, 토큰 예산이 reasoning_content에 모두 소비되어 실제 content가 비어 있게 되는 현상을 다룹니다.
핵심 포인트
- finish_reason이 'length'인 경우 토큰 예산 부족 확인 필요
- 추론 모델은 reasoning_content와 content 필드를 구분하여 처리해야 함
- 에러 메시지만 믿지 말고 raw finish_reason과 필드 값을 직접 검증할 것
에러 메시지는 모델이 빈 콘텐츠를 반환했다고 말했습니다. 저는 응답 스트림(response stream)이 끊긴 것이라고 가정했습니다. 하지만 그렇지 않았습니다.
내가 쫓고 있었던 것 (잘못된 방향)
나의 멀티 에이전트(multi-agent) 콘텐츠 파이프라인이 벽에 부딪혔습니다. 생성 단계 중 하나가 "model returned empty content" 에러를 던지며 전체 실행이 중단되었습니다. 메시지는 출력 레이어(output layer)를 가리키고 있었기에, 저는 그 부분부터 조사를 시작했습니다.
저는 스트리밍 경로(streaming path)를 계측(instrumenting)하는 데 몇 차례 시간을 보냈습니다. SSE 연결이 응답 중간에 끊기는지, 제공자(provider)가 속도 제한(rate-limiting)을 걸어 소켓(socket)을 조용히 닫아버리는지, 혹은 나의 역직렬화(deserialization) 과정에서 바이트(bytes)를 잡아먹고 있는지를 확인했습니다. 로그는 매번 깨끗했습니다. 요청이 나가고, 응답이 돌아왔으며, 전체 라운드 트립(round-trip)이 완료되었고, 타임아웃(timeout)도 없었습니다. 유일하게 누락된 것은 어시스턴트 턴(assistant turn)의 실제 콘텐츠뿐이었습니다.
그다음에는 제공자 측의 문제라고 의심했습니다. 아마도 엔드포인트(endpoint)가 잘못된 형식의 청크(chunk)를 반환했고, 나의 클라이언트가 이를 조용히 버리고 있는 것일지도 모른다고 생각했습니다. HTTP 레이어에 더 많은 로깅을 추가했습니다. 여전히 아무것도 발견되지 않았습니다. 요청은 성공적으로 완료되었습니다. finish_reason: "length". 콘텐츠 필드에는 토큰이 0개였습니다.
저는 완전히 잘못된 레이어를 쫓고 있었습니다.
실제로 일어나고 있었던 일
내가 호출하고 있던 모델 — OpenAI 호환 채널을 통한 deepseek-v4 — 은 추론 모델(reasoning model)입니다. 이 모델은 가시적인 출력을 작성하기 전에 내부적인 사고 사슬(chain-of-thought)을 실행합니다. 그 추론은 content가 아닌 reasoning_content에 담깁니다.
내가 설정한 토큰 예산(token budget)이 추론 사슬(reasoning chain)에 의해 전부 소비되고 있었습니다. 모델이 생각을 마쳤을 때, 실제 응답을 위해 남은 것이 아무것도 없었습니다. 그래서 content는 ""로 반환되었습니다. 이는 전송 에러가 아니라, 말 그대로 비어 있는 상태였습니다. reasoning_content 필드에는 텍스트가 가득했습니다. 모델은 작업을 수행했습니다. 단지 가시적인 출력을 단 하나의 토큰이라도 쓰기 전에 예산이 바닥났을 뿐입니다.
오해를 불러일으킨 부분은 이렇습니다. 제가 만든 오케스트레이션 래퍼(orchestration wrapper)는 content: ""를 확인하고 `
이 해결책은 API 호출 시 토큰 예산(token budget)을 직접 제어할 수 있을 때 유효합니다. 만약 예산 파라미터를 노출하지 않는 프록시(proxy)나 관리형 엔드포인트(managed endpoint)를 통해 라우팅하거나, 오케스트레이션 계층(orchestration layer)에서 이를 추상화하여 숨겨두었다면 다른 방식의 게이트(gate)가 필요합니다. reasoningOnly 탐지는 분류(classification) 용도로 여전히 작동하지만, 설정할 수 없는 것은 고칠 수 없습니다. 그것은 별개의 문제입니다.
제가 허비한 시간은 사실 버그 때문이 아니었습니다. 바로 에러 메시지 때문이었습니다. "model returned empty content"라는 메시지는 기술적으로는 정확하지만 완전히 쓸모가 없습니다. 이는 잘못된 계층(layer)에서 증상을 설명하고 있습니다. 가공되지 않은 finish_reason과 두 개의 콘텐츠 필드를 함께 확인하는 순간 원인은 명확해졌습니다. 에러 메시지는 단 한 번도 저를 그곳으로 안내하지 않았습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기