Agent-Fähigkeiten

Agent-Fähigkeiten sind tragbare Pakete von Anweisungen, Skripts und Ressourcen, die Agents spezielle Funktionen und Domänenkenntnisse bieten. Fähigkeiten folgen einer offenen Spezifikation und implementieren ein progressives Offenlegungsmuster, sodass Agents nur den benötigten Kontext laden, wenn sie es benötigen.

Verwenden Sie Agentenkenntnisse, wenn Sie folgendes möchten:

  • Paketdomänenkompetenz – Erfassen Sie spezielle Kenntnisse (Spesenrichtlinien, rechtliche Workflows, Datenanalysepipelinen) als wiederverwendbare, tragbare Pakete.
  • Erweitern der Agent-Funktionen – Geben Sie Agents neue Fähigkeiten, ohne ihre Kernanweisungen zu ändern.
  • Sicherstellen der Konsistenz – Umwandeln von mehrstufigen Aufgaben in wiederholbare, auditierbare Workflows.
  • Interoperabilität aktivieren – Verwenden Sie die gleichen Fähigkeiten in verschiedenen Agent-Skills-kompatiblen Produkten.

Qualifikationsstruktur

Ein Skill ist ein Verzeichnis, das eine SKILL.md-Datei mit optionalen Unterverzeichnissen für Ressourcen enthält.

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

SKILL.md Format

Die SKILL.md Datei muss YAML-Frontmatter enthalten, gefolgt von Markdowninhalten:

---
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"
---
Feld Erforderlich Description
name Ja Max. 64 Zeichen. Nur Kleinbuchstaben, Zahlen und Bindestriche. Darf nicht mit einem Bindestrich beginnen oder enden oder aufeinander folgende Bindestriche enthalten. Muss mit dem Namen des übergeordneten Verzeichnisses übereinstimmen.
description Ja Was die Fähigkeit tut und wann sie zu verwenden. Max. 1024 Zeichen. Sollte Schlüsselwörter enthalten, mit denen Agents relevante Aufgaben identifizieren können.
license Nein Lizenzname oder Verweis auf eine gebündelte Lizenzdatei.
compatibility Nein Max. 500 Zeichen. Gibt Umgebungsanforderungen an (beabsichtigtes Produkt, Systempakete, Netzwerkzugriff usw.).
metadata Nein Beliebige Schlüsselwertzuordnung für zusätzliche Metadaten.
allowed-tools Nein Durch Leerzeichen getrennte Liste der vorab genehmigten Werkzeuge, die die Fähigkeit verwenden kann. Experimentelle Unterstützung kann zwischen Agentimplementierungen variieren.

Der Markdown-Text nach dem Frontmatter enthält die Anweisungen für die Fähigkeit – schrittweise Anleitungen, Beispiele für Eingaben und Ausgaben, häufige Grenzfälle oder sonstige Inhalte, die dem Agenten bei der Erledigung der Aufgabe helfen. Halten Sie SKILL.md unter 500 Zeilen, und verschieben Sie detailliertes Referenzmaterial in separate Dateien.

Progressive Offenlegung

Agent-Fähigkeiten verwenden ein vierstufiges progressives Offenlegungsmuster, um die Kontextnutzung zu minimieren:

  1. Werben (~100 Token pro Qualifikation) – Qualifikationsnamen und Beschreibungen werden zu Beginn jeder Ausführung in die Systemaufforderung eingefügt, sodass der Agent weiß, welche Fähigkeiten verfügbar sind.
  2. Load (< empfohlen 5000 Token) – Wenn eine Aufgabe der Domäne einer Qualifikation entspricht, ruft der Agent das load_skill Tool auf, um den vollständigen SKILL.md Textkörper mit detaillierten Anweisungen abzurufen.
  3. Ressourcen lesen (nach Bedarf) – Der Agent ruft das read_skill_resource Tool auf, um ergänzende Dateien (Verweise, Vorlagen, Ressourcen) nur bei Bedarf abzurufen.
  4. Ausführen von Skripts (nach Bedarf) – Der Agent ruft das run_skill_script Tool auf, um Skripts auszuführen, die mit einer Fähigkeit gebündelt sind.

Dieses Muster sorgt dafür, dass das Kontextfenster des Agents schlanker bleibt, während er Zugriff auf umfassende Domänenkenntnisse bei Bedarf erhält.

Hinweis

load_skill wird immer beworben. read_skill_resource wird nur angekündigt, wenn mindestens eine Fähigkeit Ressourcen hat. run_skill_script wird nur beworben, wenn mindestens eine Fähigkeit Skripte hat.

Bereitstellen von Fähigkeiten für einen Agenten

