Evaluation

에이전트 프레임워크에는 에이전트 품질, 안전성 및 정확성을 측정할 수 있는 기본 제공 평가 프레임워크가 포함되어 있습니다. 개발 중에 빠른 로컬 검사를 실행하거나, 프로덕션 등급 평가에 Azure AI Foundry 클라우드 기반 평가기를 사용하거나, 단일 평가 실행에서 둘 다 결합할 수 있습니다.

평가 프레임워크는 다음과 같은 몇 가지 주요 원칙을 중심으로 설계되었습니다.

  • 공급자 독립적 - 핵심 평가 형식 및 오케스트레이션 함수는 모든 평가 공급자와 함께 작동합니다.
  • 마찰 없음 — 최소한의 코드로 "에이전트가 있음"에서 "평가 결과가 있음"으로 전환합니다.
  • 점진적 공개 - 간단한 시나리오에는 거의 0에 가까운 코드가 필요합니다. 고급 시나리오는 동일한 기본 형식을 기반으로 합니다.

핵심 개념

평가 프레임워크는 다음 세 가지 형식으로 빌드됩니다.

유형 Purpose
EvalItem 평가할 대상은 단 하나로, 전체 대화를 감싸고 분할 전략을 통해 쿼리와 응답을 도출합니다.
계산기 로컬 검사, Azure AI Foundry 또는 사용자 지정 구현과 같은 항목의 점수를 지정하는 공급자입니다.
EvalResults 평가 실행에서 집계된 결과( 통과/실패 횟수, 항목별 세부 정보 및 선택적 포털 링크).

.NET에서 평가 프레임워크는 Microsoft.Extensions.AI.Evaluation을 기반으로 구축됩니다. 평가자는 IAgentEvaluator 인터페이스를 구현하고, 오케스트레이션은 AIAgentRun의 확장 메서드를 통해 제공됩니다.

핵심 형식은 Microsoft.Agents.AI 네임스페이스에 있습니다.

using Microsoft.Agents.AI;

Python 평가 프레임워크는 핵심 agent_framework 패키지의 일부입니다. 평가자는 Evaluator 프로토콜을 구현하며, 오케스트레이션은 evaluate_agent()evaluate_workflow() 함수를 통해 제공됩니다.

from agent_framework import (
    evaluate_agent,
    evaluate_workflow,
    EvalItem,
    EvalResults,
    LocalEvaluator,
)

지역 평가자

LocalEvaluator 는 내부 루프 개발, CI 스모크 테스트 및 빠른 반복에 적합한 API 호출 없이 로컬로 검사를 실행합니다. 여러 검사 함수를 허용하고 각 함수를 모든 항목에 적용합니다.

기본 제공 검사

에이전트 프레임워크는 일반적인 시나리오에 대한 기본 제공 검사와 함께 제공됩니다.

using Microsoft.Agents.AI;

var local = new LocalEvaluator(
    EvalChecks.KeywordCheck("weather", "temperature"),  // Response must contain these keywords
    EvalChecks.ToolCalledCheck("get_weather")            // Agent must have called this tool
);

사용자 지정 함수 계산기

모든 함수를 평가기 검사를 위한 래핑 도구로 FunctionEvaluator.Create()를 사용합니다. 필요한 데이터에 따라 여러 오버로드를 사용할 수 있습니다.

using Microsoft.Agents.AI;

var local = new LocalEvaluator(
    // Simple: check only the response text
    FunctionEvaluator.Create("is_concise",
        (string response) => response.Split(' ').Length < 500),

    // With expected output: compare against ground truth
    FunctionEvaluator.Create("mentions_city",
        (string response, string? expectedOutput) =>
            expectedOutput != null && response.Contains(expectedOutput, StringComparison.OrdinalIgnoreCase)),

    // Full context: access the complete EvalItem
    FunctionEvaluator.Create("used_search",
        (EvalItem item) => item.Conversation.Any(m =>
            m.Text?.Contains("search", StringComparison.OrdinalIgnoreCase) == true))
);

기본 제공 검사

