Skip to content

Some API related fixes for the evaluation libraries #6402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal sealed class CleanCacheCommand(ILogger logger)
{
internal async Task<int> InvokeAsync(DirectoryInfo? storageRootDir, Uri? endpointUri, CancellationToken cancellationToken = default)
{
IResponseCacheProvider cacheProvider;
IEvaluationResponseCacheProvider cacheProvider;

if (storageRootDir is not null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal async Task<int> InvokeAsync(
int lastN,
CancellationToken cancellationToken = default)
{
IResultStore resultStore;
IEvaluationResultStore resultStore;

if (storageRootDir is not null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal async Task<int> InvokeAsync(
Format format,
CancellationToken cancellationToken = default)
{
IResultStore resultStore;
IEvaluationResultStore resultStore;

if (storageRootDir is not null)
{
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand All @@ -11,7 +12,7 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting.JsonSerialization;

internal static partial class AzureStorageJsonUtilities
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Default matches the generated source naming convention.")]
[SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Default matches the generated source naming convention.")]
internal static class Default
{
private static JsonSerializerOptions? _options;
Expand All @@ -24,6 +25,7 @@ internal static class Compact
{
private static JsonSerializerOptions? _options;
internal static JsonSerializerOptions Options => _options ??= CreateJsonSerializerOptions(writeIndented: false);
internal static JsonTypeInfo<CacheEntry> CacheEntryTypeInfo => Options.GetTypeInfo<CacheEntry>();
internal static JsonTypeInfo<ScenarioRunResult> ScenarioRunResultTypeInfo => Options.GetTypeInfo<ScenarioRunResult>();
}

Expand All @@ -45,14 +47,14 @@ private static JsonSerializerOptions CreateJsonSerializerOptions(bool writeInden
[JsonSerializable(typeof(CacheEntry))]
[JsonSourceGenerationOptions(
Converters = [
typeof(AzureStorageCamelCaseEnumConverter<EvaluationDiagnosticSeverity>),
typeof(AzureStorageCamelCaseEnumConverter<EvaluationRating>),
typeof(AzureStorageTimeSpanConverter)
typeof(CamelCaseEnumConverter<EvaluationDiagnosticSeverity>),
typeof(CamelCaseEnumConverter<EvaluationRating>),
typeof(TimeSpanConverter),
typeof(EvaluationContextConverter)
],
WriteIndented = true,
IgnoreReadOnlyProperties = false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)]
private sealed partial class JsonContext : JsonSerializerContext;

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
<MinMutationScore>0</MinMutationScore>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\Microsoft.Extensions.AI.Evaluation.Reporting\CSharp\JsonSerialization\CamelCaseEnumConverter.cs" Link="JsonSerialization\CamelCaseEnumConverter.cs" />
<Compile Include="..\Microsoft.Extensions.AI.Evaluation.Reporting\CSharp\JsonSerialization\EvaluationContextConverter.cs" Link="JsonSerialization\EvaluationContextConverter.cs" />
<Compile Include="..\Microsoft.Extensions.AI.Evaluation.Reporting\CSharp\JsonSerialization\TimeSpanConverter.cs" Link="JsonSerialization\TimeSpanConverter.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Azure.Storage.Files.DataLake" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ public static class AzureStorageReportingConfiguration
/// <param name="evaluators">
/// The set of <see cref="IEvaluator"/>s that should be invoked to evaluate AI responses.
/// </param>
/// <param name="timeToLiveForCacheEntries">
/// An optional <see cref="TimeSpan"/> that specifies the maximum amount of time that cached AI responses should
/// survive in the cache before they are considered expired and evicted.
/// </param>
/// <param name="chatConfiguration">
/// A <see cref="ChatConfiguration"/> that specifies the <see cref="IChatClient"/> that is used by AI-based
/// <paramref name="evaluators"/> included in the returned <see cref="ReportingConfiguration"/>. Can be omitted if
Expand All @@ -36,6 +32,10 @@ public static class AzureStorageReportingConfiguration
/// <param name="enableResponseCaching">
/// <see langword="true"/> to enable caching of AI responses; <see langword="false"/> otherwise.
/// </param>
/// <param name="timeToLiveForCacheEntries">
/// An optional <see cref="TimeSpan"/> that specifies the maximum amount of time that cached AI responses should
/// survive in the cache before they are considered expired and evicted.
/// </param>
/// <param name="cachingKeys">
/// An optional collection of unique strings that should be hashed when generating the cache keys for cached AI
/// responses. See <see cref="ReportingConfiguration.CachingKeys"/> for more information about this concept.
Expand Down Expand Up @@ -63,21 +63,21 @@ public static class AzureStorageReportingConfiguration
public static ReportingConfiguration Create(
DataLakeDirectoryClient client,
IEnumerable<IEvaluator> evaluators,
TimeSpan? timeToLiveForCacheEntries = null,
ChatConfiguration? chatConfiguration = null,
bool enableResponseCaching = true,
TimeSpan? timeToLiveForCacheEntries = null,
IEnumerable<string>? cachingKeys = null,
string executionName = Defaults.DefaultExecutionName,
Func<EvaluationMetric, EvaluationMetricInterpretation?>? evaluationMetricInterpreter = null,
IEnumerable<string>? tags = null)
#pragma warning restore S107
{
IResponseCacheProvider? responseCacheProvider =
IEvaluationResponseCacheProvider? responseCacheProvider =
chatConfiguration is not null && enableResponseCaching
? new AzureStorageResponseCacheProvider(client, timeToLiveForCacheEntries)
: null;

IResultStore resultStore = new AzureStorageResultStore(client);
IEvaluationResultStore resultStore = new AzureStorageResultStore(client);

return new ReportingConfiguration(
evaluators,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
namespace Microsoft.Extensions.AI.Evaluation.Reporting.Storage;

/// <summary>
/// An <see cref="IResponseCacheProvider"/> that returns an <see cref="IDistributedCache"/> that can cache AI responses
/// for a particular <see cref="ScenarioRun"/> under an Azure Storage container.
/// An <see cref="IEvaluationResponseCacheProvider"/> that returns an <see cref="IDistributedCache"/> that can cache AI
/// responses for a particular <see cref="ScenarioRun"/> under an Azure Storage container.
/// </summary>
/// <param name="client">
/// A <see cref="DataLakeDirectoryClient"/> with access to an Azure Storage container under which the cached AI
Expand All @@ -28,7 +28,7 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting.Storage;
/// </param>
public sealed class AzureStorageResponseCacheProvider(
DataLakeDirectoryClient client,
TimeSpan? timeToLiveForCacheEntries = null) : IResponseCacheProvider
TimeSpan? timeToLiveForCacheEntries = null) : IEvaluationResponseCacheProvider
{
private readonly Func<DateTime> _provideDateTime = () => DateTime.Now;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
namespace Microsoft.Extensions.AI.Evaluation.Reporting.Storage;

/// <summary>
/// An <see cref="IResultStore"/> implementation that stores <see cref="ScenarioRunResult"/>s under an Azure Storage
/// container.
/// An <see cref="IEvaluationResultStore"/> implementation that stores <see cref="ScenarioRunResult"/>s under an Azure
/// Storage container.
/// </summary>
/// <param name="client">
/// A <see cref="DataLakeDirectoryClient"/> with access to an Azure Storage container under which the
/// <see cref="ScenarioRunResult"/>s should be stored.
/// </param>
public sealed class AzureStorageResultStore(DataLakeDirectoryClient client) : IResultStore
public sealed class AzureStorageResultStore(DataLakeDirectoryClient client) : IEvaluationResultStore
{
private const string ResultsRootPrefix = "results";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using Microsoft.Shared.Diagnostics;

namespace Microsoft.Extensions.AI.Evaluation.Reporting;
Expand All @@ -11,19 +12,36 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting;
public static class ChatDetailsExtensions
{
/// <summary>
/// Adds <see cref="ChatTurnDetails"/> for a particular LLM chat conversation turn to the
/// Adds <see cref="ChatTurnDetails"/> for one or more LLM chat conversation turns to the
/// <see cref="ChatDetails.TurnDetails"/> collection.
/// </summary>
/// <param name="chatDetails">
/// The <see cref="ChatDetails"/> object to which the <paramref name="turnDetails"/> is to be added.
/// The <see cref="ChatDetails"/> object to which the <paramref name="turnDetails"/> are to be added.
/// </param>
/// <param name="turnDetails">
/// The <see cref="ChatTurnDetails"/> for a particular LLM chat conversation turn.
/// The <see cref="ChatTurnDetails"/> for one or more LLM chat conversation turns.
/// </param>
public static void AddTurnDetails(this ChatDetails chatDetails, ChatTurnDetails turnDetails)
public static void AddTurnDetails(this ChatDetails chatDetails, IEnumerable<ChatTurnDetails> turnDetails)
{
_ = Throw.IfNull(chatDetails);
_ = Throw.IfNull(turnDetails);

chatDetails.TurnDetails.Add(turnDetails);
foreach (ChatTurnDetails t in turnDetails)
{
chatDetails.TurnDetails.Add(t);
}
}

/// <summary>
/// Adds <see cref="ChatTurnDetails"/> for one or more LLM chat conversation turns to the
/// <see cref="ChatDetails.TurnDetails"/> collection.
/// </summary>
/// <param name="chatDetails">
/// The <see cref="ChatDetails"/> object to which the <paramref name="turnDetails"/> are to be added.
/// </param>
/// <param name="turnDetails">
/// The <see cref="ChatTurnDetails"/> for one or more LLM chat conversation turns.
/// </param>
public static void AddTurnDetails(this ChatDetails chatDetails, params ChatTurnDetails[] turnDetails)
=> chatDetails.AddTurnDetails(turnDetails as IEnumerable<ChatTurnDetails>);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public static class Defaults

/// <summary>
/// Gets a <see cref="TimeSpan"/> that specifies the default amount of time that cached AI responses should survive
/// in the <see cref="IResponseCacheProvider"/>'s cache before they are considered expired and evicted.
/// in the <see cref="IEvaluationResponseCacheProvider"/>'s cache before they are considered expired and evicted.
/// </summary>
public static TimeSpan DefaultTimeToLiveForCacheEntries { get; } = TimeSpan.FromDays(14);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,28 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting;
/// <see cref="ScenarioRun"/>.
/// </summary>
/// <remarks>
/// <see cref="IResponseCacheProvider"/> can be used to set up caching of AI-generated responses (both the AI responses
/// under evaluation as well as the AI responses for the evaluations themselves). When caching is enabled, the AI
/// responses associated with each <see cref="ScenarioRun"/> are stored in the <see cref="IDistributedCache"/> that is
/// returned from this <see cref="IResponseCacheProvider"/>. So long as the inputs (such as the content included in the
/// requests, the AI model being invoked etc.) remain unchanged, subsequent evaluations of the same
/// <see cref="ScenarioRun"/> use the cached responses instead of invoking the AI model to generate new ones. Bypassing
/// the AI model when the inputs remain unchanged results in faster execution at a lower cost.
/// <see cref="IEvaluationResponseCacheProvider"/> can be used to set up caching of AI-generated responses (both the AI
/// responses under evaluation as well as the AI responses for the evaluations themselves). When caching is enabled,
/// the AI responses associated with each <see cref="ScenarioRun"/> are stored in the <see cref="IDistributedCache"/>
/// that is returned from this <see cref="IEvaluationResponseCacheProvider"/>. So long as the inputs (such as the
/// content included in the requests, the AI model being invoked etc.) remain unchanged, subsequent evaluations of the
/// same <see cref="ScenarioRun"/> use the cached responses instead of invoking the AI model to generate new ones.
/// Bypassing the AI model when the inputs remain unchanged results in faster execution at a lower cost.
/// </remarks>
public interface IResponseCacheProvider
public interface IEvaluationResponseCacheProvider
{
/// <summary>
/// Returns an <see cref="IDistributedCache"/> that caches the AI responses associated with a particular
/// <see cref="ScenarioRun"/>.
/// Returns an <see cref="IDistributedCache"/> that caches all the AI responses associated with the
/// <see cref="ScenarioRun"/> with the supplied <paramref name="scenarioName"/> and
/// <paramref name="iterationName"/>.
/// </summary>
/// <param name="scenarioName">The <see cref="ScenarioRun.ScenarioName"/>.</param>
/// <param name="iterationName">The <see cref="ScenarioRun.IterationName"/>.</param>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> that can cancel the operation.</param>
/// <returns>
/// An <see cref="IDistributedCache"/> that caches the AI responses associated with a particular
/// <see cref="ScenarioRun"/>.
/// An <see cref="IDistributedCache"/> that caches all the AI responses associated with the
/// <see cref="ScenarioRun"/> with the supplied <paramref name="scenarioName"/> and
/// <paramref name="iterationName"/>.
/// </returns>
ValueTask<IDistributedCache> GetCacheAsync(
string scenarioName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting;
/// <summary>
/// Represents a store for <see cref="ScenarioRunResult"/>s.
/// </summary>
public interface IResultStore
public interface IEvaluationResultStore
{
/// <summary>
/// Returns <see cref="ScenarioRunResult"/>s for <see cref="ScenarioRun"/>s filtered by the specified
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
Expand All @@ -12,7 +13,7 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting.JsonSerialization;

internal static partial class JsonUtilities
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Default matches the generated source naming convention.")]
[SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Default matches the generated source naming convention.")]
internal static class Default
{
private static JsonSerializerOptions? _options;
Expand Down Expand Up @@ -45,7 +46,7 @@ private static JsonSerializerOptions CreateJsonSerializerOptions(bool writeInden
return options;
}

[JsonSerializable(typeof(EvaluationResult))]
[JsonSerializable(typeof(ScenarioRunResult))]
[JsonSerializable(typeof(Dataset))]
[JsonSerializable(typeof(CacheEntry))]
[JsonSourceGenerationOptions(
Expand Down
Loading
Loading