Das Arbeiten mit Fähigkeiten umfasst drei Bausteine:

  • Anbieter - AgentSkillsProvider (C#) oder SkillsProvider (Python) ist ein Kontextanbieter, der Fähigkeiten für einen Agent verfügbar macht. Es kündigt die verfügbaren Fähigkeiten in der Systemaufforderung an und registriert die Tools, die der Agent zum Laden von Fähigkeiten, Lesen von Ressourcen und Ausführen von Skripts verwendet.
  • Quellen - eine Quelle liefert dem Anbieter Fähigkeiten. Fähigkeiten können aus mehreren Quelltypen stammen:
    • Dateibasiert - Fähigkeiten, die aus SKILL.md Dateien in Dateisystemverzeichnissen ermittelt wurden.
    • Im Code definiert - Fähigkeiten, die direkt im Code mit AgentInlineSkill (C#) oder InlineSkill (Python) definiert werden.
    • Kursbasiert - Fähigkeiten, die in einer Klasse gekapselt werden, die von AgentClassSkill<T> (C#) oder ClassSkill (Python) abgeleitet wird.
    • MCP-basiert - Fähigkeiten, die von MCP-Servern (Model Context Protocol) über UseMcpSkills (C#) oder MCPSkillsSource (Python) ermittelt wurden.
  • Bauherr - AgentSkillsProviderBuilder (C#) fasst mehrere Quellen zu einem einzigen Anbieter zusammen, wobei Aggregation, Deduplizierung, Zwischenspeicherung und optionale Filterung angewendet werden. Verfassen Sie in Python Quellklassen wie AggregatingSkillsSource, FilteringSkillsSourceund DeduplicatingSkillsSource direkt.

In den folgenden Abschnitten wird gezeigt, wie Sie Fähigkeiten für jeden Quelltyp erstellen und wie Sie Quellen kombinieren und einen Anbieter daraus erstellen.

Dateibasierte Fähigkeiten

Erstellen Sie ein AgentSkillsProvider-Verzeichnis, das auf ein Verzeichnis verweist, das Ihre Fähigkeiten enthält, und fügen Sie es den Kontextanbietern des Agents hinzu. Übergeben Sie einen Skriptläufer, um die Ausführung von dateibasierten Skripts zu ermöglichen, die in Qualifikationsverzeichnissen enthalten sind:

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);

Warnung

DefaultAzureCredential ist praktisch für die Entwicklung, erfordert aber sorgfältige Überlegungen in der Produktion. Berücksichtigen Sie in der Produktion die Verwendung bestimmter Anmeldeinformationen (z. B. ManagedIdentityCredential), um Latenzprobleme, unbeabsichtigte Abfragen von Anmeldeinformationen und potenzielle Sicherheitsrisiken durch Ausweichmechanismen zu vermeiden.

Mehrere Qualifikationsverzeichnisse

Sie können den Anbieter auf ein einzelnes übergeordnetes Verzeichnis verweisen – jedes Unterverzeichnis, das einen SKILL.md enthält, wird automatisch als Fähigkeit erkannt:

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

Oder übergeben Sie eine Liste von Pfaden, um mehrere Stammverzeichnisse zu durchsuchen:

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

Der Anbieter durchsucht bis zu zwei Ebenen tief.

Anpassung der Ressourcen- und Skripterkennung

Standardmäßig erkennt der Anbieter Ressourcen mit den Erweiterungen .md, .json, .yaml, .yml, .csv, .xml und .txt sowie Skripts mit den Erweiterungen .py, .js, .sh, .ps1, .cs und .csx. Es durchsucht bis zu zwei Ebenen tief in jedem Qualifikationsverzeichnis. Verwenden Sie AgentFileSkillsSourceOptions, um diese Standardeinstellungen zu ändern.

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 und ScriptFilter erhalten AgentFileSkillFilterContext mit dem Skill-Namen und dem relativen Pfad der Datei, sodass Sie Dateien nach Speicherort, Benennungskonvention oder benutzerdefinierter Logik filtern können.

Skriptausführung

Übergeben Sie SubprocessScriptRunner.RunAsync als Skriptausführung, um die Ausführung von dateibasierten Skripts zu ermöglichen:

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

SubprocessScriptRunner.RunAsync entspricht ungefähr folgendem:

// 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();
}

Der Läufer führt jedes ermittelte Skript als lokaler Unterprozess aus. Dateibasierte Skripts erwarten Argumente als JSON-Array von Zeichenfolgen – jedes Arrayelement wird zu einem positionalen Befehlszeilenargument.

Warnung

SubprocessScriptRunner wird nur zu Demonstrationszwecken bereitgestellt. Für die Verwendung in der Produktion sollten Sie Folgendes hinzufügen:

  • Sandboxing (z. B. Container oder isolierte Ausführungsumgebungen)
  • Ressourcengrenzwerte (CPU, Arbeitsspeicher, Gesamtbetrachtungstimeout)
  • Eingabeüberprüfung und Zulassungsauflistung von ausführbaren Skripts
  • Strukturierte Protokollierungen und Prüfpfade

Dateibasierte Fähigkeiten

Verwenden Sie die SkillsProvider.from_paths()-Factory, um Fähigkeiten in Verzeichnissen zu entdecken, die SKILL.md-Dateien enthalten, und fügen Sie den Anbieter zu den Kontextanbietern des Agenten hinzu:

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],
)

Mehrere Qualifikationsverzeichnisse

Sie können den Anbieter auf ein einzelnes übergeordnetes Verzeichnis verweisen – jedes Unterverzeichnis, das einen SKILL.md enthält, wird automatisch als Fähigkeit erkannt:

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

Oder übergeben Sie eine Liste von Pfaden, um mehrere Stammverzeichnisse zu durchsuchen:

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

Der Anbieter durchsucht bis zu zwei Ebenen tief.

Anpassung der Ressourcen- und Skripterkennung

Standardmäßig werden Ressourcen gemäß der references/ in den Unterverzeichnissen assets/ und scripts/ gefunden und Skripts in . Erkannte Ressourcenerweiterungen sind .md, .json, .yaml, .yml, .csv, .xml und .txt. Es durchsucht bis zu zwei Ebenen tief in jedem Qualifikationsverzeichnis. Verwenden Sie resource_extensions, script_extensions, search_depth, resource_filter und script_filter, um die Erkennung anzupassen:

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/"),
)

Die resource_filter- und script_filter-Prädikate erhalten den Namen der Fähigkeit und den relativen Pfad der Datei, sodass Sie Dateien anhand von Speicherort, Benennungskonvention oder beliebiger benutzerdefinierter Logik einschränken können. Verwenden Sie ".", um Dateien auf der Stammebene des Skills zusätzlich zu Unterverzeichnissen einzuschließen.

Skriptausführung

Um die Ausführung von dateibasierten Skripts zu aktivieren, übergeben Sie eine script_runner an SkillsProvider.from_paths(). Alle Synchronisierungs- oder asynchronen Aufrufe, die das SkillScriptRunner Protokoll erfüllen, können verwendet werden:

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,
)

Der Runner erhält die aufgelösten Argumente FileSkill, FileSkillScript sowie ein optionales args-Argument. Dateibasierte Skripts erwarten Argumente als JSON-Array von Zeichenfolgen – jedes Arrayelement wird zu einem positionalen Befehlszeilenargument. Skripts werden automatisch aus .py Dateien im scripts/ Unterverzeichnis jedes Qualifikationsverzeichnisses ermittelt.

Warnung

Der obige Läufer wird nur zu Demonstrationszwecken bereitgestellt. Für die Verwendung in der Produktion sollten Sie Folgendes hinzufügen:

  • Sandboxing (z. B. Container, seccomp, oder firejail)
  • Ressourcengrenzwerte (CPU, Arbeitsspeicher, Gesamtbetrachtungstimeout)
  • Eingabeüberprüfung und Zulassungsauflistung von ausführbaren Skripts
  • Strukturierte Protokollierungen und Prüfpfade

Hinweis

Wenn dateibasierte Skills mit Skripts bereitgestellt werden, aber script_runner nicht festgelegt ist, gibt SkillsProvider einen Fehler aus, wenn versucht wird, das Skript auszuführen.

Dateibasierte Fähigkeiten

Go-Agents unterstützen Skills über das agent/skills Paket. Die Fähigkeiten folgen dem gleichen progressiven Offenlegungsmuster: werben -> laden -> Ressourcen lesen -> Ausführen von Skripts.

Ermitteln Sie Skills aus SKILL.md-Dateien auf dem Datenträger, und registrieren Sie den Skillsanbieter als Anbieter für den Agentenkontext:

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},
    },
})

Codedefinierte Fähigkeiten

Zusätzlich zu den aus SKILL.md-Dateien ermittelten dateibasierten Fähigkeiten können Sie Fähigkeiten vollständig im Code definieren, indem Sie AgentInlineSkill verwenden. Codedefinierte Fähigkeiten sind nützlich, wenn:

  • Qualifikationsinhalte werden dynamisch generiert (z. B. lesen aus einer Datenbank oder Umgebung).
  • Sie möchten Qualifikationsdefinitionen zusammen mit dem Anwendungscode beibehalten, der sie verwendet.
  • Sie benötigen Ressourcen, die Logik zum Lesezeitpunkt ausführen, anstatt statische Dateien zu verarbeiten.
  • Qualifikationsdefinitionen müssen zur Laufzeit anhand von Daten erstellt werden, z. B. das Erstellen einer personalisierten Fähigkeit für jede Benutzersitzung basierend auf ihrer Rolle oder ihren Berechtigungen.
  • Ein Skill muss auf den Aufrufkontext (lokale Variablen, Closures) zugreifen, anstatt Dienste aus einem DI-Container aufzulösen.

Grundlegende Codekompetenz

Erstellen Sie einen AgentInlineSkill mit einem Namen, einer Beschreibung und anweisungen. Ressourcen anfügen mithilfe von .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);

Dynamische Ressourcen

Übergeben Sie einen Fabrikdelegat an .AddResource(), damit der Inhalt zur Laufzeit berechnet wird. Die Stellvertretung wird jedes Mal aufgerufen, wenn der Agent die Ressource liest:

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)");

Codedefinierte Skripts

Verwenden Sie .AddScript(), um einen Delegaten als ausführbares Skript zu registrieren. Code-definierte Skripte werden in-Prozess als direkte Stellvertretungsaufrufe ausgeführt. Es ist kein Skriptläufer erforderlich. Die eingegebenen Parameter des Delegaten werden automatisch in ein JSON-Schema konvertiert, das der Agent zum Übergeben von Argumenten verwendet:

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);

Hinweis

Um im Code definierte Fähigkeiten mit dateibasierten oder klassenbasierten Fähigkeiten in einem einzigen Anbieter zu kombinieren, verwenden Sie AgentSkillsProviderBuilder; siehe Erstellen eines Anbieters.

Zusätzlich zu dateibasierten Fähigkeiten, die aus SKILL.md-Dateien ermittelt wurden, können Sie fähigkeiten vollständig in Python Code mithilfe von InlineSkill definieren. Codedefinierte Fähigkeiten sind nützlich, wenn:

  • Qualifikationsinhalte werden dynamisch generiert (z. B. lesen aus einer Datenbank oder Umgebung).
  • Sie möchten Qualifikationsdefinitionen zusammen mit dem Anwendungscode beibehalten, der sie verwendet.
  • Sie benötigen Ressourcen, die Logik zum Lesezeitpunkt ausführen, anstatt statische Dateien zu verarbeiten.
  • Qualifikationsdefinitionen müssen zur Laufzeit anhand von Daten erstellt werden, z. B. das Erstellen einer personalisierten Fähigkeit für jede Benutzersitzung basierend auf ihrer Rolle oder ihren Berechtigungen.
  • Ein Skill muss den Status der Aufrufstelle (lokale Variablen, Closures) schließen, anstatt Dienste über **kwargs aufzulösen.

Grundlegende Codekompetenz

Erstellen Sie eine InlineSkill-Instanz mit SkillFrontmatter (das den Namen und die Beschreibung enthält) und Anweisungsinhalt. Optional fügen Sie Instanzen mit statischem Inhalt an InlineSkillResource :

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)

Dynamische Ressourcen

Verwenden Sie den @skill.resource Dekorateur, um eine Funktion als Ressource zu registrieren. Die Funktion wird jedes Mal aufgerufen, wenn der Agent die Ressource liest, sodass sie aktuelle Daten zurückgeben kann. Sowohl Synchronisierungsfunktionen als auch asynchrone Funktionen werden unterstützt:

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)"

Wenn der Dekorateur ohne Argumente verwendet wird (@skill.resource), wird der Funktionsname zum Ressourcennamen, und die Docstring wird zur Beschreibung. Hiermit @skill.resource(name="...", description="...") legen Sie sie explizit fest.

Codedefinierte Skripts

Verwenden Sie den @skill.script Dekorateur, um eine Funktion als ausführbares Skript auf einer Fähigkeit zu registrieren. Codedefinierte Skripts werden im Prozess ausgeführt und erfordern keinen Skriptläufer. Sowohl Synchronisierungsfunktionen als auch asynchrone Funktionen werden unterstützt:

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})

Wenn der Dekorateur ohne Argumente verwendet wird (@skill.script), wird der Funktionsname zum Skriptnamen, und die Docstring wird zur Beschreibung. Die eingegebenen Parameter der Funktion werden automatisch in ein JSON-Schema konvertiert, das der Agent zum Übergeben von Argumenten verwendet.

Zusätzlich zu dateibasierten Fähigkeiten, die aus SKILL.md Dateien ermittelt werden, können Sie Fähigkeiten vollständig im Go-Code definieren:

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 lädt die Skill-Anweisungen nur, wenn der Agent load_skill aufruft. Skripts erhalten positionsabhängige String-Argumente im CLI-Stil, zum Beispiel ["26.2", "1.60934"], und können diese Argumente so analysieren, wie es das Skript erfordert.

Tipp

Sehen Sie sich die Kompetenzbeispiele für vollständige Runnable-Beispiele an.

Klassenbasierte Fähigkeiten

Mit klassenbasierten Fähigkeiten können Sie alle Qualifikationskomponenten – Name, Beschreibung, Anweisungen, Ressourcen und Skripts – in einer einzigen C#-Klasse bündeln. Dies erleichtert ihnen das Verpacken und Verteilen als NuGet-Pakete – Teams können Fähigkeiten unabhängig erstellen und versenden, und Verbraucher fügen sie mit dotnet add package und einem einzigen .UseSkill() Anruf hinzu. Leiten Sie ab von AgentClassSkill<T> (wobei T Ihre Klasse ist), und annotieren Sie dann Eigenschaften mit [AgentSkillResource] sowie Methoden mit [AgentSkillScript] für die automatische Ermittlung:

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 });
    }
}

Registrieren Sie die klassenbasierten Fähigkeiten bei AgentSkillsProvider:

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

Wenn das [AgentSkillResource] Attribut auf eine Eigenschaft oder Methode angewendet wird, wird der Rückgabewert als Ressourceninhalt verwendet, wenn der Agent die Ressource liest . Verwenden Sie eine Methode, wenn der Inhalt zur Lesezeit berechnet werden muss. Wenn [AgentSkillScript] auf eine Methode angewendet wird, wird die Methode aufgerufen, wenn das Skript vom Agenten ausgeführt wird. Verwenden Sie [Description] von System.ComponentModel, um jede Ressource und jedes Skript für den Agenten zu beschreiben.

Hinweis

AgentClassSkill<T> unterstützt zudem das Überschreiben von Resources und Scripts als Sammlungen für Szenarien, in denen die attributbasierte Entdeckung nicht geeignet ist.

Klassenbasierte Fähigkeiten

Mit klassenbasierten Fähigkeiten können Sie alle Qualifikationskomponenten – Name, Beschreibung, Anweisungen, Ressourcen und Skripts – in einer einzigen Python Klasse bündeln. Dadurch lassen sie sich leicht als PyPI-Pakete paketieren und verteilen – Teams können Skills unabhängig erstellen und bereitstellen, und Nutzer fügen sie mit pip install und einem einzigen Aufruf von SkillsProvider() hinzu. Leiten Sie eine Unterklasse von ClassSkill ab und verwenden Sie dann die Dekoratoren @ClassSkill.resource und @ClassSkill.script für die automatische Erkennung:

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})

Registrieren Sie die klassenbasierten Fähigkeiten bei SkillsProvider:

from agent_framework import SkillsProvider

skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)

Wenn @ClassSkill.resource als bloßer Dekorator (ohne Argumente) verwendet wird, wird der Methodenname zum Ressourcennamen, wobei Unterstriche in Bindestriche umgewandelt werden, und der Dokumentationsstring wird zur Beschreibung. Hiermit @ClassSkill.resource(name="...", description="...") legen Sie sie explizit fest. Das gleiche Muster gilt für @ClassSkill.script.

Ressourcen können entweder als reguläre Methoden oder @property Deskriptoren definiert werden. Wenn Sie @property verwenden, setzen Sie @property an die erste Stelle und @ClassSkill.resource an die zweite Stelle. Ressourcenrückgabewerte werden nach dem ersten Zugriff zwischengespeichert.

Hinweis

ClassSkill unterstützt außerdem das explizite Überschreiben der Eigenschaften resources und scripts, sodass direkt Instanzen von InlineSkillResource und InlineSkillScript zurückgegeben werden, für Szenarien, in denen die Decorator-basierte Ermittlung nicht geeignet ist.

MCP-basierte Fähigkeiten

Hinweis

MCP-basierte Fähigkeiten erfordern das Microsoft.Agents.AI.Mcp NuGet-Paket. Die MCP-Fähigkeiten-API ist experimentell und kann sich in zukünftigen Versionen ändern.

Fähigkeiten können von MCP-Servern (Model Context Protocol) ermittelt werden, die Qualifikationsressourcen im skill:// URI-Schema verfügbar machen. Der MCP-Server kündigt Fähigkeiten über ein skill://index.json Discoverydokument an, und das Framework ruft Fähigkeiten bei Bedarf ab.

MCP-basierte Fähigkeiten unterstützen zwei Indexeintragstypen:

  • skill-md – Die SKILL.md der Skills und gleichgeordneten Ressourcen werden bei Bedarf vom MCP-Server abgerufen.
  • archive - Die Fähigkeit wird als einzelnes verpacktes Archiv (ZIP, TAR oder gzip-komprimiertes TAR) verteilt, das lokal heruntergeladen und entpackt wird.