에이전트 프레임워크는 일반적인 시나리오에 대한 기본 제공 검사와 함께 제공됩니다.

확인 용도
keyword_check(*keywords) 응답에 지정된 모든 키워드가 포함되어야 합니다.
tool_called_check(*tool_names) 에이전트가 지정된 도구를 호출해야 합니다.
tool_calls_present 모든 expected_tool_calls 이름이 대화에 표시됩니다(순서가 지정되지 않음, 추가 항목 확인).
tool_call_args_match 이름 및 인수에 대한 예상 도구 호출 일치(인수의 하위 집합 일치)
from agent_framework import (
    LocalEvaluator,
    keyword_check,
    tool_called_check,
    tool_calls_present,
    tool_call_args_match,
)

local = LocalEvaluator(
    keyword_check("weather", "temperature"),  # Response must contain these keywords
    tool_called_check("get_weather"),          # Agent must have called this tool
    tool_calls_present,                        # All expected tool call names were made
    tool_call_args_match,                      # Expected tool calls match on name + args
)

사용자 지정 함수 계산기

@evaluator 데코레이터를 사용하여 모든 함수를 평가자 검사로 래핑합니다. 함수의 매개 변수 이름EvalItem로부터 데이터를 수신할 때 그것을 결정합니다.

from agent_framework import evaluator, LocalEvaluator

@evaluator
def is_concise(response: str) -> bool:
    """Check response is under 500 words."""
    return len(response.split()) < 500

@evaluator
def mentions_city(response: str, expected_output: str) -> bool:
    """Check response contains the expected city name."""
    return expected_output.lower() in response.lower()

@evaluator
def used_tools(conversation: list, tools: list) -> float:
    """Score based on tool usage. Returns 0.0–1.0 (>= 0.5 passes)."""
    tool_calls = [c for m in conversation for c in (m.contents or []) if c.type == "function_call"]
    return min(len(tool_calls) / max(len(tools), 1), 1.0)

local = LocalEvaluator(is_concise, mentions_city, used_tools)

지원되는 매개 변수 이름: query,response, expected_output, expected_tool_callsconversation, toolscontext.

반환 형식: bool, float (≥ 0.5 = pass), dictscore 키 또는 passed 또는 CheckResult. 비동기 함수는 자동으로 처리됩니다.

Azure AI Foundry 평가자

FoundryEvals는 클라우드 기반 LLM-as-judge 평가를 위해 Azure AI Foundry의 평가 서비스에 연결됩니다. 결과는 대시보드 및 비교 보기를 사용하여 Foundry 포털에서 볼 수 있습니다.

using Microsoft.Agents.AI.AzureAI;

var foundry = new FoundryEvals(chatConfiguration, FoundryEvals.Relevance, FoundryEvals.Coherence);
from agent_framework.foundry import FoundryEvals

evals = FoundryEvals(
    project_client=project_client,
    model="gpt-4o",
    evaluators=[FoundryEvals.RELEVANCE, FoundryEvals.COHERENCE],
)

기본적으로 FoundryEvals, 일관성작업 준수 평가자를 실행합니다. 항목에 도구 정의가 포함되어 있으면 도구 호출 정확도가 자동으로 추가됩니다.

사용 가능한 평가 도구

FoundryEvals 는 모든 기본 제공 계산기 이름에 대한 상수입니다.

카테고리 평가자
에이전트 동작 intent_resolution, task_adherence, , task_completion, task_navigation_efficiency
도구 사용량 tool_call_accuracy, tool_selection, tool_input_accuracy, tool_output_utilizationtool_call_success
coherence, fluency, relevance, groundedness, response_completenesssimilarity
Safety violence, sexual, , self_harm, hate_unfairness

메모

FoundryEvals AI 모델 배포를 사용하는 Azure AI Foundry 프로젝트가 필요합니다. 매개 변수는 model LLM 판사로 사용할 모델을 지정합니다.

에이전트 평가

