Background and motivation
The .NET AI ecosystem doesn't have a standardized way of representing and managing AI SKILLs when dealing with LLMs. Some implementations like Anthropic's C# SDK treat SKILLs as tools to call (see #7233 ), whilst others don't offer support for SKILLs at all.
There are potential problem areas when dealing with SKILLs that library developers or even .NET library consumers may face if they try to implement support themselves such as: resource/memory cleanup after a SKILL is no longer needed, progressive discovery of SKILLs to LLMs, and actually loading the selected SKILLs to be provided to LLMs.
I believe the prevalance of the AI SKILLs ecosystem and usage of SKILLs warrants a standardized way of dealing with them in .NET .
A standardized API for SKILLs should address or allow for:
- easy memory cleanup,
- progressive discovery of SKILLs to LLMs - LLMs should be provided SKILL frontmatter upfront so that they can choose to load SKILLs as needed
- a way to load/unload SKILLs independant of their backing type since SKILLs can have multiple backing types such as MCP Servers or, more commonly, SKILL.md files in directories - Though a provider supporting the SKILL.md file backing type should be provided as a sane default for loading local SKILL.md files.
- 3rd party AI SDK implementers to provide their own methods of loading/unloading SKILLs
API Proposal
This is a proposal for new APIs to be added to Microsoft.Extensions.AI packages.
Microsoft.Extensions.AI.Abstractions:
SkillMetadata models the SKILLs specification where some fields are mandatory and some are optional.
SkillContent separates the SKILL frontmatter description from the Markdown content underneath in a SKILL.md file.
ISkillProvider enables implementations to support different backing types for getting skill descriptions, and loading and unloading skills.
ISkillDescriptorBuilder allows for progressive discovery by building a system message containing the metadata of the skills - A consuming .NET project can add this message to a List<ChatMessage> after the System Prompt message and provide this to an IChatClient or other AI interface accepting messages. This enables the LLM to know what SKILLs are available to use and allows the LLM to choose to load any if appropriate.
namespace Microsoft.Extensions.AI.Skills;
public record SkillMetadata(
string Id,
string Name,
string Description,
string? License = null,
string? Compatibility = null,
IReadOnlyDictionary<string, object>? Metadata = null,
string? AllowedTools = null);
public record SkillContent(
SkillMetadata Metadata,
string MarkdownContent);
public interface ISkillProvider
{
Task<IList<SkillMetadata>> GetAvailableSkillsAsync(CancellationToken cancellationToken = default);
Task<SkillContent> LoadSkillAsync(string skillId, CancellationToken cancellationToken = default);
Task UnloadSkillAsync(string skillId, CancellationToken cancellationToken = default);
}
public interface ISkillDescriptorBuilder
{
ISkillPromptBuilder AddSkill(SkillMetadata skill);
ISkillPromptBuilder AddSkills(IList<SkillMetadata> skills);
ChatMessage BuildDescriptor(IList<SkillMetadata> skills);
}
Microsoft.Extensions.AI:
SkillLoaderFunction acts as function that can be called by the LLM to load the SKILL using an ISkillProvider
FileSkillProvider provides a concrete provider for loading SKILL.md files in a directory and providing a sane default for loading SKILLs.
SkillDescriptorBuilder provides a concrete builder for building a message describing the SKILLs available to the LLM.
namespace Microsoft.Extensions.AI.Skills;
public class SkillLoaderFunction : AIFunction
{
public SkillLoaderFunction(ISkillProvider provider);
public System.Threading.Tasks.ValueTask<object?> InvokeAsync(Microsoft.Extensions.AI.AIFunctionArguments? arguments = default, System.Threading.CancellationToken cancellationToken = default);
}
public class FileSkillProvider : ISkillProvider
{
public FileSkillProvider(string skillsDirectory);
public Task<IList<SkillMetadata>> GetAvailableSkillsAsync(CancellationToken cancellationToken = default);
public Task<SkillContent> LoadSkillAsync(string skillId, CancellationToken cancellationToken = default);
public Task UnloadSkillAsync(string skillId, CancellationToken cancellationToken = default);
}
public class SkillDescriptorBuilder : ISkillDescriptorBuilder
{
public SkillDescriptorBuilder();
ISkillPromptBuilder AddSkill(SkillMetadata skill);
ISkillPromptBuilder AddSkills(IList<SkillMetadata> skills);
ChatMessage BuildDescriptor(IList<SkillMetadata> skills);
}
API Usage
// Skill provider is set up.
ISkillProvider skillProvider = new FileSkillProvider(skillsDirectory: "./agents/skills");
// Discover available SKILLs and
IList<SkillMetadata> availableSkills = await skillProvider.GetAvailableSkillsAsync();
// Add SKILLs to the descriptor builder.
SkillDescriptorBuilder descriptorBuilder = new();
descriptorBuilder.AddSkills(availableSkills);
// Build the description message so that the LLM knows what SKILLs are available.
ChatMessage skillDiscoveryMessage = descriptorBuilder.BuildDescriptor();
// Add the message to the message list
List<ChatMessage> messages = new()
{
new ChatMessage(ChatRole.System, "You are a helpful AI assistant."),
skillDiscoveryMessage,
// User Message goes here
};
// Add the tool to the ChatOptions
ChatOptions options = new()
{
Tools = { new SkillLoaderFunction(skillProvider) }
};
// chatClient initialization code ommitted here
IChatClient chatClient;
// LLM is called
ChatResponse response = await chatClient.GetResponseAsync(messages, options, CancellationToken token = default);
Alternative Designs
The SkillMetadata type could be renamed to SkillSpecificationto reduce potential confusion/ambiguity.
Risks
Some implementers of Microsoft.Extensions.AI such as Anthropic may already have documented ways of dealing with SKILLs.
Background and motivation
The .NET AI ecosystem doesn't have a standardized way of representing and managing AI SKILLs when dealing with LLMs. Some implementations like Anthropic's C# SDK treat SKILLs as tools to call (see #7233 ), whilst others don't offer support for SKILLs at all.
There are potential problem areas when dealing with SKILLs that library developers or even .NET library consumers may face if they try to implement support themselves such as: resource/memory cleanup after a SKILL is no longer needed, progressive discovery of SKILLs to LLMs, and actually loading the selected SKILLs to be provided to LLMs.
I believe the prevalance of the AI SKILLs ecosystem and usage of SKILLs warrants a standardized way of dealing with them in .NET .
A standardized API for SKILLs should address or allow for:
API Proposal
This is a proposal for new APIs to be added to Microsoft.Extensions.AI packages.
Microsoft.Extensions.AI.Abstractions:
SkillMetadatamodels the SKILLs specification where some fields are mandatory and some are optional.SkillContentseparates the SKILL frontmatter description from the Markdown content underneath in a SKILL.md file.ISkillProviderenables implementations to support different backing types for getting skill descriptions, and loading and unloading skills.ISkillDescriptorBuilderallows for progressive discovery by building a system message containing the metadata of the skills - A consuming .NET project can add this message to aList<ChatMessage>after the System Prompt message and provide this to anIChatClientor other AI interface accepting messages. This enables the LLM to know what SKILLs are available to use and allows the LLM to choose to load any if appropriate.Microsoft.Extensions.AI:
SkillLoaderFunctionacts as function that can be called by the LLM to load the SKILL using anISkillProviderFileSkillProviderprovides a concrete provider for loading SKILL.md files in a directory and providing a sane default for loading SKILLs.SkillDescriptorBuilderprovides a concrete builder for building a message describing the SKILLs available to the LLM.API Usage
Alternative Designs
The
SkillMetadatatype could be renamed toSkillSpecificationto reduce potential confusion/ambiguity.Risks
Some implementers of Microsoft.Extensions.AI such as Anthropic may already have documented ways of dealing with SKILLs.