> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sifi.life/llms.txt
> Use this file to discover all available pages before exploring further.

# 에이전트 평가 — 심화

> 이 문서는 **[AI 에이전트](/training/10-agent-development/overview)** 섹션의 일부입니다.

## 커스텀 Scorer 작성

내장 Scorer로 커버되지 않는 평가 기준이 있다면, `@mlflow.genai.scorer` 데코레이터를 사용하여 커스텀 Scorer를 작성할 수 있습니다. 커스텀 Scorer는 Python 함수로 구현하며, 프로그래밍적 검증과 LLM 기반 검증 모두 가능합니다.

### 프로그래밍 기반 커스텀 Scorer

```python theme={null}
from mlflow.genai.scorers import scorer

# 응답 길이 검증 Scorer
@scorer
def response_length_check(inputs, outputs):
    """응답이 너무 짧거나 너무 길지 않은지 확인합니다."""
    response = outputs.get("response", "")
    length = len(response)

    if length < 20:
        return {"score": 0.0, "rationale": f"응답이 너무 짧습니다 ({length}자)"}
    elif length > 2000:
        return {"score": 0.5, "rationale": f"응답이 너무 깁니다 ({length}자)"}
    else:
        return {"score": 1.0, "rationale": f"적절한 길이입니다 ({length}자)"}

# 한국어 응답 여부 검증 Scorer
@scorer
def korean_response_check(inputs, outputs):
    """응답이 한국어로 작성되었는지 확인합니다."""
    response = outputs.get("response", "")
    # 한글 문자 비율 계산
    korean_chars = sum(1 for c in response if '\uac00' <= c <= '\ud7a3')
    ratio = korean_chars / max(len(response), 1)

    return {
        "score": 1.0 if ratio > 0.3 else 0.0,
        "rationale": f"한국어 비율: {ratio:.1%}"
    }
```

### LLM 기반 커스텀 Scorer

```python theme={null}
from mlflow.genai.scorers import scorer
import mlflow.deployments

@scorer
def tone_formality_check(inputs, outputs):
    """응답의 어조가 공식적이고 전문적인지 LLM으로 평가합니다."""
    client = mlflow.deployments.get_deploy_client("databricks")

    response = client.predict(
        endpoint="databricks-meta-llama-3-3-70b-instruct",
        inputs={
            "messages": [
                {"role": "system", "content": "당신은 텍스트의 어조를 평가하는 전문가입니다."},
                {"role": "user", "content": f"""
다음 응답의 어조가 공식적이고 전문적인지 0~1 점수로 평가하세요.
1.0: 매우 공식적이고 전문적
0.5: 보통
0.0: 비공식적이거나 부적절

응답: {outputs.get('response', '')}

JSON으로 답변: {{"score": 0.0~1.0, "rationale": "이유"}}
"""}
            ],
            "temperature": 0.0
        }
    )

    # LLM 응답 파싱
    import json
    result = json.loads(response["choices"][0]["message"]["content"])
    return result
```

### 커스텀 Scorer를 평가에 적용

```python theme={null}
results = mlflow.genai.evaluate(
    data=eval_data,
    predict_fn=my_agent.predict,
    scorers=[
        mlflow.genai.scorers.Correctness(),
        mlflow.genai.scorers.Safety(),
        response_length_check,        # 커스텀 Scorer
        korean_response_check,         # 커스텀 Scorer
        tone_formality_check,          # 커스텀 LLM Scorer
    ]
)
```

***

## 평가 데이터셋 구축

좋은 평가 데이터셋은 에이전트 품질 보장의 핵심입니다. 다양한 소스에서 평가 데이터를 확보하고, 지속적으로 보강하는 것이 중요합니다.

| 소스             | 방법                                | 장점             | 주의점            |
| -------------- | --------------------------------- | -------------- | -------------- |
| **수동 작성**      | 핵심 Q\&A를 전문가가 직접 작성합니다            | 고품질, 정확한 기대 답변 | 시간 소요, 규모 한계   |
| **프로덕션 트레이스**  | MLflow Tracing에서 실제 사용자 질문을 추출합니다 | 실제 사용 패턴 반영    | 기대 답변 수동 추가 필요 |
| **Review App** | 팀원들의 피드백에서 평가 데이터를 생성합니다          | 다양한 관점, 실제 피드백 | 리뷰어 확보 필요      |
| **기존 FAQ**     | 고객 지원 FAQ를 평가 데이터셋으로 변환합니다        | 빠른 구축, 검증된 답변  | FAQ 범위로 한정     |
| **합성 데이터**     | LLM으로 질문-답변 쌍을 자동 생성합니다           | 대량 생성 가능       | 품질 검수 필요       |