가장 간단한 평가 시나리오는 테스트 쿼리에 대해 에이전트를 실행하고 응답의 점수를 매깁니다. 통계적으로 의미 있는 평가를 위해 다양한 쿼리를 제공합니다.

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Foundry;

var foundry = new FoundryEvals(chatConfiguration, FoundryEvals.Relevance, FoundryEvals.Coherence);

AgentEvaluationResults results = await agent.EvaluateAsync(
    new[]
    {
        "What's the weather in Seattle?",
        "Plan a weekend trip to Portland",
        "What restaurants are near Pike Place?",
    },
    foundry);

results.AssertAllPassed();  // Throws if any item failed

EvaluateAsyncAIAgent에 대한 확장 메서드입니다. 쿼리당 한 번씩 에이전트를 실행하고, 각 상호작용을 EvalItem로 변환하고, 일괄 처리로 평가자에게 전달합니다.

from agent_framework import evaluate_agent
from agent_framework.foundry import FoundryEvals

evals = FoundryEvals(
    project_client=project_client,
    model="gpt-4o",
    evaluators=[FoundryEvals.RELEVANCE, FoundryEvals.COHERENCE],
)

results = await evaluate_agent(
    agent=my_agent,
    queries=[
        "What's the weather in Seattle?",
        "Plan a weekend trip to Portland",
        "What restaurants are near Pike Place?",
    ],
    evaluators=evals,
)

for r in results:
    print(f"{r.provider}: {r.passed}/{r.total}")
    r.raise_for_status()  # Raises EvalNotPassedError if any item failed

evaluate_agent 는 쿼리당 한 번씩 에이전트를 실행하고, 각 상호 작용을 변환 EvalItem하고, 일괄 처리를 계산기로 전달합니다. 평가자 공급자당 하나씩 EvalResults를 반환합니다.

반복을 사용하여 일관성 측정

각 쿼리를 여러 번 실행하여 비결정적 동작을 검색합니다.

AgentEvaluationResults results = await agent.EvaluateAsync(
    new[] { "What's the weather in Seattle?" },
    foundry,
    numRepetitions: 3);  // Each query runs 3 times independently
// Results contain 3 items (1 query × 3 repetitions)
results = await evaluate_agent(
    agent=my_agent,
    queries=["What's the weather in Seattle?"],
    evaluators=evals,
    num_repetitions=3,  # Each query runs 3 times independently
)
# Results contain 3 items (1 query × 3 repetitions)

예상 출력으로 평가

정확성을 평가하기 위해 근거리 예상 답변을 제공합니다. 예상 출력은 쿼리와 위치적으로 결합됩니다.

AgentEvaluationResults results = await agent.EvaluateAsync(
    new[] { "What's 2+2?", "Capital of France?" },
    foundry,
    expectedOutput: new[] { "4", "Paris" });

필요한 도구 호출을 지정할 수도 있습니다.

AgentEvaluationResults results = await agent.EvaluateAsync(
    new[] { "What's the weather in NYC?" },
    new LocalEvaluator(EvalChecks.ToolCalledCheck("get_weather")),
    expectedToolCalls: new[]
    {
        new[] { new ExpectedToolCall("get_weather") },
    });
from agent_framework import evaluate_agent, ExpectedToolCall

results = await evaluate_agent(
    agent=my_agent,
    queries=["What's 2+2?", "Capital of France?"],
    expected_output=["4", "Paris"],
    evaluators=evals,
)

필요한 도구 호출을 지정할 수도 있습니다.

results = await evaluate_agent(
    agent=my_agent,
    queries=["What's the weather in NYC?"],
    expected_tool_calls=[ExpectedToolCall("get_weather", {"location": "NYC"})],
    evaluators=local,
)

기존 응답 평가

로그 또는 이전 실행의 에이전트 응답이 이미 있는 경우 에이전트를 다시 실행하지 않고 직접 평가합니다.

var response = await agent.RunAsync(new[] { new ChatMessage(ChatRole.User, "What's the weather?") });

AgentEvaluationResults results = await agent.EvaluateAsync(
    new[] { response },
    new[] { "What's the weather?" },
    foundry);