Grundlegende Nutzung

Verwenden Sie die Erweiterungsmethode UseMcpSkills für AgentSkillsProviderBuilder, um eine Quelle für MCP-Skills hinzuzufügen:

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);

Fähigkeiten vom Typ Archiv

Verwenden Sie für Fähigkeiten vom Typ Archiv AgentMcpSkillsSourceOptions (aus dem Microsoft.Agents.AI.Mcp Paket), um das Extraktionsverhalten zu konfigurieren:

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 macht die folgenden Eigenschaften verfügbar, um die Archivextraktion zu steuern:

  • ArchiveSkillsDirectory - Basisverzeichnis für extrahierte Archive. Standardmäßig wird ein eindeutiges Unterverzeichnis im aktuellen Arbeitsverzeichnis verwendet, das für jede Quellinstanz generiert wird, um Kollisionen zwischen mehreren Quellen zu verhindern.
  • ArchiveResourceExtensions - Zulässige Erweiterungen für Ressourcen in extrahierten Archiven. Wird standardmäßig auf .md, .json, .yaml, .yml, .csv, .xml, .txt festgelegt.
  • ArchiveResourceSearchDepth – Wie tief sie innerhalb jedes extrahierten Qualifikationsverzeichnisses nach Ressourcen suchen kann. Wird standardmäßig auf 2 festgelegt.
  • ArchiveMaxFileCount - Maximale Anzahl von Dateien pro Archiv. Archive, die diesen Grenzwert überschreiten, werden übersprungen. Wird standardmäßig auf 20 festgelegt.
  • ArchiveMaxSizeBytes - Maximale Downloadgröße pro Archiv. Wird standardmäßig auf 1 MB festgelegt.
  • ArchiveMaxUncompressedSizeBytes - Maximale gesamt unkomprimierte Größe pro Archiv. Wird standardmäßig auf 1 MB festgelegt.

Important

Skripts, die in Skills vom Typ Archiv gebündelt sind, werden niemals ausgeführt. Dies ist eine bewusste Sicherheitsmaßnahme – ausführbare Inhalte von Remote-MCP-Servern erfordern explizite Vertrauensstellung.

MCP-basierte Fähigkeiten

Hinweis

MCP-basierte Fähigkeiten sind experimentell und können sich in zukünftigen Versionen ändern. Die Verwendung von MCPSkillsSource gibt unter dem Feature-Flag FutureWarning eine MCP_SKILLS aus.

Fähigkeiten können von MCP-Servern (Model Context Protocol) ermittelt werden, die Qualifikationsressourcen im skill:// URI-Schema verfügbar machen. Der MCP-Server stellt Fähigkeiten über ein skill://index.json Discovery-Dokument bereit, und das Framework ruft den SKILL.md-Inhalt jeder Fähigkeit bei Bedarf über resources/read ab.

Umschließen Sie ein MCP ClientSession mit MCPSkillsSource und übergeben Sie es an 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("...")

Hinweis

Die Python MCPSkillsSource unterstützt nur skill-md Indexeinträge (Indexeinträge eines anderen Typs werden automatisch übersprungen). Im Gegensatz zur .NET Implementierung unterstützt sie keine Archivtypfähigkeiten. Wenn skill://index.json nicht lesbar, leer oder nicht analysiert werden kann, gibt die Quelle eine leere Liste zurück.

Important

Ein externer MCP-Server steuert, welche Fähigkeitsinhalte – einschließlich Anweisungen und Skripts, die der Agent ausführen kann – den Agent erreicht. Stellen Sie nur eine Verbindung mit MCPSkillsSource Servern her, die Sie überprüft und als vertrauenswürdig eingestuft haben, und behandeln Sie deren Antworten als nicht vertrauenswürdige Eingaben.

Qualifikationsquellen

Ein AgentSkillsProvider ruft Skills aus einer oder mehreren Quellen ab – Objekte, die AgentSkillsSource implementieren. Quellen lassen sich in zwei Kategorien einteilen: Endquellen, die Fähigkeiten erkennen oder enthalten (z. B. AgentFileSkillsSource für dateibasierte Fähigkeiten), und Dekoratoren, die die Ausgabe einer anderen Quelle umwandeln (Aggregation, Deduplizierung, Zwischenspeicherung und Filterung). Sie können auch eine benutzerdefinierte Quelle erstellen.

Jede Quelle implementiert eine einzelne Methode - GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default). Die AgentSkillsSourceContext Enthält Informationen zur aktuellen Anforderung:

  • Agent - die Instanz, die AIAgent Fähigkeiten anfordert.
  • Session - das dem Aufruf zugeordnete AgentSession, oder null, wenn keine Sitzung vorhanden ist.

Dieser Kontext ist über die gesamte Quellpipeline hinweg verfügbar, sodass ein FilteringAgentSkillsSource-Prädikat oder eine benutzerdefinierte Quelle seine Logik darauf stützen kann – zum Beispiel, indem abhängig vom anfragenden Agenten ein anderer Satz an Fähigkeiten zurückgegeben wird.

Blattquellen

AgentFileSkillsSource

Ermittelt Fähigkeiten aus SKILL.md Dateien auf dem Datenträger. Akzeptiert einen oder mehrere Verzeichnispfade, einen optionalen Skriptläufer und optional AgentFileSkillsSourceOptions (dokumentiert in dateibasierten Fähigkeiten).

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

AgentInMemorySkillsSource

Kapselt AgentSkill-Instanzen (codebasiert oder klassenbasiert) im Arbeitsspeicher.

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

Kombinatoren

AggregatingAgentSkillsSource

Kombiniert mehrere Quellen in einer. Fähigkeiten werden in der Registrierungsreihenfolge ohne Deduplizierung oder Filterung zurückgegeben.

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

Dekorateure

Dekorierer umschließen eine zugrunde liegende Quelle und verändern deren Ausgabe. Sie können verkettet werden, um eine Pipeline zu erstellen.

DeduplicatingAgentSkillsSource

Entfernt doppelte Qualifikationsnamen (Groß-/Kleinschreibung, erstes Auftreten gewinnt). Duplikate werden auf Warnstufe protokolliert.

var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);

CachingAgentSkillsSource

Speichert die von der internen Quelle zurückgegebene Skill-Liste zwischen. Gleichzeitige Aufrufer werden pro Cacheschlüssel serialisiert, sodass jeweils nur ein Abruf ausgeführt wird. Akzeptiert optionales CachingAgentSkillsSourceOptions:

  • RefreshInterval (TimeSpan?) - Wenn festgelegt, laufen zwischengespeicherte Ergebnisse nach diesem Intervall ab, und die innere Quelle wird erneut aufgerufen. Wenn null (die Standardeinstellung) festgelegt ist, laufen zwischengespeicherte Ergebnisse nie ab.
  • CacheIsolationKeySelector (Func<AgentSkillsSourceContext, string?>?) - Gibt einen Cacheschlüssel zurück, um zwischengespeicherte Ergebnisse nach Kontext zu isolieren (z. B. pro Mandant). Wenn null, teilen alle Anrufer einen einzelnen Cache-Bucket.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
    RefreshInterval = TimeSpan.FromMinutes(5)
});

FilteringAgentSkillsSource

Wendet ein Prädikat an, um Fähigkeiten einzuschließen oder auszuschließen. Das Prädikat erhält den Skill und einen AgentSkillsSourceContext.

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

Benutzerdefinierte Quellen

Wenn die integrierten Quellen Ihr Szenario nicht abdecken, implementieren Sie Ihre eigenen. Unterklasse AgentSkillsSource für eine Blattquelle (eine, die Skills aus einem neuen Ursprung wie einer Datenbank oder einem Remotedienst erzeugt) oder Unterklassen DelegatingAgentSkillsSource für einen Dekorierer, der die Ausgabe einer anderen Quelle transformiert.

