Skip to content

[API Proposal]: SKILL APIs for Microsoft.Extensions.AI #7529

@alastairlundy

Description

@alastairlundy

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-aiMicrosoft.Extensions.AI librariesuntriaged

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions