Evaluation

O Agent Framework inclui uma estrutura de avaliação interna que permite medir a qualidade, a segurança e a correção do agente. Você pode executar verificações locais rápidas durante o desenvolvimento, usar os avaliadores baseados em nuvem da Fábrica de IA do Azure para avaliação de nível de produção ou combinar ambos em uma única execução de avaliação.

A estrutura de avaliação foi projetada em torno de alguns princípios principais:

  • Agnóstico em relação ao provedor — Tipos essenciais de avaliação e funções de orquestração funcionam com qualquer provedor de avaliação.
  • Atrito zero – vá de "Tenho um agente" para "Tenho resultados de avaliação" com código mínimo.
  • Divulgação progressiva – cenários simples exigem um código quase zero. Cenários avançados se baseiam nos mesmos primitivos.

Conceitos principais

A estrutura de avaliação é criada em três tipos:

Tipo Propósito
EvalItem Um único item a ser avaliado : encapsula a conversa completa e deriva a consulta/resposta por meio de uma estratégia dividida.
Avaliador Um provedor que pontua itens – verificações locais, Fábrica de IA do Azure ou qualquer implementação personalizada.
EvalResults Resultados agregados de um processo de avaliação — contagens de aprovação/falha, detalhes por item e links opcionais para o portal.

Em .NET, a estrutura de avaliação baseia-se em Microsoft. Extensions.AI.Evaluation. Os avaliadores implementam a interface IAgentEvaluator e a orquestração é fornecida por meio de métodos de extensão em AIAgent e Run.

Os tipos principais residem no namespace Microsoft.Agents.AI:

using Microsoft.Agents.AI;

Em Python, a estrutura de avaliação faz parte do pacote principal agent_framework. Os avaliadores implementam o protocolo Evaluator, e a orquestração é fornecida por meio das funções evaluate_agent() e evaluate_workflow().

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

Avaliadores locais

LocalEvaluator executa verificações localmente sem chamadas à API — ideal para desenvolvimento de loop interno, testes de fumaça de CI e iteração rápida. Ele aceita qualquer número de funções de verificação e aplica cada uma a cada item.

Verificações integradas

O Agent Framework é fornecido com verificações internas para cenários comuns:

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
);

Avaliadores de função personalizados

Use FunctionEvaluator.Create() para encapsular qualquer função como uma verificação do avaliador. Várias sobrecargas estão disponíveis dependendo de quais dados você precisa:

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))
);

Verificações integradas

O Agent Framework é fornecido com verificações internas para cenários comuns:

Verificação O que faz
keyword_check(*keywords) A resposta deve conter todas as palavras-chave especificadas
tool_called_check(*tool_names) O agente deve ter chamado as ferramentas especificadas
tool_calls_present Todos os expected_tool_calls nomes aparecem na conversa (sem ordem específica, elementos extras OK)
tool_call_args_match As chamadas de ferramenta esperadas correspondem ao nome e aos argumentos (correspondência de subconjunto em args)
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
)

Avaliadores de função personalizados

Utilize o @evaluator decorador para encapsular qualquer função como uma verificação do avaliador. Os nomes de parâmetro da função determinam quais dados ele recebe do 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)

Nomes de parâmetros com suporte: query, , response, expected_output, expected_tool_calls, conversation, , tools. context

Tipos de retorno: bool, float (≥ 0,5 = aprovado), dict com a chave score ou passed, ou chave CheckResult. As funções assíncronas são tratadas automaticamente.

Avaliadores do Fábrica de IA do Azure

FoundryEvals conecta-se ao serviço de avaliação do Fábrica de IA do Azure para avaliação LLM-as-Judge em nuvem. Os resultados podem ser exibidos no portal do Foundry com painéis e exibições de comparação.

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],
)

Por padrão, FoundryEvals executa avaliadores de relevância, coerência e adesão de tarefas . Quando os itens contêm definições de ferramenta, ele adiciona automaticamente a precisão da chamada de ferramenta.

Avaliadores disponíveis

FoundryEvals fornece constantes para todos os nomes internos do avaliador:

Categoria Avaliadores
Comportamento do agente intent_resolution, task_adherence, , task_completiontask_navigation_efficiency
Uso da ferramenta tool_call_accuracy, tool_selection, tool_input_accuracy, , tool_output_utilizationtool_call_success
Quality coherence, fluency, relevance, groundedness, response_completeness, , similarity
Safety violence, sexual, , self_harmhate_unfairness

Observação

FoundryEvals requer um projeto Fábrica de IA do Azure com uma implantação de modelo de IA. O model parâmetro especifica qual modelo usar como o juiz LLM.

Avaliar um agente

O cenário de avaliação mais simples executa um agente em consultas de teste e pontua as respostas. Forneça várias consultas diversas para avaliação estatisticamente significativa.

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

EvaluateAsync é um método de extensão em AIAgent. Ele executa o agente uma vez por consulta, converte cada interação em um EvalIteme passa o lote para o avaliador.

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 executa o agente uma vez por consulta, converte cada interação em um EvalIteme passa o lote para o avaliador. Ele retorna um EvalResults por provedor avaliador.

Medir a consistência com repetições

Execute cada consulta várias vezes para detectar um comportamento não determinístico:

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)

Avaliar com as saídas esperadas

Forneça as respostas básicas esperadas para avaliar a correção. As saídas esperadas são emparelhadas posicionalmente com consultas:

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

Você também pode especificar chamadas de ferramenta esperadas:

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,
)

Você também pode especificar chamadas de ferramenta esperadas:

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

Avaliar respostas pré-existentes

Quando você já tiver respostas de agente a partir de logs ou execuções anteriores, avalie-as diretamente sem precisar executar novamente o agente.

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,
)

Estratégias de divisão de conversa

Conversas de vários turnos devem ser divididas em partes de consulta e resposta para avaliação. Como você divide determina o que está avaliando.

Estratégia Comportamento Mais adequado para
Última curva (padrão) Divida na última mensagem do usuário. Tudo até este ponto é o contexto da consulta; tudo depois dele é a resposta. Qualidade da resposta em um ponto específico
Full A primeira mensagem do usuário é a consulta; todo o restante é a resposta. Conclusão da tarefa e trajetória geral
Por turno Cada troca de usuário para assistente é pontuada independentemente com o contexto cumulativo. Análise refinada
// 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);

Você também pode implementar um divisor personalizado implementando 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)

Você também pode fornecer um divisor personalizado, qualquer callable que aceita uma conversa e retorna (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,
)

Avaliar fluxos de trabalho

Avalie fluxos de trabalho de vários agentes com detalhamento por agente. A estrutura extrai as interações de cada sub-agente e as avalia individualmente, juntamente com a saída geral do fluxo de trabalho.

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}")

Você também pode passar queries diretamente e a estrutura executará o fluxo de trabalho para você:

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

Misturar vários avaliadores

Execute verificações locais e avaliadores baseados em nuvem em uma única avaliação. Cada avaliador produz seu próprio 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}")

Avaliadores do MEAI

A estrutura de avaliação .NET integra-se diretamente aos avaliadores do Microsoft.Extensions.AI.Evaluation. Os avaliadores de qualidade e segurança do MEAI funcionam sem nenhum adaptador:

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));

Tip

Ao usar avaliadores MEAI, forneça um chatConfiguration parâmetro com um cliente de chat configurado para o modelo de avaliação. Esse cliente é usado pelos avaliadores LLM-as-judge para pontuar respostas.

Observação

O suporte para Go a este recurso estará disponível em breve. Consulte o repositório Agent Framework Go para obter o status mais recente.

Próximas Etapas