from agent_framework import Message, evaluate_agent

response = await agent.run([Message("user", ["What's the weather?"])])

results = await evaluate_agent(
    agent=agent,
    responses=response,
    queries="What's the weather?",
    evaluators=evals,
)

대화 분할 전략

다중 턴 대화는 평가를 위해 쿼리와 응답 부분으로 나누어야 합니다. 분할 방법에 따라 평가 중인 항목이 결정됩니다.

전략 작동 방식 적합한 대상
마지막 턴 (기본값) 마지막 사용자 메시지에서 분할하십시오. 모든 것은 쿼리 컨텍스트입니다. 이후의 모든 것이 응답입니다. 특정 지점의 응답 품질
전체 첫 번째 사용자 메시지는 쿼리입니다. 나머지 전체가 응답입니다. 작업 완료 및 전체 궤도
턴당 각 사용자-어시스턴트 상호작용은 독립적으로 평가되어 누적된 컨텍스트가 고려됩니다. 세분화된 분석
// Full conversation as context
AgentEvaluationResults results = await agent.EvaluateAsync(
    new[] { "Plan a 3-day trip to Paris" },
    foundry,
    splitter: ConversationSplitters.Full);

// Per-turn: each exchange scored independently
var items = EvalItem.PerTurnItems(conversation);
var perTurnResults = await evaluator.EvaluateAsync(items);

다음을 구현하여 사용자 지정 분할자를 구현할 수도 있습니다.IConversationSplitter

public class SplitBeforeToolCall : IConversationSplitter
{
    public (IReadOnlyList<ChatMessage> QueryMessages, IReadOnlyList<ChatMessage> ResponseMessages) Split(
        IReadOnlyList<ChatMessage> conversation)
    {
        // Custom split logic
        for (int i = 0; i < conversation.Count; i++)
        {
            if (conversation[i].Text?.Contains("tool_call") == true)
                return (conversation.Take(i).ToList(), conversation.Skip(i).ToList());
        }
        return ConversationSplitters.LastTurn.Split(conversation);
    }
}
from agent_framework import evaluate_agent, ConversationSplit

# Full conversation as context
results = await evaluate_agent(
    agent=agent,
    queries=["Plan a 3-day trip to Paris"],
    evaluators=evals,
    conversation_split=ConversationSplit.FULL,
)

# Per-turn: each exchange scored independently
from agent_framework import EvalItem

items = EvalItem.per_turn_items(conversation)
# Pass items directly to an evaluator
per_turn_results = await evaluator.evaluate(items)

대화를 인자로 받아서 (query_messages, response_messages)을 반환하는 호출 가능한 사용자 지정 분할자를 제공할 수도 있습니다.

def split_before_memory(conversation):
    """Split just before a memory-retrieval tool call."""
    for i, msg in enumerate(conversation):
        for c in msg.contents or []:
            if c.type == "function_call" and c.name == "retrieve_memory":
                return conversation[:i], conversation[i:]
    # Fallback to default
    return EvalItem._split_last_turn_static(conversation)

results = await evaluate_agent(
    agent=agent,
    queries=queries,
    evaluators=evals,
    conversation_split=split_before_memory,
)

워크플로 평가

에이전트별 분석으로 다중 에이전트 워크플로를 평가합니다. 프레임워크는 각 하위 에이전트의 상호 작용을 추출하고 워크플로의 전체 출력과 함께 개별적으로 평가합니다.

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;

Run run = await workflowRunner.RunAsync(workflow, "Plan a trip to Paris");

AgentEvaluationResults results = await run.EvaluateAsync(
    new FoundryEvals(chatConfiguration, FoundryEvals.Relevance));

Console.WriteLine($"Overall: {results.Passed}/{results.Total}");

// Per-agent breakdown
if (results.SubResults != null)
{
    foreach (var (name, sub) in results.SubResults)
    {
        Console.WriteLine($"  {name}: {sub.Passed}/{sub.Total}");
    }
}

