고객 문의 텍스트에서 이름/이메일/요청유형 같은 걸 뽑아서 JSON으로 받는 추출기를 만들고 있어요. response_format을 { "type": "json_object" }로 켜뒀습니다. 유효한 JSON이 오긴 하는데, 문제는 내용이에요.
가끔 {} 처럼 아예 빈 객체가 오거나, 있어야 할 필드가 통째로 빠진 채로 옵니다. 어떨 때는 값은 다 있는데 이상하게 마크다운 코드펜스로 감싸서 오기도 하고요. 프롬프트에는 필드 이름이랑 예시 출력까지 다 적어놨는데도 이럽니다.
// 기대
{"name": "홍길동", "email": "a@b.com", "type": "환불"}
// 가끔 이렇게 옴
{}json_object 켜면 스키마대로 나오는 거 아니었나요? 후처리에서 매번 방어 코드를 덕지덕지 붙이고 있는데 근본적으로 뭘 잘못하고 있는 건지 알고 싶습니다.
댓글 3
필드 구조까지 강제하려면 json_object가 아니라 스키마 기반 구조화 출력(json_schema, strict)을 써야 합니다. required에 필드를 다 넣고 additionalProperties를 false로 잠그면, 그 필드들이 반드시 지정한 타입으로 채워져 나옵니다. 마크다운 펜스로 감싸는 것도 이 모드에선 안 생겨요.
그리고 {} 로 비어 오는 케이스 중 일부는 모델이 값을 못 찾아서가 아니라 출력이 max_tokens에 걸려 잘린 겁니다. 그때 stop_reason/finish_reason이 length인지 꼭 확인하세요. 이건 스키마로도 못 살리고 토큰을 올려야 합니다.
마지막으로 프롬프트에 예시 출력을 마크다운 블록으로 보여주면 모델이 그 펜스까지 따라 하는 경향이 있어요. 구조화 출력으로 넘어가면 그 지시 자체가 필요 없어지니 지우세요.
그러면 값이 없을 때 빈 문자열이 아니라 명시적으로 null이 옵니다. 후처리에서 null 체크로 없음/있음을 딱 구분할 수 있고요. 프롬프트에도 해당 정보가 없으면 그 필드는 null로 두라고 한 줄 박아주면 모델이 빈 문자열로 얼버무리는 걸 줄여줍니다. enum 같은 걸 섞을 땐 null 케이스를 enum에 넣지 말고 타입 레벨에서 nullable로 처리하는 게 깔끔해요.