Evaluation

Agent Framework включает встроенную платформу оценки, которая позволяет измерять качество агента, безопасность и правильность. Вы можете выполнять быстрые локальные проверки во время разработки, использовать облачные оценщики Microsoft Foundry для оценки промышленного уровня или объединить оба подхода в одном запуске оценки.

Платформа оценки разработана на основе нескольких ключевых принципов:

  • Независимый от поставщика — основные типы оценки и функции оркестрации работают с любым поставщиком оценки.
  • Нулевое трение — перейти от "У меня есть агент" к "У меня есть результаты оценки" с минимальным количеством кода.
  • Прогрессивное раскрытие . Для простых сценариев требуется почти нулевой код. Расширенные сценарии создаются на основе одних и тех же примитивов.

Основные понятия

Платформа оценки основана на трех типах:

Type Purpose
EvalItem Один элемент для оценки — упаковывает всю беседу и формирует запрос/ответ с помощью стратегии разбиения.
Оценщик Поставщик, который оценивает элементы — локальные проверки, Microsoft Foundry или любую пользовательскую реализацию.
EvalResults Агрегированные результаты запуска оценки — количество успешных и неудачных результатов, подробные сведения по каждому элементу и необязательные ссылки на портал.

В .NET платформа оценки основана на Microsoft. Extensions.AI.Evaluation. Реализаторы выполняют IAgentEvaluator интерфейс, а оркестрация предоставляется с помощью методов расширения, определенных для AIAgent и Run.

Основные типы живут в пространстве имен 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 осуществляет проверки локально без вызовов API — идеально подходит для внутреннего цикла разработки, смоук-тестов CI и быстрой итерации. Он принимает любое количество функций проверки и применяет каждую из них к каждому элементу.

Встроенные проверки

Agent Framework поставляется со встроенными проверками для распространенных сценариев:

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

Встроенные проверки

Agent Framework поставляется со встроенными проверками для распространенных сценариев:

Проверьте Что делает
keyword_check(*keywords) Ответ должен содержать все указанные ключевые слова
tool_called_check(*tool_names) Агент должен был вызвать указанные инструменты
tool_calls_present Все expected_tool_calls имена отображаются в беседе (в любом порядке, дополнительные допускаются)
tool_call_args_match Ожидаемые вызовы инструментов соответствуют имени и аргументам (совпадение подмножества в 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
)

Пользовательские оценщики функций

@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, tools. context

Возвращаемые типы: bool, float (≥ 0,5 = pass), dict с score или passed ключом или CheckResult. Асинхронные функции обрабатываются автоматически.

Оценщики Microsoft Foundry

FoundryEvals подключается к службе оценки Microsoft Foundry для облачного оценивания по модели «LLM в роли судьи». Результаты можно просматривать на портале Foundry с панелями мониторинга и представлениями сравнения.

Информацию о настройке проекта, оценке трасс, оценщиках на основе рубрик и исполняемых примерах для конкретных служб см. в разделе Microsoft Foundry evaluation.

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 предоставляет константы для всех встроенных имен вычислителя:

Category Оценщиков
Поведение агента intent_resolution, task_adherence, task_completion, task_navigation_efficiency
Использование инструмента tool_call_accuracy, , tool_selectiontool_input_accuracy, tool_output_utilizationtool_call_success
Качество coherence, fluency, groundedness, relevance, response_completeness, similarity
Safety violence, sexual, self_harm, hate_unfairness

Замечание

FoundryEvalsтребуется проект Microsoft 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

EvaluateAsync — это метод расширения на AIAgent. Он запускает агент один раз на запрос, преобразует каждое взаимодействие в 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,
)

Ответы агента Python сохраняют снимки только схемы инструментов-функций, которые были предоставлены во время выполнения, включая инструменты от поставщиков контекста. evaluate_agent автоматически использует эти снимки для оценки с учетом инструментов. Моментальные снимки сохраняются при сериализации в формате JSON и сериализации pickle и не включают исполняемые реализации инструментов.

Передайте tools= в evaluate_agent, чтобы переопределить захваченные определения только для оценки. Передайте tools=[], чтобы выполнить оценку без определений инструментов. Автоматическое обнаружение вызывает, ValueError если вызываемое средство использовало разные входные схемы под тем же именем во время записанной беседы. Используйте отдельные имена инструментов, оцените сегменты отдельно или передайте явные определения инструментов.

Замечание

Входные схемы инструментов должны содержать значения, совместимые с JSON. Запись пользовательской схемы может вызвать ошибку во время запуска агента, если схема не может быть сериализована.

Стратегии разделения бесед

Для оценки многоэтапные беседы необходимо разделить на части: запросы и ответы. Разделение диктует , что именно вы оцениваете.

Стратегия Behavior лучше всего подходит для
Последняя очередь (по умолчанию) Разделить на последнем сообщении пользователя. Все, что до него, — это контекст запроса; все, что после, — это ответ. Качество отклика в определенной точке
Полное Первое сообщение пользователя — это запрос; вся оставшаяся часть является ответом. Завершение задачи и общая траектория
На ход Каждое взаимодействие между пользователем и ассистентом оценивается независимо, учитывая накопление контекста. Детализированный анализ
// 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));

Tip

При использовании оценщиков MEAI, предоставьте параметр chatConfiguration, связанный с клиентом чата, настроенным для модели оценки. Этот клиент используется оценщиками LLM в роли судьи для оценки ответов.

Замечание

Поддержка Go для этой функции скоро появится. Сведения о последнем состоянии см. в репозитории Agent Framework Go .

Дальнейшие действия