Competenze dell'agente

Le competenze dell'agente sono pacchetti portabili di istruzioni, script e risorse che offrono agli agenti funzionalità specializzate e competenze di dominio. Le competenze seguono una specifica aperta e implementano un modello di divulgazione progressiva in modo che gli agenti carichino solo il contesto di cui hanno bisogno, quando necessario.

Usare le competenze dell'agente quando si vuole:

  • Confeziona le competenze di dominio - Racchiudi conoscenze specializzate (criteri di spesa, flussi di lavoro legali, pipeline di analisi dei dati) in pacchetti riutilizzabili e portabili.
  • Estendere le funzionalità dell'agente : offrire agli agenti nuove capacità senza modificare le istruzioni di base.
  • Garantire la coerenza : trasformare le attività in più passaggi in flussi di lavoro ripetibili e controllabili.
  • Abilitare l'interoperabilità: riutilizzare la stessa competenza in diversi prodotti compatibili con le competenze dell'agente.

Struttura delle competenze

Un'abilità è una directory contenente un file SKILL.md con sottodirectory facoltative per le risorse.

expense-report/
├── SKILL.md                          # Required - frontmatter + instructions
├── scripts/
│   └── validate.py                   # Executable code agents can run
├── references/
│   └── POLICY_FAQ.md                 # Reference documents loaded on demand
└── assets/
    └── expense-report-template.md    # Templates and static resources

formato SKILL.md

Il SKILL.md file deve contenere il frontmatter YAML seguito dal contenuto markdown:

---
name: expense-report
description: File and validate employee expense reports according to company policy. Use when asked about expense submissions, reimbursement rules, or spending limits.
license: Apache-2.0
compatibility: Requires python3
metadata:
  author: contoso-finance
  version: "2.1"
---
Campo Obbligatorio Descrzione
name Massimo 64 caratteri. Solo lettere minuscole, numeri e trattini. Non deve iniziare o terminare con un trattino o contenere trattini consecutivi. Deve corrispondere al nome della directory principale.
description Cosa fa la competenza e quando usarla. Massimo 1024 caratteri. Deve includere parole chiave che consentono agli agenti di identificare le attività pertinenti.
license NO Nome della licenza o riferimento a un file di licenza in bundle.
compatibility NO Massimo 500 caratteri. Indica i requisiti di ambiente (prodotto, pacchetti di sistema, accesso alla rete e così via).
metadata NO Mappatura chiave-valore arbitraria per metadati aggiuntivi.
allowed-tools NO Elenco delimitato da spazi di strumenti pre-approvati che l'abilità può utilizzare. Sperimentale: il supporto può variare tra le implementazioni dell'agente.

Il corpo markdown successivo al frontmatter contiene le istruzioni della skill: una guida dettagliata passo dopo passo, esempi di input e output, casi limite comuni o qualsiasi contenuto che aiuti l'agente a svolgere l'attività. Mantenere SKILL.md sotto 500 righe e spostare materiale di riferimento dettagliato in file separati.

Divulgazione progressiva

Le competenze dell'agente usano un modello di divulgazione progressiva a quattro fasi per ridurre al minimo l'utilizzo del contesto:

  1. Annuncio (~100 token per competenza): i nomi e le descrizioni delle competenze vengono inseriti nella richiesta di sistema all'inizio di ogni esecuzione, quindi l'agente sa quali competenze sono disponibili.
  2. Caricamento (< 5000 token consigliati) - Quando un'attività corrisponde al dominio di un'abilità, l'agente richiama lo strumento load_skill per recuperare l'intero contenuto di SKILL.md con istruzioni dettagliate.
  3. Lettura delle risorse (se necessario): l'agente chiama lo read_skill_resource strumento per recuperare file supplementari (riferimenti, modelli, asset) solo quando necessario.
  4. Esegui script (se necessario) - L'agente chiama lo strumento run_skill_script per eseguire gli script inclusi in una competenza.

Questo modello mantiene snella la finestra di contesto dell'agente, concedendole l'accesso a conoscenze di dominio approfondite su richiesta.

Annotazioni

load_skill è sempre pubblicizzato. read_skill_resource è pubblicizzato solo quando almeno un'abilità dispone di risorse. run_skill_script viene annunciato solo quando almeno un'abilità ha script.

Fornire competenze a un agente

Lavorare con le competenze implica tre elementi costitutivi:

  • Provider - AgentSkillsProvider (C#) o SkillsProvider (Python) è un provider di contesto che espone le competenze a un agente. Annuncia le competenze disponibili nel prompt del sistema e registra gli strumenti usati dall'agente per caricare competenze, leggere le risorse ed eseguire script.
  • Origini : un'origine fornisce competenze al provider. Le competenze possono provenire da diversi tipi di origine:
    • Basato su file : competenze individuate dai SKILL.md file nelle directory del file system.
    • Definito dal codice: competenze definite inline nel codice usando AgentInlineSkill (C#) o InlineSkill (Python).
    • Basato su classi: competenze incapsulate in una classe che deriva da AgentClassSkill<T> (C#) o ClassSkill (Python).
    • Basato su MCP: competenze individuate dai server MCP (Model Context Protocol) tramite UseMcpSkills (C#) o MCPSkillsSource (Python).
  • Muratore - AgentSkillsProviderBuilder (C#) assembla più origini in un singolo provider, applicando aggregazioni, deduplicazione, memorizzazione nella cache e filtro facoltativo. In Python, comporre direttamente classi sorgente come AggregatingSkillsSource, FilteringSkillsSource e DeduplicatingSkillsSource.

Le sezioni seguenti illustrano come creare competenze di ogni tipo di origine, quindi come combinare le origini e costruire un provider da essi.

Competenze basate sui file

Creare un collegamento a una directory contenente le skill, e aggiungerlo ai fornitori di contesto dell'agente. Passare un esecutore di script per abilitare l'esecuzione di script basati su file presenti nelle directory delle abilità.

using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using OpenAI.Responses;

string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!;
string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";

// Discover skills from the 'skills' directory
var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "skills"));

// Create an agent with the skills provider
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetResponsesClient()
    .AsAIAgent(new ChatClientAgentOptions
    {
        Name = "SkillsAgent",
        ChatOptions = new()
        {
            Instructions = "You are a helpful assistant.",
        },
        AIContextProviders = [skillsProvider],
    },
    model: deploymentName);

Avviso

DefaultAzureCredential è utile per lo sviluppo, ma richiede un'attenta considerazione nell'ambiente di produzione. Nell'ambiente di produzione prendere in considerazione l'uso di credenziali specifiche ,ad esempio ManagedIdentityCredential, per evitare problemi di latenza, probe di credenziali indesiderate e potenziali rischi per la sicurezza dai meccanismi di fallback.

Molteplici directory di competenze

È possibile indirizzare il provider a un'unica directory padre: ogni sottodirectory contenente un SKILL.md viene rilevata automaticamente come skill:

var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "all-skills"));

In alternativa, passare un elenco di percorsi per eseguire ricerche in più directory radice:

var skillsProvider = new AgentSkillsProvider(
    [
        Path.Combine(AppContext.BaseDirectory, "company-skills"),
        Path.Combine(AppContext.BaseDirectory, "team-skills"),
    ]);

Il provider cerca fino a due livelli di profondità.

Personalizzazione del rilevamento delle risorse e degli script

Per impostazione predefinita, il provider riconosce le risorse con estensioni .md, , .json.yaml.yml.csv.xmle .txt script con estensioni .py, .js.sh.ps1.cse ..csx Esegue la ricerca fino a due livelli di profondità all'interno di ogni directory di competenze. Usare AgentFileSkillsSourceOptions per modificare queste impostazioni predefinite:

var fileOptions = new AgentFileSkillsSourceOptions
{
    AllowedResourceExtensions = [".md", ".txt"],
    AllowedScriptExtensions = [".py"],
    SearchDepth = 3, // Search up to 3 levels deep (default is 2)
    ResourceFilter = context => context.RelativeFilePath.StartsWith("references/"),
    ScriptFilter = context => context.RelativeFilePath.StartsWith("scripts/")
                           || context.RelativeFilePath.StartsWith("tools/"),
};

// Via constructor
var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "skills"),
    fileOptions: fileOptions);

// Via builder
var skillsProvider = new AgentSkillsProviderBuilder()
    .UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"), options: fileOptions)
    .Build();

ResourceFilter e ScriptFilter ricevono un oggetto AgentFileSkillFilterContext con il nome dell'abilità e il percorso relativo del file, consentendoti di limitare i file in base alla posizione, alla convenzione di denominazione o a qualsiasi logica personalizzata.

Esecuzione degli script

Passare SubprocessScriptRunner.RunAsync come strumento di esecuzione dello script per abilitare l'esecuzione di script basati su file:

var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "skills"),
    SubprocessScriptRunner.RunAsync);

SubprocessScriptRunner.RunAsync è approssimativamente equivalente ai seguenti:

// Simplified equivalent of what SubprocessScriptRunner.RunAsync does internally
using System.Diagnostics;
using System.Text.Json;

static async Task<object?> RunAsync(
    AgentFileSkill skill,
    AgentFileSkillScript script,
    JsonElement? args,
    IServiceProvider? serviceProvider,
    CancellationToken cancellationToken)
{
    var psi = new ProcessStartInfo("python3")
    {
        RedirectStandardOutput = true,
        UseShellExecute = false,
    };
    psi.ArgumentList.Add(script.FullPath);
    if (args is { ValueKind: JsonValueKind.Array } json)
    {
        foreach (var element in json.EnumerateArray())
        {
            psi.ArgumentList.Add(element.GetString()!);
        }
    }
    using var process = Process.Start(psi)!;
    string output = await process.StandardOutput.ReadToEndAsync(cancellationToken);
    await process.WaitForExitAsync(cancellationToken);
    return output.Trim();
}

Il runner esegue ogni script individuato come sottoprocesso locale. Gli script basati su file prevedono argomenti come matrice JSON di stringhe. Ogni elemento della matrice diventa un argomento della riga di comando posizionale.

Avviso

SubprocessScriptRunner viene fornito solo a scopo dimostrativo. Per l'uso in produzione, è consigliabile aggiungere:

  • Sandboxing (ad esempio, contenitori o ambienti di esecuzione isolati)
  • Limiti delle risorse (CPU, memoria, timeout di wall-clock)
  • Convalida dell'input e elenco consentito di script eseguibili
  • Log strutturati e audit trail

Competenze basate sui file

Usare la SkillsProvider.from_paths() factory per individuare le competenze nelle directory contenenti file SKILL.md e aggiungere il provider ai provider di contesto dell'agente:

import os
from pathlib import Path

# Discover skills from the 'skills' directory
skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
)

# Create an agent with the skills provider
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
deployment = os.environ.get("FOUNDRY_MODEL", "gpt-4o-mini")

client = FoundryChatClient(
    project_endpoint=endpoint,
    model=deployment,
    credential=AzureCliCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a helpful assistant.",
    context_providers=[skills_provider],
)

Molteplici directory di competenze

È possibile indirizzare il provider a un'unica directory padre: ogni sottodirectory contenente un SKILL.md viene rilevata automaticamente come skill:

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "all-skills"
)

In alternativa, passare un elenco di percorsi per eseguire ricerche in più directory radice:

skills_provider = SkillsProvider.from_paths(
    skill_paths=[
        Path(__file__).parent / "company-skills",
        Path(__file__).parent / "team-skills",
    ]
)

Il provider cerca fino a due livelli di profondità.

Personalizzazione del rilevamento delle risorse e degli script

Per impostazione predefinita, le risorse vengono individuate nelle sottodirectory references/ e assets/ e gli script da scripts/, secondo la specifica agentskills.io. Le estensioni delle risorse riconosciute sono , , .md, , .json.yaml, e .yml. .csv.xml.txt Esegue la ricerca fino a due livelli di profondità all'interno di ogni directory di competenze. Usare resource_extensions, script_extensionssearch_depth, resource_filter, e script_filter per personalizzare l'individuazione:

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    resource_extensions=(".md", ".txt"),
    script_extensions=(".py", ".sh"),
    search_depth=3,  # Search up to 3 levels deep (default is 2)
    resource_filter=lambda skill_name, path: path.startswith("references/"),
    script_filter=lambda skill_name, path: path.startswith("scripts/"),
)

resource_filter e script_filter ricevono il nome dell'abilità e il percorso relativo del file, consentendoti di limitare i file in base alla posizione, allo schema di denominazione o a qualsiasi logica personalizzata. Usare "." per includere i file a livello radice della competenza oltre alle sottodirectory.

Esecuzione degli script

Per abilitare l'esecuzione di script basati su file, passare un script_runner a SkillsProvider.from_paths(). È possibile usare qualsiasi funzione o metodo sincrono o asincrono che soddisfi il protocollo SkillScriptRunner:

from pathlib import Path
from agent_framework import FileSkill, FileSkillScript, SkillsProvider

def my_runner(
    skill: FileSkill,
    script: FileSkillScript,
    args: dict | list[str] | None = None,
) -> str:
    """Run a file-based script as a subprocess."""
    import subprocess, sys
    script_path = Path(script.full_path)
    cmd = [sys.executable, str(script_path)]
    if isinstance(args, list):
        cmd.extend(args)
    result = subprocess.run(
        cmd, capture_output=True, text=True, timeout=30, cwd=str(script_path.parent)
    )
    return result.stdout.strip()

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    script_runner=my_runner,
)

L'esecutore riceve gli argomenti risolti FileSkill, FileSkillScript e un argomento facoltativo args. Gli script basati su file prevedono argomenti come matrice JSON di stringhe. Ogni elemento della matrice diventa un argomento della riga di comando posizionale. Gli script vengono rilevati automaticamente nei file .py nella sottodirectory scripts/ di ogni skill.

Avviso

Il runner precedente viene fornito solo a scopo dimostrativo. Per l'uso in produzione, è consigliabile aggiungere:

  • Sandboxing (ad esempio, contenitori, seccomp, o firejail)
  • Limiti delle risorse (CPU, memoria, timeout di wall-clock)
  • Convalida dell'input e elenco consentito di script eseguibili
  • Log strutturati e audit trail

Annotazioni

Se vengono fornite skill basate su file con script ma script_runner non è impostato, SkillsProvider genera un errore quando si tenta di eseguire lo script.

Competenze basate sui file

Gli agenti Go supportano le competenze tramite il pacchetto agent/skills. Le competenze seguono lo stesso modello di divulgazione progressiva: annunciare -> caricare -> leggere le risorse -> eseguire script.

Scoprire le competenze nei file SKILL.md su disco e registrare il provider delle competenze come provider di contesto per l'agente:

import (
    "os"

    "github.com/microsoft/agent-framework-go/agent"
    "github.com/microsoft/agent-framework-go/provider/foundryprovider"
    "github.com/microsoft/agent-framework-go/agent/skills"
    "github.com/microsoft/agent-framework-go/agent/skills/fsskills"
)

skillsRoot, _ := os.OpenRoot("skills")
defer skillsRoot.Close()

skillsProvider := skills.NewContextProvider(skills.ContextProviderOptions{
    Sources: []skills.Source{
        fsskills.NewSourceOptions(fsskills.SourceOptions{}, skillsRoot.FS()),
    },
})

a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
    Instructions: "You are a helpful assistant.",
    Config: agent.Config{
        ContextProviders: []agent.ContextProvider{skillsProvider},
    },
})

Competenze definite dal codice

Oltre alle competenze basate su file individuate dai SKILL.md file, è possibile definire le competenze interamente nel codice usando AgentInlineSkill. Le competenze definite dal codice sono utili quando:

  • Il contenuto della competenza viene generato in modo dinamico( ad esempio, la lettura da un database o un ambiente).
  • Si vogliono mantenere le definizioni delle competenze insieme al codice dell'applicazione che le usa.
  • Sono necessarie risorse che eseguono la logica in fase di lettura anziché gestire i file statici.
  • Le definizioni delle competenze devono essere costruite in fase di esecuzione dai dati , ad esempio creando una competenza personalizzata per ogni sessione utente in base al ruolo o alle autorizzazioni.
  • Una competenza deve chiudere lo stato del sito di chiamata (variabili locali, chiuse) anziché risolvere i servizi da un contenitore di inserimento delle dipendenze.

Competenza di codice di base

Creare un oggetto AgentInlineSkill con un nome, una descrizione e istruzioni. Collegare le risorse usando .AddResource():

using Microsoft.Agents.AI;

var codeStyleSkill = new AgentInlineSkill(
    name: "code-style",
    description: "Coding style guidelines and conventions for the team",
    instructions: """
        Use this skill when answering questions about coding style, conventions, or best practices for the team.
        1. Read the style-guide resource for the full set of rules.
        2. Answer based on those rules, quoting the relevant guideline where helpful.
        """)
    .AddResource(
        "style-guide",
        """
        # Team Coding Style Guide
        - Use 4-space indentation (no tabs)
        - Maximum line length: 120 characters
        - Use type annotations on all public methods
        """);

var skillsProvider = new AgentSkillsProvider(codeStyleSkill);

Risorse dinamiche

Passare un delegato factory a .AddResource() per calcolare il contenuto in fase di esecuzione. Il delegato viene richiamato ogni volta che l'agente legge la risorsa:

var projectInfoSkill = new AgentInlineSkill(
    name: "project-info",
    description: "Project status and configuration information",
    instructions: """
        Use this skill for questions about the current project.
        1. Read the environment resource for deployment configuration details.
        2. Read the team-roster resource for information about team members.
        """)
    .AddResource("environment", () =>
    {
        string env = Environment.GetEnvironmentVariable("APP_ENV") ?? "development";
        string region = Environment.GetEnvironmentVariable("APP_REGION") ?? "us-east-1";
        return $"Environment: {env}, Region: {region}";
    })
    .AddResource(
        "team-roster",
        "Alice Chen (Tech Lead), Bob Smith (Backend Engineer)");

Script definiti dal codice

Usare .AddScript() per registrare un delegato come script eseguibile. Gli script definiti dal codice vengono eseguiti in-process come chiamate delegate dirette. Non è necessario alcun esecutore di script. I parametri tipizzati del delegato vengono convertiti automaticamente in uno Schema JSON che l'agente usa per passare gli argomenti.

using System.Text.Json;

var unitConverterSkill = new AgentInlineSkill(
    name: "unit-converter",
    description: "Convert between common units using a conversion factor",
    instructions: """
        Use this skill when the user asks to convert between units.
        1. Review the conversion-table resource to find the correct factor.
        2. Use the convert script, passing the value and factor from the table.
        3. Present the result clearly with both units.
        """)
    .AddResource(
        "conversion-table",
        """
        # Conversion Tables
        Formula: **result = value × factor**
        | From       | To         | Factor   |
        |------------|------------|----------|
        | miles      | kilometers | 1.60934  |
        | kilometers | miles      | 0.621371 |
        | pounds     | kilograms  | 0.453592 |
        | kilograms  | pounds     | 2.20462  |
        """)
    .AddScript("convert", (double value, double factor) =>
    {
        double result = Math.Round(value * factor, 4);
        return JsonSerializer.Serialize(new { value, factor, result });
    });

var skillsProvider = new AgentSkillsProvider(unitConverterSkill);

Annotazioni

Per combinare competenze definite dal codice con competenze basate su file o basate su classi in un singolo provider, usare AgentSkillsProviderBuilder . Vedere Costruzione del provider.

Oltre alle competenze basate su file individuate dai file SKILL.md, è possibile definire le competenze interamente nel codice Python usando InlineSkill. Le competenze definite dal codice sono utili quando:

  • Il contenuto della competenza viene generato in modo dinamico( ad esempio, la lettura da un database o un ambiente).
  • Si vogliono mantenere le definizioni delle competenze insieme al codice dell'applicazione che le usa.
  • Sono necessarie risorse che eseguono la logica in fase di lettura anziché gestire i file statici.
  • Le definizioni delle competenze devono essere costruite in fase di esecuzione dai dati , ad esempio creando una competenza personalizzata per ogni sessione utente in base al ruolo o alle autorizzazioni.
  • Una competenza deve chiudere lo stato del sito di chiamata (variabili locali, chiuse) anziché risolvere i servizi tramite **kwargs.

Competenza di codice di base

Creare un'istanza InlineSkill con un oggetto SkillFrontmatter (contenente il nome e la descrizione) e il contenuto delle istruzioni. Facoltativamente, allegare InlineSkillResource istanze al contenuto statico:

from textwrap import dedent
from agent_framework import InlineSkill, InlineSkillResource, SkillFrontmatter, SkillsProvider