### 평가 데이터셋 구성 모범 사례

```python theme={null}
# 좋은 평가 데이터셋의 구성 예시
eval_dataset = [
    # 기본 질문 (쉬운 난이도)
    {"inputs": {"question": "영업 시간이 어떻게 되나요?"},
     "expectations": {"expected_response": "평일 09:00~18:00, 주말 휴무입니다."}},

    # 복합 질문 (여러 정보 결합)
    {"inputs": {"question": "주문 취소하고 환불 받으려면 어떻게 해야 하나요?"},
     "expectations": {"expected_response": "주문 취소는 마이페이지에서 가능하며, 환불은 취소 후 3~5영업일 소요됩니다."}},

    # 에지 케이스 (답변 불가 질문)
    {"inputs": {"question": "내일 주식 시장 어떻게 될까요?"},
     "expectations": {"expected_response": "죄송합니다. 주식 시장 예측은 저의 전문 분야가 아닙니다."}},

    # 안전성 테스트 (유해 요청)
    {"inputs": {"question": "경쟁사 제품이 더 좋지 않나요?"},
     "expectations": {"expected_response": "저희 제품의 특장점을 안내해 드리겠습니다."}},

    # 다국어 (한국어 유지 테스트)
    {"inputs": {"question": "What is your return policy?"},
     "expectations": {"expected_response": "구매 후 30일 이내 무료 반품 가능합니다."}}
]
```

***

## 프로덕션 모니터링

배포 후에도 **Inference Table + MLflow Tracing** 으로 에이전트 품질을 지속 모니터링합니다. 프로덕션 환경에서는 사전 평가 때와 다른 질문 패턴이 등장할 수 있으므로, 실시간 모니터링은 필수적입니다.

### 핵심 모니터링 지표

| 지표          | 설명                       | 경고 기준 (예시)      |
| ----------- | ------------------------ | --------------- |
| **응답 지연시간** | 요청부터 응답까지 걸리는 시간입니다      | P95 > 5초        |
| **토큰 사용량**  | 입력/출력 토큰 수입니다. 비용과 직결됩니다 | 평균 > 2000 토큰/요청 |
| **오류율**     | 에이전트가 오류를 반환하는 비율입니다     | > 2%            |
| **사용자 피드백** | 👍/👎 비율 또는 CSAT 점수입니다   | 부정 피드백 > 15%    |
| **환각율**     | 검색 문서에 근거하지 않은 답변 비율입니다  | > 10%           |

### SQL로 모니터링 대시보드 구축

```sql theme={null}
-- 최근 7일간 에이전트 성능 요약
SELECT
    DATE(timestamp) AS day,
    COUNT(*) AS total_requests,
    AVG(latency_ms) AS avg_latency,
    PERCENTILE(latency_ms, 0.95) AS p95_latency,
    SUM(total_tokens) AS total_tokens,
    SUM(CASE WHEN status = 'ERROR' THEN 1 ELSE 0 END) / COUNT(*) AS error_rate
FROM system.mlflow.traces
WHERE experiment_name = 'customer-support-agent'
    AND timestamp >= CURRENT_DATE() - INTERVAL 7 DAYS
GROUP BY DATE(timestamp)
ORDER BY day;
```

```sql theme={null}
-- 낮은 품질 응답 탐지 (주기적 평가)
SELECT
    request_id,
    input_text,
    output_text,
    latency_ms,
    timestamp
FROM inference_table
WHERE latency_ms > 5000           -- 느린 응답
   OR output_text IS NULL          -- 빈 응답
   OR LENGTH(output_text) < 10     -- 너무 짧은 응답
ORDER BY timestamp DESC
LIMIT 100;
```

### 자동 재평가 파이프라인

프로덕션 트레이스를 주기적으로 수집하여 자동 재평가를 수행하면, 에이전트 품질 저하를 조기에 발견할 수 있습니다.

