Conceptly
← 전체 목록
📐

Structured Output

오케스트레이션자연어 대신 스키마로 결과를 받는 방식

structured output은 모델 결과를 자유로운 문장 대신 스키마에 맞는 객체나 필드 구조로 받는 방식입니다. 사람이 읽기 좋은 답을 만드는 것보다, 코드가 바로 읽고 검증하고 다음 단계로 넘길 수 있게 만드는 데 초점이 있습니다.

아키텍처 다이어그램

🔄 프로세스 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

자연어로만 결과를 받으면 같은 의미라도 표현이 매번 달라져서 파싱이 깨지기 쉽습니다. '우선순위는 높음'과 'priority: high'는 사람에게는 같은 말이지만 코드에는 전혀 다른 입력입니다. 자동화 파이프라인에서 이 흔들림을 그대로 두면 parsing 예외, 잘못된 분기, 누락된 필드가 반복됩니다.

왜 이런 방식이 등장했나요?

LLM이 사람과 채팅만 할 때는 문장이 조금 달라도 큰 문제가 없었습니다. 하지만 추출, 분류, 툴 호출, UI 렌더링처럼 결과를 기계가 바로 소비해야 하는 경우가 늘면서 출력 형식 자체를 계약으로 다루는 접근이 필요해졌습니다.

내부적으로 어떻게 동작하나요?

애플리케이션은 필요한 필드와 타입, 허용 값, 필수 조건을 스키마로 정의합니다. 모델은 그 스키마를 만족하는 객체를 만들고, 런타임은 결과를 파싱해 유효성을 검사합니다. 검증에 실패하면 재시도하거나 안전한 기본 경로로 빠지기 때문에, 자연어 파싱보다 훨씬 예측 가능한 흐름을 만들 수 있습니다.

코드로 보면

출력 계약을 먼저 고정

{
  "type": "object",
  "properties": {
    "priority": { "type": "string", "enum": ["low", "medium", "high"] },
    "reason": { "type": "string" },
    "needs_review": { "type": "boolean" }
  },
  "required": ["priority", "reason", "needs_review"],
  "additionalProperties": false
}

모델에게 자유 텍스트가 아니라 필드 이름, 타입, 허용 값을 먼저 계약으로 건다는 점이 핵심입니다.

검증된 객체만 다음 단계로 넘김

const result = await runModel({ prompt, schema });

if (!result.valid) {
  return retryOrFallback();
}

handleTicket(result.output);

structured output은 JSON처럼 보이게 만드는 데서 끝나지 않고, 검증에 통과한 객체만 코드가 소비하도록 만드는 흐름입니다.

경계와 구분

prompt engineering과 structured output, tool use는 모두 모델 출력을 시스템에 연결하는 층이지만 역할이 다릅니다. 판단 기준이 흔들리면 prompt engineering을 보고, 결과 형식과 필수 필드가 흔들리면 structured output을 보고, 검증된 결과로 실제 조회나 실행을 해야 하면 tool use를 봐야 합니다. 스키마가 맞더라도 내용 자체가 틀릴 수 있으므로 structured output만으로 사실성까지 보장되지는 않습니다.

언제 쓰나요?

실무에서는 엔티티 추출, 분류, UI 상태 생성, 툴 인자 생성에 널리 쓰입니다. 필드 구조가 안정되면 평가도 훨씬 쉬워지고, 어떤 필드가 자주 비거나 잘못 채워지는지 바로 볼 수 있습니다. 반대로 스키마를 지나치게 느슨하게 두면 자유 텍스트 parsing보다 조금 나은 수준으로 다시 돌아가기 쉽습니다.

정보 추출툴 인자 생성UI 상태 생성분류 파이프라인