Blattquelle

Von AgentSkillsSource ableiten und GetSkillsAsync implementieren. Mit AgentSkillsSourceContext dem Argument kann die Quelle ihr Ergebnis auf die aktuelle Anforderung anpassen , z. B. je nach anfordernder Agent eine andere Gruppe von Fähigkeiten zurückgeben. Überschreiben Sie Dispose(bool), wenn die Quelle Ressourcen wie einen Client oder eine Verbindung verwaltet.

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);
    }
}

Benutzerdefinierter Dekorateur

Leiten Sie von DelegatingAgentSkillsSource ab, rufen Sie InnerSource.GetSkillsAsync auf und transformieren Sie das Ergebnis oder beobachten Sie es. Dies ist dasselbe Muster, das die integrierten Dekoratoren für Caching, Deduplizierung und Filterung verwenden. Beispielsweise ein Dekorateur, der erfasst, wie viele Fähigkeiten pro Anforderung zurückgegeben wurden, ohne das Ergebnis zu ändern:

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;
    }
}

Beide benutzerdefinierten Quellen können direkt an AgentSkillsProvider übergeben oder in eine größere Pipeline eingebettet werden, genau wie die integrierten Quellen.

Provider-Konstruktion

AgentSkillsProvider ist die Komponente, die Fähigkeiten einem Agenten zur Verfügung stellt. Es umschließt eine oder mehrere Quellen und registriert die load_skill, read_skill_resourceund run_skill_script Tools. Es gibt drei Möglichkeiten zum Erstellen eines:

  1. AgentSkillsProviderBuilder – fasst mehrere Skill-Typen zu einem Anbieter mit automatischer Aggregation, Deduplizierung, Zwischenspeicherung und optionalem Filtern zusammen. Am besten geeignet für Szenarien, die dateibasierte, codedefinierte, klassenbasierte und MCP-basierte Fähigkeiten kombinieren.
  2. Direkte Quellkomposition – Erstellen Sie die Quellpipeline selbst mithilfe der öffentlichen AgentSkillsSource Klassen. Es wird keine automatische Zwischenspeicherung oder Deduplizierung angewendet – Sie steuern die vollständige Pipeline. Am besten, wenn Sie die Kontrolle über die Sortierung, bedingte Logik oder das benutzerdefinierte Dekorateurverhalten benötigen.
  3. Komfortkonstruktoren – erstellen einen Provider direkt aus einem Dateipfad oder einer oder mehreren Skill-Instanzen. Wendet automatisch Deduplizierung und Zwischenspeicherung an. Am besten geeignet für Szenarien mit einer Quelle.

Verwenden von AgentSkillsProviderBuilder

Verwenden Sie AgentSkillsProviderBuilder, wenn Sie eine der folgenden benötigen:

  • Gemischte Qualifikationstypen – kombinieren Sie dateibasierte, codedefinierte (AgentInlineSkill), klassenbasierte (AgentClassSkill) und MCP-basierte Fähigkeiten in einem einzigen Anbieter.
  • Qualifikationsfilterung – Einschließen oder Ausschließen von Fähigkeiten mithilfe eines Prädikats.

Gemischte Fähigkeiten

Kombinieren Sie mehrere Fertigkeitstypen in einem Anbieter durch das Verketten von UseFileSkill, UseSkill, UseMcpSkills und 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();

Qualifikationsfilterung

Verwenden Sie UseFilter, um nur die Skills einzuschließen, die Ihren Kriterien entsprechen – zum Beispiel, um Skills aus einem freigegebenen Verzeichnis zu laden, aber experimentelle auszuschließen:

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();

Direktes Zusammenstellen von Quellen

Wenn der Generator das benötigte Steuerelement nicht anbietet, verfassen Sie Selbst Quellklassen, und übergeben Sie die resultierende Pipeline an AgentSkillsProvider. Die vollständige Liste der verfügbaren Quellen und deren Optionen finden Sie in den Qualifikationsquellen .

Im folgenden Beispiel wird eine vergleichbare Mehrquellenpipeline erstellt, Sie haben jedoch explizite Kontrolle über jeden Dekorierer:

// 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);

Hinweis

Wenn ownsSourcetrue ist, wird beim Freigeben des Providers auch die gesamte Quellpipeline freigegeben. Setzen Sie sie auf false, wenn Sie den Lebenszyklus der Quelle selbst verwalten.

Komfortkonstruktoren

Verwenden Sie für Szenarien mit einer Quelle die AgentSkillsProvider Konstruktoren direkt. Diese wenden automatisch Deduplizierung und Zwischenspeicherung an, ohne dass ein Generator oder eine manuelle Quellkomposition erforderlich ist.

Aus einem Dateipfad:

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

Aus Skill-Instanzen:

var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);

Qualifikationsquellen

Ein SkillsProvider ruft Fähigkeiten aus einer oder mehreren Quellen ab – Objekte, die von SkillsSource abgeleitet sind. Quellen lassen sich in zwei Kategorien einteilen: Endquellen, die Fähigkeiten erkennen oder enthalten (z. B. FileSkillsSource für dateibasierte Fähigkeiten), und Dekoratoren, die die Ausgabe einer anderen Quelle umwandeln (Aggregation, Deduplizierung, Zwischenspeicherung und Filterung). Sie können auch eine benutzerdefinierte Quelle erstellen.

Jede Quelle implementiert eine einzelne Methode - async def get_skills(self, context: SkillsSourceContext) -> list[Skill]. Die SkillsSourceContext Enthält Informationen zur aktuellen Anforderung:

  • agent - der Agent (SupportsAgentRun), der Kompetenzen anfordert.
  • session - das dem Aufruf zugeordnete AgentSession, oder None, wenn keine Sitzung vorhanden ist.

Dieser Kontext fließt durch die gesamte Quellpipeline, sodass ein FilteringSkillsSource Prädikat oder eine benutzerdefinierte Quelle seine Logik darauf stützen kann – zum Beispiel, um abhängig vom anfragenden Agenten eine andere Menge an Fähigkeiten zurückzugeben.

Blattquellen

  • FileSkillsSource - entdeckt Fähigkeiten von SKILL.md-Dateien auf dem Datenträger. Akzeptiert einen oder mehrere Verzeichnispfade, ein optionales script_runner sowie Erkennungsoptionen (resource_extensions, script_extensions, search_depth, resource_filter, script_filter), die in Dateibasierte Fähigkeiten dokumentiert sind.
  • InMemorySkillsSource - umschließt Skill Instanzen (codedefiniert oder klassenbasiert) im Arbeitsspeicher.
  • MCPSkillsSource - entdeckt Fähigkeiten von einem MCP-Server (siehe MCP-basierte Fähigkeiten).
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])

Kombinierer

AggregatingSkillsSource kombiniert mehrere Quellen in einer. Fähigkeiten werden in der Registrierungsreihenfolge ohne Deduplizierung oder Filterung zurückgegeben.

from agent_framework import AggregatingSkillsSource

aggregated = AggregatingSkillsSource([file_source, in_memory_source])

Dekorateure

