prompt 시행착오 - 말 안 듣는 인공지능 요약시키기
문제 개요
오류 상황과 영향 범위 (예: 특정 코드 실행 시 발생, 특정 라이브러리 버전 호환 문제 등) 발생 배경 (예: 코드 테스트 중, 배포 중 문제 발견 등)
제미니 기반의 요약 시스템을 도입하는 과정에서 출력값의 한국어가 일정 확률로 깨지는 문제가 발생했고 이로 인해 시스템 전반의 신뢰도가 떨어졌다. 처음에는 모델의 한계로 의심했지만 프롬프트를 직접 입력했을 때는 문제가 없었던 반면 도플러를 통해 환경변수로 주입한 이후부터 문제가 반복되는 모습이 관찰되어 입력 방식 자체에 원인이 있을 것으로 판단했다.
프롬프트를 바이트 배열로 추출한 뒤 UTF-8로 다시 디코딩하는 방법을 적용하자 깨지는 현상이 사라졌다. 그러나 이번에는 JSON 형식이 무너지는 문제가 발생했고 title이나 summary 키가 중복되거나 줄바꿈이나 특수문자가 비정상적으로 포함되며 JSON 파싱 오류가 자주 발생했다.
ObjectMapper 설정을 수정해 제어 문자를 허용하도록 구성했지만 문제는 완전히 해결되지 않았다. 프롬프트를 수정하면 세 문단으로 요청하는 프롬프트 자체가 줄바꿈을 유도하면서 JSON 파싱에 영향을 준다는 것을 파악하게 되었고, 프롬프트를 수정해 summary의 값에는 절대로 큰따옴표를 포함하지 않고 줄바꿈을 사용하지 않으며 summary 키는 하나만 존재해야 한다는 조건을 명확하게 명시하자 출력이 어느 정도 안정되기 시작했다.
그럼에도 여전히 예상치 못한 형태의 출력이 존재했기 때문에 후처리 로직에서는 JSON 파싱이 실패하면 가장 앞에 있는 키워드를 사용해 대체 포스트를 생성하도록 구성해 요약이 실패한 상황에서도 시스템은 전체적으로 동작할 수 있도록 만들었다.
이후 챗지피티 및 클로드 인공지능 추가로, 만약 처음 요약이 실패할 경우 이어서 다른 인공지능을 이용해 요약을 진행하게 코드를 수정했다.
오류 메시지 및 원인 분석
오류 코드, 오류 메시지 포함 HTTP 상태 코드, 애플리케이션 로그, 서버 로그 등 구체적인 오류 정보 정리 및 로그 메시지를 통한 분석 제공 문제 발생 원인에 대한 심층 분석
요약들 중 일부 출력값이 다음과 같은 형태로 내려오며 JSON 파싱이 실패했다.
{
"title": "내용 안의 “쌍따옴표”",
"summary": "첫번째 줄 \\n\\\\\\n\\\\\\n두 번째 줄\\nn\\n세 번째 줄"
}
summary의 키에 줄바꿈이 지나치게 많이 포함돼 있었고 이스케이프 문자가 중복된 형태로 출력되었다. 일부는 역슬래시만 남아 있어Unexpected character ('\\' (code 92)) 오류가 계속해서 발생했다.
또 다른 상황은 summary 키, 값이 세 번 중복되어 JSON으로 파싱할 수 없는 형태가 되었다.
{
"title": "내용",
"summary": "요약",
"summary": "요약",
"summary": "요약"
}
이 경우에는 Jackson이 Duplicate field 'summary' 오류를 발생시키며 이후 로직이 중단되었고 실제 응답이 JSON으로 시작되더라도 내부가 파싱되지 않기 때문에 파라미터 검증 단계에서 HttpMessageNotReadableException 이 발생했다.
무엇보다 결정적인 문제는 특정 키나 형식의 유무보다도, 이를 해결하기 위한 프롬프트가 구체적일수록 오히려 모델이 의도와 다른 방식으로 출력하게 만든다는 점이었다. 모델이 생성하는 텍스트가 JSON의 문법적 유효성을 지속적으로 위반하는 현상이 반복되었다.
해결 및 고민 과정
처음 문제를 접했을 때 고려했던 대안들과 선택하지 않은 이유 실험적으로 적용한 방법이 실패한 사례와 그 이유 여러 해결책 중 최적의 방안을 선택한 과정
- 문자 깨짐 문제 해결
- Doppler 환경변수에서 프롬프트를 주입하는 방식이 인코딩 문제를 유발했다.
- 바이트 배열로 추출 후 UTF-8로 재디코딩했다.
- ObjectMapper 설정 변경
- JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS 활성화했다.
- 제어문자 허용 설정을 적용했다.
- 어느정도 결과가 나아졌으나 JSON으로 데이터를 받는 다른 부분에서 문제가 발생하고 완전한 해결책이 되지 않아 설정을 되돌렸다.
- @Configuration public class ObjectMapperConfig { @Bean @Primary public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true); return mapper; } }
- 프롬프트 조정
- 줄바꿈 제거, 큰따옴표 포함 금지 조건을 추가했다.
- summary 키는 하나만 존재해야 함을 명시했다.
- 예시 출력 양식을 명확히 포함시켰다.
- 후처리 보완
- JSON 파싱 실패 시 가장 앞쪽 키워드를 활용해 요약 실패 시에도 포스트 작성이 유지되도록 했다.
- 이후 다른 인공지능 추가로 요약 실패 시 다른 인공지능에게 다시 요약을 요청하는 프로세스로 변경했다.
최종 해결책 및 구현
문제 해결을 위한 단계별 조치 방법과 코드 예시 (예: 특정 애노테이션 추가, 라이브러리 버전 조정, 설정 변경 등) 참고 자료 (관련 공식 문서, 개발자 커뮤니티 게시물 등)
- 프롬프트 수정:
- title 및 summary 값에 큰따옴표(")를 포함하지 않는다.프롬프트에 명시.
- 제일 문제가 발행하던 줄바꿈 요청을 지우기
- summary 키는 반드시 단일 키로, 결코 summary가 중복되지 않아야 한다. 로 summary가 중복되는 문제를 해결
- 최종 프롬프트
- ## System 당신은 20년차 한국 언론사 출신의 한국어 트렌드 요약 전문가이다. JSON 스펙 외의 텍스트를 절대 포함하지 않는다. 출력 형식 예시: {"title": "봄맞이 여행 트렌드", "summary": "1문단 내용... 2문단 내용... 3문단 내용..." } ## User 제공된 소스들의 제목, 설명, URL, 플랫폼 정보를 바탕으로, 1. title은 흥미를 끌 수 있는 한국어 문구로 최대 50자로 작성하라. 2. summary는 한국어 3문단으로 작성하라. 3. 반드시 한국어로 작성하되 정말 필요한 경우에는 단어 단위로만 영어를 사용한다. 4. 특수문자(이모지, 기호)나 한국어·영어 외 언어는 소스에 존재하더라도 포함하지 않는다. 5. 작정자, 기자명, 신문사명 등 소스의 출처 관련으로 보이는 내용은 절대 포함하지 않는다. 6. 반드시 단일 JSON 객체 하나만 출력해야 한다. 배열([…]) 형태는 절대 허용되지 않는다. 7. summary 키는 반드시 단일 키로, 결코 summary가 중복되지 않아야 한다. 8. title 및 summary 값에 큰따옴표(")를 포함하지 않는다.
- 후처리:
- JSON 파싱 실패 시 예외 처리 후 fallback으로 다른 인공지능에게 요청하고 그럼에도 실패하면 요약을 시도한 소스 데이터 중 첫번째 뉴스를 요약 포스트에 넣도록 했다.
결과 및 성능 분석
개선 후 응답 속도, DB 부하 감소 수치 등 구체적인 데이터 포함 문제 해결 전/후 성능 비교 그래프나 로그 분석 내용 포함 이슈 트래킹 및 자동화 방안 추가 (내부 개발자가 반복적인 문제 해결을 효율적으로 관리할 수 있도록 가이드 제공)
- 출력 깨짐 현상이 완전히 사라졌다.
- JSON 파싱 오류 빈도가 약 80% 이상 감소했다.
- 예외 상황에서도 전체 파이프라인은 중단되지 않고 계속 동작했다.
- 프롬프트 안정성이 향상되어 운영 측 신뢰도가 개선되었다.
추후 개선 및 고려할 점
유사한 문제를 방지하기 위한 주의할 점 (예: 애노테이션 명시 여부, 프레임워크 업데이트 주기 확인 등) 문제 해결 과정에서 배운 점 및 중요한 교훈 공유 보안 고려 사항 추가 (해결 과정에서 발생할 수 있는 보안 리스크 및 예방 조치 포함)
- 완전한 해결은 불가능하다는 점을 전제로, 예외 대응 체계와 유연한 후처리 로직 설계를 병행해야 한다.
- AI 출력은 언제든 예외가 발생할 수 있다는 전제를 기반으로 코드와 같은 에러 자체를 방지하는 방식보다는 로직 방어 설계가 필요하다.