Umiejętności agenta

Umiejętności agenta to przenośne pakiety instrukcji, skryptów i zasobów, które zapewniają agentom wyspecjalizowane możliwości i wiedzę na temat domeny. Umiejętności są zgodne z otwartą specyfikacją i implementują stopniowy wzorzec ujawniania, aby agenty ładowały tylko ten kontekst, którego potrzebują, kiedy jest to potrzebne.

Użyj umiejętności agenta, jeśli chcesz:

  • Pakietyzuj wiedzę dziedzinową — ujmij specjalistyczną wiedzę (zasady rozliczania wydatków, procesy prawne, potoki analizy danych) w postaci przenośnych pakietów wielokrotnego użytku.
  • Rozszerzanie możliwości agenta — udostępniaj agentom nowe możliwości bez zmieniania podstawowych instrukcji.
  • Zapewnianie spójności — przekształcanie zadań wieloetapowych w powtarzalne, poddawane inspekcji przepływy pracy.
  • Włącz współdziałanie — użyj ponownie tych samych umiejętności w różnych produktach zgodnych z umiejętnościami agenta.

Struktura umiejętności

Umiejętność to katalog zawierający plik SKILL.md z opcjonalnymi podkatalogami na zasoby.

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

format SKILL.md

Plik SKILL.md musi zawierać frontmatter YAML, po którym następuje zawartość języka Markdown:

---
name: expense-report
description: File and validate employee expense reports according to company policy. Use when asked about expense submissions, reimbursement rules, or spending limits.
license: Apache-2.0
compatibility: Requires python3
metadata:
  author: contoso-finance
  version: "2.1"
---
(No changes needed) Wymagane Opis
name Tak Maksymalnie 64 znaki. Tylko małe litery, cyfry i łączniki. Nie może rozpoczynać ani kończyć się łącznikiem lub zawierać kolejne łączniki. Nazwa musi odpowiadać nazwie katalogu nadrzędnego.
description Tak Co robi umiejętność i kiedy należy jej używać. Maksymalna liczba znaków: 1024. Powinny zawierać słowa kluczowe, które ułatwiają agentom identyfikowanie odpowiednich zadań.
license Nie. Nazwa licencji lub odwołanie do dołączonego pliku licencji.
compatibility Nie. Maksymalnie 500 znaków. Wskazuje wymagania dotyczące środowiska (zamierzony produkt, pakiety systemowe, dostęp sieciowy itp.).
metadata Nie. Dowolne mapowanie wartości klucza dla dodatkowych metadanych.
allowed-tools Nie. Lista zatwierdzonych narzędzi oddzielona spacjami, których może używać ta funkcja. Eksperymentalne — obsługa może się różnić w zależności od implementacji agenta.

Treść języka Markdown po frontmatterze zawiera instrukcje dotyczące umiejętności — wskazówki krok po kroku, przykłady danych wejściowych i wyjściowych, typowe przypadki brzegowe lub dowolną zawartość, która pomaga agentowi wykonać zadanie. Zachowaj SKILL.md poniżej 500 wierszy i przenieś szczegółowy materiał referencyjny do oddzielnych plików.

Stopniowe ujawnianie

Umiejętności agenta używają czteroetapowego wzorca stopniowego ujawniania, aby zminimalizować użycie kontekstu:

  1. Ogłaszanie (ok. 100 tokenów na umiejętność) — nazwy umiejętności i opisy są dodawane do promptu systemowego na początku każdego uruchomienia, dzięki czemu agent wie, jakie umiejętności są dostępne.
  2. Załaduj (< zalecane 5000 tokenów) — gdy zadanie pasuje do domeny umiejętności, agent wywołuje load_skill narzędzie, aby pobrać pełną treść SKILL.md ze szczegółowymi instrukcjami.
  3. Odczyt zasobów (zgodnie z potrzebami) — agent wywołuje read_skill_resource narzędzie w celu pobrania dodatkowych plików (odwołań, szablonów, zasobów) tylko wtedy, gdy jest to wymagane.
  4. Uruchamianie skryptów (zgodnie z potrzebami) — agent wywołuje run_skill_script narzędzie do wykonywania skryptów powiązanych z umiejętnością.

Ten wzorzec utrzymuje przychylenie okna kontekstowego agenta, jednocześnie zapewniając mu dostęp do głębokiej wiedzy o domenie na żądanie.

Uwaga / Notatka

load_skill jest zawsze reklamowany. read_skill_resource jest reklamowany tylko wtedy, gdy przynajmniej jedna umiejętność ma zasoby. run_skill_script jest reklamowany tylko wtedy, gdy co najmniej jedna umiejętność zawiera skrypty.

Zapewnianie umiejętności agentowi

Praca z umiejętnościami obejmuje trzy bloki konstrukcyjne:

  • Dostawca - AgentSkillsProvider (C#) lub SkillsProvider (Python) to dostawca kontekstu, który uwidacznia umiejętności agentowi. Anonsuje dostępne umiejętności w wierszu polecenia systemu i rejestruje narzędzia używane przez agenta do ładowania umiejętności, odczytywania zasobów i uruchamiania skryptów.
  • Źródła — źródło dostarcza umiejętności dostawcy. Umiejętności mogą pochodzić z kilku typów źródłowych:
    • Oparte na plikach — umiejętności odnalezione na podstawie SKILL.md plików w katalogach systemu plików.
    • Definiowane w kodzie — umiejętności definiowane bezpośrednio w kodzie przy użyciu AgentInlineSkill (C#) lub InlineSkill (Python).
    • Oparte na klasach — umiejętności hermetyzowane w klasie pochodzącej z AgentClassSkill<T> (C#) lub ClassSkill (Python).
    • Oparte na protokole MCP — umiejętności odnalezione na serwerach MCP (Model Context Protocol) za pośrednictwem UseMcpSkills (C#) lub MCPSkillsSource (Python).
  • Konstruktor - AgentSkillsProviderBuilder (C#) łączy wiele źródeł w jednego dostawcę, stosując agregację, deduplikację, buforowanie i opcjonalne filtrowanie. W Python utwórz klasy źródłowe, takie jak AggregatingSkillsSource, FilteringSkillsSourcei DeduplicatingSkillsSource bezpośrednio.

W poniższych sekcjach pokazano, jak tworzyć umiejętności każdego typu źródłowego, a następnie jak połączyć źródła i utworzyć od nich dostawcę.

Umiejętności oparte na plikach

Utwórz AgentSkillsProvider wskazujący na katalog zawierający twoje umiejętności i dodaj go do elementów dostarczających kontekst agenta. Przekaż moduł uruchamiający skrypt, aby umożliwić wykonywanie skryptów opartych na plikach znajdujących się w katalogach umiejętności:

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

Ostrzeżenie

DefaultAzureCredential jest wygodne do programowania, ale wymaga starannego rozważenia w środowisku produkcyjnym. W środowisku produkcyjnym rozważ użycie określonego poświadczenia (np. ManagedIdentityCredential), aby uniknąć problemów z opóźnieniami, niezamierzonego sondowania poświadczeń i potencjalnych zagrożeń bezpieczeństwa wynikających z mechanizmów awaryjnych.

Wiele katalogów umiejętności

Możesz wskazać dostawcy pojedynczy katalog nadrzędny — każdy podkatalog zawierający element SKILL.md jest automatycznie rozpoznawany jako umiejętność:

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

Możesz też przekazać listę ścieżek do wyszukiwania wielu katalogów głównych:

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

Dostawca wyszukuje do dwóch poziomów głębokości.

Dostosowywanie odnajdywania zasobów i skryptów

Domyślnie dostawca rozpoznaje zasoby z rozszerzeniami .md, , .json.yaml.yml.csv.xmli .txt i skryptami z rozszerzeniami .py, , .js.sh.ps1, , .csi ..csx Wyszukuje do dwóch poziomów głęboko w każdym katalogu umiejętności. Użyj AgentFileSkillsSourceOptions, aby zmienić te wartości domyślne:

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 i ScriptFilter otrzymują element AgentFileSkillFilterContext z nazwą umiejętności i ścieżką względną pliku, co pozwala ograniczać pliki według lokalizacji, konwencji nazewnictwa lub dowolnej własnej logiki.

Wykonywanie skryptu

Przekaż SubprocessScriptRunner.RunAsync jako moduł uruchamiający skrypty, aby umożliwić wykonywanie skryptów opartych na plikach:

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

SubprocessScriptRunner.RunAsync jest w przybliżeniu równoważne z następującymi elementami:

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

Uruchamia każdy odnaleziony skrypt jako lokalny podproces. Skrypty plikowe oczekują argumentów w postaci tablicy JSON zawierającej ciągi znaków — każdy element tablicy staje się pozycyjnym argumentem wiersza polecenia.

Ostrzeżenie

SubprocessScriptRunner jest dostarczany tylko do celów demonstracyjnych. W przypadku użycia w środowisku produkcyjnym rozważ dodanie:

  • Sandboxing (na przykład kontenery lub izolowane środowiska uruchomieniowe)
  • Limity zasobów (procesor, pamięć, limit czasu zegara)
  • Walidacja danych wejściowych i lista dozwolonych skryptów wykonywalnych
  • Rejestrowanie strukturalne i dzienniki inspekcji

Umiejętności oparte na plikach

SkillsProvider.from_paths() Użyj fabryki do odkrywania umiejętności w katalogach zawierających pliki SKILL.md i dodaj dostawcę do dostawców kontekstu agenta:

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

Wiele katalogów umiejętności

Możesz wskazać dostawcy pojedynczy katalog nadrzędny — każdy podkatalog zawierający element SKILL.md jest automatycznie rozpoznawany jako umiejętność:

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

Możesz też przekazać listę ścieżek do wyszukiwania wielu katalogów głównych:

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

Dostawca wyszukuje do dwóch poziomów głębokości.

Dostosowywanie odnajdywania zasobów i skryptów

Domyślnie zasoby są wykrywane w podkatalogach references/ i assets/, a skrypty w scripts/, zgodnie ze specyfikacją agentskills.io. Rozpoznane rozszerzenia zasobów to .md, , .json, .yaml.yml, , .csv, .xml, i .txt. Wyszukuje do dwóch poziomów głęboko w każdym katalogu umiejętności. Użyj resource_extensions, script_extensions, search_depth, resource_filter i script_filter, aby dostosować wyszukiwanie:

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

Predykaty resource_filter i script_filter otrzymują nazwę umiejętności i ścieżkę względną pliku, umożliwiając ograniczenie plików według lokalizacji, konwencji nazewnictwa lub dowolnej logiki niestandardowej. Użyj ".", aby uwzględniać pliki w katalogu głównym umiejętności, a także w podkatalogach.

Wykonywanie skryptu

Aby włączyć wykonywanie skryptów opartych na plikach, przekaż element script_runner do SkillsProvider.from_paths(). Każde synchronowe lub asynchroniczne wywołanie, które przestrzega protokołu SkillScriptRunner, można zastosować:

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

Moduł uruchamiający otrzymuje ustalone argumenty FileSkill, FileSkillScript oraz opcjonalny argument args. Skrypty plikowe oczekują argumentów w postaci tablicy JSON zawierającej ciągi znaków — każdy element tablicy staje się pozycyjnym argumentem wiersza polecenia. Skrypty są automatycznie wykrywane w plikach .py w podkatalogu scripts/ każdego katalogu umiejętności.

Ostrzeżenie

Powyższy biegacz jest dostarczany tylko do celów demonstracyjnych. W przypadku użycia w środowisku produkcyjnym rozważ dodanie:

  • Sandboxing (na przykład kontenery, seccomp, lub firejail)
  • Limity zasobów (procesor, pamięć, limit czasu zegara)
  • Walidacja danych wejściowych i lista dozwolonych skryptów wykonywalnych
  • Rejestrowanie strukturalne i dzienniki inspekcji

Uwaga / Notatka

Jeśli podano umiejętności oparte na plikach zawierających skrypty, ale nie ustawiono elementu script_runner, element SkillsProvider zgłasza błąd podczas próby wykonania skryptu.

Umiejętności oparte na plikach

Agenty Go obsługują umiejętności za pomocą pakietu agent/skills. Umiejętności są zgodne z tym samym schematem stopniowego ujawniania: ogłaszanie -> ładowanie -> odczytywanie zasobów -> uruchamianie skryptów.

Odkryj umiejętności z plików SKILL.md na dysku i zarejestruj dostawcę umiejętności jako dostawcę kontekstu agenta:

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

Umiejętności zdefiniowane w kodzie

Oprócz umiejętności opartych na plikach odkrytych z plików SKILL.md, można definiować umiejętności w całości w kodzie za pomocą AgentInlineSkill. Umiejętności zdefiniowane w kodzie są przydatne, gdy:

  • Zawartość umiejętności jest generowana dynamicznie (na przykład odczyt z bazy danych lub środowiska).
  • Chcesz zachować definicje umiejętności obok kodu aplikacji, który z nich korzysta.
  • Potrzebujesz zasobów, które wykonują logikę w czasie odczytu, zamiast obsługiwać pliki statyczne.
  • Definicje umiejętności muszą być tworzone w czasie wykonywania na podstawie danych — na przykład utworzenie spersonalizowanej umiejętności dla każdej sesji użytkownika na podstawie ich roli lub uprawnień.
  • Umiejętność musi zamknąć stan lokacji wywołania (zmienne lokalne, zamknięcia) zamiast rozwiązywać usługi z kontenera DI.

Podstawowa umiejętność kodowania

Utwórz element AgentInlineSkill z nazwą, opisem i instrukcjami. Dołączanie zasobów przy użyciu polecenia .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);

Zasoby dynamiczne

Pl-PL: Przekaż delegata fabryki do .AddResource(), aby obliczyć zawartość w czasie wykonywania. Delegat jest wywoływany za każdym razem, gdy agent odczytuje zasób:

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

Skrypty zdefiniowane za pomocą kodu

Służy .AddScript() do rejestrowania delegata jako skryptu wykonywalnego. Skrypty zdefiniowane w kodzie są uruchamiane wewnątrz procesu jako bezpośrednie wywołania delegatów. Nie jest wymagany moduł uruchamiający skrypty. Parametry wpisane przez delegata są automatycznie konwertowane na schemat JSON używany przez agenta do przekazywania argumentów:

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

Uwaga / Notatka

Aby połączyć umiejętności zdefiniowane przez kod z umiejętnościami opartymi na plikach lub opartych na klasach w jednym dostawcy, użyj polecenia AgentSkillsProviderBuilder — zobacz Konstruowanie dostawcy.

Oprócz umiejętności opartych na plikach wykrywanych z plików SKILL.md można definiować umiejętności w całości w kodzie Python przy użyciu InlineSkill. Umiejętności zdefiniowane w kodzie są przydatne, gdy:

  • Zawartość umiejętności jest generowana dynamicznie (na przykład odczyt z bazy danych lub środowiska).
  • Chcesz zachować definicje umiejętności obok kodu aplikacji, który z nich korzysta.
  • Potrzebujesz zasobów, które wykonują logikę w czasie odczytu, zamiast obsługiwać pliki statyczne.
  • Definicje umiejętności muszą być tworzone w czasie wykonywania na podstawie danych — na przykład utworzenie spersonalizowanej umiejętności dla każdej sesji użytkownika na podstawie ich roli lub uprawnień.
  • Funkcja musi przechwytywać stan miejsca wywołania (zmienne lokalne, domknięcia), zamiast uzyskiwać usługi za pośrednictwem **kwargs.

Podstawowa umiejętność kodowania

Utwórz instancję InlineSkill z elementem SkillFrontmatter (zawierającym nazwę i opis) oraz treścią instrukcji. Opcjonalnie dołącz wystąpienia InlineSkillResource z zawartością statyczną.

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)

Zasoby dynamiczne

Użyj dekoratora @skill.resource , aby zarejestrować funkcję jako zasób. Funkcja jest wywoływana za każdym razem, gdy agent odczytuje zasób, dzięki czemu może zwrócić aktualne dane. Obsługiwane są zarówno funkcje synchronizacji, jak i asynchroniczne:

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

Gdy dekorator jest używany bez argumentów (@skill.resource), nazwa funkcji staje się nazwą zasobu, a dokument staje się opisem. Użyj polecenia @skill.resource(name="...", description="...") , aby jawnie je ustawić.

Skrypty zdefiniowane za pomocą kodu

Użyj dekoratora @skill.script, aby zarejestrować funkcję jako skrypt wykonywalny w umiejętności. Skrypty zdefiniowane przez kod są uruchamiane w procesie i nie wymagają modułu uruchamiającego skrypty. Obsługiwane są zarówno funkcje synchronizacji, jak i asynchroniczne:

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

Gdy dekorator jest używany bez argumentów (@skill.script), nazwa funkcji staje się nazwą skryptu, a dokument staje się opisem. Parametry typizowane funkcji są automatycznie konwertowane na schemat JSON używany przez agenta do przekazywania argumentów.

Oprócz umiejętności opartych na plikach wykrytych w plikach SKILL.md możesz definiować umiejętności bezpośrednio w kodzie Go:

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

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

GetContent ładuje instrukcje umiejętności tylko wtedy, gdy agent wywołuje polecenie load_skill. Skrypty otrzymują pozycyjne argumenty tekstowe w stylu CLI, na przykład ["26.2", "1.60934"], i mogą analizować te argumenty w dowolny sposób wymagany przez skrypt.

Wskazówka

Zobacz przykłady umiejętności, aby uzyskać kompletne przykłady do uruchomienia.

Umiejętności oparte na klasie

Umiejętności oparte na klasach umożliwiają łączenie wszystkich składników umiejętności — nazwy, opisu, instrukcji, zasobów i skryptów — w jedną klasę języka C#. Dzięki temu można je łatwo pakować i dystrybuować jako pakiety NuGet — zespoły mogą niezależnie tworzyć i publikować skille, a użytkownicy mogą je dodawać za pomocą dotnet add package i pojedynczego wywołania .UseSkill(). Od dziedziczenia z AgentClassSkill<T> (gdzie T jest twoją klasą), następnie dodaj adnotacje do właściwości za pomocą [AgentSkillResource] i metod za pomocą [AgentSkillScript] dla automatycznego odnajdowania:

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

Zarejestruj umiejętności oparte na klasie za pomocą polecenia AgentSkillsProvider:

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

[AgentSkillResource] Gdy atrybut jest stosowany do właściwości lub metody, jego wartość zwracana jest używana jako zawartość zasobu, gdy agent odczytuje zasób — użyj metody, gdy zawartość musi być obliczana w czasie odczytu. Kiedy [AgentSkillScript] jest zastosowany do metody, metoda jest wywoływana, gdy agent uruchamia skrypt. Użyj polecenia [Description] , System.ComponentModel aby opisać każdy zasób i skrypt dla agenta.

Uwaga / Notatka

AgentClassSkill<T>Obsługuje również zastępowanie Resources i Scripts jako kolekcji w scenariuszach, w których odnajdywanie oparte na atrybutach nie pasuje.

Umiejętności oparte na klasie

Umiejętności oparte na klasach umożliwiają łączenie wszystkich składników umiejętności — nazwy, opisu, instrukcji, zasobów i skryptów — w jedną klasę Python. Dzięki temu można je łatwo pakować i dystrybuować jako pakiety PyPI — zespoły mogą niezależnie tworzyć i dostarczać umiejętności, a użytkownicy mogą je dodawać za pomocą pip install oraz pojedynczego wywołania SkillsProvider(). Utwórz klasę pochodną z ClassSkill, a następnie użyj dekoratorów @ClassSkill.resource i @ClassSkill.script do automatycznego wykrywania:

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

Zarejestruj umiejętności oparte na klasie za pomocą polecenia SkillsProvider:

from agent_framework import SkillsProvider

skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)

Gdy @ClassSkill.resource jest użyty jako samodzielny dekorator (bez argumentów), nazwa metody staje się nazwą zasobu (z podkreśleniami zamienionymi na łączniki), a docstring staje się opisem. Użyj polecenia @ClassSkill.resource(name="...", description="...") , aby jawnie je ustawić. Ten sam wzorzec ma zastosowanie do @ClassSkill.script.

Zasoby można zdefiniować jako zwykłe metody lub @property deskryptory. Używając @property, umieść najpierw @property, a następnie @ClassSkill.resource. Wartości zwracanych zasobów są buforowane po pierwszym dostępie.

Uwaga / Notatka

ClassSkill obsługuje również jawne przesłanianie właściwości resources i scripts, aby bezpośrednio zwracać instancje InlineSkillResource i InlineSkillScript w scenariuszach, w których wykrywanie oparte na dekoratorach się nie sprawdza.

Umiejętności oparte na programie MCP

Uwaga / Notatka

Umiejętności oparte na MCP wymagają pakietu Microsoft.Agents.AI.Mcp NuGet. Interfejs API umiejętności MCP ma charakter eksperymentalny i może ulec zmianie w przyszłych wersjach.

Umiejętności można wykrywać na serwerach MCP (Model Context Protocol), które udostępniają zasoby umiejętności w schemacie URI skill://. Serwer MCP udostępnia informacje o umiejętnościach za pośrednictwem dokumentu wykrywania skill://index.json, a framework pobiera treść umiejętności na żądanie.

Umiejętności oparte na protokole MCP obsługują dwa typy pozycji indeksu:

  • skill-md — Zasób SKILL.md umiejętności i powiązane z nim zasoby są pobierane na żądanie z serwera MCP.
  • archive — Umiejętność jest dystrybuowana jako pojedyncze archiwum pakietu (ZIP, TAR lub TAR skompresowane gzipem), które jest pobierane i rozpakowywane lokalnie.

Podstawowy sposób użycia

Użyj metody rozszerzenia UseMcpSkills na AgentSkillsProviderBuilder, aby dodać źródło umiejętności MCP:

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

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

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

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

Umiejętności dotyczące typów archiwum

W przypadku umiejętności typu archiwum użyj AgentMcpSkillsSourceOptions (z pakietu Microsoft.Agents.AI.Mcp), aby skonfigurować sposób wyodrębniania:

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 udostępnia następujące właściwości do kontrolowania ekstrakcji archiwum:

  • ArchiveSkillsDirectory - Katalog podstawowy dla wyodrębnionych archiwów. Domyślnie używany jest unikalny podkatalog w bieżącym katalogu roboczym, generowany dla każdego wystąpienia źródła, aby zapobiec kolizjom między wieloma źródłami.
  • ArchiveResourceExtensions - Dozwolone rozszerzenia dla zasobów w wyodrębnionych archiwach. Domyślnie: .md, .json, .yaml, .yml, .csv, .xml, .txt.
  • ArchiveResourceSearchDepth - Jak głęboko wyszukiwać zasoby w każdym wyodrębnionym katalogu umiejętności. Wartość domyślna to 2.
  • ArchiveMaxFileCount - Maksymalna liczba plików na archiwum. Archiwa przekraczające ten limit są pomijane. Wartość domyślna to 20.
  • ArchiveMaxSizeBytes - Maksymalny rozmiar pobierania dla archiwum. Wartość domyślna to 1 MB.
  • ArchiveMaxUncompressedSizeBytes - Maksymalny całkowity nieskompresowany rozmiar na archiwum. Wartość domyślna to 1 MB.

Important

Skrypty powiązane z umiejętnościami typu archiwum nigdy nie są wykonywane. Jest to celowa miara zabezpieczeń — zawartość wykonywalna ze zdalnych serwerów MCP wymaga jawnego zaufania.

Umiejętności oparte na programie MCP

Uwaga / Notatka

Umiejętności oparte na programie MCP są eksperymentalne i mogą ulec zmianie w przyszłych wersjach. Użycie MCPSkillsSource emituje element FutureWarning pod flagą MCP_SKILLS funkcji.

Umiejętności można wykrywać na serwerach MCP (Model Context Protocol), które udostępniają zasoby umiejętności w schemacie URI skill://. Serwer MCP udostępnia informacje o umiejętnościach za pośrednictwem dokumentu wykrywania skill://index.json, a framework pobiera na żądanie treść SKILL.md każdej umiejętności przez resources/read.

Owiń MCP ClientSession w MCPSkillsSource i przekaż go do 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("...")

Uwaga / Notatka

MCPSkillsSource Python obsługuje tylko skill-md elementy indeksu (elementy indeksu dowolnego innego typu są pomijane bez powiadomienia). W przeciwieństwie do implementacji .NET nie obsługuje umiejętności typu archiwum. Jeśli skill://index.json jest nieobecny, nieczytelny, pusty lub nie można przeanalizować, źródło zwraca pustą listę.

Important

Zewnętrzny serwer MCP kontroluje, jaka treść umiejętności — w tym instrukcje i skrypty, które agent może uruchamiać — trafia do agenta. Łącz się tylko z serwerami MCPSkillsSource, które zostały przez Ciebie zweryfikowane i którym ufasz, a ich odpowiedzi traktuj jako niezaufane dane wejściowe.

Źródła umiejętności

AgentSkillsProvider pobiera umiejętności z jednego lub większej liczby źródeł — obiektów implementujących AgentSkillsSource. Źródła dzielą się na dwie kategorie: źródła końcowe, które odkrywają lub zawierają umiejętności (na przykład AgentFileSkillsSource w przypadku umiejętności opartych na plikach), oraz dekoratory, które przekształcają dane wyjściowe innego źródła (agregacja, deduplikacja, buforowanie i filtrowanie). Możesz również utworzyć źródło niestandardowe.

Każde źródło implementuje jedną metodę — GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default). Element AgentSkillsSourceContext zawiera informacje o bieżącym żądaniu:

  • Agent — instancja AIAgent żądająca umiejętności.
  • SessionAgentSession powiązane z wywołaniem lub null, gdy nie ma sesji.

Ten kontekst jest dostępny w całym potoku źródłowym, więc predykat FilteringAgentSkillsSource lub niestandardowe źródło mogą opierać na nim swoją logikę — na przykład zwracać inny zestaw umiejętności w zależności od agenta wysyłającego żądanie.

Źródła liści

AgentFileSkillsSource

Wykrywa umiejętności z plików SKILL.md na dysku. Akceptuje jedną lub więcej ścieżek katalogów, opcjonalny program uruchamiający skrypty oraz opcjonalny AgentFileSkillsSourceOptions (opisany w sekcji Umiejętności oparte na plikach).

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

AgentInMemorySkillsSource

Zawija AgentSkill wystąpienia (zdefiniowane kodowo lub oparte na klasach) w pamięci.

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

Kombinatory

AggregatingAgentSkillsSource

Łączy wiele źródeł w jeden. Umiejętności są zwracane w kolejności rejestracji bez zastosowania deduplikacji ani filtrowania.

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

Decorators

Dekoratory owijają źródło wewnętrzne i przekształcają jego dane wyjściowe. Można je połączyć w łańcuch w celu utworzenia potoku.

DeduplicatingAgentSkillsSource

Usuwa zduplikowane nazwy umiejętności (bez uwzględniania wielkości liter, pierwsze wystąpienie wygrywa). Duplikaty są rejestrowane na poziomie ostrzeżenia.

var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);

CachingAgentSkillsSource

Buforuje listę umiejętności zwracaną przez źródło wewnętrzne. Równoczesne wywołania są szeregowane osobno dla każdego klucza pamięci podręcznej, dzięki czemu naraz wykonywane jest tylko jedno pobranie. Akceptuje opcjonalne:CachingAgentSkillsSourceOptions

  • RefreshInterval (TimeSpan?) — po ustawieniu buforowane wyniki wygasają po tym interwale, a źródło wewnętrzne zostanie ponownie wywołane. Gdy null (wartość domyślna), buforowane wyniki nigdy nie wygasają.
  • CacheIsolationKeySelector (Func<AgentSkillsSourceContext, string?>?) - zwraca klucz pamięci podręcznej, aby oddzielić wyniki zapisane w pamięci podręcznej ze względu na kontekst (na przykład dla każdego dzierżawcy). Gdy nullwszystkie osoby wywołujące współużytkują pojedynczy zasobnik pamięci podręcznej.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
    RefreshInterval = TimeSpan.FromMinutes(5)
});

FilteringAgentSkillsSource

Stosuje predykat do dołączania lub wykluczania umiejętności. Predykat otrzymuje umiejętności i .AgentSkillsSourceContext

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

Źródła niestandardowe

Jeśli wbudowane źródła nie obejmują twojego scenariusza, zaimplementuj własne. Utwórz klasę pochodną AgentSkillsSource dla źródła końcowego (takiego, które tworzy umiejętności z nowego źródła, takiego jak baza danych lub usługa zdalna) albo utwórz klasę pochodną DelegatingAgentSkillsSource dla dekoratora, który przekształca wyniki innego źródła.

Źródło liścia

Dziedzicz po AgentSkillsSource i zaimplementuj GetSkillsAsync. Argument AgentSkillsSourceContext pozwala źródłu dostosować wynik do aktualnego żądania — na przykład na zwrócenie innego zestawu umiejętności w zależności od agenta wysyłającego żądanie. Zastąpić Dispose(bool) , jeśli źródło jest właścicielem zasobów, takich jak klient lub połączenie.

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

Dekorator niestandardowy

Dziedzicz po DelegatingAgentSkillsSource, wywołaj InnerSource.GetSkillsAsync i przekształć lub obserwuj wynik. Jest to ten sam wzorzec używany przez wbudowane dekoratory buforowania, deduplikacji i filtrowania. Na przykład dekorator rejestrujący liczbę zwróconych umiejętności na żądanie bez zmiany wyniku:

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

Oba niestandardowe źródła można przekazywać bezpośrednio do AgentSkillsProvider lub zagnieżdżać w większym potoku, podobnie jak źródła wbudowane.

Budowa dostawcy

AgentSkillsProvider to składnik, który uwidacznia umiejętności agenta. Opakowuje co najmniej jedno źródło i rejestruje narzędzia load_skill, read_skill_resource i run_skill_script. Istnieją trzy sposoby tworzenia jednego:

  1. AgentSkillsProviderBuilder — łączy wiele typów umiejętności w jednego dostawcę z automatyczną agregacją, deduplikacją, buforowaniem i opcjonalnym filtrowaniem. Najlepsze rozwiązanie do scenariuszy łączących umiejętności oparte na plikach, definiowane w kodzie, oparte na klasach i na MCP.
  2. Kompozycja źródła bezpośredniego — samodzielnie skonstruuj potok źródłowy przy użyciu klas publicznych AgentSkillsSource . Nie zastosowano automatycznego buforowania ani deduplikacji — kontrolujesz pełny potok. Najlepiej, gdy potrzebujesz kontroli nad kolejnością, logiką warunkową lub niestandardowym zachowaniem dekoratora.
  3. Konstruktory pomocnicze — tworzą dostawcę bezpośrednio na podstawie ścieżki pliku lub instancji umiejętności. Automatycznie stosuje deduplikację i buforowanie. Najlepsze w przypadku scenariuszy z jednym źródłem.