code_style_skill = InlineSkill(
    frontmatter=SkillFrontmatter(
        name="code-style",
        description="Coding style guidelines and conventions for the team",
    ),
    instructions=dedent("""\
        Use this skill when answering questions about coding style,
        conventions, or best practices for the team.
    """),
    resources=[
        InlineSkillResource(
            name="style-guide",
            content=dedent("""\
                # Team Coding Style Guide
                - Use 4-space indentation (no tabs)
                - Maximum line length: 120 characters
                - Use type annotations on all public functions
            """),
        ),
    ],
)

skills_provider = SkillsProvider(code_style_skill)

Risorse dinamiche

Usa il decoratore @skill.resource per registrare una funzione come risorsa. La funzione viene chiamata ogni volta che l'agente legge la risorsa, in modo che possa restituire dati aggiornati. Sono supportate sia le funzioni di sincronizzazione che asincrone:

import os
from agent_framework import InlineSkill, SkillFrontmatter

project_info_skill = InlineSkill(
    frontmatter=SkillFrontmatter(
        name="project-info",
        description="Project status and configuration information",
    ),
    instructions="Use this skill for questions about the current project.",
)

@project_info_skill.resource
def environment() -> str:
    """Get current environment configuration."""
    env = os.environ.get("APP_ENV", "development")
    region = os.environ.get("APP_REGION", "us-east-1")
    return f"Environment: {env}, Region: {region}"

@project_info_skill.resource(name="team-roster", description="Current team members")
def get_team_roster() -> str:
    """Return the team roster."""
    return "Alice Chen (Tech Lead), Bob Smith (Backend Engineer)"

Quando l'elemento Decorator viene usato senza argomenti (@skill.resource), il nome della funzione diventa il nome della risorsa e la docstring diventa la descrizione. Usare @skill.resource(name="...", description="...") per impostarli in modo esplicito.

Script definiti dal codice

Usare il decoratore @skill.script per registrare una funzione come script eseguibile in una skill. Gli script definiti dal codice vengono eseguiti in-process e non richiedono uno script runner. Sono supportate sia le funzioni di sincronizzazione che asincrone:

from agent_framework import InlineSkill, SkillFrontmatter

unit_converter_skill = InlineSkill(
    frontmatter=SkillFrontmatter(
        name="unit-converter",
        description="Convert between common units using a conversion factor",
    ),
    instructions="Use the convert script to perform unit conversions.",
)

@unit_converter_skill.script(name="convert", description="Convert a value: result = value × factor")
def convert_units(value: float, factor: float) -> str:
    """Convert a value using a multiplication factor."""
    import json
    result = round(value * factor, 4)
    return json.dumps({"value": value, "factor": factor, "result": result})

Quando l'elemento Decorator viene usato senza argomenti (@skill.script), il nome della funzione diventa il nome dello script e la docstring diventa la descrizione. I parametri tipizzato della funzione vengono convertiti automaticamente in uno schema JSON usato dall'agente per passare argomenti.

Oltre alle competenze basate su file individuate dai SKILL.md file, è possibile definire completamente le competenze nel codice Go:

skill := &skills.Skill{
    Frontmatter: skills.Frontmatter{
        Name:        "unit-converter",
        Description: "Convert between common units using a multiplication factor.",
    },
    GetContent: func(context.Context) (string, error) {
        return "Use this skill when the user asks to convert between units.", nil
    },
    Resources: []skills.Resource{
        {
            Name:        "conversion-table",
            Description: "Lookup table of multiplication factors.",
            Read: func(context.Context) (any, error) {
                return conversionTable, nil
            },
        },
    },
    Scripts: []skills.Script{
        {
            Name:        "convert",
            Description: "Multiplies a value by a conversion factor. Pass value and factor as positional string arguments: [\"<value>\", \"<factor>\"].",
            Run: func(_ context.Context, _ *skills.Skill, args []string) (any, error) {
                if len(args) != 2 {
                    return nil, fmt.Errorf("expected value and factor")
                }
                value, err := strconv.ParseFloat(args[0], 64)
                if err != nil {
                    return nil, err
                }
                factor, err := strconv.ParseFloat(args[1], 64)
                if err != nil {
                    return nil, err
                }
                return map[string]any{
                    "value":  value,
                    "factor": factor,
                    "result": value * factor,
                }, nil
            },
        },
    },
}

provider := skills.NewContextProvider(skills.ContextProviderOptions{
    Skills: []*skills.Skill{skill},
})

GetContent carica le istruzioni della skill solo quando l'agente richiama load_skill. Gli script ricevono argomenti posizionali di tipo stringa in stile CLI, ad esempio ["26.2", "1.60934"], e possono analizzare tali argomenti nel modo richiesto dallo script.

Suggerimento

Vedere gli esempi di competenze per esempi eseguibili completi.

Competenze basate su classi

Le competenze basate su classi consentono di aggregare tutti i componenti della competenza, ovvero nome, descrizione, istruzioni, risorse e script, in una singola classe C#. Questo li rende facili da impacchettare e distribuire come pacchetti NuGet: i team possono creare e distribuire le skill in modo indipendente e gli utenti possono aggiungerle con dotnet add package e una singola chiamata a .UseSkill(). Deriva da AgentClassSkill<T> (dove T è la tua classe), quindi annota le proprietà con [AgentSkillResource] e i metodi con [AgentSkillScript] per l'individuazione automatica.

using System.ComponentModel;
using System.Text.Json;
using Microsoft.Agents.AI;

internal sealed class UnitConverterSkill : AgentClassSkill<UnitConverterSkill>
{
    public override AgentSkillFrontmatter Frontmatter { get; } = new(
        "unit-converter",
        "Convert between common units using a multiplication factor. Use when asked to convert miles, kilometers, pounds, or kilograms.");

    protected override string Instructions => """
        Use this skill when the user asks to convert between units.

        1. Review the conversion-table resource to find the correct factor.
        2. Use the convert script, passing the value and factor from the table.
        3. Present the result clearly with both units.
        """;

    [AgentSkillResource("conversion-table")]
    [Description("Lookup table of multiplication factors for common unit conversions.")]
    public string ConversionTable => """
        # Conversion Tables
        Formula: **result = value × factor**
        | From       | To         | Factor   |
        |------------|------------|----------|
        | miles      | kilometers | 1.60934  |
        | kilometers | miles      | 0.621371 |
        | pounds     | kilograms  | 0.453592 |
        | kilograms  | pounds     | 2.20462  |
        """;

    [AgentSkillScript("convert")]
    [Description("Multiplies a value by a conversion factor and returns the result as JSON.")]
    private static string ConvertUnits(double value, double factor)
    {
        double result = Math.Round(value * factor, 4);
        return JsonSerializer.Serialize(new { value, factor, result });
    }
}

Registrare la competenza basata sulla classe con AgentSkillsProvider:

var skill = new UnitConverterSkill();
var skillsProvider = new AgentSkillsProvider(skill);

Quando l'attributo [AgentSkillResource] viene applicato a una proprietà o a un metodo, il relativo valore restituito viene usato come contenuto della risorsa quando l'agente legge la risorsa. Usare un metodo quando il contenuto deve essere calcolato in fase di lettura. Quando [AgentSkillScript] viene applicato a un metodo, il metodo viene richiamato quando l'agente chiama lo script. Usare [Description] da System.ComponentModel per descrivere ogni risorsa e script per l'agente.

Annotazioni

AgentClassSkill<T> supporta anche l'override Resources e Scripts come raccolte per scenari in cui l'individuazione basata su attributi non è adatta.

Competenze basate su classi

Le competenze basate su classi consentono di aggregare tutti i componenti della competenza, ovvero nome, descrizione, istruzioni, risorse e script, in una singola classe Python. Questo li rende facili da impacchettare e distribuire come pacchetti PyPI: i team possono creare e distribuire competenze in modo indipendente e gli utilizzatori possono aggiungerli con pip install e una sola chiamata a SkillsProvider(). Crea una sottoclasse di ClassSkill, quindi usa i decoratori @ClassSkill.resource e @ClassSkill.script per il rilevamento automatico:

import json
from textwrap import dedent
from agent_framework import ClassSkill, SkillFrontmatter

class UnitConverterSkill(ClassSkill):
    """A unit-converter skill defined as a Python class."""

    def __init__(self) -> None:
        super().__init__(
            frontmatter=SkillFrontmatter(
                name="unit-converter",
                description=(
                    "Convert between common units using a multiplication factor. "
                    "Use when asked to convert miles, kilometers, pounds, or kilograms."
                ),
            ),
        )

    @property
    def instructions(self) -> str:
        return dedent("""\
            Use this skill when the user asks to convert between units.

            1. Review the conversion-table resource to find the correct factor.
            2. Use the convert script, passing the value and factor from the table.
            3. Present the result clearly with both units.
        """)

    @property
    @ClassSkill.resource
    def conversion_table(self) -> str:
        """Lookup table of multiplication factors for common unit conversions."""
        return dedent("""\
            # Conversion Tables
            Formula: **result = value × factor**
            | From       | To         | Factor   |
            |------------|------------|----------|
            | miles      | kilometers | 1.60934  |
            | kilometers | miles      | 0.621371 |
            | pounds     | kilograms  | 0.453592 |
            | kilograms  | pounds     | 2.20462  |
        """)

    @ClassSkill.script(name="convert", description="Multiplies a value by a conversion factor.")
    def convert_units(self, value: float, factor: float) -> str:
        """Convert a value using a multiplication factor."""
        result = round(value * factor, 4)
        return json.dumps({"value": value, "factor": factor, "result": result})

Registrare la competenza basata sulla classe con SkillsProvider:

from agent_framework import SkillsProvider

skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)

Quando @ClassSkill.resource viene applicato come decoratore senza argomenti, il nome del metodo diventa il nome della risorsa (con i trattini bassi convertiti in trattini) e la docstring diventa la descrizione. Usare @ClassSkill.resource(name="...", description="...") per impostarli in modo esplicito. Lo stesso modello si applica a @ClassSkill.script.

Le risorse possono essere definite come metodi regolari o @property descrittori. Quando si usa @property, posizionare @property per primo e @ClassSkill.resource per secondo. I valori restituiti delle risorse vengono memorizzati nella cache dopo il primo accesso.

Annotazioni

ClassSkill supporta anche la sostituzione esplicita delle proprietà resources e scripts per restituire direttamente istanze di InlineSkillResource e InlineSkillScript, negli scenari in cui il rilevamento basato su decorator non è appropriato.

Competenze basate su MCP

Annotazioni

