-
Notifications
You must be signed in to change notification settings - Fork 840
Rework cache key handling in caching client / generator #5641
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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; | ||
| using System.Collections.Generic; | ||
| using System.Text.Json; | ||
| using System.Threading; | ||
|
|
@@ -19,8 +20,17 @@ namespace Microsoft.Extensions.AI; | |
| /// </remarks> | ||
| public class DistributedCachingChatClient : CachingChatClient | ||
| { | ||
| /// <summary>A boxed <see langword="true"/> value.</summary> | ||
| private static readonly object _boxedTrue = true; | ||
|
|
||
| /// <summary>A boxed <see langword="false"/> value.</summary> | ||
| private static readonly object _boxedFalse = false; | ||
|
|
||
| /// <summary>The <see cref="IDistributedCache"/> instance that will be used as the backing store for the cache.</summary> | ||
| private readonly IDistributedCache _storage; | ||
| private JsonSerializerOptions _jsonSerializerOptions; | ||
|
|
||
| /// <summary>The <see cref="JsonSerializerOptions"/> to use when serializing cache data.</summary> | ||
| private JsonSerializerOptions _jsonSerializerOptions = AIJsonUtilities.DefaultOptions; | ||
|
|
||
| /// <summary>Initializes a new instance of the <see cref="DistributedCachingChatClient"/> class.</summary> | ||
| /// <param name="innerClient">The underlying <see cref="IChatClient"/>.</param> | ||
|
|
@@ -29,7 +39,6 @@ public DistributedCachingChatClient(IChatClient innerClient, IDistributedCache s | |
| : base(innerClient) | ||
| { | ||
| _storage = Throw.IfNull(storage); | ||
| _jsonSerializerOptions = AIJsonUtilities.DefaultOptions; | ||
| } | ||
|
|
||
| /// <summary>Gets or sets JSON serialization options to use when serializing cache data.</summary> | ||
|
|
@@ -90,13 +99,16 @@ protected override async Task WriteCacheStreamingAsync(string key, IReadOnlyList | |
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override string GetCacheKey(bool streaming, IList<ChatMessage> chatMessages, ChatOptions? options) | ||
| protected override string GetCacheKey(bool streaming, IList<ChatMessage> chatMessages, ChatOptions? options) => | ||
| GetCacheKey([streaming ? _boxedTrue : _boxedFalse, chatMessages, options]); | ||
|
|
||
| /// <summary>Gets a cache key based on the supplied values.</summary> | ||
| /// <param name="values">The values to inform the key.</param> | ||
| /// <returns>The computed key.</returns> | ||
| /// <remarks>This provides the default implementation for <see cref="GetCacheKey(bool, IList{ChatMessage}, ChatOptions?)"/>.</remarks> | ||
| protected string GetCacheKey(ReadOnlySpan<object?> values) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @stephentoub Just a thought - should this function also be overridable? If a derived class were to take over the cache key computation by overriding There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not sure I follow. base.GetCacheKey(bool, IList, ...) uses base.GetCacheKey(ROS). The intent is the latter represents the default algorithm for handling multiple objects. An override of GetCacheKey(bool, IList, ...) can delegate to either of the methods on the base. Could you elaborate on the concern? I'm not clear on what making it virtual would solve. Maybe it needs a different name? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah here is an example of what I meant. Consider the case where we have Now consider the case where a consumer of this Depending on how different the caching algorithm used in the two base types happens to be, the returned key could have different lengths, different set of allowed characters (which could be important if the key is used as the name of a file or directory on disk for example) etc. This could be especially problematic in cases like below where the derived class wants to keep the base implementation unchanged in the default case and override only it under certain conditions. Each level in the inheritance hierarchy has a choice between the following options -
And regardless of which choice is made in a particular inheritance level, it would be ideal if subsequent derived implementations can also retain the same flexibility to
Having the ability to individually override Another option may be to eliminate I realize my response is a bit rambling and perhaps I am over thinking it 😄, but I hope this clarifies the concern. Happy to sync up offline to discuss if needed. |
||
| { | ||
| // While it might be desirable to include ChatOptions in the cache key, it's not always possible, | ||
| // since ChatOptions can contain types that are not guaranteed to be serializable or have a stable | ||
| // hashcode across multiple calls. So the default cache key is simply the JSON representation of | ||
| // the chat contents. Developers may subclass and override this to provide custom rules. | ||
| _jsonSerializerOptions.MakeReadOnly(); | ||
| return CachingHelpers.GetCacheKey(chatMessages, streaming, _jsonSerializerOptions); | ||
| return CachingHelpers.GetCacheKey(values, _jsonSerializerOptions); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.