Evaluation

代理框架包含一个内置的评估框架,可用于衡量代理质量、安全性和正确性。 可以在开发期间运行快速本地检查,使用 Microsoft Foundry 的基于云的评估器进行生产级评估,或在单个评估运行中合并两者。

评估框架围绕几个关键原则进行设计:

  • 与提供程序无关 - 核心评估类型和业务流程函数适用于任何评估提供程序。
  • 零摩擦 - 从“我有代理”到“我有一个评估结果”,只需最少的代码。
  • 渐进式披露 - 简单方案需要接近零的代码。 高级方案基于同一基元生成。

核心概念

评估框架基于三种类型构建:

类型 Purpose
EvalItem 要评估的单项 - 包装整个对话并通过拆分策略派生查询/响应。
评估器 对项进行评分的提供程序-本地检查、Microsoft 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 在没有 API 调用的情况下在本地运行检查 - 非常适合内部循环开发、CI 冒烟测试和快速迭代。 它接受任意数量的检查函数,并将每个函数应用于每个项。

内置检查

代理框架附带了针对常见场景的内置检查:

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、、、responseexpected_outputexpected_tool_callsconversationtools、。 context

返回类型: boolfloat (≥ 0.5 = pass)、 dictscorepassed 键或 CheckResult。 异步函数会自动处理。

Microsoft Foundry 计算器

FoundryEvals连接到 Microsoft Foundry 的评估服务,用于基于云的 LLM 即评评估。 可以通过仪表板和比较视图在 Foundry 门户中查看结果。

有关项目设置、跟踪评估、标准评估器和可运行的服务特定示例,请参阅 Microsoft 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_resolutiontask_adherencetask_completiontask_navigation_efficiency
工具用法 tool_call_accuracytool_selectiontool_input_accuracytool_output_utilizationtool_call_success
Quality coherencefluencyrelevancegroundednessresponse_completenesssimilarity
Safety violencesexualself_harmhate_unfairness

注释

FoundryEvals需要使用 AI 模型部署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

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 即裁判评估程序将使用此客户端对响应进行评分。

注释

Go 语言对该功能的支持即将推出。 有关最新状态,请参阅 Agent Framework Go 存储库

后续步骤