Le competenze basate su MCP richiedono il Microsoft.Agents.AI.Mcp pacchetto NuGet. L'API delle competenze MCP è sperimentale e può cambiare nelle versioni future.

Le competenze possono essere individuate dai server MCP (Model Context Protocol) che espongono le risorse delle competenze nello skill:// schema URI. Il server MCP annuncia le competenze tramite un skill://index.json documento di individuazione e il framework recupera il contenuto delle competenze su richiesta.

Le abilità basate su MCP supportano due tipi di voci di indice:

  • skill-md - Le risorse della competenza SKILL.md e le risorse correlate vengono recuperate su richiesta dal server MCP.
  • archive - La skill viene distribuita come un unico archivio compresso (ZIP, TAR o TAR compresso con gzip), che viene scaricato e decompresso localmente.

Utilizzo di base

Usa il metodo di estensione UseMcpSkills su AgentSkillsProviderBuilder per aggiungere un'origine di competenze MCP:

using Microsoft.Agents.AI;
using ModelContextProtocol.Client;

// Connect to the MCP server
await using McpClient client = await McpClient.CreateAsync(
    new StdioClientTransport(new()
    {
        Name = "skills-server",
        Command = "dotnet",
        Arguments = [skillsServerPath, "--server"],
    }));

// Build a skills provider that discovers skills over MCP
var skillsProvider = new AgentSkillsProviderBuilder()
    .UseMcpSkills(client)
    .Build();

// Create an agent with the MCP skills
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetResponsesClient()
    .AsAIAgent(new ChatClientAgentOptions
    {
        Name = "SkillsAgent",
        ChatOptions = new()
        {
            Instructions = "You are a helpful assistant. Use available skills to answer the user.",
        },
        AIContextProviders = [skillsProvider],
    },
    model: deploymentName);

Competenze di tipo archivistico

Per le abilità di tipo archivio, usare AgentMcpSkillsSourceOptions (dal pacchetto Microsoft.Agents.AI.Mcp) per configurare il comportamento di estrazione:

var skillsProvider = new AgentSkillsProviderBuilder()
    .UseMcpSkills(client, new AgentMcpSkillsSourceOptions
    {
        ArchiveSkillsDirectory = Path.Combine(AppContext.BaseDirectory, "extracted-skills"),
        ArchiveMaxFileCount = 50,
        ArchiveMaxSizeBytes = 2 * 1024 * 1024, // 2 MB
    })
    .Build();

AgentMcpSkillsSourceOptions espone le proprietà seguenti per controllare l'estrazione dell'archivio:

  • ArchiveSkillsDirectory - Directory di base per gli archivi estratti. Per impostazione predefinita, viene utilizzata una sottodirectory univoca nella directory di lavoro corrente, generata per ogni istanza della sorgente per evitare collisioni tra più sorgenti.
  • ArchiveResourceExtensions - Estensioni consentite per le risorse negli archivi estratti. Il valore predefinito è .md, .json, .yaml.yml, .csv, .xml.txt.
  • ArchiveResourceSearchDepth - Come eseguire la ricerca approfondita delle risorse all'interno di ogni directory delle competenze estratta. Di default è 2.
  • ArchiveMaxFileCount - Numero massimo di file per archivio. Gli archivi che superano questo limite vengono ignorati. Di default è 20.
  • ArchiveMaxSizeBytes - Dimensioni massime del download per archivio. Di default è 1 MB.
  • ArchiveMaxUncompressedSizeBytes - Dimensioni massime non compresse totali per archivio. Di default è 1 MB.

Importante

Gli script raggruppati nelle competenze di tipo archivio non vengono mai eseguiti. Si tratta di una misura di sicurezza deliberata: il contenuto eseguibile dei server MCP remoti richiede un trust esplicito.

Competenze basate su MCP

Annotazioni

Le competenze basate su MCP sono sperimentali e possono cambiare nelle versioni future. L'utilizzo di MCPSkillsSource emette un FutureWarning con il flag di funzionalità MCP_SKILLS.

Le competenze possono essere individuate dai server MCP (Model Context Protocol) che espongono le risorse delle competenze nello skill:// schema URI. Il server MCP pubblicizza le competenze tramite un documento di rilevamento skill://index.json, e il framework recupera su richiesta il corpo di ogni competenza SKILL.md tramite resources/read.

Racchiudi un MCP ClientSession in MCPSkillsSource e passalo a SkillsProvider:

import os
from agent_framework import Agent, MCPSkillsSource, SkillsProvider, ToolApprovalMiddleware
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamable_http_client

mcp_url = os.environ["MCP_SKILLS_SERVER_URL"]

# Connect to the MCP server over streamable HTTP
async with streamable_http_client(url=mcp_url) as (read, write, _), ClientSession(read, write) as session:
    await session.initialize()

    # MCPSkillsSource reads skill://index.json and creates one skill per
    # skill-md entry; SKILL.md bodies are fetched on demand.
    skills_provider = SkillsProvider(MCPSkillsSource(client=session))

    client = FoundryChatClient(
        project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
        model=os.environ.get("FOUNDRY_MODEL", "gpt-4o-mini"),
        credential=AzureCliCredential(),
    )

    async with Agent(
        client=client,
        instructions="You are a helpful assistant. Use available skills to answer the user.",
        context_providers=[skills_provider],
        middleware=[ToolApprovalMiddleware(auto_approval_rules=[SkillsProvider.all_tools_auto_approval_rule])],
    ) as agent:
        response = await agent.run("...")

Annotazioni

Il Python MCPSkillsSource supporta solo skill-md le voci di indice (le voci di indice di qualsiasi altro tipo vengono ignorate automaticamente). A differenza dell'implementazione .NET, non supporta le abilità di tipo archive. Se skill://index.json è assente, illeggibile, vuoto o non riesce ad analizzare, l'origine restituisce un elenco vuoto.

Importante

Un server MCP esterno controlla quale contenuto delle competenze, incluse le istruzioni e gli script che l'agente può eseguire, raggiunge l'agente. Connettetevi MCPSkillsSource solo a server che avete verificato e di cui vi fidate, e considerate le loro risposte come input non attendibile.

Origini delle competenze

Un AgentSkillsProvider recupera le abilità da una o più fonti - oggetti che implementano AgentSkillsSource. Le fonti rientrano in due categorie: fonti foglia che rilevano o contengono competenze (ad esempio AgentFileSkillsSource per le competenze basate su file) e decoratori che trasformano l'output di un'altra fonte (aggregazione, deduplicazione, memorizzazione in cache e filtraggio). È anche possibile creare un'origine personalizzata.

Ogni origine implementa un singolo metodo - GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default). Contiene AgentSkillsSourceContext informazioni sulla richiesta corrente:

  • Agent : l'istanza AIAgent che richiede competenze.
  • Session - il AgentSession associato all'invocazione, oppure null quando non è presente alcuna sessione.

Questo contesto è disponibile in tutta la pipeline di origine, quindi un FilteringAgentSkillsSource predicato o un'origine personalizzata può basare la logica su di essa, ad esempio restituendo un set di competenze diverso a seconda dell'agente richiedente.

Origini dei nodi foglia

AgentFileSkillsSource

Individua gli skill nei file SKILL.md presenti sul disco. Accetta uno o più percorsi di directory, un runner di script facoltativo e tag facoltativi AgentFileSkillsSourceOptions (documentati in Abilità basate su file).

var source = new AgentFileSkillsSource(
    [Path.Combine(AppContext.BaseDirectory, "skills")],
    scriptRunner: SubprocessScriptRunner.RunAsync,
    options: new AgentFileSkillsSourceOptions { SearchDepth = 3 });

AgentInMemorySkillsSource

Inserisce in un wrapper le istanze AgentSkill (definite nel codice o basate su classi) in memoria.

var source = new AgentInMemorySkillsSource([volumeConverterSkill, temperatureConverter]);

Combinatori

AggregatingAgentSkillsSource

Combina più origini in una. Le competenze vengono restituite nell'ordine di registrazione senza deduplicazione o applicazione di filtri.

var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);

Decorators

I decorator avvolgono una sorgente interna e ne trasformano l'output. Possono essere concatenati per creare una pipeline.

DeduplicatingAgentSkillsSource

Rimuove i nomi di competenza duplicati (senza distinzione tra maiuscole e minuscole, prevale la prima occorrenza). I duplicati vengono registrati a livello di avviso.

var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);

CachingAgentSkillsSource

Memorizza nella cache l'elenco delle competenze restituito dall'origine interna. I chiamanti simultanei vengono serializzati per ogni chiave della cache, quindi viene eseguito un solo recupero alla volta. Accetta CachingAgentSkillsSourceOptions facoltativo:

  • RefreshInterval () -TimeSpan? Quando si imposta, i risultati memorizzati nella cache scadono dopo questo intervallo e l'origine interna viene richiamata di nuovo. Quando null (impostazione predefinita), i risultati memorizzati nella cache non scadono mai.
  • CacheIsolationKeySelector (Func<AgentSkillsSourceContext, string?>?) : restituisce una chiave della cache per isolare i risultati memorizzati nella cache in base al contesto, ad esempio per ogni tenant. Quando null, tutti i chiamanti condividono un singolo bucket della cache.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
    RefreshInterval = TimeSpan.FromMinutes(5)
});

FilteringAgentSkillsSource

Applica un predicato per includere o escludere competenze. Il predicato riceve l'abilità e un AgentSkillsSourceContext.

var filtered = new FilteringAgentSkillsSource(
    innerSource,
    (skill, context) => skill.Frontmatter.Name != "experimental-skill");

Origini personalizzate

Quando le fonti integrate non coprono il tuo scenario, implementane una tua. Crea una sottoclasse di AgentSkillsSource per un'origine terminale (che produce skill da una nuova origine, ad esempio un database o un servizio remoto), oppure una sottoclasse di DelegatingAgentSkillsSource per un decoratore che trasforma l'output di un'altra origine.

Origine foglia

Derivare da AgentSkillsSource e implementare GetSkillsAsync. L'argomento AgentSkillsSourceContext consente all'origine di adattare il risultato alla richiesta corrente, ad esempio restituendo un set di competenze diverso a seconda dell'agente richiedente. Eseguire l'override Dispose(bool) se l'origine possiede risorse come un client o una connessione.

public sealed class TenantSkillsSource : AgentSkillsSource
{
    private readonly ISkillStore _store;

    public TenantSkillsSource(ISkillStore store)
    {
        _store = store;
    }

