QA Agent planning 시간 30분에서 6초로, GLM 빈 응답 폴백

26년 04월 14일

planning 시간 30분에서 6초

이날은 숨겨진 근본 원인을 찾아서 해결한 날이었다.

가장 극적인 건 QA Agent의 planning 시간을 30분에서 6초로 줄인 거다.

그리고 ClawMux에서 ZAI GLM이 빈 응답을 보내는 문제도 잡았다.

여러 프로젝트의 숨은 버그를 하나씩 뽑아낸 날이었다.

가장 큰 성과는 Explore 서브에이전트 문제를 해결한 거다.

Explore 서브에이전트는 planning 단계에서 브라우저를 탐색하는 역할이다.

테스트 대상 페이지 구조를 파악하고 어디에 뭐가 있는지 알아낸다.

그런데 이 에이전트가 자주 실패했다.

속도 제한에 걸리거나 응답이 없었다.

그러니까 planning이 최대 30분까지 걸렸다.

30분이면 실행 하나에 30분이 날아간다.

이건 쓸 수 없는 수준이었다.

근본 원인을 파니까 세 가지가 겹쳐 있었다.

인증 타입이 불일치했다.

환경변수가 누락되어 있었다.

그리고 속도 제한 처리가 안 되어 있었다.

이 세 가지를 다

잡으니까 planning 시간이 30분에서 6초로 떨어졌다.

6초다.

300배 빨라진 거다.

표면적으로 “속도 제한에 걸리니까 재시도를 늘리자” 하는 식의 우회가 아니라, 인증이랑 환경변수라는 근본 원인을 잡으니까

이런 결과가 나왔다.

Langfuse 직접 연동으로 전환

며칠 전에 Langfuse 연동을 완성했다.

LLM 호출을 추적하는 관측 플랫폼이다.

근데 그때는 도커 프록시 3개를 띄워서 쓰는 구조였다.

LLM 프로바이더마다 프록시를 따로 두는 방식이었다.

이날 그 프록시 3개를 없애고 플러그인 훅 기반 직접 연동으로 바꿨다.

컨테이너 3개를 유지보수하는 운영 복잡도가 사라졌다.

그리고 실행 전체 흐름을 Trace ID로 추적할 수 있게 구조가 단순해졌다.

구조를 단순하게 만드는 결정이 종종 가장 좋은 결정이다.

프록시 3개는 돌아가긴 했지만 유지비가 있었다.

직접 연동으로 바꾸니까 같은 기능을 더 단순하게 얻었다.

GLM 빈 응답 폴백

ClawMux 쪽에서는 ZAI GLM 응답 파싱 버그를 잡았다.

증상이 묘했다.

ClawMux는 정상적으로 돌아가고 있었는데, 라우팅 결과가 누락되는 거다.

응답이 비어서 돌아왔다.

원인을 찾아보니 ZAI GLM이 텍스트를 예상한 필드가 아닌 다른 필드에 담아 보내고 있었다.

응답 본문은 content가 아니라 추론 내용 필드 필드에 들어 있었다.

기존 파서는 content만 보니까, 응답이 비어 있다고 판단한 거다.

해결은 추론 내용 필드 폴백을 추가하는 거다.

content가 비어 있으면 추론 내용 필드를 확인하는 식이다.

그리고 명시적으로 빈 값인지 확인하도록 로직을 고쳤다.

단순히 거짓 같은 값인지 보는 게 아니라, 정확히 비어 있는지 검사하는 거다.

스트리밍 응답도 같이 고쳤다.

스트림에서 시작 메시지 없이 내용이 먼저 오면 자동으로 시작 메시지를 끼워 넣는 로직을 추가했다.

수정하고 나서 587개 테스트가 전부 통과했다.

판타지 일기 TTS 대사 포맷

개인 프로젝트인 판타지 일기도 만졌다.

한국 괴담을 수집해서 각색하고 TTS 소설로 만드는 자동화 시스템이다.

TTS 대사 포맷을 바꿨다.

직접 인용부호랑 화자 태그를 금지했다.

대신 간접 화법, 내면 서술, 행동 묘사로 대화를 전달하게 만들었다.

이유는 TTS 음성 합성 품질 때문이다.

인용부호랑 화자 태그가 있으면 음성 합성이 부자연스러워진다.

그리고 선택지랑 투표 기능을 전면 제거했다.

에피소드를 일직선 진행 방식으로 단순화했다.

데이터베이스에서 투표 테이블이랑 선택지 테이블을 삭제하고 관련 코드 다섯 파일을 지웠다.

이 결정은 약 두 달 뒤에 더 큰 방향 전환으로 이어진다. 시드 기반 에피소드 생성 파이프라인 전체를 버리고 괴담 각색 전용 구조로 재편했다.

이때 선택지를 없앤 게 그 방향 전환의 징조였다.

회사 프로젝트 작업

회사 교육 플랫폼에서도 버그를 잡았다.

챌린지 통계 페이지에서 401 에러가 났다.

원인은 통계 API 호출에 코스 식별자가 누락된 거였다.

백엔드가 코스 식별자를 필수로 바꿨는데, 프론트엔드가 그 스펙 변경을 따라가지 못한 거다.

프론트엔드에서 코스 식별자를 제대로 넘기도록 수정하고 로컬 테스트를 돌려서 확인한 뒤 알파 환경에 배포했다.

마무리

내가 이날 배운 핵심은 다음과 같다.

하루의 패턴이 하나로 관통했다.

숨겨진 근본 원인을 찾아서 표면적 우회가 아니라 구조적으로 해결하는 거다.

planning 30분 문제가 가장 극적이었다.

재시도를 늘리거나 타임아웃을 늘리는 식의 우회가 아니라, 인증이랑 환경변수라는 근본 원인을 잡으니까 300배 빨라졌다.

GLM 빈 응답도 마찬가지다.

응답이 비었다고 에러 처리를 하는 게 아니라, 응답이 다른 필드에 들어 있다는 근본 원인을 찾아서 폴백을 추가했다.

근본 원인을 찾으면 해결은 의외로 간단한 경우가 많다.

문제는 그 근본 원인을 찾는 과정이다.

30분짜리 지연이 인증 불일치 때문이라는 걸 알아내는 데 시간이 걸린다.

근데 알아내고 나면 수정은 금방이다.