Korzystanie z AgentSkillsProviderBuilder

Użyj AgentSkillsProviderBuilder, jeśli potrzebujesz dowolnego z następujących:

  • Typy umiejętności mieszanych — łączenie umiejętności opartych na plikach, zdefiniowanych w kodzie (AgentInlineSkill), opartych na klasach (AgentClassSkill) i opartych na programie MCP umiejętności w jednym dostawcy.
  • Filtrowanie umiejętności — dołączanie lub wykluczanie umiejętności przy użyciu predykatu.

Mieszane typy umiejętności

Połącz wiele typów umiejętności u jednego dostawcy, łącząc szeregowo UseFileSkill, UseSkill, UseMcpSkills i 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();

Filtrowanie umiejętności

Użyj UseFilter, aby uwzględnić tylko umiejętności spełniające Twoje kryteria — na przykład aby załadować umiejętności z udostępnionego katalogu, ale wykluczyć te eksperymentalne:

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

Bezpośrednie tworzenie źródeł

Gdy kreator nie oferuje potrzebnego elementu sterującego, samodzielnie utwórz klasy źródła i przekaż utworzony potok do AgentSkillsProvider. Zobacz Źródła umiejętności , aby uzyskać pełną listę dostępnych źródeł i ich opcji.

Poniższy przykład tworzy porównywalny potok wieloźródłowy, ale zapewnia jawną kontrolę nad każdym dekoratorem:

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

Uwaga / Notatka

Gdy ownsSource ma wartość true, usunięcie dostawcy powoduje również zwolnienie całego potoku źródłowego. Ustaw ją na false, jeśli samodzielnie zarządzasz cyklem życia źródła.

Konstruktory wygody

W przypadku scenariuszy z jednym źródłem użyj bezpośrednio konstruktorów AgentSkillsProvider. Automatycznie stosują deduplikację i buforowanie bez konieczności użycia buildera ani ręcznego składania źródeł.

Ze ścieżki pliku:

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

Z instancji umiejętności:

var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);

Źródła umiejętności

SkillsProvider pobiera skille z jednego lub większej liczby źródeł — obiektów dziedziczących po SkillsSource. Źródła dzielą się na dwie kategorie: źródła końcowe, które odkrywają lub zawierają umiejętności (na przykład FileSkillsSource w przypadku umiejętności opartych na plikach), oraz dekoratory, które przekształcają dane wyjściowe innego źródła (agregacja, deduplikacja, buforowanie i filtrowanie). Możesz również utworzyć źródło niestandardowe.

Każde źródło implementuje jedną metodę — async def get_skills(self, context: SkillsSourceContext) -> list[Skill]. Element SkillsSourceContext zawiera informacje o bieżącym żądaniu:

  • agent — agent (SupportsAgentRun) wnioskujący o umiejętności.
  • sessionAgentSession powiązane z wywołaniem lub None, gdy nie ma sesji.

Ten kontekst przepływa przez cały potok źródłowy, więc predykat FilteringSkillsSource lub niestandardowe źródło może opierać na nim swoją logikę — na przykład zwracając inny zestaw umiejętności w zależności od agenta wysyłającego żądanie.

Źródła liści

  • FileSkillsSource — wykrywa umiejętności z plików SKILL.md na dysku. Akceptuje co najmniej jedną ścieżkę katalogu, opcjonalne script_runner oraz opcje odkrywania (resource_extensions, script_extensions, search_depth, resource_filter, script_filter) opisane w sekcji Umiejętności oparte na plikach.
  • InMemorySkillsSource — opakowuje Skill wystąpienia (zdefiniowane kodowo lub oparte na klasach) w pamięci.
  • MCPSkillsSource - odkrywa umiejętności z serwera MCP (zobacz umiejętności oparte na MCP).
from pathlib import Path
from agent_framework import FileSkillsSource, InMemorySkillsSource

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

Kombinator

AggregatingSkillsSource łączy wiele źródeł w jeden. Umiejętności są zwracane w kolejności rejestracji bez zastosowania deduplikacji ani filtrowania.

from agent_framework import AggregatingSkillsSource

aggregated = AggregatingSkillsSource([file_source, in_memory_source])

Decorators