Dekorierer umschließen eine zugrunde liegende Quelle und verändern deren Ausgabe. Sie können verkettet werden, um eine Pipeline zu erstellen.

  • DeduplicatingSkillsSource – entfernt doppelte Namen von Skills (Groß-/Kleinschreibung wird nicht beachtet, das erste Vorkommen bleibt erhalten). Duplikate werden auf Warnstufe protokolliert.
  • CachingSkillsSource - speichert die von der inneren Quelle zurückgegebene Qualifikationsliste zwischen. Gleichzeitige Aufrufer für denselben Cacheschlüssel teilen einen einzelnen In-Flight-Abruf, sodass die innere Quelle höchstens einmal pro Schlüssel abgefragt wird. Akzeptiert zwei optionale Schlüsselwortargumente:
    • refresh_interval (timedelta | None) - Bei Festlegung wird eine zwischengespeicherte Liste als veraltet behandelt, sobald sie älter als das Intervall ist, sodass der nächste Aufruf die innere Quelle erneut abfragt. Wenn None (die Standardeinstellung) festgelegt ist, laufen zwischengespeicherte Ergebnisse nie ab. Nützlich für interne Quellen, deren Fähigkeiten sich im Laufe der Prozesslebensdauer ändern, wie z. B. MCPSkillsSource.
    • cache_isolation_key_selector (Callable[[SkillsSourceContext], str | None]) - leitet einen Cacheschlüssel aus dem Kontext ab, um zwischengespeicherte Ergebnisse zu isolieren (z. B. pro Agent oder Mandant). Schlüssel sollten eine geringe Kardinalität aufweisen und stabil sein. Wenn None zurückgegeben wird (oder es None bleibt), wird ein gemeinsamer Cache-Bucket verwendet.
  • FilteringSkillsSource - wendet ein Prädikat an, um Fähigkeiten einzuschließen oder auszuschließen. Das Prädikat erhält die Fähigkeit und ein 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",
)

Benutzerdefinierte Quellen

Wenn die integrierten Quellen Ihr Szenario nicht abdecken, implementieren Sie Ihre eigenen. Unterklasse SkillsSource für eine Blattquelle (eine, die Skills aus einem neuen Ursprung wie einer Datenbank oder einem Remotedienst erzeugt) oder Unterklassen DelegatingSkillsSource für einen Dekorierer, der die Ausgabe einer anderen Quelle transformiert.

Blattquelle

Von SkillsSource ableiten und get_skills implementieren. Mit SkillsSourceContext dem Argument kann die Quelle ihr Ergebnis auf die aktuelle Anforderung anpassen , z. B. je nach anfordernder Agent eine andere Gruppe von Fähigkeiten zurückgeben:

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)

Benutzerdefinierter Dekorateur

Leiten Sie von DelegatingSkillsSource ab, rufen Sie self.inner_source.get_skills(context) auf und transformieren Sie das Ergebnis oder beobachten Sie es. Dies ist dasselbe Muster, das die integrierten Dekoratoren für Caching, Deduplizierung und Filterung verwenden. Beispielsweise ein Dekorateur, der protokolliert, wie viele Fähigkeiten pro Anforderung zurückgegeben wurden, ohne das Ergebnis zu ändern:

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

Beide benutzerdefinierten Quellen können direkt an SkillsProvider übergeben oder in eine größere Pipeline eingebettet werden, genau wie die integrierten Quellen.

Provider-Konstruktion

SkillsProvider ist die Komponente, die Fähigkeiten einem Agenten zur Verfügung stellt. Es umschließt eine oder mehrere Quellen und registriert die load_skill, read_skill_resourceund run_skill_script Tools. Es gibt drei Möglichkeiten zum Erstellen eines:

  1. Aus Skill-Instanzen – übergeben Sie eine einzelne Skill oder eine Sequenz von Skills an den Konstruktor. Am besten geeignet für codedefinierte und klassenbasierte Fähigkeiten. Wendet automatisch Deduplizierung und Zwischenspeicherung an.
  2. Aus Dateipfaden – verwenden Sie die SkillsProvider.from_paths() Factory-Methode. Am besten geeignet für dateibasierte Einzelquellenfähigkeiten. Wendet automatisch Deduplizierung und Zwischenspeicherung an.
  3. Direkte Quellkomposition – Erstellen Sie die Quellpipeline selbst mithilfe der öffentlichen SkillsSource Klassen, und übergeben Sie sie an den Konstruktor. Sie steuern die vollständige Pipeline. Am besten, wenn Sie die Kontrolle über sortierung, bedingte Logik, Zwischenspeicherungsschlüssel oder benutzerdefiniertes Dekorateurverhalten benötigen.

Aus Skill-Instanzen

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])

Aus Dateipfaden

from pathlib import Path
from agent_framework import SkillsProvider

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

Direktes Zusammenstellen von Quellen

Wenn Sie vollzugriff benötigen, verfassen Sie Quellklassen selbst, und übergeben Sie die resultierende Pipeline an SkillsProvider. Die vollständige Liste der verfügbaren Quellen und deren Optionen finden Sie in den Qualifikationsquellen .

Das folgende Beispiel erstellt eine Pipeline mit mehreren Quellen und expliziter Steuerung jedes Decorators. Im Beispiel werden Platzhalterobjekte verwendet:

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)

Important

Ein vom Aufrufer bereitgestellter SkillsSource wird unverändert verwendet: Es wird nicht automatisch dedupliziert oder in einen CachingSkillsSource eingeschlossen. Das automatische Zwischenspeichern einer kontextabhängigen Quelle in einem einzigen gemeinsam genutzten Bucket könnte dazu führen, dass die Fähigkeiten eines Agenten oder Mandanten auf einen anderen übertragen werden. Erstellen Sie DeduplicatingSkillsSource und CachingSkillsSource (optional mit cache_isolation_key_selector) selbst, wenn Sie sie benötigen. Die automatische Deduplizierung und Zwischenspeicherung gilt nur, wenn Sie Fähigkeiten oder Dateipfade direkt übergeben (Optionen 1 und 2 oben).

Gemischte Fähigkeiten

Kombinieren Sie dateibasierte, codedefinierte und klassenbasierte Fähigkeiten in einem Anbieter mithilfe von 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]),
        ])
    )
)

Qualifikationsfilterung

Verwenden Sie FilteringSkillsSource, um zu steuern, welche Fähigkeiten der Agent sieht. Das Prädikat erhält jedes Skill sowie das SkillsSourceContext und gibt True zurück, um die Fertigkeit einzubeziehen. Um beispielsweise Fähigkeiten aus einem freigegebenen Verzeichnis zu laden, aber ein experimentelles Verzeichnis auszublenden:

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",
        )
    )
)

Verhalten beim Zwischenspeichern

Standardmäßig umschließt der Builder die Quellpipeline mit einem CachingAgentSkillsSource, das die Liste der von den zugrunde liegenden Quellen zurückgegebenen Skills zwischenspeichert. Sobald die Skills für die erste Anforderung aufgelöst wurden, verwenden nachfolgende Anforderungen die zwischengespeicherte Liste wieder, ohne die Quellen erneut abfragen zu müssen. Um das Caching zu deaktivieren (z. B. während der Entwicklung, wenn sich Skill-Definitionen häufig ändern), verwenden Sie auf dem Builder DisableCaching():

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

Hinweis

Das Deaktivieren der Zwischenspeicherung ist während der Entwicklung nützlich, wenn sich Qualifikationsinhalte häufig ändern. Lassen Sie in der Produktion die Zwischenspeicherung aktiviert (Standardeinstellung), um eine bessere Leistung zu erzielen.

Verhalten beim Zwischenspeichern

Standardmäßig werden Qualifikationstools und Anweisungen nach dem ersten Build zwischengespeichert. Setzen Sie disable_caching=True, um bei jedem Aufruf einen Neuaufbau zu erzwingen:

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

disable_caching ist auch für den SkillsProvider-Konstruktor für codedefinierte und klassenbasierte Fähigkeiten verfügbar.

Um das Caching aktiviert zu lassen, aber Fähigkeiten regelmäßig neu zu erkennen (z. B. wenn sich eine dateibasierte oder MCP-Quelle während der Laufzeit des Prozesses ändert), übergeben Sie cache_refresh_interval. Der integrierte Cache wird als veraltet behandelt, sobald er älter als das Intervall ist, sodass die nächste Ausführung die Quelle erneut abfragt:

from datetime import timedelta

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

cache_refresh_interval betrifft nur den Cache, den der Provider intern erstellt (aus Skills oder Dateipfaden); sie wird ignoriert, wenn disable_caching=True, und hat keine Auswirkungen auf ein vom Aufrufer bereitgestelltes SkillsSource (stellen Sie Ihr eigenes CachingSkillsSource dafür mit einem refresh_interval selbst zusammen).

Hinweis

Das Deaktivieren der Zwischenspeicherung ist während der Entwicklung nützlich, wenn sich Qualifikationsinhalte häufig ändern. Lassen Sie in der Produktion die Zwischenspeicherung aktiviert (Standardeinstellung), um eine bessere Leistung zu erzielen.

Toolgenehmigung

Alle von AgentSkillsProvider bereitgestellten Tools (load_skill, read_skill_resource, run_skill_script) erfordern standardmäßig eine Genehmigung. Wenn ein Toolaufruf eine Genehmigung erfordert, pausiert der Agent und gibt stattdessen ein ToolApprovalRequestContent zurück, anstatt ihn sofort auszuführen. Verwenden Sie UseToolApproval Middleware mit Regeln für die automatische Genehmigung, um Aufforderungen für vertrauenswürdige Vorgänge selektiv zu umgehen:

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();

So genehmigen Sie alle Fähigkeitstools automatisch, einschließlich Skriptausführung:

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

Deaktivieren der Genehmigung für bestimmte Tools

Verwenden Sie AgentSkillsProviderOptions, um die Genehmigung für einzelne Tools zu deaktivieren und sie vollständig aus dem Genehmigungsablauf zu entfernen:

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
    });

Wenn einige Tools eine Genehmigung erfordern und andere nicht in derselben Antwort enthalten sind, ruft das Modell möglicherweise beide Typen gleichzeitig auf. Legen Sie EnableNonApprovalRequiredFunctionBypassing fest, dass genehmigungsfreie Tools sofort ausgeführt werden, während der Benutzer nur für die verbleibenden tools aufgefordert wird:

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();

Behandeln von Genehmigungsanforderungen

Wenn Tools eine Freigabe erfordern (und keine Regel zur automatischen Freigabe zutrifft), gibt der Agent ToolApprovalRequestContent Elemente zurück, die genehmigt oder abgelehnt werden müssen, bevor fortgefahren werden kann:

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();
}

Skriptfehlerdetails

Wenn die Ausführung eines Fähigkeitsskripts fehlschlägt, wird die Ausnahme standardmäßig an die zugrunde liegende FunctionInvokingChatClientDatei weitergegeben. Wenn die IncludeDetailedErrors Eigenschaft auf true festgelegt ist, wird die Ausnahmemeldung an das Modell weitergeleitet, sodass sie sich selbst korrigieren lässt, indem sie mit unterschiedlichen Argumenten erneut versucht wird:

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());

Wenn Sie nicht direkt konfigurieren FunctionInvokingChatClient können, legen Sie stattdessen fest AgentSkillsProviderOptions.IncludeDetailedErrors . Dadurch wird die Ausnahme auf Der Ebene des Kompetenzanbieters erfasst und die Fehlermeldung direkt an das Modell zurückgegeben:

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

Warnung

Beide Ansätze können dem Modell Rohdetails zu Ausnahmen offenlegen. Ausnahmemeldungen können vertrauliche Informationen wie Verbindungszeichenfolgen, Dateipfade oder interne Dienstnamen enthalten. Zusätzlich könnte ein böswillig gestaltetes Skript, wenn Skills oder Skripte aus nicht vertrauenswürdigen Quellen stammen, eine Ausnahme auslösen, deren Fehlermeldung einen Prompt-Injection-Payload enthält.

Alle von SkillsProvider bereitgestellten Tools (load_skill, read_skill_resource und run_skill_script) sind standardmäßig genehmigungspflichtig. Wenn der Aufruf eines Tools eine Genehmigung erfordert, pausiert der Agent und übermittelt Genehmigungsanfragen über result.user_input_requests, anstatt ihn sofort auszuführen. Sie genehmigen oder ablehnen jede Anforderung mit request.to_function_approval_response(approved=...) und senden die Antworten zurück:

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)

Wenn ein Toolaufruf abgelehnt wird (approved=False), wird der Agent darüber informiert, dass der Benutzer abgelehnt wurde und entsprechend reagieren kann.

Automatische Genehmigung vertrauenswürdiger Tools

Anstatt bei jedem Aufruf eine Bestätigung anzufordern, installieren Sie ToolApprovalMiddleware mit einer der statischen Auto-Genehmigungsregeln, die von SkillsProvider bereitgestellt werden. Dadurch können die Tools mit Lesezugriff automatisch ausgeführt werden, während für die Skriptausführung weiterhin eine Aufforderung angezeigt wird:

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],
)

Es stehen zwei Regeln zur Verfügung:

  • SkillsProvider.read_only_tools_auto_approval_rule – genehmigt nur die Tools mit Lesezugriff (load_skill, read_skill_resource) und fordert für run_skill_script weiterhin zur Bestätigung auf.
  • SkillsProvider.all_tools_auto_approval_rule - genehmigt jedes Qualifikationstool, einschließlich run_skill_script (keine manuelle Genehmigungsschleife erforderlich).

Beide Regeln lehnen jeden Aufruf ab, der ein server_label enthält, sodass sie auf die lokalen Tools dieses Anbieters beschränkt bleiben und niemals automatisch ein gehostetes Tool mit demselben Namen genehmigen. Die Regeln gelten nur für Tools, die noch genehmigt werden müssen – Tools, die über die unten stehenden disable_*_approval Argumente von der Genehmigungspflicht ausgenommen wurden, werden unabhängig davon ohne Genehmigung ausgeführt.

Deaktivieren der Genehmigung für bestimmte Tools

Bei vertrauenswürdigen Skills übergeben Sie disable_load_skill_approval, disable_read_skill_resource_approval und/oder disable_run_skill_script_approval, um einzelne Tools vollständig vom Genehmigungsablauf auszunehmen (sie werden mit approval_mode="never_require" registriert):

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
)

Diese Argumente sind auch auf SkillsProvider.from_paths() verfügbar.

Warnung

Deaktivieren Sie nur die Genehmigung oder die Automatische Genehmigung der Skriptausführung für Fähigkeiten und Skripts aus Quellen, die Sie vertrauen. Qualifikationsanweisungen werden in den Kontext des Agents eingefügt und run_skill_script führt Code aus, der von der Quelle bereitgestellt wird.

Benutzerdefinierte Systemaufforderung

