왜 Agent Testing이 깨졌는가
I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have the article, I’ll keep the source link unchanged and translate the rest into Korean while preserving all formatting, markdown, and technical terms.
Source: …
왜 에이전트 테스트가 깨졌는가
그리고 이를 해결하기 위한 방안.
소프트웨어 테스트는 수십 년 동안 해결돼 왔습니다. 함수를 작성하고, 그 출력값을 검증하고, CI가 초록색이면 배포합니다. 계약은 명확합니다: 같은 입력에 대해 언제나 같은 출력을 반환한다는 것.
LLM 에이전트는 이 계약을 완전히 깨뜨렸으며—대부분의 팀은 아직 이를 눈치채지 못하고 있습니다.
- 오늘 에이전트에게 “이 계약을 요약해줘”라고 물어보면 괜찮은 답변을 얻을 수 있습니다.
- 모델 업데이트, 프롬프트 미세 조정, 혹은 컨텍스트 윈도우 변경 후 내일 다시 물어보면 미묘하게 다른 답변을 받게 됩니다. 정확히 틀린 것은 아니지만… 다릅니다. 다운스트림 시스템이 이를 파싱하는 과정에서 새벽 2시에 조용히 깨지는 정도로 다릅니다.
이는 가상의 시나리오가 아닙니다. 안정적인 시스템을 배포하고 있다고 생각했던 기업들의 프로덕션 환경에서 실제로 일어나고 있습니다.
왜 이 실패 모드가 교묘한가
- 예외가 없음 – 에이전트는 항상 응답합니다. 응답 자체도 그럴듯합니다. 실패는 구문이 아니라 의미론적인 것입니다.
- 요청 시 재현 불가 – 모델 행동의 변화를
git bisect할 수 없습니다. 모델 자체가 바뀐 것이 아니라 프롬프트가 바뀌었거나, API 제공업체가 조용히 모델을 업데이트했거나, 주입하는 컨텍스트가 변했기 때문입니다. - 기존 테스트가 잡아내지 못함 – 단위 테스트는 LLM을 완전히 모킹합니다. 통합 테스트는 API 호출이 성공했는지만 확인합니다. 두 테스트 모두 응답 내용이 다운스트림 기대치를 여전히 만족하는지는 검증하지 않습니다.
- 인지에 대한 회귀 테스트 스위트가 없음 – 눈이 먼 채로 비행하고 있는 셈입니다.
전통적인 소프트웨어는 결정론적입니다. LLM은 언어에 대한 학습된 표현 위에서 동작하는 확률적 시스템입니다. 모델을 업데이트한다는 것은 함수를 패치하는 것이 아니라 분포를 이동시키는 것입니다.
Claude‑3.5와 Claude‑4가 법률 요약 프롬프트에 대해 3 % 정도 다르게 응답한다면, 수동 검토에서는 눈에 띄지 않을 수 있지만, **“termination”**이라는 단어가 모든 출력에 반드시 포함되어야 하는 파이프라인에서는 재앙이 될 수 있습니다.
업계의 대응은 더 많은 평가(evals)를 추가하는 것이었습니다—정교한 인간 선호 데이터셋, MMLU 벤치마크, 레드팀 스위트 등. 이는 모델 구축자에게는 가치가 있지만, 애플리케이션 개발자에게는 거의 쓸모가 없습니다.
애플리케이션 개발자가 필요로 하는 것은 **“이 모델이 일반적으로 능력이 있는가?”**가 아니라 “내가 만든 특정 프롬프트와 특정 컨텍스트에서 이 모델이 여전히 내 시스템이 의존할 수 있는 출력을 생성하는가?” 입니다.
이 질문에 대한 좋은 답은 오늘날 존재하지 않습니다.
LLM 애플리케이션을 배포하는 팀들 사이에서 관찰된 실제 패턴
| 월 | 사건 |
|---|---|
| 1 | 팀이 프롬프트를 작성하고, 에이전트를 배포하며, 출력이 괜찮아 보이는지 수동으로 검증합니다. |
| 2 | 누군가 톤을 개선하기 위해 시스템 프롬프트를 “조금” 수정합니다. 세 개의 다운스트림 파서가 간헐적으로 실패하기 시작합니다. |
| 3 | 모델 제공업체가 동일한 API 엔드포인트 뒤에서 모델을 조용히 업데이트합니다. 응답 형식이 15 % 정도 변동합니다. 에이전트는 데모에서는 여전히 동작합니다. |
| 4 | 고객이 요약된 계약서에 책임 조항이 누락됐다고 보고합니다. 사후 분석 결과 문제가 2월에 시작된 것으로 드러납니다. 행동 테스트가 없었기 때문에 아무도 눈치채지 못했습니다. |
이것이 예외가 아니라 표준입니다.
에이전트 출력에 대한 새로운 사고 방식
에이전트 출력을 함수 반환값처럼 다루지 마세요. 행동 계약을 가진 확률적 프로세스에 의해 생성된 문서라고 생각하세요.
계약: 이 종류의 입력이 주어졌을 때, 출력은 다음과 같은 구조적·의미적 속성을 만족해야 합니다.
계약을 테스트하려면 다음이 필요합니다
- 베이스라인 캡처 – 시스템의 알려진 정상 버전으로 시나리오를 실행하고 출력을 기록합니다. 이것이 여러분의 행동 지문입니다.
- 포함 검사 – 모든 출력에 반드시 포함되어야 할 내용을 정의합니다. 정확한 텍스트가 아니라(매 실행마다 실패하게 됨) 의미적 앵커: 핵심 용어, 필수 섹션, 구조적 요소.
- 드리프트 감지 – 새로운 출력을 베이스라인과 비교합니다. 유사도가 허용 임계값 이하로 떨어지면 빌드를 실패 처리합니다. 엔지니어가 변경이 의도된 것인지 판단하도록 합니다.
- CI 통합 – 푸시마다, 모델 버전이 바뀔 때마다, 프롬프트가 수정될 때마다 실행합니다. 유닛 테스트를 실행하는 것과 같은 방식으로.
이것은 복잡하지 않습니다. 단지 아직 실행되지 않았을 뿐입니다.
The Tooling Gap
기존 평가 프레임워크(RAGAS, LangSmith 등)는 다음 중 하나에 해당합니다:
- 특정 프레임워크(LangChain 등)에 종속되어 있음
- 행동 회귀보다는 RAG 품질 지표에 초점을 맞춤
- 호스팅 인프라와 계정이 필요함
- 오후에 CI 파이프라인에 추가하기엔 너무 복잡함
시장이 필요로 하는 것은 에이전트를 위한 pytest입니다: 가볍고, 조합 가능하며, 로컬에서 실행되고, 인프라가 전혀 필요 없으며, 동작이 깨지면 코드 1로 종료됩니다.
Minimum‑Viable Interface Example
# scenarios/summarize_contract.yaml
name: summarize_contract
input: |
Summarize this contract clause in 5 bullet points:
"...The Contractor shall indemnify...termination upon 30 days notice..."
expected_contains:
- liability
- termination
max_tokens: 512
# Run against real model, compare to baseline
agentprobe run scenarios/ \
--backend anthropic \
--baseline baseline.json \
--tolerance 0.8
✓ PASS summarize_contract
✗ FAIL extract_parties
Drift detected: similarity 0.61
에이전트 테스트가 깨진 이유는 아직 적절한 도구가 만들어지지 않았기 때문입니다. 이는 해결 가능한 문제입니다.