Dekoratory owijają źródło wewnętrzne i przekształcają jego dane wyjściowe. Można je połączyć w łańcuch w celu utworzenia potoku.

  • DeduplicatingSkillsSource — usuwa zduplikowane nazwy umiejętności (bez uwzględniania wielkości liter, pierwsze wystąpienie wygrywa). Duplikaty są rejestrowane na poziomie ostrzeżenia.
  • CachingSkillsSource — buforuje listę umiejętności zwracaną przez źródło wewnętrzne. Równoczesne wywołania dla tego samego klucza pamięci podręcznej współdzielą jedno trwające pobieranie, więc wewnętrzne źródło jest odpytywane co najwyżej raz dla każdego klucza. Akceptuje dwa opcjonalne argumenty słów kluczowych:
    • refresh_interval (timedelta | None) — po ustawieniu buforowana lista jest traktowana jako nieaktualna, gdy jest starsza niż interwał, więc następne wywołanie ponownie wysyła zapytanie do źródła wewnętrznego. Gdy None (wartość domyślna), buforowane wyniki nigdy nie wygasają. Przydatne dla źródeł wewnętrznych, których możliwości zmieniają się w trakcie trwania procesu, takich jak MCPSkillsSource.
    • cache_isolation_key_selector (Callable[[SkillsSourceContext], str | None]) — wyprowadza klucz pamięci podręcznej z kontekstu, aby odizolować wyniki zapisane w pamięci podręcznej (na przykład dla agenta lub dzierżawcy). Klucze powinny mieć małą liczbę unikalnych wartości i być stabilne. Zwrócenie None (lub pozostawienie go jako None) powoduje użycie jednego współdzielonego zasobnika pamięci podręcznej.
  • FilteringSkillsSource - stosuje predykat do dołączania lub wykluczania umiejętności. Predykat otrzymuje umiejętności i : SkillsSourceContextCallable[[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",
)

Źródła niestandardowe

Jeśli wbudowane źródła nie obejmują twojego scenariusza, zaimplementuj własne. Utwórz klasę pochodną SkillsSource dla źródła końcowego (takiego, które tworzy umiejętności z nowego źródła, takiego jak baza danych lub usługa zdalna) albo utwórz klasę pochodną DelegatingSkillsSource dla dekoratora, który przekształca wyniki innego źródła.

Źródło liścia

Dziedzicz po SkillsSource i zaimplementuj get_skills. Argument SkillsSourceContext pozwala źródłu dostosować swój wynik do bieżącego żądania — na przykład zwracając inny zestaw umiejętności w zależności od agenta wysyłającego żądanie:

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)

Dekorator niestandardowy

Dziedzicz po DelegatingSkillsSource, wywołaj self.inner_source.get_skills(context) i przekształć lub obserwuj wynik. Jest to ten sam wzorzec używany przez wbudowane dekoratory buforowania, deduplikacji i filtrowania. Na przykład dekorator rejestrujący liczbę zwróconych umiejętności na żądanie bez zmiany wyniku:

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

Oba niestandardowe źródła można przekazywać bezpośrednio do SkillsProvider lub zagnieżdżać w większym potoku, podobnie jak źródła wbudowane.

Budowa dostawcy

SkillsProvider to składnik, który uwidacznia umiejętności agenta. Opakowuje co najmniej jedno źródło i rejestruje narzędzia load_skill, read_skill_resource i run_skill_script. Istnieją trzy sposoby tworzenia jednego:

  1. Na podstawie instancji umiejętności — przekaż do konstruktora pojedynczą Skill lub sekwencję umiejętności. Najlepsze dla umiejętności zdefiniowanych w kodzie i opartych na klasie. Automatycznie stosuje deduplikację i buforowanie.
  2. Z ścieżek plików — użyj elementu SkillsProvider.from_paths() factory. Najlepsze dla umiejętności opartych na plikach z jednym źródłem. Automatycznie stosuje deduplikację i buforowanie.
  3. Bezpośrednia kompozycja źródła — samodzielnie skonstruuj potok źródłowy przy użyciu klas publicznych SkillsSource i przekaż go do konstruktora. Kontrolujesz cały potok przetwarzania. Najlepiej, gdy potrzebujesz kontroli nad kolejnością, logiką warunkową, kluczami buforowania lub zachowaniem niestandardowego dekoratora.

Z wystąpień umiejętności

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

Ze ścieżek plików

from pathlib import Path
from agent_framework import SkillsProvider

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

Bezpośrednie tworzenie źródeł

Gdy potrzebujesz pełnej kontroli, samodzielnie utwórz klasy źródłowe i przekaż powstały potok do SkillsProvider. Zobacz Źródła umiejętności , aby uzyskać pełną listę dostępnych źródeł i ich opcji.

Poniższy przykład tworzy potok wieloźródłowy z jawną kontrolą nad każdym dekoratorem. W przykładzie użyto obiektów zastępczych:

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

Dostarczony przez wywołującego SkillsSource jest używany w niezmienionej postaci: nie jest automatycznie usuwany jako duplikat ani opakowywany w CachingSkillsSource. Automatyczne buforowanie źródła uwzględniającego kontekst we wspólnym zasobniku może spowodować użycie umiejętności jednego agenta lub dzierżawcy u innego. Skomponuj DeduplicatingSkillsSource i CachingSkillsSource (opcjonalnie z cache_isolation_key_selector) samodzielnie, gdy ich potrzebujesz. Automatyczna deduplikacja i buforowanie ma zastosowanie tylko wtedy, gdy przekazujesz umiejętności lub ścieżki plików bezpośrednio (opcje 1 i 2 powyżej).

Mieszane typy umiejętności

Połącz umiejętności oparte na plikach, zdefiniowane w kodzie i oparte na klasach w jednym dostawcy za pomocą 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]),
        ])
    )
)

Filtrowanie umiejętności

Użyj FilteringSkillsSource, aby określić, jakie umiejętności widzi agent. Predykat otrzymuje każde Skill i SkillsSourceContext oraz zwraca True, aby uwzględnić umiejętność. Na przykład, aby załadować umiejętności z udostępnionego katalogu, ale ukryć umiejętność eksperymentalną:

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

Zachowanie buforowania

Domyślnie konstruktor opakowuje potok źródłowy za pomocą elementu CachingAgentSkillsSource , który buforuje listę umiejętności zwracanych przez bazowe źródła. Gdy umiejętności zostaną ustalone przy pierwszym żądaniu, kolejne żądania wykorzystają listę z pamięci podręcznej bez ponownego odpytywania źródeł. Aby wyłączyć buforowanie (na przykład podczas programowania, gdy definicje umiejętności zmieniają się często), użyj DisableCaching() w konstruktorze:

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

Uwaga / Notatka

Wyłączenie buforowania jest przydatne podczas rozwoju, gdy zawartość umiejętności zmienia się często. W środowisku produkcyjnym pozostaw włączone buforowanie (jest to ustawienie domyślne), aby uzyskać lepszą wydajność.

Zachowanie buforowania

Domyślnie narzędzia i instrukcje umiejętności są buforowane po pierwszej kompilacji. Ustaw disable_caching=True, aby wymusić przebudowę przy każdym wywołaniu:

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

disable_caching jest również dostępny w konstruktorze SkillsProvider dla umiejętności zdefiniowanych w kodzie i opartych na klasach.

Aby zachować włączone buforowanie, ale okresowo ponownie wykrywać umiejętności (na przykład gdy źródło oparte na plikach lub źródło MCP ulegnie zmianie podczas działania procesu), przekaż cache_refresh_interval. Wbudowana pamięć podręczna jest traktowana jako nieaktualna, gdy jest starsza niż interwał, więc następne uruchomienie ponownie wykonuje zapytanie o źródło:

from datetime import timedelta

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

cache_refresh_interval wpływa tylko na pamięć podręczną, którą dostawca buduje wewnętrznie (na podstawie umiejętności lub ścieżek plików); jest ignorowany, gdy disable_caching=True, i nie ma wpływu na SkillsSource dostarczony przez wywołującego (w takim przypadku utwórz własne CachingSkillsSource z refresh_interval).

