재시도가 0%밖에 안 되던 문제
전날에 QA Agent를 멀티 에이전트 구조로 갈아엎었다.
오늘은 그 구조가 드러낸 문제를 잡는 날이었다.
가장 큰 문제는 재시도 성공률이 0%라는 거였다.
막힌 케이스를 다시 돌려도 하나도 안 통과했다.
전날 만든 2단계 재시도 구조에 치명적인 문제가 있었다.
1단계에서 막힌 케이스를 2단계에서 다시 돌리는데, 성공률이 0%였다.
원인은 단순했다.
재시도를 할 때 막힌 원인을 분석하지 않고 그냥 다시 돌렸기 때문이다.
케이스가 타임아웃으로 막혔든, 브라우저 에러로 막혔든, 데이터가 없어서 막혔든, 같은 상태로 다시 돌리니까 같은 이유로 또 막힌다.
재시도라기보다는 반복에 가까웠다.
그래서 Inspector라는 에이전트를 배포했다.
Inspector 에이전트
Inspector의 역할은 실행 중인 Executor를 감시하고 케이스가 막혔을 때 왜 막혔는지 분석하는 거다.
케이스가 막히면 Inspector가 달려간다.
타임아웃인지, 브라우저 에러인지, 데이터가 없어서인지 원인을 분류한다.
그리고 그 분석 결과를 재시도에 주입한다.
이제 재시도는 막힌 원인을 알고 출발한다.
예를 들어 타임아웃으로 막혔으면 재시도할 때 대기 시간을 늘리거나 대체 경로를 시도할 수 있다.
데이터가 없어서 막혔으면 어디서 데이터를 가져와야 하는지 힌트를 줄 수 있다.
원인을 모르고 다시 돌리는 것과, 원인을 알고 다시 돌리는 건 완전히 다르다.
이렇게 하니까 재시도 성공률이 0%에서 올라갔다.
막힌 케이스가 실제로 통과하기 시작했다.
Inspector를 설계할 때 한 가지를 더 신경 썼다. Inspector가 실행을 멈출 때 Executor의 중간 상태를 보존하는 거다.
그래야 분석할 때 맥락을 잃지 않는다.
실행을 멈추고 처음부터 다시 시작하면 왜 막혔는지 단서가 날아간다.
스킬 주입 race condition
두 번째 문제는 동시성 버그였다.
Managed Skills를 Executor 프롬프트에 주입하는 경로에 race condition이 있었다.
병렬로 Executor를 돌리기 시작하니까, 스킬을 로드하는 타이밍이 꼬이는 경우가 생겼다.
여러 Executor가 동시에 스킬을 읽으려다가 충돌이 났다.
이 경로를 수정하고 테스트도 붙였다.
병렬로 돌리기 시작하면 이런 동시성 버그가 튀어나오는 게 당연한데, 미리 테스트로 잡아두는 게 중요하다.
스크린샷 누락 버그
세 번째는 스크린샷이 가끔 안 찍히는 버그였다.
QA 결과에서 스크린샷은 증거다.
테스트가 실패했을 때 화면을 봐야 원인을 파악할 수 있다.
근데 가끔 스크린샷이 아예 안 찍히는 경우가 있었다.
에이전트가 스크린샷 단계를 조용히 건너뛰는 거다.
원인을 진단하고 재발 방지용으로 체크리스트를 달았다.
에이전트가 스크린샷 단계를 빼먹지 못하도록 단계별로 완료 여부를 확인하는 장치를 만들었다.
에이전트는 자기가 빠뜨린 단계가 있으면 스스로 알아차리기 어렵다.
그래서 외부에서 체크리스트로 검증하는 게 필요했다.
브라우저 안정성
자잘한 브라우저 문제도 같이 잡았다.
하나는 beforeunload 다이얼로그 때문에 브라우저가 멈추는 문제였다.
페이지를 벗어날 때 “정말 나가시겠습니까” 같은 확인 창이 뜨면, 자동화가 거기서 막힌다.
이걸 우회하는 처리를 넣었다.
다른 하나는 Chrome 메모리 최적화였다.
브라우저를 오래 띄워두면 메모리가 쌓이는데, 이걸 정리하지 않으면 결국 브라우저가 느려지거나 죽는다.
메모리 관리를 보강했다.
마무리
전날 구조를 바꾸고 오늘 그 구조가 드러낸 문제를 잡았다.
재시도 성공률 0%가 가장 치명적이었는데, Inspector를 배포하니까 실제로 막힌 케이스가 통과하기 시작했다.
Inspector가 핵심이었던 이유는, 원인 분석 없는 재시도는 반복일 뿐이라는 걸 깨달았기 때문이다.
같은 상태로 같은 행동을 반복하면 같은 결과가 나온다.
다른 결과를 원하면 다른 정보를 넣어야 한다.
Inspector가 바로 그 “다른 정보”를 만드는 역할이었다.
이날 이후로 QA Agent가 실제로 쓸 만해지기 시작했다.
구조는 전날 잡았고 오늘 그 구조를 믿을 수 있게 만들었다.