dotnet / dotnet/extensions

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

Open
#7,529 1 comment 1 reaction 1 assignee Claimed by @jozkee View on GitHub
api-suggestion area-ai enhancement
Dominant language
C#
Stars
3.2k
Forks
894
Avg merge
1d 12h
Merged PRs (30d)
23

Description

### 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](https://agentskills.io/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`` 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.

```csharp
namespace Microsoft.Extensions.AI.Skills;

public record SkillMetadata(
string Id,
string Name,
string Description,
string? License = null,
string? Compatibility = null,
IReadOnlyDictionary? Metadata = null,
string? AllowedTools = null);

public record SkillContent(
SkillMetadata Metadata,
string MarkdownContent);

public interface ISkillProvider
{
Task> GetAvailableSkillsAsync(CancellationToken cancellationToken = default);

Task LoadSkillAsync(string skillId, CancellationToken cancellationToken = default);

Task UnloadSkillAsync(string skillId, CancellationToken cancellationToken = default);
}

public interface ISkillDescriptorBuilder
{

ISkillPromptBuilder AddSkill(SkillMetadata skill);
ISkillPromptBuilder AddSkills(IList skills);

ChatMessage BuildDescriptor(IList 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.

```csharp
namespace Microsoft.Extensions.AI.Skills;

public class SkillLoaderFunction : AIFunction
{
public SkillLoaderFunction(ISkillProvider provider);

public System.Threading.Tasks.ValueTask InvokeAsync(Microsoft.Extensions.AI.AIFunctionArguments? arguments = default, System.Threading.CancellationToken cancellationToken = default);
}

public class FileSkillProvider : ISkillProvider
{
public FileSkillProvider(string skillsDirectory);

public Task> GetAvailableSkillsAsync(CancellationToken cancellationToken = default);

public Task 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 skills);

ChatMessage BuildDescriptor(IList skills);
}
```

### API Usage

```csharp
// Skill provider is set up.
ISkillProvider skillProvider = new FileSkillProvider(skillsDirectory: "./agents/skills");

// Discover available SKILLs and
IList 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 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 ``SkillSpecification``to reduce potential confusion/ambiguity.

### Risks

Some implementers of Microsoft.Extensions.AI such as Anthropic may already have documented ways of dealing with SKILLs.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.