Uwaga / Notatka

Wyłączenie buforowania jest przydatne podczas rozwoju, gdy zawartość umiejętności zmienia się często. W środowisku produkcyjnym pozostaw włączone buforowanie (jest to ustawienie domyślne), aby uzyskać lepszą wydajność.

Zatwierdzanie narzędzi

Wszystkie narzędzia udostępniane przez AgentSkillsProvider (load_skill, read_skill_resource, run_skill_script) domyślnie wymagają zatwierdzenia. Gdy wywołanie narzędzia wymaga zatwierdzenia, agent wstrzymuje działanie i zwraca ToolApprovalRequestContent zamiast natychmiast je wykonać. Użyj UseToolApproval oprogramowania pośredniczącego z regułami automatycznego zatwierdzania, aby selektywnie pominąć monity dotyczące zaufanych operacji:

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

Aby automatycznie zatwierdzić wszystkie narzędzia umiejętnościowe, w tym wykonywanie skryptów:

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

Wyłączanie zatwierdzania dla określonych narzędzi

Użyj AgentSkillsProviderOptions, aby wyłączyć zatwierdzanie dla poszczególnych narzędzi, całkowicie usuwając je z procesu zatwierdzania:

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

Jeśli w tej samej odpowiedzi niektóre narzędzia wymagają zatwierdzenia, a inne nie, model może jednocześnie uruchomić oba typy. Ustaw EnableNonApprovalRequiredFunctionBypassing, aby narzędzia niewymagające zatwierdzenia były wykonywane natychmiast, a użytkownik był proszony o zatwierdzenie tylko pozostałych:

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

Obsługa żądań zatwierdzenia

Gdy narzędzia wymagają zatwierdzenia (i żadna reguła automatycznego zatwierdzania nie ma zastosowania), agent zwraca ToolApprovalRequestContent elementów, które muszą zostać zatwierdzone lub odrzucone, zanim będzie można kontynuować:

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

Szczegóły błędu skryptu

Domyślnie, gdy wykonywanie skryptu umiejętności kończy się niepowodzeniem, wyjątek jest przekazywany do elementu bazowego FunctionInvokingChatClient. Jeśli jej IncludeDetailedErrors właściwość jest ustawiona na true, komunikat o wyjątku jest przekazywany do modelu, umożliwiając mu samodzielne poprawianie przez ponawianie próby przy użyciu różnych argumentów:

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

Jeśli nie można skonfigurować FunctionInvokingChatClient bezpośrednio, ustaw AgentSkillsProviderOptions.IncludeDetailedErrors zamiast tego. To przechwytuje wyjątek na poziomie dostawcy umiejętności i zwraca komunikat o błędzie bezpośrednio do modelu:

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

Ostrzeżenie

Oba podejścia mogą ujawnić modelowi surowe szczegóły wyjątku. Komunikaty o wyjątkach mogą zawierać poufne informacje, takie jak parametry połączenia, ścieżki plików lub nazwy usług wewnętrznych. Ponadto, jeśli funkcje lub skrypty pochodzą z niezaufanych źródeł, złośliwie spreparowany skrypt może zgłosić wyjątek, którego komunikat zawiera ładunek ataku typu prompt injection.

Wszystkie narzędzia udostępniane przez SkillsProvider (load_skill, read_skill_resource i run_skill_script) domyślnie wymagają zatwierdzenia. Gdy wywołanie narzędzia wymaga zatwierdzenia, agent wstrzymuje działanie i przekazuje prośby o zatwierdzenie za pośrednictwem result.user_input_requests, zamiast natychmiast je wykonywać. Zatwierdzasz lub odrzucasz każde żądanie za pomocą request.to_function_approval_response(approved=...) i odsyłasz odpowiedzi:

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)

Gdy wywołanie narzędzia zostanie odrzucone (approved=False), agent zostanie poinformowany, że użytkownik odrzucił i może odpowiednio odpowiedzieć.

Automatyczne zatwierdzanie zaufanych narzędzi

Zamiast wyświetlać monit przy każdym wywołaniu, zainstaluj ToolApprovalMiddleware z jedną ze statycznych reguł automatycznego zatwierdzania udostępnianych przez SkillsProvider. Dzięki temu narzędzia tylko do odczytu działają automatycznie, przy zachowaniu monitu o uruchomienie skryptu:

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

Dostępne są dwie reguły:

  • SkillsProvider.read_only_tools_auto_approval_rule - akceptuje tylko narzędzia tylko do odczytu (load_skill, read_skill_resource), ale nadal wymaga potwierdzenia dla run_skill_script.
  • SkillsProvider.all_tools_auto_approval_rule — zatwierdza każde narzędzie związane z umiejętnościami, w tym run_skill_script (nie jest wymagany proces ręcznego zatwierdzania).

Obie reguły odrzucają każde wywołanie zawierające server_label, więc pozostają ograniczone do lokalnych narzędzi tego dostawcy i nigdy nie zatwierdzają automatycznie hostowanego narzędzia o tej samej nazwie. Reguły dotyczą tylko narzędzi, które nadal wymagają zatwierdzenia — narzędzia wyłączone z tego wymogu za pomocą poniższych argumentów disable_*_approval i tak działają bez zatwierdzenia.

Wyłączanie zatwierdzania dla określonych narzędzi

W przypadku zaufanych funkcji przekaż disable_load_skill_approval, disable_read_skill_resource_approval i/lub disable_run_skill_script_approval, aby całkowicie wyłączyć poszczególne narzędzia z procesu zatwierdzania (są zarejestrowane w approval_mode="never_require"):

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

Te argumenty są również dostępne w systemie SkillsProvider.from_paths().

Ostrzeżenie

Wyłącz zatwierdzanie lub włącz automatyczne zatwierdzanie uruchamiania skryptów tylko dla umiejętności i skryptów ze źródeł, którym ufasz. Instrukcje umiejętności są wprowadzane do kontekstu agenta, a run_skill_script wykonuje kod dostarczony przez źródło.

Niestandardowy monit systemowy

Domyślnie dostawca umiejętności wprowadza monit systemowy zawierający listę dostępnych umiejętności i instruuje agenta do użycia load_skill i read_skill_resource. Możesz dostosować ten monit:

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

Uwaga / Notatka

Szablon niestandardowy musi zawierać {skills} jako symbol zastępczy dla wygenerowanej listy umiejętności. Literalne nawiasy klamrowe muszą być zeskapowane jako {{ i }}.

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

Uwaga / Notatka

Szablon niestandardowy musi zawierać symbol zastępczy {skills} dla wygenerowanej listy umiejętności. Może opcjonalnie zawierać symbole zastępcze {resource_instructions} (podpowiedź narzędzia zasobów) oraz {runner_instructions} (podpowiedź narzędzia skryptowego); jeśli są obecne, są uzupełniane wbudowanymi wskazówkami, a jeśli zostaną pominięte, po prostu nie są renderowane (powiązane narzędzia nadal są rejestrowane). Literalne nawiasy klamrowe muszą być zeskapowane jako {{ i }}.

Wstrzykiwanie usług i argumentów środowiska uruchomieniowego

