Eval 공부 #2 (유사도 · 테스트셋 설계) 에 이어서. 저번까지는 RAG 를 Eval 했다. 오늘은 에이전트 를 Eval.
Table of contents
Open Table of contents
RAG Eval vs 에이전트 Eval — 판정 축이 확 늘어난다
RAG Eval 은 단순했다 — 질문 → 검색 결과의 top-k 안에 정답 청크가 있는가. 축이 하나.
에이전트는 판정 축이 최소 6개다:
- 도구 선택 — 맞는 도구를 골랐는가
- 인자 추출 — 도구에 넘긴 인자가 맞는가
- 멀티스텝 궤적 — 여러 도구를 올바른 순서로 호출했는가
- 종료 판단 — 언제 멈춰야 할지 알았는가
- 안전장치 — 위험한 작업에서 멈췄는가
- 최종 답변 품질 — 도구 결과를 잘 종합했는가
축이 많을수록 하나 실패해도 다른 축은 성공 인 케이스가 흔하다. → 원인 특정을 위해 축을 분리해서 봐야 한다. 통합 테스트 전에 단위 테스트부터 하는 것과 같은 원리.
오늘 초점은 도구 선택 + 멀티스텝 + 함정 회귀 세 축. 지난번 만든 MCP 에이전트 와 HITL 에이전트 를 대상으로.
Eval 코드 구성
1) MCP 서버 도구 메타 입력
먼저 대상 에이전트가 쓸 수 있는 도구 정보 를 eval 코드에 넣는다:
- 이름 (name)
- 설명 (description)
- 입력 스키마 (input schema)
에이전트가 “어떤 도구를 골라야 하는지” 를 판단하는 근거가 되는 그대로의 재료를 eval 에도 그대로 넣는 것.
2) 테스트셋
각 케이스를 (질문 · 기대 도구 · 기대 인자 · 레벨) 로 라벨링:
{
"question": "포장 라인 전력 사용량 알려줘",
"expected_tool": "get_energy_consumption",
"expected_args": {"line_id": "packaging"},
"level": "easy",
}
3) 실행 → 수치화
테스트셋의 질문들을 에이전트에 넣고, 예측 도구/인자 vs 기대 도구/인자 를 대조. 결과를 정확도로 뽑는다.
단일 스텝 eval — 도구 선택 정확도 84.6%

- 도구 선택 11/13 = 84.6%
- easy 6/7, hard 5/6 — 레벨별로 나눠서 확인
- 인자 추출 3/3 = 100% (도구를 맞게 고른 케이스에 한해서)
실패 2건이 재미있는 학습 지점이었다.
실패 케이스 1 — 단일 스텝 채점의 한계
한 케이스는 “질문 표현이 달라서 LLM 이 예상 도구를 못 찾음” 이었다. 그런데 실제 궤적을 보면 멀티스텝으로 여러 도구를 호출하는 흐름 안에서 이 도구를 순서에 맞게 부르고 있었다.
- 단일 스텝 eval: “이 질문 → 이 도구 하나” 로 채점 → 실패
- 실제: 멀티스텝 궤적 안에서 정답
즉 단일 스텝 채점은 멀티스텝 정답 궤적을 오탐 한다. 이 케이스를 제대로 확인하려면 멀티스텝 eval 로 넘어가야 한다.
실패 케이스 2 — 도구 description 이 모호했다
다른 케이스: “전기 요금 얼마나 나와?” 라고 물었더니 비용 (cost) 도구 가 아니라 사용량 (consumption) 도구 를 골랐다.
그런데 같은 뜻을 다르게 물어보면 결과가 갈렸다:
- “전기 요금 얼마나 나와?” → consumption 오선택 ❌
- “돈 얼마 나와?” → cost 정답 ✓
원인 파악: “돈” 이라는 직접적 표현이 cost 도구를 트리거. “전기 요금” 은 애매해서 consumption 쪽으로 새어감. 즉 도구 description 이 요금·비용 도메인 어휘를 충분히 커버 못 했음.
description 을 고쳐도 여전히 실패. 결국 시스템 프롬프트 에 “‘전기 요금’ 은 cost 계열 도구를 우선 검토” 같은 힌트를 주면 통과했다.
여기서 중요한 감각:
eval 을 통과시키기 위해 시스템 프롬프트를 고치면 그 자체가 과적합이다. 원인을 이해하기 위한 실험은 OK 지만, 이걸 정답이라고 배포하면 안 된다.
멀티스텝 eval — 궤적 채점
멀티스텝 eval 은 채점 포인트가 여러 개라 단일보다 훨씬 어렵다:
- 필요한 도구를 다 불렀는가
- 요구 순서대로 불렀는가
- 앞 도구의 결과를 다음 단계에서 실제로 썼는가
- 무한 루프에 빠지지 않고 적절히 종료했는가
테스트셋에서도 각 케이스마다 “필요한 도구 리스트 + 순서 요구 여부” 를 함께 라벨링.