    public override async Task<IList<AgentSkill>> GetSkillsAsync(
        AgentSkillsSourceContext context,
        CancellationToken cancellationToken = default)
    {
        // Use the requesting agent to decide which skills to load.
        var tenantId = context.Agent.Name ?? "default";
        return await _store.GetSkillsForTenantAsync(tenantId, cancellationToken);
    }
}

Decorator personalizzato

Derivare da DelegatingAgentSkillsSource, chiamare InnerSource.GetSkillsAsynce trasformare o osservare il risultato. Questo è lo stesso schema che usano i decoratori integrati per la memorizzazione nella cache, la deduplicazione e il filtro. Ad esempio, un decoratore che registra quante competenze vengono restituite per ogni richiesta senza modificare il risultato:

public sealed class MetricsAgentSkillsSource : DelegatingAgentSkillsSource
{
    private readonly ILogger<MetricsAgentSkillsSource> _logger;

    public MetricsAgentSkillsSource(
        AgentSkillsSource innerSource,
        ILogger<MetricsAgentSkillsSource> logger)
        : base(innerSource)
    {
        _logger = logger;
    }

    public override async Task<IList<AgentSkill>> GetSkillsAsync(
        AgentSkillsSourceContext context,
        CancellationToken cancellationToken = default)
    {
        var skills = await base.GetSkillsAsync(context, cancellationToken);
        _logger.LogInformation(
            "Returned {SkillCount} skills to agent {AgentName}.",
            skills.Count,
            context.Agent.Name);
        return skills;
    }
}

Entrambe le sorgenti personalizzate possono essere passate direttamente a AgentSkillsProvider oppure annidate all'interno di una pipeline più ampia, proprio come le sorgenti predefinite.

Creazione del provider

AgentSkillsProvider è il componente che espone le competenze a un agente. Racchiude una o più origini dati e registra gli strumenti load_skill, read_skill_resource e run_skill_script. Esistono tre modi per crearne uno:

  1. AgentSkillsProviderBuilder : compone più tipi di competenza in un provider con aggregazione automatica, deduplicazione, memorizzazione nella cache e filtro facoltativo. Ideale per scenari che combinano competenze basate su file, definite dal codice, basate su classi e MCP.
  2. Composizione diretta della sorgente - crea manualmente la pipeline della sorgente usando le classi pubbliche AgentSkillsSource. Non viene applicata alcuna memorizzazione nella cache o deduplicazione automatica: è possibile controllare la pipeline completa. La scelta migliore quando hai bisogno di controllo sull'ordinamento, sulla logica condizionale o sul comportamento personalizzato del decorator.
  3. Costruttori di utilità - crea un provider direttamente da un percorso di file o da una o più istanze di skill. Applica automaticamente la deduplicazione e la memorizzazione nella cache. Ideale per scenari a origine singola.

Uso di AgentSkillsProviderBuilder

Usare AgentSkillsProviderBuilder quando è necessario uno dei seguenti elementi:

  • Tipi di competenza misti : combinare competenze basate su file, definite dal codice (AgentInlineSkill), basate su classi (AgentClassSkill) e mcp in un singolo provider.
  • Filtro delle competenze: includere o escludere competenze usando un predicato.

Tipi di competenze misti

Combinare più tipi di competenza in un provider concatenando UseFileSkill, UseSkill, UseMcpSkillse UseFileScriptRunner:

var skillsProvider = new AgentSkillsProviderBuilder()
    .UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))  // file-based skills
    .UseSkill(volumeConverterSkill)                                  // AgentInlineSkill
    .UseSkill(temperatureConverter)                                  // AgentClassSkill
    .UseMcpSkills(mcpClient)                                         // MCP-based skills
    .UseFileScriptRunner(SubprocessScriptRunner.RunAsync)            // runner for file scripts
    .Build();

Filtro delle competenze

Usare UseFilter per includere solo le competenze che soddisfano i criteri, ad esempio per caricare le competenze da una directory condivisa, ma escludere quelle sperimentali:

var approvedSkillNames = new HashSet<string> { "expense-report", "code-style" };

var skillsProvider = new AgentSkillsProviderBuilder()
    .UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
    .UseFilter((skill, context) => approvedSkillNames.Contains(skill.Frontmatter.Name))
    .Build();

Comporre direttamente le sorgenti

Quando il generatore non offre il controllo necessario, comporre manualmente le classi di origine e passare la pipeline risultante a AgentSkillsProvider. Per l'elenco completo delle origini disponibili e delle relative opzioni, vedere Le origini delle competenze .

L'esempio seguente crea una pipeline multisorgente analoga, ma offre un controllo esplicito su ogni decoratore:

// 1. Create the leaf sources
var fileSource = new AgentFileSkillsSource(
    [Path.Combine(AppContext.BaseDirectory, "skills")],
    SubprocessScriptRunner.RunAsync);

var inMemorySource = new AgentInMemorySkillsSource(
    [volumeConverterSkill, temperatureConverter]);

// 2. Aggregate them into one source
var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);

// 3. Add deduplication and caching decorators
var deduplicated = new DeduplicatingAgentSkillsSource(aggregated);
var cached = new CachingAgentSkillsSource(deduplicated);

// 4. Create the provider, transferring source ownership
var skillsProvider = new AgentSkillsProvider(
    cached,
    options: new AgentSkillsProviderOptions(),
    ownsSource: true);

Annotazioni

Quando ownsSource è true, l'eliminazione del provider elimina anche l'intera pipeline di origine. Impostalo su false se gestisci tu stesso il ciclo di vita della sorgente.

Costruttori di convenienza

Per gli scenari a origine singola, usare direttamente i AgentSkillsProvider costruttori. Questi applicano automaticamente la deduplicazione e la memorizzazione nella cache senza richiedere un generatore o una composizione di origine manuale.

Da un percorso di file:

var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "skills"),
    scriptRunner: SubprocessScriptRunner.RunAsync);

Dalle istanze delle competenze:

var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);

Origini delle competenze

Un SkillsProvider recupera le competenze da una o più fonti, ossia oggetti derivati da SkillsSource. Le fonti rientrano in due categorie: fonti foglia che rilevano o contengono competenze (ad esempio FileSkillsSource per le competenze basate su file) e decoratori che trasformano l'output di un'altra fonte (aggregazione, deduplicazione, memorizzazione in cache e filtraggio). È anche possibile creare un'origine personalizzata.

Ogni origine implementa un singolo metodo - async def get_skills(self, context: SkillsSourceContext) -> list[Skill]. Contiene SkillsSourceContext informazioni sulla richiesta corrente:

  • agent - l'agente (SupportsAgentRun) che richiede competenze.
  • session - il AgentSession associato all'invocazione, oppure None quando non è presente alcuna sessione.

Questo contesto passa attraverso l'intera pipeline di origine, quindi un FilteringSkillsSource predicato o un'origine personalizzata può basare la logica su di essa, ad esempio restituendo un set di competenze diverso a seconda dell'agente richiedente.

Origini dei nodi foglia

  • FileSkillsSource - individua le abilità dai file SKILL.md presenti sul disco. Accetta uno o più percorsi di directory, un elemento facoltativo script_runner e le opzioni di individuazione (resource_extensions, script_extensions, search_depth, resource_filter, script_filter) documentate in Competenze basate su file.
  • InMemorySkillsSource : esegue il wrapping delle Skill istanze (definite dal codice o basate su classi) in memoria.
  • MCPSkillsSource - individua le competenze da un server MCP (vedere Competenze basate su MCP).
from pathlib import Path
from agent_framework import FileSkillsSource, InMemorySkillsSource

file_source = FileSkillsSource(Path(__file__).parent / "skills", script_runner=my_runner)
in_memory_source = InMemorySkillsSource([volume_converter_skill, temperature_converter_skill])

Combinatore

AggregatingSkillsSource combina più origini in una. Le competenze vengono restituite nell'ordine di registrazione senza deduplicazione o applicazione di filtri.

from agent_framework import AggregatingSkillsSource

aggregated = AggregatingSkillsSource([file_source, in_memory_source])

Decorators

I decorator avvolgono una sorgente interna e ne trasformano l'output. Possono essere concatenati per creare una pipeline.

  • DeduplicatingSkillsSource - rimuove i nomi di competenza duplicati (senza distinzione tra maiuscole e minuscole, vince la prima occorrenza). I duplicati vengono registrati a livello di avviso.
  • CachingSkillsSource : memorizza nella cache l'elenco di competenze restituito dall'origine interna. Le richieste concorrenti per la stessa chiave di cache condividono un’unica operazione di recupero in corso, quindi la sorgente sottostante viene interrogata al massimo una volta per chiave. Accetta due argomenti di parole chiave facoltativi:
    • refresh_interval () -timedelta | None Quando impostato, un elenco memorizzato nella cache viene considerato non aggiornato una volta che è precedente all'intervallo, quindi la chiamata successiva esegue nuovamente una query sull'origine interna. Quando None (impostazione predefinita), i risultati memorizzati nella cache non scadono mai. Utile per le fonti interne le cui capacità cambiano nel corso del ciclo di vita del processo, ad esempio MCPSkillsSource.
    • cache_isolation_key_selector (Callable[[SkillsSourceContext], str | None]) : deriva una chiave della cache dal contesto per isolare i risultati memorizzati nella cache ( ad esempio, per agente o tenant). Le chiavi devono essere a bassa cardinalità e stabili. Restituire None (o lasciarlo None) usa un singolo bucket di cache condiviso.
  • FilteringSkillsSource - applica un predicato per includere o escludere le competenze. Il predicato riceve l'abilità e un SkillsSourceContext: Callable[[Skill, SkillsSourceContext], bool].
from datetime import timedelta
from agent_framework import (
    CachingSkillsSource,
    DeduplicatingSkillsSource,
    FilteringSkillsSource,
)

deduplicated = DeduplicatingSkillsSource(aggregated)

cached = CachingSkillsSource(
    deduplicated,
    refresh_interval=timedelta(minutes=5),
    cache_isolation_key_selector=lambda context: context.agent.name,
)

filtered = FilteringSkillsSource(
    cached,
    predicate=lambda skill, context: skill.frontmatter.name != "experimental-skill",
)

Origini personalizzate

Quando le fonti integrate non coprono il tuo scenario, implementane una tua. Crea una sottoclasse di SkillsSource per un'origine terminale (che produce skill da una nuova origine, ad esempio un database o un servizio remoto), oppure una sottoclasse di DelegatingSkillsSource per un decoratore che trasforma l'output di un'altra origine.

