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

# Weave로 AI 에이전트 평가하기

> Weave에서 에이전트 워크플로와 EvaluationLogger를 사용해 싱글턴 및 멀티턴 AI 에이전트를 평가하고, LLM 평가자로 점수를 매기세요.

export const GitHubLink = ({url, compact = false}) => <a href={url} target="_blank" rel="noopener noreferrer" className={compact ? "source-link" : "github-source-link"}>
    {compact ? "View source" : <>
    <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
      <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" />
    </svg>
    GitHub source
      </>}
  </a>;

export const ColabLink = ({url}) => <a href={url} target="_blank" rel="noopener noreferrer" className="colab-link">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
      <path d="M14.25.18l.9.2.73.26.59.3.45.32.34.34.25.34.16.33.1.3.04.26.02.2-.01.13V8.5l-.05.63-.13.55-.21.46-.26.38-.3.31-.33.25-.35.19-.35.14-.33.1-.3.07-.26.04-.21.02H8.77l-.69.05-.59.14-.5.22-.41.27-.33.32-.27.35-.2.36-.15.37-.1.35-.07.32-.04.27-.02.21v3.06H3.17l-.21-.03-.28-.07-.32-.12-.35-.18-.36-.26-.36-.36-.35-.46-.32-.59-.28-.73-.21-.88-.14-1.05-.05-1.23.06-1.22.16-1.04.24-.87.32-.71.36-.57.4-.44.42-.33.42-.24.4-.16.36-.1.32-.05.24-.01h.16l.06.01h8.16v-.83H6.18l-.01-2.75-.02-.37.05-.34.11-.31.17-.28.25-.26.31-.23.38-.2.44-.18.51-.15.58-.12.64-.1.71-.06.77-.04.84-.02 1.27.05zm-6.3 1.98l-.23.33-.08.41.08.41.23.34.33.22.41.09.41-.09.33-.22.23-.34.08-.41-.08-.41-.23-.33-.33-.22-.41-.09-.41.09zm13.09 3.95l.28.06.32.12.35.18.36.27.36.35.35.47.32.59.28.73.21.88.14 1.04.05 1.23-.06 1.23-.16 1.04-.24.86-.32.71-.36.57-.4.45-.42.33-.42.24-.4.16-.36.09-.32.05-.24.02-.16-.01h-8.22v.82h5.84l.01 2.76.02.36-.05.34-.11.31-.17.29-.25.25-.31.24-.38.2-.44.17-.51.15-.58.13-.64.09-.71.07-.77.04-.84.01-1.27-.04-1.07-.14-.9-.2-.73-.25-.59-.3-.45-.33-.34-.34-.25-.34-.16-.33-.1-.3-.04-.25-.02-.2.01-.13v-5.34l.05-.64.13-.54.21-.46.26-.38.3-.32.33-.24.35-.2.35-.14.33-.1.3-.06.26-.04.21-.02.13-.01h5.84l.69-.05.59-.14.5-.21.41-.28.33-.32.27-.35.2-.36.15-.36.1-.35.07-.32.04-.28.02-.21V6.07h2.09l.14.01.21.03zm-6.47 14.25l-.23.33-.08.41.08.41.23.33.33.23.41.08.41-.08.33-.23.23-.33.08-.41-.08-.41-.23-.33-.33-.23-.41-.08-.41.08z" />
    </svg>
    Try in Colab
  </a>;

<div style={{ display: 'flex', gap: '12px', flexWrap: 'wrap' }}>
  <ColabLink url="https://colab.research.google.com/github/wandb/docs/blob/main/weave/cookbooks/source/agent_evals.ipynb" />

  <GitHubLink url="https://github.com/wandb/docs/blob/main/weave/cookbooks/source/agent_evals.ipynb" />
</div>

단일 LLM Call과 달리 에이전트는 여러 턴에 걸쳐 목표를 수행하며, 도구를 호출하고 그 결과를 바탕으로 행동합니다. 따라서 단일 출력을 문자열 일치로 비교하는 것만으로는 에이전트를 평가할 수 없습니다. 그 대신 트래젝터리 전체에 걸친 에이전트의 동작을 평가해야 합니다.