Funkcje zasobów umiejętności i skryptów mogą odbierać zewnętrzny kontekst aplikacji dostarczony w czasie wykonywania.

Zasób umiejętności i delegaty skryptu mogą zadeklarować parametr IServiceProvider, który jest automatycznie wstrzykiwany przez framework Agent Framework. Dzięki temu umiejętności mogą rozwiązywać problemy z zarejestrowanymi usługami aplikacji na żądanie.

Konfiguracja

Zarejestruj usługi aplikacji i przekaż skompilowany IServiceProvider agentowi za pomocą parametru services :

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

Umiejętności zdefiniowane w kodzie z DI

Zadeklaruj IServiceProvider jako parametr w delegatach AddResource lub AddScript — platforma automatycznie rozpoznaje i wstrzykuje ten parametr, gdy agent odczytuje zasób lub uruchamia skrypt:

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

Umiejętności oparte na klasach z di

Opatrz metody adnotacjami [AgentSkillResource] lub [AgentSkillScript] i zadeklaruj parametr IServiceProvider — platforma wykrywa te składowe za pomocą mechanizmu refleksji i automatycznie wstrzykuje dostawcę usług:

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

Wskazówka

Umiejętności oparte na klasach mogą również rozwiązywać zależności za pomocą ich konstruktora. Zarejestruj klasę umiejętności w obiekcie ServiceCollection i rozwiąż ją z kontenera zamiast wywoływać new bezpośrednio:

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

Jest to przydatne, gdy sama klasa umiejętności potrzebuje wstrzyknięcia usług ponad to, z czego korzystają delegaci zasobów i skryptów.

Funkcje zasobów i skryptów, które akceptują **kwargs, automatycznie odbierają argumenty słów kluczowych podczas uruchomienia przekazane do agent.run(). Dzięki temu funkcje umiejętności uzyskują dostęp do kontekstu aplikacji — takiego jak konfiguracja, tożsamość użytkownika lub klienci usługi — bez konieczności kodowania ich w definicji umiejętności.

Przekazywanie argumentów środowiska uruchomieniowego

Przekaż function_invocation_kwargs do agent.run(), aby przekazać argumenty kluczowe, które platforma dalej przesyła do funkcji zasobów oraz funkcji skryptów.

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

Zdolności definiowane w kodzie z kwargs

Gdy funkcja zasobu deklaruje **kwargs, platforma przekazuje argumenty słowa kluczowego środowiska uruchomieniowego za każdym razem, gdy agent odczytuje zasób:

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

Funkcje zasobów bez **kwargs są wywoływane bez argumentów i nie odbierają kontekstu środowiska uruchomieniowego.

Gdy funkcja skryptu deklaruje **kwargs, platforma przekazuje argumenty słów kluczowych w trakcie działania programu wraz z tymi args, które są podane przez agenta.

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

Agent udostępnia value i factor za pośrednictwem wywołania args narzędzia; aplikacja udostępnia precision za pośrednictwem function_invocation_kwargs metody. Funkcje skryptu bez **kwargs odbierają tylko argumenty dostarczone przez agenta.

Umiejętności oparte na klasach z kwargs

Metody umiejętności oparte na klasach mogą także przyjmować **kwargs, aby otrzymywać argumenty środowiska uruchomieniowego. Wzorzec działa w ten sam sposób — deklarowanie **kwargs metod zasobów lub metod skryptu:

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

Najlepsze rozwiązania dotyczące zabezpieczeń

Umiejętności agenta powinny być traktowane tak samo jak każdy kod strony trzeciej, który wprowadzasz do swojego projektu. Ponieważ instrukcje umiejętności są wstrzykiwane do kontekstu agenta — a umiejętności mogą obejmować skrypty — niezbędne jest stosowanie takiego samego poziomu przeglądu i nadzoru, jak w przypadku zależności open source.

  • Przed użyciem zapoznaj się — przed wdrożeniem przeczytaj całą zawartość umiejętności (SKILL.md, skrypty i zasoby). Sprawdź, czy rzeczywiste zachowanie skryptu jest zgodne z jego deklarowaną intencją. Sprawdź instrukcje niepożądane, które próbują obejść wytyczne dotyczące bezpieczeństwa, eksfiltrować dane lub modyfikować pliki konfiguracji agenta.
  • Zaufane źródło — instaluj tylko umiejętności od zaufanych autorów lub zweryfikowanych wewnętrznych współtwórców. Preferuj umiejętności z wyraźnym pochodzeniem, kontrolą wersji i aktywną konserwacją. Zwróć uwagę na nazwy umiejętności podszywające się pod popularne pakiety.
  • Piaskownica — uruchamianie umiejętności obejmujących skrypty wykonywalne w środowiskach izolowanych. Ogranicz system plików, sieć i dostęp na poziomie systemu tylko do tego, czego wymaga umiejętność. Wymagaj jawnego potwierdzenia użytkownika przed wykonaniem potencjalnie poufnych operacji.
  • Inspekcja i rejestrowanie — rejestruj, które umiejętności są ładowane, które zasoby są odczytywane i które skrypty są wykonywane. Dzięki temu dziennik inspekcji umożliwia śledzenie zachowania agenta z powrotem do określonej zawartości umiejętności, jeśli coś pójdzie nie tak.

Kiedy należy używać umiejętności czy przepływów pracy

Przepływy pracy dotyczące umiejętności agenta i struktury agentów rozszerzają możliwości agentów, ale działają zasadniczo na różne sposoby. Wybierz podejście, które najlepiej odpowiada twoim wymaganiom:

  • Kontrola — przy użyciu umiejętności sztuczna inteligencja decyduje o sposobie wykonywania instrukcji. Jest to idealne rozwiązanie, gdy chcesz, aby agent był kreatywny lub adaptacyjny. Za pomocą przepływu pracy jawnie zdefiniujesz ścieżkę wykonywania. Używaj przepływów pracy, gdy potrzebujesz deterministycznego, przewidywalnego zachowania.
  • Odporność — umiejętność działa w ramach jednego kroku agenta. Jeśli coś nie powiedzie się, należy ponowić próbę wykonania całej operacji. Przepływy pracy obsługują tworzenie punktów kontrolnych, dzięki czemu mogą być wznawiane od ostatniego pomyślnego kroku po awarii. Wybierz przepływy pracy, gdy koszt ponownego wykonania całego procesu jest wysoki.
  • Skutki uboczne — umiejętności są odpowiednie, gdy operacje są idempotentne lub obarczone niskim ryzykiem. Preferuj przepływy pracy, gdy kroki powodują skutki uboczne (wysyłanie wiadomości e-mail, naliczanie opłat), które nie powinny być powtarzane podczas ponawiania próby.
  • Złożoność — umiejętności najlepiej nadają się do skoncentrowanych zadań z jedną domeną, które może obsłużyć jeden agent. Przepływy pracy lepiej nadają się do wieloetapowych procesów biznesowych, które koordynują wielu uczestników, zatwierdzenia przez ludzi lub integracje z systemami zewnętrznymi.

Wskazówka

Zasadniczo: jeśli chcesz, aby sztuczna inteligencja dowiedziała się, jak wykonać zadanie, użyj umiejętności. Jeśli musisz zagwarantować, jakie kroki są wykonywane i w jakiej kolejności, użyj przepływu pracy.

Dalsze kroki