Standardmäßig fügt der Kompetenzanbieter eine Systemaufforderung ein, die verfügbare Fähigkeiten auflistet und den Agenten anweist, diese zu nutzen sowie load_skill und read_skill_resource zu verwenden. Sie können diese Eingabeaufforderung anpassen:

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.
            """
    });

Hinweis

Die benutzerdefinierte Vorlage muss als Platzhalter für die generierte Kompetenzliste enthalten {skills} . Literale geschweifte Klammern müssen als {{ und }} maskiert werden.

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}"
    ),
)

Hinweis

Die benutzerdefinierte Vorlage muss den {skills} Platzhalter für die generierte Kompetenzliste enthalten. Es kann optional die Platzhalter {resource_instructions} (Ressourcentoolhinweis) und {runner_instructions} (Skripttoolhinweis) enthalten; wenn sie vorhanden sind, werden sie mit integrierten Hinweisen gefüllt, und wenn sie weggelassen werden, werden sie einfach nicht angezeigt (die entsprechenden Tools sind weiterhin registriert). Literale geschweifte Klammern müssen als {{ und }} maskiert werden.

Einfügen von Diensten und Laufzeitargumenten

Skill-Ressourcen- und Skriptfunktionen können externen Anwendungskontext empfangen, der zur Laufzeit bereitgestellt wird.

Skill-Ressourcen- und Skriptdelegaten können einen IServiceProvider-Parameter deklarieren, den das Agent-Framework automatisch einsetzt. Dies ermöglicht es Skills, registrierte Anwendungsdienste bei Bedarf aufzulösen.

Konfiguration

Registrieren Sie Ihre Anwendungsdienste und übergeben Sie das gebaute IServiceProvider dem Agenten über den services-Parameter:

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);

Codedefinierte Fähigkeiten mit DI

Deklarieren Sie IServiceProvider als Parameter in AddResource- oder AddScript-Delegates – das Framework löst ihn automatisch auf und fügt ihn ein, wenn der Agent eine Ressource liest oder ein Skript ausführt:

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);
    });

Klassenbasierte Skills mit DI

Kennzeichnen Sie Methoden mit [AgentSkillResource] oder [AgentSkillScript] und deklarieren Sie einen IServiceProvider-Parameter – das Framework erkennt diese Member per Reflexion und injiziert den Dienstanbieter automatisch:

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);
    }
}

Tipp

Klassenbasierte Fähigkeiten können Abhängigkeiten auch über ihren Konstruktor auflösen. Registrieren Sie den Qualifikationskurs im ServiceCollection Container, und lösen Sie ihn aus dem Container, anstatt direkt aufzurufen new :

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

Dies ist nützlich, wenn die Skillklasse selbst injektierte Dienste benötigt, die über die Verwendung der Ressourcen- und Skriptdelegaten hinausgehen.

Ressourcen- und Skriptfunktionen, die **kwargs akzeptieren, erhalten automatisch Laufzeit-Schlüsselwortargumente, die an agent.run() übergeben werden. Auf diese Weise können Skill-Funktionen auf den Anwendungskontext zugreifen – etwa auf die Konfiguration, die Benutzeridentität oder Service-Clients –, ohne diese fest in der Skill-Definition zu verankern.

Übergeben von Laufzeitargumenten

Übergeben Sie function_invocation_kwargs an agent.run(), um Schlüsselwortargumente zu übergeben, die das Framework an Ressourcen- und Skriptefunktionen weiterleitet:

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

Codedefinierte Fähigkeiten mit Kwargs

Wenn eine Ressourcenfunktion **kwargs deklariert, leitet das Framework die Laufzeitstichwortargumente jedes Mal weiter, wenn der Agent die Ressource liest.

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}"

Ressourcenfunktionen ohne **kwargs Argumente werden ohne Argumente aufgerufen und erhalten keinen Laufzeitkontext.

Wenn eine Skriptfunktion **kwargs deklariert, leitet das Framework die zur Laufzeit übergebenen Schlüsselwortargumente zusammen mit dem vom Agenten bereitgestellten args weiter.

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})

Der Agent stellt value und factor über den Toolaufruf argsbereit; die Anwendung bietet precision über function_invocation_kwargs. Skriptfunktionen ohne **kwargs erhalten nur die vom Agenten bereitgestellten Argumente.

Klassenbasierte Fähigkeiten mit kwargs

Klassenbasierte Skill-Methoden können auch **kwargs akzeptieren, um Laufzeitargumente entgegenzunehmen. Das Muster funktioniert genauso – deklarieren Sie **kwargs auf Ressourcenmethoden oder Skriptmethoden:

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})

Bewährte Methoden für die Sicherheit

Agent Skills sollten wie jeder Drittanbietercode behandelt werden, den Sie in Ihr Projekt einbringen. Da Qualifikationsanweisungen in den Kontext des Agenten eingefügt werden - und Fähigkeiten können Skripts enthalten - das gleiche Maß an Überprüfung und Governance anwenden, das Sie auf eine Open-Source-Abhängigkeit anwenden würden, ist unerlässlich.

  • Vor der Verwendung prüfen – Lesen Sie vor der Bereitstellung alle Skill-Inhalte (SKILL.md, Skripts und Ressourcen). Stellen Sie sicher, dass das tatsächliche Verhalten eines Skripts mit der angegebenen Absicht übereinstimmt. Suchen Sie nach adversarialen Anweisungen, die versuchen, Sicherheitsrichtlinien zu umgehen, Daten zu exfiltrieren oder Agentkonfigurationsdateien zu ändern.
  • Quellvertrauen – Installieren Sie nur Fähigkeiten von vertrauenswürdigen Autoren oder überprüften internen Mitwirkenden. Bevorzugen Sie Fähigkeiten mit eindeutiger Provenienz, Versionssteuerung und aktiver Wartung. Achten Sie auf Typosquatting bei Paketnamen, die beliebte Pakete nachahmen.
  • Sandboxing - Führen Sie Skills, die ausführbare Skripte enthalten, in isolierten Umgebungen aus. Beschränken Sie den Zugriff auf Dateisystem, Netzwerk und Systemebene nur auf das, was die Qualifikation erfordert. Fordern Sie eine explizite Benutzerbestätigung vor dem Ausführen potenziell vertraulicher Vorgänge an.
  • Überwachung und Protokollierung – Aufzeichnen, welche Fähigkeiten geladen werden, welche Ressourcen gelesen werden und welche Skripts ausgeführt werden. Dadurch erhalten Sie einen Überwachungspfad, um das Verhalten des Agent zurück auf bestimmte Qualifikationsinhalte zu verfolgen, wenn etwas schief geht.

Gründe für die Verwendung von Fähigkeiten im Vergleich zu Workflows

Agent Skills and Agent Framework Workflows erweitern beide, was Agents tun können, aber sie funktionieren grundsätzlich auf unterschiedliche Weise. Wählen Sie den Ansatz aus, der Ihren Anforderungen am besten entspricht:

  • Steuerung – Mit einer Fähigkeit entscheidet die KI, wie die Anweisungen ausgeführt werden. Dies ist ideal, wenn der Agent kreativ oder adaptiv sein soll. Mit einem Workflow definieren Sie explizit den Ausführungspfad. Verwenden Sie Workflows, wenn Sie deterministisches, vorhersagbares Verhalten benötigen.
  • Resilienz - Eine Fähigkeit wird innerhalb einer einzelnen Agentenrunde ausgeführt. Wenn ein Fehler auftritt, muss der gesamte Vorgang erneut ausgeführt werden. Workflows unterstützen Checkpointing, sodass sie nach einem Fehler vom letzten erfolgreichen Schritt fortgesetzt werden können. Wählen Sie Workflows aus, wenn die Kosten für die erneute Ausführung des gesamten Prozesses hoch sind.
  • Nebenwirkungen - Fähigkeiten sind geeignet, wenn Operationen idempotent oder risikoarm sind. Bevorzugen Sie Workflows, wenn Schritte Nebenwirkungen erzeugen (Senden von E-Mails, Aufladen von Zahlungen), die beim Wiederholen nicht wiederholt werden sollten.
  • Komplexität – Fähigkeiten eignen sich am besten für fokussierte Einzeldomänenaufgaben, die ein Agent verarbeiten kann. Workflows eignen sich besser für mehrstufige Geschäftsprozesse, die mehrere Agents, menschliche Genehmigungen oder integrationen externer Systeme koordinieren.

Tipp

Faustregel: Wenn Sie möchten, dass die KI herausfinden soll , wie sie eine Aufgabe erledigen kann, verwenden Sie eine Fähigkeit. Wenn Sie garantieren müssen , welche Schritte ausgeführt werden und in welcher Reihenfolge, verwenden Sie einen Workflow.

Nächste Schritte