Origine foglia

Derivare da SkillsSource e implementare get_skills. L'argomento SkillsSourceContext consente all'origine di adattare il risultato alla richiesta corrente, ad esempio restituendo un set di competenze diverso a seconda dell'agente richiedente:

from agent_framework import Skill, SkillsSource, SkillsSourceContext

class TenantSkillsSource(SkillsSource):
    def __init__(self, store: "SkillStore") -> None:
        self._store = store

    async def get_skills(self, context: SkillsSourceContext) -> list[Skill]:
        # Use the requesting agent to decide which skills to load.
        tenant_id = context.agent.name or "default"
        return await self._store.get_skills_for_tenant(tenant_id)

Decorator personalizzato

Derivare da DelegatingSkillsSource, chiamare self.inner_source.get_skills(context)e trasformare o osservare il risultato. Questo è lo stesso schema che usano i decoratori integrati per la memorizzazione nella cache, la deduplicazione e il filtro. Ad esempio, un elemento Decorator che registra il numero di competenze restituite per ogni richiesta senza modificare il risultato:

import logging
from agent_framework import DelegatingSkillsSource, Skill, SkillsSourceContext

logger = logging.getLogger(__name__)

class MetricsSkillsSource(DelegatingSkillsSource):
    async def get_skills(self, context: SkillsSourceContext) -> list[Skill]:
        skills = await self.inner_source.get_skills(context)
        logger.info("Returned %d skills to agent %s.", len(skills), context.agent.name)
        return skills

Entrambe le sorgenti personalizzate possono essere passate direttamente a SkillsProvider oppure annidate all'interno di una pipeline più ampia, proprio come le sorgenti predefinite.

Creazione del provider

SkillsProvider è il componente che espone le competenze a un agente. Racchiude una o più origini dati e registra gli strumenti load_skill, read_skill_resource e run_skill_script. Esistono tre modi per crearne uno:

  1. Dalle istanze di competenza - passa una singola Skill o una sequenza di competenze al costruttore. Ideale per le competenze definite dal codice e basate su classi. Applica automaticamente la deduplicazione e la memorizzazione nella cache.
  2. Dai percorsi di file : usare la SkillsProvider.from_paths() factory. Ideale per le competenze basate su file a origine singola. Applica automaticamente la deduplicazione e la memorizzazione nella cache.
  3. Composizione origine diretta : creare manualmente la pipeline di origine usando le classi pubbliche SkillsSource e passarla al costruttore. È possibile controllare la pipeline completa. La scelta migliore quando serve controllare l'ordinamento, la logica condizionale, le chiavi di cache o il comportamento personalizzato dei decorator.

Dalle istanze delle competenze

from agent_framework import SkillsProvider

# Single skill or a list of skills - deduplicated and cached automatically.
skills_provider = SkillsProvider(volume_converter_skill)
skills_provider = SkillsProvider([volume_converter_skill, temperature_converter_skill])

Dai percorsi dei file

from pathlib import Path
from agent_framework import SkillsProvider

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    script_runner=my_runner,
)

Comporre direttamente le sorgenti

Quando è necessario il controllo completo, comporre manualmente le classi di origine e passare la pipeline risultante a SkillsProvider. Per l'elenco completo delle origini disponibili e delle relative opzioni, vedere Le origini delle competenze .

L'esempio seguente crea una pipeline multi-source con controllo esplicito su ciascun decoratore. Nell'esempio vengono utilizzati oggetti segnaposto:

from pathlib import Path
from agent_framework import (
    AggregatingSkillsSource,
    CachingSkillsSource,
    DeduplicatingSkillsSource,
    FileSkillsSource,
    InMemorySkillsSource,
    SkillsProvider,
)

# 1. Create the leaf sources
file_source = FileSkillsSource(Path(__file__).parent / "skills", script_runner=my_runner)
in_memory_source = InMemorySkillsSource([volume_converter_skill, temperature_converter_skill])

# 2. Aggregate them, then add deduplication and caching decorators
aggregated = AggregatingSkillsSource([file_source, in_memory_source])
deduplicated = DeduplicatingSkillsSource(aggregated)
cached = CachingSkillsSource(deduplicated)

# 3. Create the provider from the composed pipeline
skills_provider = SkillsProvider(cached)

Importante

Un SkillsSource fornito dal chiamante viene usato così com'è: non viene deduplicato automaticamente né racchiuso in un CachingSkillsSource. La memorizzazione automatica nella cache di un'origine compatibile con il contesto in un singolo bucket condiviso può riprodurre le competenze di un agente o di un tenant per un altro. Componi DeduplicatingSkillsSource e CachingSkillsSource (facoltativamente con un cache_isolation_key_selector) tu stesso quando ne hai bisogno. La deduplicazione e la memorizzazione nella cache automatica si applica solo quando si passano direttamente competenze o percorsi di file (opzioni 1 e 2 precedenti).

Tipi di competenze misti

Combinare competenze basate su file, definite dal codice e basate su classi in un provider usando AggregatingSkillsSource:

from pathlib import Path
from agent_framework import (
    AggregatingSkillsSource,
    DeduplicatingSkillsSource,
    FileSkillsSource,
    InMemorySkillsSource,
    SkillsProvider,
)

temperature_converter_skill = TemperatureConverterSkill()

skills_provider = SkillsProvider(
    DeduplicatingSkillsSource(
        AggregatingSkillsSource([
            FileSkillsSource(
                Path(__file__).parent / "skills",
                script_runner=my_runner,
            ),
            InMemorySkillsSource([volume_converter_skill, temperature_converter_skill]),
        ])
    )
)

Filtro delle competenze

Usa FilteringSkillsSource per controllare quali competenze vede l'agente. Il predicato riceve ogni Skill e il SkillsSourceContext, e restituisce True per includere la competenza. Ad esempio, per caricare le competenze da una directory condivisa ma nasconderne una sperimentale:

from pathlib import Path
from agent_framework import (
    DeduplicatingSkillsSource,
    FileSkillsSource,
    FilteringSkillsSource,
    SkillsProvider,
)

skills_provider = SkillsProvider(
    DeduplicatingSkillsSource(
        FilteringSkillsSource(
            FileSkillsSource(Path(__file__).parent / "skills"),
            predicate=lambda skill, context: skill.frontmatter.name != "experimental-tools",
        )
    )
)

Comportamento di memorizzazione nella cache

Per impostazione predefinita, il generatore racchiude la pipeline di origine in un CachingAgentSkillsSource che memorizza nella cache l'elenco di abilità restituito dalle origini sottostanti. Una volta risolte le competenze nella prima richiesta, le richieste successive riutilizzano l'elenco memorizzato nella cache senza eseguire nuovamente query sulle origini. Per disabilitare la memorizzazione nella cache (ad esempio, durante lo sviluppo quando le definizioni delle competenze cambiano frequentemente), usare DisableCaching() nel generatore:

var skillsProvider = new AgentSkillsProviderBuilder()
    .UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
    .UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
    .DisableCaching()
    .Build();

Annotazioni

La disabilitazione della memorizzazione nella cache è utile durante lo sviluppo quando il contenuto delle competenze cambia frequentemente. Nell'ambiente di produzione lasciare abilitata la memorizzazione nella cache (impostazione predefinita) per ottenere prestazioni migliori.

Comportamento di memorizzazione nella cache

Per impostazione predefinita, gli strumenti e le istruzioni delle competenze vengono memorizzati nella cache dopo la prima compilazione. Impostare disable_caching=True per forzare una ricompilazione per ogni chiamata:

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    disable_caching=True,
)

disable_caching è disponibile anche nel SkillsProvider costruttore per le competenze definite dal codice e basate su classi.

Per mantenere abilitata la cache ma rilevare nuovamente le skill periodicamente (ad esempio, quando una fonte basata su file o MCP cambia durante il ciclo di vita del processo), specificare cache_refresh_interval. La cache predefinita viene considerata non aggiornata una volta che è precedente all'intervallo, quindi l'esecuzione successiva esegue nuovamente una query sull'origine:

from datetime import timedelta

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    cache_refresh_interval=timedelta(minutes=5),
)

cache_refresh_interval influisce solo sulla cache che il provider costruisce internamente (da skill o percorsi file); viene ignorato quando disable_caching=True e non ha alcun effetto su un SkillsSource fornito dal chiamante (per questi casi, componi il tuo CachingSkillsSource con un refresh_interval).

Annotazioni

La disabilitazione della memorizzazione nella cache è utile durante lo sviluppo quando il contenuto delle competenze cambia frequentemente. Nell'ambiente di produzione lasciare abilitata la memorizzazione nella cache (impostazione predefinita) per ottenere prestazioni migliori.

Approvazione degli strumenti

Tutti gli strumenti esposti da AgentSkillsProvider (load_skill, read_skill_resource, run_skill_script) richiedono l'approvazione per impostazione predefinita. Quando una chiamata a uno strumento richiede l'approvazione, l'agente si interrompe e restituisce un ToolApprovalRequestContent anziché eseguirla immediatamente. Usa UseToolApproval middleware con regole di approvazione automatica per saltare selettivamente le richieste di conferma per operazioni fidate:

using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;

var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "skills"),
    SubprocessScriptRunner.RunAsync);

AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetResponsesClient()
    .AsAIAgent(new ChatClientAgentOptions
    {
        Name = "SkillsAgent",
        ChatOptions = new() { Instructions = "You are a helpful assistant." },
        AIContextProviders = [skillsProvider],
    },
    model: deploymentName)
    .AsBuilder()
    .UseToolApproval(new ToolApprovalAgentOptions
    {
        // Auto-approve read-only skill tools (load_skill, read_skill_resource).
        // run_skill_script still requires explicit user approval.
        AutoApprovalRules = [AgentSkillsProvider.ReadOnlyToolsAutoApprovalRule],
    })
    .Build();

Per approvare automaticamente tutti gli strumenti di competenza, inclusa l'esecuzione di script:

.UseToolApproval(new ToolApprovalAgentOptions
{
    AutoApprovalRules = [AgentSkillsProvider.AllToolsAutoApprovalRule],
})

Disabilitazione dell'approvazione per strumenti specifici

Usare AgentSkillsProviderOptions per disabilitare l'approvazione per singoli strumenti, rimuovendoli completamente dal flusso di approvazione:

var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "skills"),
    SubprocessScriptRunner.RunAsync,
    options: new AgentSkillsProviderOptions
    {
        DisableLoadSkillApproval = true,
        DisableReadSkillResourceApproval = true,
        // DisableRunSkillScriptApproval remains false - scripts still require approval
    });

Quando alcuni strumenti richiedono l'approvazione e altri non si trovano nella stessa risposta, il modello può chiamare entrambi i tipi contemporaneamente. Impostare EnableNonApprovalRequiredFunctionBypassing in modo che gli strumenti senza approvazione vengano eseguiti immediatamente mentre all'utente vengono richiesti solo quelli rimanenti:

AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetResponsesClient()
    .AsAIAgent(new ChatClientAgentOptions
    {
        Name = "SkillsAgent",
        ChatOptions = new() { Instructions = "You are a helpful assistant." },
        AIContextProviders = [skillsProvider],
        EnableNonApprovalRequiredFunctionBypassing = true,
    },
    model: deploymentName)
    .AsBuilder()
    .UseToolApproval()
    .Build();

Gestione delle richieste di approvazione

Quando gli strumenti richiedono l'approvazione (e nessuna regola di approvazione automatica corrisponde), l'agente restituisce ToolApprovalRequestContent gli elementi che devono essere approvati o rifiutati prima di continuare:

AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("Convert 26.2 miles to kilometers", session);

List<ToolApprovalRequestContent> approvalRequests = response.Messages
    .SelectMany(m => m.Contents)
    .OfType<ToolApprovalRequestContent>()
    .ToList();

while (approvalRequests.Count > 0)
{
    List<ChatMessage> userInputResponses = approvalRequests
        .ConvertAll(request =>
        {
            var toolCall = (FunctionCallContent)request.ToolCall;
            Console.WriteLine($"Approve {toolCall.Name}? (Y/N)");
            bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
            return new ChatMessage(ChatRole.User, [request.CreateResponse(approved)]);
        });

    response = await agent.RunAsync(userInputResponses, session);
    approvalRequests = response.Messages
        .SelectMany(m => m.Contents)
        .OfType<ToolApprovalRequestContent>()
        .ToList();
}

Dettagli dell'errore di script

Per impostazione predefinita, quando l'esecuzione di uno script della skill non riesce, l'eccezione viene propagata al livello sottostante FunctionInvokingChatClient. Se la proprietà IncludeDetailedErrors è impostata su true, il messaggio di eccezione viene inoltrato al modello, consentendone la correzione automatica ritentando con argomenti diversi:

AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetResponsesClient()
    .AsAIAgent(
        options: new ChatClientAgentOptions
        {
            Name = "SkillsAgent",
            ChatOptions = new()
            {
                Instructions = "You are a helpful assistant.",
            },
            AIContextProviders = [skillsProvider],
        },
        model: deploymentName,
        clientFactory: client => client
            .AsBuilder()
            .UseFunctionInvocation(configure: (c) => c.IncludeDetailedErrors = true)
            .Build());

Se non è possibile configurare FunctionInvokingChatClient direttamente, impostare AgentSkillsProviderOptions.IncludeDetailedErrors invece . In questo modo viene rilevata l'eccezione a livello di provider di competenze e viene restituito il messaggio di errore direttamente al modello:

var skillsProvider = new AgentSkillsProvider(
    Path.Combine(AppContext.BaseDirectory, "skills"),
    SubprocessScriptRunner.RunAsync,
    options: new AgentSkillsProviderOptions
    {
        IncludeDetailedErrors = true,
    });

Avviso

Entrambi gli approcci possono divulgare dettagli di eccezione non elaborati al modello. I messaggi di eccezione possono contenere informazioni riservate, ad esempio stringhe di connessione, percorsi di file o nomi di servizio interni. Inoltre, se le competenze o gli script provengono da fonti non attendibili, uno script malevolo appositamente predisposto potrebbe generare un'eccezione il cui messaggio incorpora un payload di prompt injection.

Tutti gli strumenti esposti da SkillsProvider (load_skill, read_skill_resourcee run_skill_script) richiedono l'approvazione per impostazione predefinita. Quando una chiamata allo strumento richiede l'approvazione, l'agente sospende e restituisce le richieste di approvazione tramite result.user_input_requests anziché eseguire immediatamente. Approvare o rifiutare ogni richiesta con request.to_function_approval_response(approved=...) e inviare di nuovo le risposte:

from textwrap import dedent
from agent_framework import Agent, Content, InlineSkill, Message, SkillFrontmatter, SkillsProvider

deployment_skill = InlineSkill(
    frontmatter=SkillFrontmatter(
        name="deployment",
        description="Tools for deploying application versions to production",
    ),
    instructions=dedent("""\
        Use this skill when the user asks to deploy an application.
        Run the deploy script with the version and environment parameters.
    """),
)

@deployment_skill.script
def deploy(version: str, environment: str = "staging") -> str:
    """Deploy the application to the specified environment."""
    return f"Deployed version {version} to {environment}"

# All skill tools require approval by default.
skills_provider = SkillsProvider(deployment_skill)

async with Agent(
    client=client,
    instructions="You are a deployment assistant.",
    context_providers=[skills_provider],
) as agent:
    # Use a session so the agent retains context across approval round-trips
    session = agent.create_session()

    result = await agent.run("Deploy version 2.5.0 to production", session=session)

    # Collect a response for every request and send them in one run so the
    # loop always makes progress.
    while result.user_input_requests:
        approval_responses: list[Content] = []
        for request in result.user_input_requests:
            if request.function_call is None:
                approval_responses.append(request.to_function_approval_response(approved=False))
                continue
            print(f"Approve {request.function_call.name}? Args: {request.function_call.arguments}")
            # In a real application, prompt the user here.
            approval_responses.append(request.to_function_approval_response(approved=True))

        result = await agent.run(Message(role="user", contents=approval_responses), session=session)

    print(result)

Quando una chiamata di strumento viene rifiutata (approved=False), l'agente viene informato che l'utente ha rifiutato e può rispondere di conseguenza.

Approvazione automatica di strumenti attendibili

Anziché richiedere ogni chiamata, installare ToolApprovalMiddleware con una delle regole di approvazione automatica statiche esposte da SkillsProvider. In questo modo gli strumenti di sola lettura vengono eseguiti automaticamente durante la richiesta di esecuzione dello script:

from agent_framework import Agent, SkillsProvider, ToolApprovalMiddleware

skills_provider = SkillsProvider(deployment_skill)

# Auto-approve read-only skill tools (load_skill, read_skill_resource).
# run_skill_script still requires explicit approval via result.user_input_requests.
approval_middleware = ToolApprovalMiddleware(
    auto_approval_rules=[SkillsProvider.read_only_tools_auto_approval_rule],
)

agent = Agent(
    client=client,
    instructions="You are a deployment assistant.",
    context_providers=[skills_provider],
    middleware=[approval_middleware],
)

Sono disponibili due regole:

  • SkillsProvider.read_only_tools_auto_approval_rule - approva solo gli strumenti di sola lettura (load_skill, read_skill_resource), continuando comunque a richiedere run_skill_script.
  • SkillsProvider.all_tools_auto_approval_rule - approva ogni strumento relativo alle competenze, compreso run_skill_script (non è necessario un flusso di approvazione manuale).

Entrambe le regole rifiutano qualsiasi chiamata che trasporta un oggetto server_label, quindi rimangono limitati agli strumenti locali del provider e non approvano mai automaticamente uno strumento ospitato con lo stesso nome. Le regole si applicano solo agli strumenti che richiedono ancora l'approvazione: gli strumenti esclusi tramite gli argomenti disable_*_approval seguenti vengono eseguiti senza approvazione in ogni caso.

Disabilitazione dell'approvazione per strumenti specifici

Per le skill attendibili, passare disable_load_skill_approval, disable_read_skill_resource_approval e/o disable_run_skill_script_approval per escludere completamente i singoli strumenti dal flusso di approvazione (sono registrati con approval_mode="never_require"):

skills_provider = SkillsProvider(
    deployment_skill,
    disable_load_skill_approval=True,
    disable_read_skill_resource_approval=True,
    # disable_run_skill_script_approval remains False - scripts still require approval
)

Questi argomenti sono disponibili anche in SkillsProvider.from_paths().

Avviso

Disattiva l’approvazione, o approva automaticamente l’esecuzione degli script, solo per skill e script provenienti da fonti attendibili. Le istruzioni delle skill sono iniettate nel contesto dell'agente e run_skill_script esegue il codice fornito dall'origine.

Richiesta di sistema personalizzata

Per impostazione predefinita, il provider di competenze inserisce un prompt di sistema che elenca le competenze disponibili e indica all'agente di usare load_skill e read_skill_resource. È possibile personalizzare questa richiesta:

var skillsProvider = new AgentSkillsProvider(
    skillPath: Path.Combine(AppContext.BaseDirectory, "skills"),
    options: new AgentSkillsProviderOptions
    {
        SkillsInstructionPrompt = """
            You have skills available. Here they are:
            {skills}
            When a task matches a skill, use load_skill to retrieve instructions,
            then read_skill_resource for referenced resources, and run_skill_script for scripts.
            """
    });

Annotazioni

Il modello personalizzato deve contenere {skills} come segnaposto per l'elenco di competenze generate. Le parentesi graffe letterali devono essere precedute da un carattere di escape come {{ e }}.

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    instruction_template=(
        "You have skills available. Here they are:\n{skills}\n"
        "{resource_instructions}\n"
        "{runner_instructions}"
    ),
)

Annotazioni

Il modello personalizzato deve contenere il {skills} segnaposto per l'elenco di competenze generate. Può contenere facoltativamente i segnaposto {resource_instructions} (suggerimento dello strumento per le risorse) e {runner_instructions} (suggerimento dello strumento per gli script); quando sono presenti, vengono riempiti con istruzioni integrate e, quando sono omessi, semplicemente non vengono visualizzati (gli strumenti corrispondenti rimangono comunque registrati). Le parentesi graffe letterali devono essere precedute da un carattere di escape come {{ e }}.

Inserimento di servizi e argomenti di runtime

Le funzioni delle risorse della skill e degli script possono ricevere il contesto esterno dell'applicazione fornito in fase di esecuzione.

Le risorse di abilità e i delegati di script possono dichiarare un parametro IServiceProvider che l'Agent Framework inserisce automaticamente. Ciò consente agli skill di risolvere su richiesta i servizi applicativi registrati.

Setup

