AgentSpec을 활용한 AI 에이전트 테스트: 비결정적 동작을 위한 Jest
요약
비결정적인 AI 에이전트의 특성을 고려하여 설계된 테스트 프레임워크 AgentSpec을 소개합니다. 기존 Jest와 같은 도구가 해결하지 못하는 에이전트의 동작 변화를 감지하고 검증하는 방법을 다룹니다.
핵심 포인트
- 비결정적 AI 출력을 검증하기 위한 전용 단언(Assertions) 제공
- 동작 차이 보고서(Behavior diff reports)를 통한 정밀한 디버깅 지원
- LLM-as-judge 기능을 활용한 품질 기반 테스트 가능
- CI/CD 통합 및 성능/비용 게이트 설정 지원
AI 에이전트는 비결정적 (non-deterministic)입니다. 이는 에이전트의 초능력이기도 하지만, 테스트 측면에서는 가장 큰 도전 과제이기도 합니다.
프롬프트 (prompt)를 변경하거나, 모델 (model)을 교체하거나, 도구 (tool) 정의를 업데이트하면 에이전트의 동작은 예측할 수 없는 방식으로 변화합니다. 전통적인 테스트 도구들 (Jest, Vitest, Playwright)은 결정적 (deterministic) 코드에 맞춰 구축되었습니다. 즉, 이들은 정확한 문자열 일치 (exact string matching)를 기대합니다. 하지만 AI 에이전트는 그런 방식으로 작동하지 않습니다.
지난주, 저는 고객 지원 에이전트의 시스템 프롬프트 (system prompt)를 변경했습니다. 여전히 우리의 모든 Jest 테스트는 통과했습니다 (함수가 여전히 문자열을 반환했기 때문입니다). 하지만 에이전트는 비밀번호 재설정 도움을 제공하는 것을 중단했습니다. 이는 사용자가 불만을 제기했을 때에야 비로소 드러난 회귀 (regression) 문제였습니다.
그것이 제가 AgentSpec을 만든 이유입니다.
AgentSpec이란 무엇인가?
AgentSpec은 AI 에이전트를 위해 특별히 설계된 테스트 프레임워크 (testing framework)입니다. 비결정적 출력을 처리하는 단언 (assertions), 무엇이 변했는지 보여주는 동작 차이 보고서 (behavior diff reports), 그리고 즉시 사용 가능한 CI/CD 통합 기능을 제공합니다.
AI 출력을 위한 단언 (Assertions)
정확한 문자열 일치 대신, AgentSpec은 AI 응답의 가변성 (variability)에 대응하는 단언들을 제공합니다:
# agentspec.yaml
name: "support agent"
tests:
...
사용 가능한 단언:
- contains / not_contains — 부분 문자열 체크
- contains_any / contains_all — 유연한 다중 문자열 매칭
- regex — 패턴 매칭 (에러 코드, ID)
- tool_called — 특정 도구가 호출되었는지 확인
- max_latency_ms / max_tokens — 성능 및 비용 게이트 (gates)
- semantically_similar — 단어 중첩 유사도 (API 불필요)
- json_path — JSON 에이전트 출력에서 필드를 추출하고 검증
- llm_judge — 로컬 LLM을 사용하여 출력 품질 평가
동작 차이 보고서 (Behavior diff reports)
이것이 핵심 기능 (killer feature)입니다. AgentSpec은 테스트당 마지막으로 통과한 출력을 저장합니다. 동작이 변경되면, 무엇이 변했는지 정확하게 확인할 수 있습니다:
⚠️ REGRESSION support agent > handles expired token
⚠ Behavior REGRESSED — test was passing, now failing
+ added: your, token, has, expired, please, contact, support
...
단순히 테스트가 실패했다는 사실을 아는 대신, 무엇이(WHAT) 변했는지 알 수 있습니다. 이를 통해 디버깅 과정이 "무엇이 고장 났는가?"에서 "모델이 'refresh token'이라고 말하는 것을 멈추고 'renew credentials'라고 말하기 시작했다"로 바뀝니다.
로컬 모델을 활용한 LLM-as-judge
가장 강력한 단언(assertion)은 llm_judge입니다. 문자열 매칭(string matching)으로 표현할 수 없는 품질 기준을 충족하는지 평가하기 위해 LLM을 사용합니다:
tests:
- name: "response is helpful"
input: "How do I reset my password?"
...
기본적으로 AgentSpec은 로컬 Ollama 모델을 판사(judge)로 사용합니다. API 비용이 발생하지 않으며, 데이터가 기기를 벗어나지도 않습니다:
agentspec run --judge-endpoint http://127.0.0.1:11434/v1/chat/completions --judge-model qwen2.5:7b
실제 에이전트 테스트하기
AgentSpec에는 HTTP로 접근 가능한 모든 AI 에이전트를 테스트할 수 있는 HTTP 에이전트 어댑터(HTTP agent adapter)가 포함되어 있습니다:
agentspec run --endpoint https://my-agent.example.com/chat
이 어댑터는 귀하의 엔드포인트에 {input: "..."}를 POST로 전송하고 응답을 읽습니다. HTTP API를 노출하는 모든 에이전트와 함께 작동합니다.
CI/CD 통합
AgentSpec은 어떤 CI 파이프라인에도 바로 적용할 수 있도록 설계되었습니다:
# 실패 시 종료 코드(Exit code) 1 반환
agentspec run --ci
...
GitHub Action도 제공됩니다:
- uses: agentspec/action@v1
with:
test-dir: tests
시작하기
npm install -g @ozperium/agentspec
agentspec init
agentspec run
이것으로 끝입니다. YAML 테스트 정의, 비결정적(non-deterministic) 출력에 대한 단언(assertion), 차이점(diff) 보고서, CI 통합까지 갖추고 있습니다. 클라우드, 계정, 텔레메트리(telemetry)는 필요 없습니다.
- GitHub: Ozperium/agentspec
- Landing: agentspec.pages.dev
다음 사항에 대한 피드백을 부탁드립니다:
- YAML이 적절한 형식인가요, 아니면 TS(TypeScript) 테스트 정의를 선호하시나요?
- 귀하의 AI 에이전트를 위해 부족한 단언(assertion) 기능은 무엇인가요?
- 로컬 모델을 사용한 LLM-as-judge를 사용하실 의향이 있으신가요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기