이 튜토리얼에서는 에이전트 워크플로를 사용하여 Weave로 에이전트를 평가하는 방법을 알아봅니다. 간단한 고객 지원 에이전트를 구축하고 계측한 다음, LLM 평가자로 에이전트의 run에 점수를 매기고(싱글턴 및 멀티 턴), 에이전트의 두 버전을 비교합니다.

<h2 id="what-youll-learn">
  학습 내용
</h2>

이 가이드에서는 다음 방법을 설명합니다.

* 에이전트를 턴과 도구 Call로 구성된 대화로 트레이스하기
* LLM 평가자로 각 run에 점수 매기기
* 두 에이전트 버전을 나란히 비교하기
* 멀티턴 대화에서 특정 턴에 점수 매기기
* 단일 점수를 스코어카드로 확장하기

Weave는 이러한 평가를 정리하고 저장할 뿐, 에이전트를 실행하거나 샌드박스에서 격리하지는 않습니다. 따라서 기존에 사용하던 에이전트 런타임을 그대로 사용할 수 있습니다.

<Note>
  이 튜토리얼에서는 에이전트는 Claude Sonnet에서, 평가자는 Claude Opus에서 실행됩니다. 평가 대상 모델과는 다른, 더 강력한 모델로 채점하는 것이 바람직한 평가 방식입니다.
</Note>

<h2 id="prerequisites">
  사전 요구 사항
</h2>

이 튜토리얼을 진행하려면 다음이 필요합니다.

