k
korAI
고급 전체
🔥 고급2026-07-256~8분

에이전트 평가 파이프라인 설계: 행동 trace 기반 Ground-truth 구축과 회귀 방지

에이전트는 최종 출력만이 아니라 중간 tool 호출 순서와 인자까지 평가해야 한다. Trace 레코딩과 LLM-as-judge를 결합한 자동 회귀 탐지 파이프라인을 설계한다.

evaluationagentsobservability

에이전트 평가가 어려운 이유

단순 QA와 달리 에이전트는 같은 목표를 여러 tool 호출 경로로 달성할 수 있다. 최종 답변이 정확해도 비효율적인 경로(예: 불필요한 검색 3회)를 사용했다면 비용·지연 문제가 된다. 반대로 경로가 달라도 결과가 맞을 수 있어 단순 exact-match는 무의미하다. 핵심은 행동 trace를 기록하고, 의도 단위로 평가하는 것이다.

Trace 수집과 Ground-truth 구조

tool 호출마다 입력·출력·타임스탬프를 수집한다. Ground-truth는 세 가지 레이어로 구성한다.

  • 결과 레이어: 최종 응답이 기대 답변 집합에 포함되는가 (정확도)
  • 효율 레이어: tool 호출 횟수가 기준 N회 이하인가 (비용)
  • 안전 레이어: 금지 tool 또는 금지 인자가 사용되지 않았는가 (안전)

Ground-truth는 초기에 사람이 20~50개 케이스를 레이블링하고, 이후 프로덕션 trace 중 신뢰도 높은 케이스를 자동 추가한다.

import anthropic
import json
from dataclasses import dataclass, field
from typing import Any

@dataclass
class AgentTrace:
    query: str
    tool_calls: list[dict] = field(default_factory=list)
    final_answer: str = ""

def run_agent_with_trace(query: str) -> AgentTrace:
    client = anthropic.Anthropic()
    trace = AgentTrace(query=query)
    tools = [
        {
            "name": "search",
            "description": "Search documents",
            "input_schema": {
                "type": "object",
                "properties": {"q": {"type": "string"}},
                "required": ["q"],
            },
        }
    ]
    messages = [{"role": "user", "content": query}]
    for _ in range(5):  # 최대 5턴
        resp = client.messages.create(
            model="claude-opus-4-5",
            max_tokens=1024,
            tools=tools,
            messages=messages,
        )
        if resp.stop_reason == "end_turn":
            trace.final_answer = resp.content[0].text
            break
        for block in resp.content:
            if block.type == "tool_use":
                trace.tool_calls.append(
                    {"name": block.name, "input": block.input}
                )
                # 실제 환경에서는 tool 실행 결과를 추가
                messages.append({"role": "assistant", "content": resp.content})
                messages.append({
                    "role": "user",
                    "content": [{"type": "tool_result",
                                 "tool_use_id": block.id,
                                 "content": "mock result"}],
                })
                break
    return trace

def evaluate_trace(trace: AgentTrace, ground_truth: dict) -> dict:
    result_ok = trace.final_answer in ground_truth["expected_answers"]
    efficiency_ok = len(trace.tool_calls) <= ground_truth["max_tool_calls"]
    forbidden = ground_truth.get("forbidden_tools", [])
    safety_ok = all(tc["name"] not in forbidden for tc in trace.tool_calls)
    return {"result": result_ok, "efficiency": efficiency_ok, "safety": safety_ok}

회귀 탐지와 운영 체크리스트

자동 회귀 탐지 흐름: CI 파이프라인에서 모델 버전 또는 시스템 프롬프트 변경 시 저장된 케이스 전체를 재실행한다. 결과 정확도 기준선 대비 3% 이상 하락, 평균 tool 호출 수 20% 이상 증가 중 하나라도 해당하면 배포를 블록한다.

트레이드오프

  • LLM-as-judge로 결과 레이어를 평가하면 비용이 케이스당 약 $0.01~$0.03 발생하지만 사람 레이블링 대비 10배 빠르다.
  • Ground-truth 케이스를 50개 미만으로 유지하면 분포 커버리지가 부족해 회귀를 놓친다. 최소 100개, 도메인별 레이어 분리를 권장한다.

운영 체크리스트

  • [ ] 모든 tool 호출 trace를 구조화 로그로 영속 저장
  • [ ] Ground-truth 케이스 버전 관리 (Git 또는 전용 DB)
  • [ ] CI 단계에 평가 파이프라인 연결 및 실패 시 배포 블록
  • [ ] 결과·효율·안전 지표를 대시보드에서 별도 추적
  • [ ] 월 1회 Ground-truth 케이스 샘플링 재검토 및 갱신