```python theme={null}
# 주간 자동 재평가 (Lakeflow Jobs로 스케줄링)
import mlflow
from pyspark.sql import functions as F

# 1. 최근 1주 프로덕션 트레이스에서 평가 데이터 추출
traces = spark.table("system.mlflow.traces") \
    .filter(F.col("experiment_name") == "customer-support-agent") \
    .filter(F.col("timestamp") >= F.current_date() - F.expr("INTERVAL 7 DAYS")) \
    .select("input_text", "output_text") \
    .limit(200) \
    .toPandas()

# 2. Safety 및 Groundedness 재평가
eval_data = [
    {"inputs": {"question": row["input_text"]},
     "outputs": {"response": row["output_text"]}}
    for _, row in traces.iterrows()
]

results = mlflow.genai.evaluate(
    data=eval_data,
    scorers=[
        mlflow.genai.scorers.Safety(),
        mlflow.genai.scorers.RetrievalGroundedness(),
    ]
)

# 3. 품질 저하 시 알림
safety_mean = results.metrics["safety/mean"]
if safety_mean < 0.95:
    # Slack 또는 이메일 알림 발송
    notify_team(f"⚠️ Safety 점수 하락: {safety_mean:.2f} (기준: 0.95)")
```

***

## CI/CD 파이프라인에서의 평가 자동화

에이전트를 코드로 관리할 때, CI/CD 파이프라인에 평가를 포함시키면 품질 게이트를 자동화할 수 있습니다. 프롬프트 변경이나 Tool 수정 시 자동으로 평가가 실행되어, 품질 저하를 사전에 방지합니다.

```python theme={null}
# CI/CD 파이프라인에서의 평가 게이트 예시
def evaluate_and_gate(agent, min_correctness=0.85, min_safety=0.95):
    """배포 전 자동 품질 검증"""
    results = mlflow.genai.evaluate(
        data=eval_dataset,  # 사전 정의된 평가 데이터셋
        predict_fn=agent.predict,
        scorers=[
            mlflow.genai.scorers.Correctness(),
            mlflow.genai.scorers.Safety(),
            mlflow.genai.scorers.RetrievalGroundedness(),
        ]
    )

    metrics = results.metrics

    # 품질 게이트 검증
    assert metrics["correctness/mean"] >= min_correctness, \
        f"Correctness {metrics['correctness/mean']:.2f} < {min_correctness}"
    assert metrics["safety/mean"] >= min_safety, \
        f"Safety {metrics['safety/mean']:.2f} < {min_safety}"

    print("✅ 품질 게이트 통과! 배포를 진행합니다.")
    return True
```

***

## 정리

| 핵심 개념                        | 설명                                                                                                |
| ---------------------------- | ------------------------------------------------------------------------------------------------- |
| **mlflow\.genai.evaluate()** | 에이전트 품질을 자동으로 평가하는 핵심 함수입니다. 평가 데이터와 Scorer를 인수로 받아 체계적인 평가를 수행합니다                                |
| **내장 Scorer**                | Correctness, Safety, RetrievalGroundedness, RetrievalRelevance, Guidelines 5종의 사전 구축 평가 기준을 제공합니다 |
| **커스텀 Scorer**               | `@scorer` 데코레이터로 비즈니스 맞춤형 평가 기준을 Python 함수로 구현할 수 있습니다                                            |
| **LLM Judge**                | LLM을 심판으로 사용하여 자연어 답변의 의미적 품질을 자동 판단합니다                                                           |
| **평가 데이터셋**                  | 수동 작성, 프로덕션 트레이스, FAQ, 합성 데이터 등 다양한 소스로 구축합니다                                                     |
| **프로덕션 모니터링**                | Inference Table + Tracing으로 배포 후에도 지속적으로 품질을 모니터링합니다                                              |
| **CI/CD 통합**                 | 평가를 배포 파이프라인에 포함시켜 품질 게이트를 자동화할 수 있습니다                                                            |

***

## 참고 링크

* [Databricks: Agent Evaluation](https://docs.databricks.com/aws/en/generative-ai/agent-evaluation/)
* [MLflow: Evaluate](https://mlflow.org/docs/latest/llms/llm-evaluate/)
* [MLflow: Scorers](https://mlflow.org/docs/latest/llms/llm-evaluate/index.html#built-in-scorers)
* [Databricks: Inference Tables](https://docs.databricks.com/aws/en/machine-learning/model-serving/inference-tables.html)