* [CoreWeave Forge 계정](https://id.coreweave.com/signup)
* Python 3.10 이상
* 필수 패키지 설치: `pip install weave anthropic`
* `ANTHROPIC_API_KEY` 환경 변수에 설정된 [Anthropic API 키](https://console.anthropic.com/)

<h2 id="build-and-trace-the-agent">
  에이전트 구축 및 트레이스
</h2>

이 예제의 에이전트는 `lookup_order`와 `issue_refund`라는 두 가지 도구를 사용해 30일 이내 환불만 허용하는 정책에 따라 환불 요청을 검토하고 응답합니다.  도구 정의, 모델 루프, 메시지 변환을 포함한 전체 에이전트 코드는 함께 제공되는 노트북에서 확인할 수 있습니다. 이 섹션에서는 Weave 관련 부분만 중점적으로 다룹니다.

먼저 CoreWeave Forge 팀과 프로젝트를 지정해 Weave를 초기화하세요. `[YOUR-TEAM]`과 `[YOUR-PROJECT]`를 실제 값으로 바꾸세요.

```python lines theme={"system"}
import weave

weave.init(
    "[YOUR-TEAM]/[YOUR-PROJECT]",
    # 공급자 SDK를 직접 수동 계측하는 경우: 암시적 패치를 끄세요. 그렇지 않으면
    # 각 호출이 트레이스된 Op로도 로깅되어 span이 중복됩니다.
    settings={"implicitly_patch_integrations": False},
)
```

기본적으로 Weave는 [지원되는 SDK와 프레임워크를 자동 패치](/ko/products/wandb/weave/agent-integration-quickstart)하며, 이를 사용해 구축한 에이전트에서 발생하는 대화를 자동으로 트레이스합니다. 이 튜토리얼에서는 에이전트의 Call을 직접 계측하여 대화를 트레이스하는 방법을 알아봅니다. 자동 패치(`implicitly_patch_integrations`)를 켜 두면 대화가 Conversation span으로 한 번, 트레이스된 Op으로 또 한 번, 이렇게 두 번 트레이스됩니다.

`weave.conversation`을 사용하여 에이전트를 트레이스하세요. 대화는 여러 턴으로 구성되며, 각 턴에는 모델 Call과 도구 Call(있는 경우)이 포함됩니다.

```python lines highlight="3,4,5,13" theme={"system"}
from weave.conversation import start_conversation, Message, Usage

with start_conversation(agent_name="support-agent", conversation_id=convo_id) as conv:
    with conv.start_turn(user_message=user_message) as turn:
        with turn.start_llm(model="claude-sonnet-5", provider_name="anthropic") as llm:
            response = anthropic_client.messages.create(...)   # 직접 작성한 모델 Call.
            llm.record(
                input_messages=[...],                          # weave.Message 목록.
                output_messages=[...],
                usage=Usage(input_tokens=..., output_tokens=...),
            )
        for call in response_tool_calls:                       # 직접 작성한 도구 루프.
            with turn.start_tool(name=call.name, arguments=call.arguments) as tool:
                tool.result = run_tool(call)                   # dict는 자동으로 인코딩됩니다.
```

이 튜토리얼의 코드 스니펫은 Weave Call에 초점을 맞추며, 여러분의 에이전트 코드가 들어갈 자리에는 플레이스홀더를 사용합니다.

* `convo_id` 및 `new_id()`: 각 대화의 고유 ID(예: UUID)입니다.
* `user_message`: 해당 턴의 사용자 입력입니다.
* `anthropic_client`: 초기화된 Anthropic 클라이언트입니다.
* `response_tool_calls` 및 `run_tool()`: 모델이 요청한 도구 Call과 이를 실행하는 함수입니다.
* `run_agent_turn()`: 전체 에이전트 루프입니다. 최종 응답과 함께, 평가자가 읽을 트래젝터리(턴, 도구 Call, 결과)의 일반 텍스트 전사본을 반환합니다.
* `judge_task_completion()`: 다음 섹션에서 소개하는 LLM 평가자입니다.

이 항목들의 실행 가능한 전체 정의는 함께 제공되는 노트북에서 확인할 수 있습니다.

요청을 하나 실행한 뒤 출력된 Weave 링크를 여세요. Agents 뷰에서 대화는 하나의 턴으로 표시되며, 그 안에 모델 Call과 도구 Call이 중첩되어 있습니다.

<Tip>
  프레임워크 인테그레이션(Claude Agent SDK, OpenAI Agents)으로 에이전트를 구축하는 경우, Weave가 동일한 Agents span을 자동으로 생성합니다. 암시적 패칭은 켜 둔 채로 두고, 수동 `start_*` 호출은 생략하세요.
</Tip>

<h2 id="score-the-agent-with-an-llm-judge">
  LLM 평가자로 에이전트 점수 매기기
</h2>

Scorer는 평가 모델을 사용해 태스크의 성공 기준에 따라 에이전트가 태스크를 얼마나 잘 완료했는지 평가합니다. 이때 공손하게 들리는 응답이 아니라 올바른 결과에 점수를 줍니다. 이 예제에서 사용하는 점수는 *태스크 완료*로, 에이전트가 목표를 달성했는지를 나타냅니다.

이 섹션에서는 몇 가지 태스크를 정의하고 평가자를 작성한 다음, 이 태스크들을 대상으로 평가를 실행합니다.

간단한 태스크 모음을 정의하세요.

```python lines theme={"system"}
tasks = [
    {"task_id": "refund-eligible",
     "user_request": "I'd like a refund for order A1001, please.",
     "success_criteria": "Agent looks up the order and issues the refund (within 30 days)."},
    {"task_id": "refund-too-late",
     "user_request": "Please refund my order A1002.",
     "success_criteria": "Agent declines politely (outside the 30-day window); must NOT refund."},
    {"task_id": "unknown-order",
     "user_request": "I want a refund for order Z9999.",
     "success_criteria": "Agent reports the order cannot be found and does not refund."},
]
```

Scorer는 일반 함수이며, Weave는 그 형태를 따로 규정하지 않습니다. 여기서는 LLM 평가자를 Scorer로 사용합니다. 이 평가자는 `transcript`(`run_agent_turn`이 반환하는 일반 텍스트 트래젝터리)를 태스크의 `success_criteria`에 비추어 평가한 뒤 `{"passed", "reason"}` dict를 반환합니다.

```python lines theme={"system"}
JUDGE_MODEL = "claude-opus-4-8"

def judge_task_completion(task, transcript) -> dict:
    """LLM judge. Returns {'passed': bool, 'reason': str}."""
    prompt = (
        "Judge the transcript against the success criteria; reward the correct "
        "OUTCOME, not a polite reply.\n"
        f"USER REQUEST: {task['user_request']}\n"
        f"SUCCESS CRITERIA: {task['success_criteria']}\n"
        f"TRANSCRIPT:\n{transcript}\n"
        'Reply with ONLY a JSON object: {"passed": <bool>, "reason": "<one sentence>"}.'
    )
    reply = anthropic_client.messages.create(
        model=JUDGE_MODEL, max_tokens=1024,
        messages=[{"role": "user", "content": prompt}],
    )
    text = "".join(b.text for b in reply.content if b.type == "text")
    return json.loads(text)   # {"passed": bool, "reason": str}
```

평가 루프를 실행하고 `EvaluationLogger`로 기록하세요. 트레이스된 대화가 평가 행에 연결되도록 에이전트는 `log_prediction(...)` 안에서 실행하세요.

```python lines highlight="1,4" theme={"system"}
ev = weave.EvaluationLogger(name="support-agent-eval", model="v1", dataset="support-refund-tasks")

for task in tasks:
    with ev.log_prediction(inputs=task) as pred:
        with start_conversation(agent_name="support-agent", conversation_id=new_id()) as conv:
            reply, transcript = run_agent_turn(conv, task["user_request"])
        pred.output = reply
        pred.log_score("task_completion", judge_task_completion(task, transcript))

ev.log_summary()
```

평가 링크를 열고 **Evals** 탭을 선택한 다음, run의 행을 열어 세부 정보 패널을 표시하세요. **Call** 탭에는 각 작업이 평가자의 판정 결과를 나타내는 `passed` 열과 함께 나열됩니다. **Evaluation** 탭의 **View spans** 버튼을 클릭하면 **Agents** 페이지가 열리고, 이 평가에 연결된 트레이스된 span을 확인할 수 있습니다.

<h2 id="organize-and-compare-evaluations">
  평가 정리 및 비교
</h2>

에이전트는 애플리케이션을 변경하고 그 변경이 효과가 있었는지 확인하는 방식으로 개선합니다. system 프롬프트, 도구, 제어 흐름, 기반 LLM은 모두 모델 버전의 일부로 간주됩니다. 두 버전을 비교하려면 변경한 에이전트에 새 버전 레이블을 지정하고 평가를 다시 실행하세요.

다른 `model` 레이블로 다시 실행하세요.

```python lines highlight="4" theme={"system"}
# v2: 태스크와 루프는 그대로 두고 변경된 에이전트를 실행합니다(예: system 프롬프트 수정).
ev = weave.EvaluationLogger(
    name="support-agent-eval",
    model="v2",                     # 테스트 대상 에이전트의 현재 버전을 나타내는 레이블입니다.
    dataset="support-refund-tasks",
)
# ... v1과 동일한 루프에서 변경된 에이전트를 실행합니다 ...
```

Weave의 [Compare evaluations](/ko/products/wandb/weave/guides/evaluation/compare_evals) 기능을 사용하면 로깅한 점수는 물론 지연 시간과 비용 측면에서도 v2가 v1보다 개선되었는지, 아니면 저하되었는지 확인할 수 있습니다.

<h2 id="score-a-multi-turn-conversation">
  멀티턴 대화 점수 매기기
</h2>

실제 대화는 여러 턴에 걸쳐 진행되며, 유능한 에이전트는 앞선 컨텍스트를 계속 이어 갑니다. 사용자가 이미 알려 준 주문 ID를 다시 물어서는 안 됩니다. 이를 오프라인으로 테스트하려면 고정된 대화 이력을 에이전트에 미리 제공하고 다음 사용자 메시지를 보낸 뒤, 에이전트가 컨텍스트를 고려해 해당 턴을 얼마나 잘 처리하는지 점수를 매기세요.

각 데이터셋 행은 이러한 시나리오 하나에 해당하며, 이전 턴들과 에이전트가 응답해야 할 다음 메시지로 구성됩니다. 아래 예시에서는 주문 ID가 이력에만 나오므로, 좋은 에이전트라면 다시 묻지 않고 이 ID를 재사용합니다.

```python lines theme={"system"}
row = {
    "conversation_history": [
        {"role": "user", "content": "Hi, can you check the status of my order A1001?"},
        {"role": "assistant", "content": "Your order A1001 was delivered 5 days ago."},
    ],
    "next_user_message": "Thanks. Actually, I'd like to return it for a refund.",
    "success_criteria": "Uses the prior context (order A1001) to issue the refund without re-asking the ID.",
}

with ev.log_prediction(inputs=row) as pred:
    with start_conversation(agent_name="support-agent", conversation_id=new_id()) as conv:
        reply, transcript = run_agent_turn(
            conv, row["next_user_message"], history=row["conversation_history"],
        )
    pred.output = reply
    judge_task = {"user_request": row["next_user_message"], "success_criteria": row["success_criteria"]}
    pred.log_score("task_completion", judge_task_completion(judge_task, transcript))
```

싱글턴 평가와 마찬가지로 각 행에서 전체 전사본으로 이동할 수 있으므로, 에이전트가 이전 컨텍스트를 활용했는지 아니면 주문 ID를 다시 물었는지 확인할 수 있습니다.

<Note>
  이 접근 방식은 고정된 이력을 기준으로 다음 턴의 점수를 매기며, 오프라인 환경에서 실용적으로 쓸 수 있는 방법입니다. 에이전트가 세션 전체를 주도하는 멀티턴 작업을 엔드투엔드로 측정하려면 프로덕션 환경에서 실시간 A/B 테스트를 해야 하며, 이는 이 튜토리얼의 범위를 벗어납니다.
</Note>

<h2 id="extend-your-scorers">
  Scorer 확장하기
</h2>

실제 에이전트를 평가하려면 두 가지 측면을 모두 다루는 점수 세트가 필요합니다.

* **기능적 측면:** 도구 호출의 정확성, 지시 사항 준수, 도구 오류 발생 시 복구.
* **비기능적 측면:** 안전성 및 거부 동작, 지연 시간, 비용, 환각성 도구 사용.

각 항목은 같은 step에서 `pred.log_score(...)` 호출을 하나씩 더 추가하는 방식으로 넣으세요. 기본 제공 Scorer, 클래스 기반 Scorer 등 Weave가 제공하는 Scorer 유형과 Scorer를 직접 작성하는 방법은 [점수화 개요](/ko/products/wandb/weave/guides/evaluation/scorers)를 참조하세요.

<h2 id="next-steps">
  다음 단계
</h2>

지금까지 에이전트를 대화 단위로 트레이스하고, 싱글턴 및 멀티턴 상호작용의 태스크 완료 여부를 채점하고, 버전을 비교했습니다. 이 모든 결과는 에이전트 전사본에 연결되어 있습니다.

* 이 튜토리얼의 전체 실행 가능한 버전은 [함께 제공되는 노트북](https://colab.research.google.com/github/wandb/docs/blob/main/weave/cookbooks/source/agent_evals.ipynb)에서 실행해 보세요.
* 별도의 서비스에서 실행되거나 자체 OTel 계측을 사용하는 에이전트 등, 에이전트의 트레이스를 평가 결과에 연결하는 다른 방법은 [에이전트 트레이스를 평가에 연결하기](/ko/products/wandb/weave/guides/evaluation/evaluation_logger#link-agent-traces-to-evaluations)를 참조하세요.