결과 4/4 = 100%.
- “도장 라인 전력 사용량 알려줘” —
list_production_lines→get_energy_consumption(순서 요구 O, 맞음) - “line_4 전력 사용량 알려줘” —
get_energy_consumption단독 (순서 요구 X, 맞음) - “포장 라인이랑 도장 라인 중 뭐가 전기 더 써?” —
list_production_lines→compare_lines(순서 요구 O, 맞음) - “공장 라인 목록 보여줘” —
list_production_lines단독
단일 스텝 eval 에서 실패 처리된 케이스가 멀티스텝에서는 통과. 궤적이 의도대로 정답이었기 때문. 이론상 그렇긴 하지만 실제 수치로 확인하니 신기했다.
회고
에이전트 Eval 에서 얻은 감각 3가지:
- 채점 축을 분리해라 — 도구 선택/인자/순서를 하나로 뭉치면 “어디서 틀렸는지” 를 못 찾는다. 축별로 나누면 원인 특정이 빠르다. 통합 테스트 전 단위 테스트.
- 단일 스텝 채점은 멀티스텝 정답을 오탐한다 — 궤적 위에서 정답인 케이스를 못 잡아냄. 에이전트가 멀티스텝을 의도한 시스템이면 반드시 멀티스텝 eval 로 확장해야 한다.
- Eval 을 통과시키기 위한 프롬프트/description 수정은 과적합 — 실패 원인을 이해하는 용도로만. 통과시키려고 프롬프트를 계속 넣으면 eval 셋에만 잘 되는 에이전트가 나온다.
남은 숙제
오늘은 4개 케이스로만 멀티스텝 평가. 확장 방향:
- 함정 (trap) 케이스 추가 — 도구를 부르지 말아야 하는 질문에 안 부르는지
- 스텝 수 측정 — 한 스텝으로 끝낼 수 있는데 두 스텝을 부르면 효율 저하. 스텝 수를 지표에 넣으면 감지 가능
- 종료 판단 · 안전장치 · 최종 답변 품질 — 오늘 다루지 않은 나머지 3축
개발 환경 노트 — Windows 인코딩 문제
Eval 개발하다 Windows 인코딩 문제 로 몇 번 막힘. LLM 공부는 막바지라 이대로 진행했지만, 백엔드 공부 쪽에서는 WSL2 로 옮겨서 진행 중. 개발 환경을 갈아엎는 건 시점 문제.
더 공부해볼 것
1. 에이전트 Eval 프레임워크
- LangSmith — LangChain/LangGraph 계열 에이전트 궤적 추적 + eval
- Ragas 의 에이전트 eval 확장
- OpenAI Evals — 도구 사용 벤치마크 케이스들
- 프레임워크가 채점 축을 어떻게 나누는지 비교
2. Trace-level Eval — 궤적 자체를 채점
- 도구 호출 트리 (call tree) 를 파싱해서 채점 로직에 넣는 방법
- 앞 결과를 뒤 스텝의 인자에서 참조하는지 (data flow) 를 어떻게 자동으로 확인하는가
3. 함정 (trap) 테스트 설계
- “도구를 부르지 말아야 하는 질문” 을 어떻게 만드는가
- 안전장치가 필요한 위험 케이스 (파일 삭제 · 결제 · 외부 API 호출) 설계
- 오답률을 눈금으로 매기는 방법
4. 도구 description 최적화
- LLM 이 도구를 잘 고르게 하는 description 작성 원칙
- 참고: Anthropic 의 tool use 가이드
- description 을 자동으로 개선하는 pipeline — DSPy 계열
5. Windows 개발 환경 정리
- WSL2 로 완전 이관 시점 판단 기준
- Windows 로컬 vs WSL2 vs Docker 각각의 함정 정리