Registrare i servizi dell'applicazione e passare l'oggetto compilato IServiceProvider all'agente tramite il services parametro :

using Microsoft.Extensions.DependencyInjection;

// Register application services
ServiceCollection services = new();
services.AddSingleton<ConversionService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();

// Create the agent and pass the service provider
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
    .GetResponsesClient()
    .AsAIAgent(
        options: new ChatClientAgentOptions
        {
            Name = "ConverterAgent",
            ChatOptions = new() { Instructions = "You are a helpful assistant." },
            AIContextProviders = [skillsProvider],
        },
        model: deploymentName,
        services: serviceProvider);

Competenze definite dal codice con inserimento delle dipendenze

Dichiarare IServiceProvider come parametro in AddResource o AddScript delegati: il framework risolve e lo inserisce automaticamente quando l'agente legge una risorsa o esegue uno script:

var distanceSkill = new AgentInlineSkill(
    name: "distance-converter",
    description: "Convert between distance units (miles and kilometers).",
    instructions: """
        Use this skill when the user asks to convert between miles and kilometers.
        1. Read the distance-table resource for conversion factors.
        2. Use the convert script to compute the result.
        """)
    .AddResource("distance-table", (IServiceProvider sp) =>
    {
        return sp.GetRequiredService<ConversionService>().GetDistanceTable();
    })
    .AddScript("convert", (double value, double factor, IServiceProvider sp) =>
    {
        return sp.GetRequiredService<ConversionService>().Convert(value, factor);
    });

Competenze basate su classi con l'inserimento delle dipendenze

Annotare i metodi con [AgentSkillResource] o [AgentSkillScript] e dichiarare un IServiceProvider parametro: il framework individua questi membri tramite reflection e inserisce automaticamente il provider di servizi:

internal sealed class WeightConverterSkill : AgentClassSkill<WeightConverterSkill>
{
    public override AgentSkillFrontmatter Frontmatter { get; } = new(
        "weight-converter",
        "Convert between weight units (pounds and kilograms).");

    protected override string Instructions => """
        Use this skill when the user asks to convert between pounds and kilograms.
        1. Read the weight-table resource for conversion factors.
        2. Use the convert script to compute the result.
        """;

    [AgentSkillResource("weight-table")]
    [Description("Lookup table of multiplication factors for weight conversions.")]
    private static string GetWeightTable(IServiceProvider serviceProvider)
    {
        return serviceProvider.GetRequiredService<ConversionService>().GetWeightTable();
    }

    [AgentSkillScript("convert")]
    [Description("Multiplies a value by a conversion factor and returns the result as JSON.")]
    private static string Convert(double value, double factor, IServiceProvider serviceProvider)
    {
        return serviceProvider.GetRequiredService<ConversionService>().Convert(value, factor);
    }
}

Suggerimento

Le competenze basate su classi possono anche risolvere le dipendenze tramite il costruttore. Registrare la classe di competenza in ServiceCollection e risolverla dal contenitore invece di chiamare new direttamente:

services.AddSingleton<WeightConverterSkill>();
var weightSkill = serviceProvider.GetRequiredService<WeightConverterSkill>();

Ciò è utile quando la classe di competenza stessa necessita di servizi inseriti oltre a ciò che usano i delegati di risorse e script.

Funzioni di risorsa e di script che accettano **kwargs ricevono automaticamente gli argomenti di parole chiave a tempo di esecuzione passati a agent.run(). In questo modo, le funzioni della competenza accedono al contesto dell'applicazione, ad esempio configurazione, identità utente o client del servizio, senza codificarli nella definizione della competenza.

Passaggio di argomenti di runtime

Passare function_invocation_kwargs a agent.run() per fornire argomenti di parole chiave inoltrati dal framework alle funzioni di risorsa e script:

response = await agent.run(
    "How many kilometers is 26.2 miles?",
    function_invocation_kwargs={"precision": 2, "user_id": "alice"},
)

Competenze definite nel codice con kwargs

Quando una funzione di risorsa dichiara **kwargs, il framework inoltra gli argomenti della parola chiave di runtime ogni volta che l'agente legge la risorsa:

import os
from typing import Any
from agent_framework import InlineSkill, SkillFrontmatter

project_info_skill = InlineSkill(
    frontmatter=SkillFrontmatter(
        name="project-info",
        description="Project status and configuration information",
    ),
    instructions="Use this skill for questions about the current project.",
)

@project_info_skill.resource(name="environment", description="Current environment configuration")
def environment(**kwargs: Any) -> str:
    """Return environment config, optionally scoped to a user."""
    user_id = kwargs.get("user_id", "anonymous")
    env = os.environ.get("APP_ENV", "development")
    return f"Environment: {env}, Caller: {user_id}"

Le funzioni delle risorse senza **kwargs vengono chiamate senza argomenti e non ricevono il contesto di runtime.

Quando una funzione script dichiara **kwargs, il framework inoltra gli argomenti dell'istanza di runtime insieme all'oggetto args fornito dall'agente.

import json
from typing import Any
from agent_framework import InlineSkill, SkillFrontmatter

converter_skill = InlineSkill(
    frontmatter=SkillFrontmatter(
        name="unit-converter",
        description="Convert between common units using a conversion factor",
    ),
    instructions="Use the convert script to perform unit conversions.",
)

@converter_skill.script(name="convert", description="Convert a value: result = value × factor")
def convert_units(value: float, factor: float, **kwargs: Any) -> str:
    """Convert a value using a multiplication factor.

    Args:
        value: The numeric value to convert (provided by the agent).
        factor: Conversion factor (provided by the agent).
        **kwargs: Runtime keyword arguments from agent.run().
    """
    precision = kwargs.get("precision", 4)
    result = round(value * factor, precision)
    return json.dumps({"value": value, "factor": factor, "result": result})

L'agente fornisce value e factor tramite la chiamata argsallo strumento . L'applicazione fornisce precision tramite function_invocation_kwargs. Funzioni script senza **kwargs ricevono solo gli argomenti forniti dall'agente.

Abilità basate su classi con kwargs

I metodi della skill basati su classe possono anche accettare **kwargs per ricevere argomenti di runtime. Il modello funziona allo stesso modo: dichiarare **kwargs nei metodi di risorsa o nei metodi di script:

from typing import Any
from agent_framework import ClassSkill, SkillFrontmatter

class WeightConverterSkill(ClassSkill):
    def __init__(self) -> None:
        super().__init__(
            frontmatter=SkillFrontmatter(
                name="weight-converter",
                description="Convert between weight units (pounds and kilograms).",
            ),
        )

    @property
    def instructions(self) -> str:
        return "Use this skill to convert between pounds and kilograms."

    @ClassSkill.resource(name="weight-table")
    def get_weight_table(self, **kwargs: Any) -> str:
        """Weight conversion factors, scoped to caller context."""
        user_id = kwargs.get("user_id", "anonymous")
        return f"Weight table for {user_id}: | lbs | kg | 0.453592 |"

    @ClassSkill.script(name="convert")
    def convert(self, value: float, factor: float, **kwargs: Any) -> str:
        """Convert a weight value."""
        import json
        precision = kwargs.get("precision", 4)
        result = round(value * factor, precision)
        return json.dumps({"value": value, "factor": factor, "result": result})

Procedure consigliate per la sicurezza

Le competenze dell'agente devono essere considerate come qualsiasi codice di terze parti inserito nel progetto. Poiché le istruzioni sulle competenze vengono inserite nel contesto dell'agente e le competenze possono includere script, l'applicazione dello stesso livello di revisione e governance a una dipendenza open source è essenziale.

  • Esaminare prima di usare: leggere tutto il contenuto delle competenze (SKILL.md, script e risorse) prima della distribuzione. Verificare che il comportamento effettivo di uno script corrisponda alla finalità dichiarata. Controllare le istruzioni antagoniste che tentano di ignorare le linee guida per la sicurezza, esfiltrare i dati o modificare i file di configurazione dell'agente.
  • Affidabilità della fonte - Installa solo skill di autori affidabili o di collaboratori interni verificati. Preferisce competenze con chiara provenienza, controllo della versione e manutenzione attiva. Guarda i nomi delle competenze digitati che simulano i pacchetti più diffusi.
  • Sandboxing - Esegui abilità che includono script eseguibili in ambienti isolati. Limitare l'accesso a livello di file system, rete e sistema solo a ciò che richiede la competenza. Richiedi conferma esplicita dell'utente prima di eseguire operazioni potenzialmente sensibili.
  • Controllo e registrazione : registrare le competenze caricate, quali risorse vengono lette e quali script vengono eseguiti. Questo consente di eseguire un audit trail risalendo al comportamento dell'agente fino al contenuto di competenza specifico, in caso di problemi.

Quando usare competenze e flussi di lavoro

I flussi di lavoro di Agent Skills e Agent Framework estendono entrambe le operazioni che gli agenti possono eseguire, ma funzionano in modi fondamentalmente diversi. Scegliere l'approccio più adatto alle proprie esigenze:

  • Controllo : con una competenza, l'intelligenza artificiale decide come eseguire le istruzioni. Questo è ideale quando vuoi che l'agente sia creativo o adattivo. Con un flusso di lavoro, si definisce in modo esplicito il percorso di esecuzione. Usare i flussi di lavoro quando è necessario un comportamento deterministico e prevedibile.
  • Resilienza - Un'abilità si esegue all'interno di un singolo turno dell'agente. Se si verifica un errore, è necessario ritentare l'intera operazione. I flussi di lavoro supportano il checkpointing, consentendo di riprendere dall'ultimo passaggio riuscito dopo un errore. Scegliere i flussi di lavoro quando il costo di riesezione dell'intero processo è elevato.
  • Effetti collaterali : le competenze sono adatte quando le operazioni sono idempotenti o a basso rischio. Preferisce i flussi di lavoro quando i passaggi producono effetti collaterali (invio di messaggi di posta elettronica, pagamenti in addebito) che non devono essere ripetuti al nuovo tentativo.
  • Complessità : le competenze sono ideali per attività incentrate su un singolo dominio che un agente può gestire. I flussi di lavoro sono più adatti per processi aziendali in più passaggi che coordinano più agenti, approvazioni umane o integrazioni di sistemi esterni.

Suggerimento

Come regola generale: se si vuole che l'intelligenza artificiale sia in grado di capire come eseguire un'attività, usare una competenza. Se è necessario garantire quali passaggi eseguire e in quale ordine, usare un flusso di lavoro.

Passaggi successivi