results.AssertAllPassed();
from agent_framework import evaluate_workflow
from agent_framework.foundry import FoundryEvals

evals = FoundryEvals(project_client=project_client, model="gpt-4o")
result = await workflow.run("Plan a trip to Paris")

eval_results = await evaluate_workflow(
    workflow=workflow,
    workflow_result=result,
    evaluators=evals,
)

for r in eval_results:
    print(f"{r.provider}: {r.passed}/{r.total}")
    for name, sub in r.sub_results.items():
        print(f"  {name}: {sub.passed}/{sub.total}")

또한 직접 queries를 전달할 수도 있으며 프레임워크가 워크플로를 실행해 줍니다.

eval_results = await evaluate_workflow(
    workflow=workflow,
    queries=["Plan a trip to Paris", "Book a flight to London"],
    evaluators=evals,
)

여러 평가자 혼합

단일 평가에서 로컬 검사 및 클라우드 기반 평가기를 함께 실행합니다. 각 평가자는 자체적으로 EvalResults를 생성합니다.

using Microsoft.Agents.AI;
using Microsoft.Agents.AI.AzureAI;

IReadOnlyList<AgentEvaluationResults> results = await agent.EvaluateAsync(
    new[] { "What's the weather in Seattle?" },
    evaluators: new IAgentEvaluator[]
    {
        new LocalEvaluator(
            EvalChecks.KeywordCheck("weather"),
            FunctionEvaluator.Create("is_helpful", (string r) => r.Split(' ').Length > 10)),
        new FoundryEvals(chatConfiguration, FoundryEvals.Relevance, FoundryEvals.Coherence),
    });

// results[0] = local evaluator results
// results[1] = Foundry evaluator results
foreach (var r in results)
{
    Console.WriteLine($"{r.Provider}: {r.Passed}/{r.Total}");
}
from agent_framework import evaluate_agent, evaluator, LocalEvaluator, keyword_check
from agent_framework.foundry import FoundryEvals

@evaluator
def is_helpful(response: str) -> bool:
    return len(response.split()) > 10

foundry = FoundryEvals(
    project_client=project_client,
    model="gpt-4o",
    evaluators=[FoundryEvals.RELEVANCE, FoundryEvals.COHERENCE],
)

results = await evaluate_agent(
    agent=agent,
    queries=["What's the weather in Seattle?"],
    evaluators=[
        LocalEvaluator(is_helpful, keyword_check("weather")),
        foundry,
    ],
)

# results[0] = local evaluator results
# results[1] = Foundry evaluator results
for r in results:
    print(f"{r.provider}: {r.passed}/{r.total}")

MEAI 평가자

.NET 평가 프레임워크는 Microsoft.Extensions.AI.Evaluation 평가자와 직접 통합됩니다. MEAI의 품질 및 안전 평가기는 어댑터 없이 작동합니다.

using Microsoft.Extensions.AI.Evaluation;
using Microsoft.Extensions.AI.Evaluation.Quality;
using Microsoft.Extensions.AI.Evaluation.Safety;

// Quality evaluators
AgentEvaluationResults results = await agent.EvaluateAsync(
    new[] { "What's the weather?" },
    new CompositeEvaluator(
        new RelevanceEvaluator(),
        new CoherenceEvaluator(),
        new GroundednessEvaluator()),
    chatConfiguration: new ChatConfiguration(evalClient));

// Safety evaluators
AgentEvaluationResults safetyResults = await agent.EvaluateAsync(
    new[] { "What's the weather?" },
    new ContentHarmEvaluator(),
    chatConfiguration: new ChatConfiguration(evalClient));

팁 (조언)

MEAI 평가자를 사용하는 경우 평가 모델에 대해 구성된 채팅 클라이언트를 사용하여 매개 변수를 제공합니다 chatConfiguration . 이 클라이언트는 LLM-as-judge 평가자가 응답을 채점하는 데 사용됩니다.

메모

이 기능에 대한 지원은 곧 제공될 예정입니다. 최신 상태는 에이전트 프레임워크 Go 리포지토리 를 참조하세요.

다음 단계