실제 AI 어시스턴트를 대상으로 한 스킬 회귀 테스트: 155초의 사례에서 10분 실행까지
요약
AI 어시스턴트의 스킬(skill) 작동 방식을 검증하기 위해 실제 사용 환경을 모방한 회귀 테스트 스위트를 구축했습니다. 이 시스템은 Playwright와 Chrome DevTools Protocol을 사용하여 실제 Muse 계정에서 상호작용하며, 카드 존재 여부, 서버 호출 로그 등을 점수화하여 정확도를 측정합니다. 특히 AI 어시스턴트의 '메모리'가 상태(state)로 작용하는 문제를 해결하기 위해 메모리 일시 정지 기능을 도입했습니다.
핵심 포인트
- 실제 사용자 상호작용을 모방한 회귀 테스트 스위트를 구축하여 정확도를 측정합니다.
- Playwright와 Chrome DevTools Protocol을 활용해 실제 브라우저 환경에서 테스트를 수행합니다.
- AI 어시스턴트의 '메모리'가 상태로 작용하는 문제를 해결하기 위해 메모리 일시 정지 기능을 도입했습니다.
문제점
우리는 AI 어시스턴트용 메시징 네트워크인 Mushare를 구축했습니다. 사용자가 Meta의 Muse에게 "앨리스에게 토요일과 일요일 중 언제 가능한지 물어봐"라고 말하면, 앨리스의 Muse가 터치로 답변할 수 있는 카드를 보여줍니다. Muse에서 Mushare는 스킬(skill)입니다. 참고 자료가 담긴 SKILL.md 파일과, Muse가 자체 클라우드 컴퓨터에서 실행하는 작은 Python CLI로 구성되어 있습니다.
이 CLI에는 200개의 단위 테스트가 있으며 모두 통과합니다. 하지만 이 테스트들은 가장 실패율이 높은 부분, 즉 Muse가 우리가 의도한 방식으로 스킬을 읽는지에 대해서는 아무것도 말해주지 못합니다. "앨리스에게 제가 늦었다고 알려줘"라는 우리의 스킬을 선택할까요? 올바른 명령을 실행할까요? 카드를 보여줄까요, 아니면 자신의 말로 내용을 다시 설명할까요? 오직 실제 어시스턴트만이 답할 수 있으며, 그 답변은 실행마다 다릅니다.
그래서 우리는 사용자가 브라우저에서 하는 것처럼 Muse와 상호작용하며 돌아오는 결과를 점수화하는 회귀 테스트 스위트를 구축했습니다.
테스트 환경(Harness)
각 테스트 계정은 실제 Muse 계정이며, 자체 Chrome 프로필에 한 번 로그인합니다. Node 스크립트가 Playwright를 사용하여 Chrome DevTools Protocol을 통해 브라우저를 구동합니다. 하나의 테스트 사례는 실제 사용자가 말할 문장과 그 결과로 발생해야 할 일의 목록입니다. 이 사례에서 스크립트는 다음 작업을 수행합니다:
- 이전 대화 내용이 새어 나오지 않도록 새로운 사이드 채팅을 엽니다.
- 예를 들어 "앨리스에게: 코스트코가 토요일 또는 일요일에 가능한가요? 두 가지 옵션을 알려줘"와 같이 요청을 말합니다. 때로는 이 실행을 위해 그린 영수증 이미지가 첨부되기도 합니다.
- Muse가 완료할 때까지 기다립니다 (자세한 내용은 아래에서 다룹니다).
- 페이지에 있는 Mushare 카드, 답변 텍스트, 그리고 스크린샷을 수집합니다. (각 카드는 우리의 CLI가 렌더링하는 iframe입니다).
- 실행 후, 우리 서버의 도구 호출 로그를 가져와 계정과 시간 창을 기준으로 각 호출을 사례와 일치시킵니다.
- 각 사례에 점수를 매깁니다: 최소한 하나의 카드 존재 여부, 카드가 올바른 단어를 포함하는지, 올바른 서버 호출(send_message, recall_message)이 발생했는지, 내용이 일반 텍스트가 아닌 공유 카드 형태로 나갔는지, 그리고 Muse가 "이미 이걸 보냈어"라고 말하지 않았는지 등을 확인합니다.
출력 결과는 케이스별 한 줄 요약(PASS, FAIL, FLAKY 및 이유와 마지막 실행 대비 ▲ 또는 ▼ 표시)과 스크린샷이 포함된 HTML 보고서입니다. 저희는 스킬 텍스트를 반복적으로 개선하는 동안 영향을 받은 케이스만 테스트하고, 각 릴리스 전에 전체 테스트군을 실행합니다.
메모리는 상태이다 (Memory is state)
첫 번째 놀라움은 동일한 SKILL.md가 오전에 15/16점을 받았다가 오후에는 10/16점으로 점수가 떨어졌다는 것입니다. 저희 코드에는 아무것도 변경되지 않았습니다. 바뀐 것은 Muse였습니다. 하루에 수십 번의 테스트를 거치자, Muse는 그 내용을 기억했습니다. 명령어 실행 대신 "무엇을 처리해야 하나요?"라는 질문에 메모리에서 답변했습니다. 또한 "이 영수증은 어젯밤 Alice에게 이미 보냈어요"라고 말하며 멈추기도 했습니다. 심지어 사용자가 수동으로 계산한 청구서 미리보기를 원한다는 '선호도(preference)'까지 저희 자체 테스트 문장에서 학습하여 저장했습니다.
세 가지 변경 사항을 통해 테스트 실행이 다시 비교 가능해졌습니다.
- 모든 케이스는 Muse에게 해당 채팅에 대한 메모리 일시 정지를 요청하는 한 줄로 시작합니다. 메모리를 유지하는 유일한 경우는 "지금 찾아보고, 메모리로 답변하지 마세요"를 테스트하는 경우입니다.
- 콘텐츠는 실행마다 새로 생성됩니다: 비교할 무작위 제품, 영수증으로 그려진 다른 레스토랑과 요리, 메시지별 시간 및 이유 등도 마찬가지입니다. 하나의 실행 내에서 반복되는 시도 역시 새로운 콘텐츠를 얻습니다.
- "이미 보냈다" 또는 "다시 보내겠어요?"라는 답변은 스킬 실패가 아닌 오래된 상태(stale state)로 점수화됩니다.
교훈은 비서 AI의 메모리가 데이터베이스와 같은 테스트 상태라는 것입니다. 이를 초기화하지 않으면 하루 동안 결과가 표류할 수 있습니다.
155초의 대기 시간 (The 155-second wait)
21개 케이스 전체 실행에 62분이 걸렸으며, 거의 모든 케이스가 정확히 154초 또는 155초가 소요되었습니다. 심지어 "Mushare는 무엇을 할 수 있나요?"라는 질문도 마찬가지였습니다. 비서 AI는 느리지만, 그 간격이 규칙적이지는 않습니다.
우리는 페이지를 읽기 전용 스크립트로 관찰했고, 우리 코드 자체에서 원인을 발견했습니다. 채팅 내용을 읽으려면 하네스(harness)가 Playwright에게 main의 텍스트를 요청했지만, Muse의 웹 앱에는 더 이상 main 요소가 없었습니다. 따라서 모든 확인 과정은 Playwright의 30초 타임아웃을 기다린 후 전체 페이지를 읽는 방식으로 대체되었습니다. "완료"는 세 번 연속으로 변경되지 않은 확인 과정을 의미했기 때문에, 매번 대기 시간이 약 155초에 달했습니다. Muse 자체는 보통 30~40분 만에 완료되곤 했습니다.
수정 사항은 두 부분으로 나뉘었습니다:
- 요소(element)를 기다리는 대신 페이지의 텍스트를 제자리에서 읽어오는 것(
document.body.innerText)과 사이드 패널을 제거하는 것입니다. - 앱이 작동하는 동안 표시되는 내용, 즉 입력창 옆에 있는 '중지(Stop)' 버튼과 어시스턴트의 상태 표시줄("메시지 작성 중", "메시지 전송 중")을 통해 "완료" 여부를 판단하도록 결정한 것입니다. 더 이상 "연결됨(Connected)"이라는 문구는 사용하지 않습니다. 완료 조건은 '중지' 버튼이 없고, 연결된 상태이며, 6초 동안 조용히 유지되는 것입니다.
'중지' 버튼만으로는 충분하지 않았습니다. 도구 단계 사이사이에 잠시 사라지는 경우가 있었고, 한 경우는 Muse가 여전히 작동하고 있음에도 불구하고 일찍 중단되었습니다. 이 상태 표시줄이 그 간극을 메워주었습니다.
이제 전체 실행 시간은 9분에서 10분이 걸립니다. 또한, 어떤 채팅 내용이 바뀌었는지, 그리고 무엇이 바뀌었는지를 대기 과정별로 기록하여, 다음 느린 단계가 우리의 인내심 속이 아닌 보고서에 나타나도록 했습니다.
두 계정 그룹과 신규 계정이 밝혀낸 것들
실행 시간을 절반으로 줄이기 위해 테스트 계정 쌍을 하나 더 추가하고 두 쌍을 나란히 실행했습니다. 브라우저 프로필당 하나의 계정을 사용합니다: 같은 브라우저의 탭들은 동일한 로그인 정보를 공유합니다. 케이스는 계정이 아닌 역할(발신자, 친구)에 따라 이름을 지정하며, 다른 케이스에 의존하는 경우("Leo가 보낸 청구서 확인")에는 해당 그룹 내에서 순차적으로 실행됩니다.
새로운 쌍은 단순히 시간을 절약하는 것 이상의 효과를 가져왔습니다. 이전 계정들에서는 "앨리스에게 내가 늦을 거라고 전해줘"라는 메시지가 항상 Mushare를 거쳐 전달되었습니다. 하지만 새로운 계정들에서는 Muse가 Messenger와 WhatsApp를 찾고, 앨리스에게 도달할 방법이 없다고 말하며 대신 Messenger로 연결하는 것을 제안했습니다. 이전 계정들은 앨리스가 Mushare 친구였다는 몇 달 치의 기억을 가지고 있었지만, 신규 사용자는 아무것도 모릅니다. 저희 점수 측정은 오직 재방문 사용자만을 측정하고 있었습니다.
원인은 스킬의 프론트매터(frontmatter)에 있는 한 줄, 즉 includeInPrompt: false 때문이었습니다. 이 설정 때문에 Muse는 해당 스킬을 자신이 가진 스킬 목록에 포함하지 않습니다. 검색을 시도할 때만 찾게 됩니다. 이를 true로 설정하면 모든 대화에 설명 라인이 표시됩니다 (전체 SKILL.md 파일 전체가 아닌, 오직 설명 부분만). 그리고 저희는 라우팅 규칙(routing rule)을 이 설명 라인의 맨 앞으로 옮겼습니다: 사용자가 사람의 이름을 언급하고 앱이 지정되지 않은 경우, Mushare를 먼저 확인하도록 했습니다. 다음 전체 실행까지 진행되자 신규 계정의 성공률은 5/10에서 8/10로 높아졌습니다.
이제 저희는 두 그룹을 두 가지 유형의 사용자로 간주합니다: 기존 쌍(old pair)은 재방문 사용자이고, 새로운 쌍(new pair)은 신규 사용자이며, 각 그룹을 자체적으로 비교합니다.
어시스턴트에게 이유를 묻기 (Ask the assistant why)
특정 사례가 계속 실패할 경우, 가장 유용한 디버깅 단계는 해당 계정에서 새 채팅을 열고 Muse에게 '왜 그랬는지' 물어보는 것이었습니다. 메모리가 일시 중지된 상태에서는 이전 대화 내용을 볼 수 없지만, 어떻게 결정하는지 설명해 줄 수 있었고, 그것만으로도 보통 충분했습니다:
이틀 만에 전체 테스트 스위트(full suite)는 한 계정 쌍에서 13/16을 기록하다가 두 계정에서는 22/22를 달성했고, 전체 실행 시간은 약 한 시간에서 10분 미만으로 단축되었습니다. 점수의 대부분은 스킬이 안전하게 시도할 수 있도록 변경된 스킬-텍스트(skill-text) 변화에서 나왔습니다. 그중 하나는 저희가 작성하지 않은 테스트 케이스에서 나온 것인데, (스크린샷을 찍다가 발견한 것으로 이제 자체 사례가 된) '저녁 7시에 저녁 식사 확정하고, 달력에 추가해'라는 문장을 달력 이벤트 대신 공유 카드(share card)로 변환하는 규칙이었습니다.
| Skill version | What changed | Cases passed | Full run |
|---|---|---|---|
| 0.61.2 | 스킬을 Simplified Technical English로 재작성함 | 13/16 (한 쌍) | 약 45분 |
| ... | |||
| CI(지속적 통합, Continuous Integration)는 같은 주에 5.5분에서 3분으로 단축되었고 (세 개의 병렬 샤드), 스킬 텍스트만 변경하는 배포는 더 이상 기다릴 필요가 없습니다: CI는 어시스턴트가 문장을 어떻게 읽는지 테스트할 수 없지만, 회귀 테스트 스위트(regression suite)는 할 수 있습니다. |
초보자에게 전하고 싶은 것들
- 실행되는 곳에서 스킬을 테스트하세요. 단위 테스트(Unit tests)는 코드를 다루지만, 실제 어시스턴트만이 사용자의 말을 어떻게 읽는지 알려줍니다.
- 두 방향에서 점수를 매기세요. 페이지는 사용자가 본 것을 보여주고; 서버 로그는 실제로 무슨 일이 일어났는지를 보여줍니다. 전송(send)이 없는 카드, 또는 카드가 없는 전송 모두 실패입니다.
- 메모리를 상태(state)로 취급하세요. 일시 중지하고, 새로운 콘텐츠를 생성하며, '이미 완료됨' 답변을 스킬 실패로 처리하는 대신 오래된 것으로 표시하세요.
- 새 계정을 유지하세요. 예전 테스트 계정은 가장 충성도 높은 사용자입니다. 새 계정은 낯선 사람이 무엇을 받는지 보여줍니다.
- 모든 대기 시간을 측정하세요. 일정한 지속 시간은 모델의 버그가 아니라 하네스(harness)의 버그입니다.
- 에이전트에게 질문하고, 그 다음 검증하세요. 에이전트의 설명은 좋은 가설이지만; 실제 사례들이 결정합니다.
- 스킬을 명료하게 작성하세요. 저희는 ASD-STE100 Simplified Technical English로 작성합니다: 짧은 문장, 각 문장은 하나의 지시를 담고 있으며, 조건(condition)이 먼저 옵니다. Muse가 단락 중간에 묻힌 조건을 놓친다고 했고, 점수도 이를 뒷받침했습니다.
Rong Zhou는 Mushare(https://mushare.ai)의 CTO이자 두 명의 창업자 중 한 명입니다. Mushare는 AI 어시스턴트를 위한 메시징 네트워크입니다.
본문은 mushare.ai에 최초 게재되었습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기