Keterampilan Agen

Keterampilan Agen adalah paket petunjuk, skrip, dan sumber daya portabel yang memberi agen kemampuan khusus dan keahlian domain. Keterampilan mengikuti spesifikasi terbuka dan menerapkan pola pengungkapan progresif sehingga agen hanya memuat konteks yang mereka butuhkan, ketika mereka membutuhkannya.

Gunakan Keterampilan Agen saat Anda ingin:

  • Keahlian domain paket - Menangkap pengetahuan khusus (kebijakan pengeluaran, alur kerja hukum, alur analisis data) sebagai paket portabel yang dapat digunakan kembali.
  • Memperluas kemampuan agen - Memberi agen kemampuan baru tanpa mengubah instruksi inti mereka.
  • Pastikan konsistensi - Ubah tugas multi-langkah menjadi alur kerja yang dapat diaudit berulang.
  • Aktifkan interoperabilitas - Gunakan kembali keterampilan yang sama di berbagai produk yang kompatibel dengan Keterampilan Agen.

Struktur keterampilan

Keterampilan adalah direktori yang SKILL.md berisi file dengan subdirektori opsional untuk sumber daya:

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

File SKILL.md harus berisi frontmatter YAML diikuti dengan konten 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"
---
Bidang Diperlukan Deskripsi
name Yes Maksimal 64 karakter. Huruf kecil, angka, dan tanda hubung saja. Tidak boleh dimulai atau diakhir dengan tanda hubung atau berisi tanda hubung berturut-turut. Harus cocok dengan nama direktori induk.
description Yes Apa fungsi keterampilan ini dan kapan harus digunakan. Maksimal 1024 karakter. Harus menyertakan kata kunci yang membantu agen mengidentifikasi tugas yang relevan.
license Tidak. Nama lisensi atau referensi ke file lisensi yang dibundel.
compatibility Tidak. Maksimal 500 karakter. Menunjukkan persyaratan lingkungan (produk yang dimaksudkan, paket sistem, akses jaringan, dll.).
metadata Tidak. Pemetaan nilai kunci arbitrer untuk metadata tambahan.
allowed-tools Tidak. Daftar alat yang dipisahkan oleh spasi yang telah disetujui sebelumnya yang dapat digunakan kemampuan. Eksperimental - dukungan dapat bervariasi bergantung pada implementasi agen.

Isi markdown setelah frontmatter berisi instruksi keterampilan—panduan langkah demi langkah, contoh input dan output, kasus batas yang umum, atau konten apa pun yang membantu agen menyelesaikan tugas. Simpan SKILL.md di bawah 500 baris dan pindahkan materi referensi terperinci ke file terpisah.

Pengungkapan progresif

Keterampilan Agen menggunakan pola pengungkapan progresif empat tahap untuk meminimalkan penggunaan konteks:

  1. Iklankan (~100 token per keterampilan) - Nama dan deskripsi keterampilan disuntikkan ke dalam prompt sistem di awal setiap eksekusi, sehingga agen tahu keterampilan apa yang tersedia.
  2. Muatkan (< disarankan 5000 token) - Saat tugas sesuai dengan domain keterampilan, agen memanggil alat load_skill untuk mengambil seluruh isi SKILL.md dengan instruksi terperinci.
  3. Membaca sumber daya (sesuai kebutuhan) - Agen memanggil read_skill_resource alat untuk mengambil file tambahan (referensi, templat, aset) hanya jika diperlukan.
  4. Menjalankan skrip (sesuai kebutuhan) - Agen memanggil alat run_skill_script untuk menjalankan skrip yang disertakan dengan keterampilan.

Pola ini membuat jendela konteks agen tetap ramping sambil memberinya akses ke pengetahuan domain yang mendalam sesuai permintaan.

Nota

load_skill selalu diiklankan. read_skill_resource hanya diiklankan ketika setidaknya satu keterampilan memiliki sumber daya. run_skill_script hanya diiklankan ketika setidaknya satu kemampuan menggunakan skrip.

Memberikan keterampilan kepada agen

Bekerja dengan keterampilan terdiri atas tiga komponen dasar:

  • Penyedia - AgentSkillsProvider (C#) atau SkillsProvider (Python) adalah penyedia konteks yang mengekspos keterampilan ke agen. Ini mengiklankan keterampilan yang tersedia dalam permintaan sistem dan mendaftarkan alat yang digunakan agen untuk memuat keterampilan, membaca sumber daya, dan menjalankan skrip.
  • Sumber - sumber memasok keterampilan ke penyedia. Keterampilan dapat berasal dari beberapa jenis sumber:
    • Berbasis file - keterampilan yang ditemukan dari SKILL.md file di direktori sistem file.
    • Didefinisikan dalam kode - keterampilan yang didefinisikan secara inline di dalam kode menggunakan AgentInlineSkill (C#) atau InlineSkill (Python).
    • Berbasis kelas - keterampilan yang dirangkum dalam kelas yang berasal dari AgentClassSkill<T> (C#) atau ClassSkill (Python).
    • Berbasis MCP - keterampilan yang ditemukan dari server MCP (Model Context Protocol) melalui UseMcpSkills (C#) atau MCPSkillsSource (Python).
  • Builder - AgentSkillsProviderBuilder (C#) menggabungkan beberapa sumber menjadi satu penyedia, dengan menerapkan agregasi, deduplikasi, cache, dan penyaringan opsional. Dalam Python, buat kelas sumber seperti AggregatingSkillsSource, , FilteringSkillsSourcedan DeduplicatingSkillsSource langsung.

Bagian berikut menunjukkan cara membuat keterampilan dari setiap jenis sumber, lalu cara menggabungkan sumber dan membangun penyedia dari mereka.

Keterampilan berbasis file

Buat penunjuk AgentSkillsProvider ke direktori yang berisi keterampilan Anda, dan tambahkan ke konteks penyedia agen. Berikan runner skrip untuk mengaktifkan eksekusi skrip berbasis file yang ditemukan di direktori skill.

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

Peringatan

DefaultAzureCredential nyaman untuk pengembangan tetapi membutuhkan pertimbangan yang cermat dalam produksi. Dalam produksi, pertimbangkan untuk menggunakan kredensial tertentu (misalnya, ManagedIdentityCredential) untuk menghindari masalah latensi, pemeriksaan kredensial yang tidak diinginkan, dan potensi risiko keamanan dari mekanisme fallback.

Beberapa direktori keterampilan

Anda dapat mengarahkan penyedia ke satu direktori induk - setiap subdirektori yang berisi SKILL.md akan otomatis dikenali sebagai keterampilan:

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

Atau berikan daftar jalur untuk mencari beberapa direktori akar:

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

Penyedia mencari hingga dua tingkat dalam.

Menyesuaikan penemuan sumber daya dan skrip

Secara default, penyedia mengenali sumber daya dengan ekstensi .md, , .json, .yaml.yml, .csv, .xml, dan dan .txt skrip dengan ekstensi .py, , .js, .sh.ps1, .cs, dan .csx. Ini mencari hingga dua tingkat jauh dalam setiap direktori keterampilan. Gunakan AgentFileSkillsSourceOptions untuk mengubah default ini:

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 dan ScriptFilter menerima AgentFileSkillFilterContext dengan nama keterampilan dan jalur relatif berkas, sehingga Anda dapat membatasi berkas berdasarkan lokasi, konvensi penamaan, atau logika khusus apa pun.

Pelaksanaan Skrip

Berikan SubprocessScriptRunner.RunAsync sebagai runner skrip untuk mengaktifkan eksekusi skrip berbasis file:

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

SubprocessScriptRunner.RunAsync kira-kira setara dengan yang berikut:

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

Runner menjalankan setiap skrip yang ditemukan sebagai subproses lokal. Skrip berbasis berkas mengharuskan argumen dalam bentuk larik JSON berisi string - setiap elemen larik menjadi argumen baris perintah posisional.

Peringatan

SubprocessScriptRunner disediakan hanya untuk tujuan demonstrasi. Untuk penggunaan produksi, pertimbangkan untuk menambahkan:

  • Sandboxing (misalnya, kontainer atau lingkungan eksekusi terisolasi)
  • Batas sumber daya (CPU, memori, batas waktu jam dinding)
  • Validasi input dan daftar izin skrip yang dapat dieksekusi
  • Jejak pengelogan dan audit terstruktur

Keterampilan berbasis file

Gunakan factory SkillsProvider.from_paths() untuk menemukan skill dari direktori yang berisi file SKILL.md, dan tambahkan penyedia tersebut ke penyedia konteks agen:

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

Beberapa direktori keterampilan

Anda dapat mengarahkan penyedia ke satu direktori induk - setiap subdirektori yang berisi SKILL.md akan otomatis dikenali sebagai keterampilan:

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

Atau berikan daftar jalur untuk mencari beberapa direktori akar:

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

Penyedia mencari hingga dua tingkat dalam.

Menyesuaikan penemuan sumber daya dan skrip

Secara default, sumber daya ditemukan dari references/ dan assets/ subdirektori, dan skrip dari scripts/, sesuai spesifikasi agentskills.io. Ekstensi sumber daya yang dikenali adalah .md, , .json.yaml, .yml, .csv, .xml, dan .txt. Ini mencari hingga dua tingkat jauh dalam setiap direktori keterampilan. Gunakan resource_extensions, , script_extensionssearch_depth, resource_filter, dan script_filter untuk menyesuaikan penemuan:

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

Predikat resource_filter dan script_filter menerima nama skill dan jalur relatif berkasnya, sehingga Anda dapat membatasi berkas berdasarkan lokasi, konvensi penamaan, atau logika kustom lainnya. Gunakan "." untuk menyertakan file di level root skill selain di subdirektori.

Pelaksanaan Skrip

Untuk mengaktifkan eksekusi skrip berbasis file, teruskan script_runner ke SkillsProvider.from_paths(). Setiap pemanggilan sinkron atau asinkron yang memenuhi protokol SkillScriptRunner dapat digunakan.

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

Runner menerima argumen FileSkill dan FileSkillScript yang telah ditetapkan nilainya, serta argumen args opsional. Skrip berbasis berkas mengharuskan argumen dalam bentuk larik JSON berisi string - setiap elemen larik menjadi argumen baris perintah posisional. Skrip secara otomatis terdeteksi dari berkas .py di subdirektori scripts/ setiap direktori skill.

Peringatan

Pelari di atas disediakan hanya untuk tujuan demonstrasi. Untuk penggunaan produksi, pertimbangkan untuk menambahkan:

  • Sandboxing (misalnya, kontainer, seccomp, atau firejail)
  • Batas sumber daya (CPU, memori, batas waktu jam dinding)
  • Validasi input dan daftar izin skrip yang dapat dieksekusi
  • Jejak pengelogan dan audit terstruktur

Nota

Jika skill berbasis file dengan skrip disediakan tetapi script_runner tidak ditetapkan, SkillsProvider menghasilkan error ketika eksekusi skrip dicoba.

Keterampilan berbasis file

Agen Go mendukung skill melalui paket agent/skills. Keterampilan mengikuti pola pengungkapan progresif yang sama: iklan -> muat -> baca sumber daya -> jalankan skrip.

Temukan keterampilan dari file SKILL.md di disk dan daftarkan penyedia keterampilan sebagai penyedia konteks agen:

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

Keterampilan berbasis kode

Selain keterampilan berbasis file yang ditemukan dari SKILL.md file, Anda dapat menentukan keterampilan sepenuhnya dalam kode menggunakan AgentInlineSkill. Keterampilan yang ditentukan kode berguna ketika:

  • Konten keterampilan dihasilkan secara dinamis (misalnya, membaca dari database atau lingkungan).
  • Anda ingin menyimpan definisi keterampilan bersama kode aplikasi yang menggunakannya.
  • Anda memerlukan sumber daya yang menjalankan logika pada waktu baca daripada melayani file statis.
  • Definisi keterampilan perlu dibangun saat runtime berdasarkan data - misalnya, membuat keterampilan yang dipersonalisasi untuk setiap sesi pengguna berdasarkan peran atau izin mereka.
  • Keterampilan perlu menutup status situs panggilan (variabel lokal, penutupan) daripada menyelesaikan layanan dari kontainer DI.

Keterampilan kode dasar

Buat sebuah AgentInlineSkill dengan nama, deskripsi, dan instruksi. Lampirkan sumber daya menggunakan .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);

Sumber daya dinamis

Lewatkan delegasi pabrik ke .AddResource() untuk menghitung konten pada saat runtime. Delegasi dipanggil setiap kali agen membaca sumber daya:

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

Skrip yang ditentukan oleh kode

Gunakan .AddScript() untuk mendaftarkan delegasi sebagai skrip yang dapat dieksekusi. Skrip yang diatur oleh kode berjalan secara in-process sebagai panggilan delegasi langsung. Tidak diperlukan pelaksana skrip. Parameter yang diketik delegasi secara otomatis dikonversi menjadi Skema JSON yang digunakan agen untuk meneruskan argumen:

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

Nota

Untuk menggabungkan keterampilan yang ditentukan kode dengan keterampilan berbasis file atau berbasis kelas dalam satu penyedia, gunakan AgentSkillsProviderBuilder - lihat Konstruksi penyedia.

Selain keterampilan berbasis file yang ditemukan dari file SKILL.md, Anda dapat menentukan keterampilan sepenuhnya dalam kode Python menggunakan InlineSkill. Keterampilan yang ditentukan kode berguna ketika:

  • Konten keterampilan dihasilkan secara dinamis (misalnya, membaca dari database atau lingkungan).
  • Anda ingin menyimpan definisi keterampilan bersama kode aplikasi yang menggunakannya.
  • Anda memerlukan sumber daya yang menjalankan logika pada waktu baca daripada melayani file statis.
  • Definisi keterampilan perlu dibangun saat runtime berdasarkan data - misalnya, membuat keterampilan yang dipersonalisasi untuk setiap sesi pengguna berdasarkan peran atau izin mereka.
  • Keterampilan perlu menutup status situs panggilan (variabel lokal, penutupan) daripada menyelesaikan layanan melalui **kwargs.

Keterampilan kode dasar

Buat instance InlineSkill dengan SkillFrontmatter (yang berisi nama dan deskripsi) serta konten petunjuk. Opsional, lampirkan instans InlineSkillResource dengan konten statis.

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)

Sumber daya dinamis

Gunakan dekorator @skill.resource untuk mendaftarkan fungsi sebagai sumber daya. Fungsi ini dipanggil setiap kali agen membaca sumber daya, sehingga dapat mengembalikan data up-to-date. Fungsi sinkronisasi dan asinkron didukung:

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

Ketika dekorator digunakan tanpa argumen (@skill.resource), nama fungsi menjadi nama sumber daya dan docstring menjadi deskripsi. Gunakan @skill.resource(name="...", description="...") untuk mengaturnya secara eksplisit.

Skrip yang ditentukan oleh kode

Gunakan dekorator @skill.script untuk mendaftarkan fungsi sebagai skrip yang dapat dieksekusi pada fitur tersebut. Skrip yang ditentukan oleh kode berjalan di dalam proses dan tidak memerlukan eksekutor skrip. Fungsi sinkronisasi dan asinkron didukung:

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

Ketika dekorator digunakan tanpa argumen (@skill.script), nama fungsi menjadi nama skrip dan docstring menjadi deskripsi. Parameter yang diketik fungsi secara otomatis dikonversi menjadi Skema JSON yang digunakan agen untuk meneruskan argumen.

Selain keterampilan berbasis file yang ditemukan dari SKILL.md file, Anda dapat menentukan keterampilan sepenuhnya dalam kode 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 memuat instruksi keterampilan hanya ketika agen memanggil load_skill. Skrip menerima argumen string posisional bergaya CLI, misalnya ["26.2", "1.60934"], dan dapat mengurai argumen tersebut dengan cara apa pun yang diperlukan skrip.

Tip

Lihat contoh keterampilan untuk sampel lengkap yang dapat dijalankan.

Keterampilan berbasis kelas

Keterampilan berbasis kelas memungkinkan Anda menggabungkan semua komponen keterampilan - nama, deskripsi, instruksi, sumber daya, dan skrip - ke dalam satu kelas C#. Ini membuatnya mudah untuk dikemas dan didistribusikan sebagai paket NuGet - tim dapat membuat dan merilis skill secara independen, dan pengguna dapat menambahkannya dengan dotnet add package dan satu pemanggilan .UseSkill(). Berasal dari AgentClassSkill<T> (di mana T adalah kelas Anda), lalu anotasi properti dengan [AgentSkillResource] dan metode dengan [AgentSkillScript] untuk penemuan otomatis.

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

Daftarkan keterampilan berbasis kelas dengan AgentSkillsProvider:

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

[AgentSkillResource] Ketika atribut diterapkan ke properti atau metode, nilai pengembaliannya digunakan sebagai konten sumber daya saat agen membaca sumber daya - gunakan metode ketika konten perlu dihitung pada waktu baca. Ketika [AgentSkillScript] diterapkan ke metode, metode dipanggil ketika agen memanggil skrip. Gunakan [Description] dari System.ComponentModel untuk menjelaskan setiap sumber daya dan skrip untuk agen.

Nota

AgentClassSkill<T> juga mendukung menggantikan Resources dan Scripts sebagai koleksi untuk skenario di mana penemuan berbasis atribut tidak cocok.

Keterampilan berbasis kelas

Keterampilan berbasis kelas memungkinkan Anda menggabungkan semua komponen keterampilan - nama, deskripsi, instruksi, sumber daya, dan skrip - ke dalam satu kelas Python. Ini membuatnya mudah untuk dikemas dan didistribusikan sebagai paket PyPI—tim dapat menulis dan merilis skill secara independen, dan pengguna dapat menambahkannya dengan pip install dan satu panggilan SkillsProvider(). Subkelas ClassSkill, lalu gunakan @ClassSkill.resource dekorator dan @ClassSkill.script untuk penemuan otomatis:

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

Daftarkan keterampilan berbasis kelas dengan SkillsProvider:

from agent_framework import SkillsProvider

skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)

Ketika @ClassSkill.resource diterapkan sebagai dekorator telanjang (tanpa argumen), nama metode menjadi nama sumber daya (dengan garis bawah dikonversi menjadi tanda hubung) dan docstring menjadi deskripsi. Gunakan @ClassSkill.resource(name="...", description="...") untuk mengaturnya secara eksplisit. Pola yang sama berlaku untuk @ClassSkill.script.

Sumber daya dapat didefinisikan sebagai metode reguler atau @property deskriptor. Saat menggunakan @property, tempatkan @property pertama dan @ClassSkill.resource kedua. Nilai pengembalian sumber daya di-cache setelah akses pertama.

Nota

ClassSkill juga mendukung penimpaan properti resources dan scripts secara eksplisit agar mengembalikan instance InlineSkillResource dan InlineSkillScript secara langsung, untuk skenario ketika penemuan berbasis dekorator tidak sesuai.

Keterampilan berbasis MCP

Nota

Keterampilan berbasis MCP memerlukan Microsoft.Agents.AI.Mcp paket NuGet. API keterampilan MCP bersifat eksperimental dan dapat berubah dalam rilis mendatang.

Keterampilan dapat ditemukan pada server MCP (Model Context Protocol) yang menyediakan sumber daya keterampilan di bawah skema URI skill://. Server MCP mengiklankan keterampilan melalui skill://index.json dokumen penemuan, dan kerangka kerja mengambil konten keterampilan sesuai permintaan.

Keterampilan berbasis MCP mendukung dua jenis entri indeks:

  • skill-md - Sumber daya keterampilan SKILL.md dan saudara diambil sesuai permintaan dari server MCP.
  • archive - Skill didistribusikan sebagai arsip paket tunggal (ZIP, TAR, atau TAR terkompresi gzip) yang diunduh dan diekstrak secara lokal.

Penggunaan dasar

UseMcpSkills Gunakan metode ekstensi pada AgentSkillsProviderBuilder untuk menambahkan sumber keterampilan 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);

Keterampilan jenis arsip

Untuk skill jenis arsip, gunakan AgentMcpSkillsSourceOptions (dari paket Microsoft.Agents.AI.Mcp) untuk mengonfigurasi perilaku ekstraksi:

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 mengekspos properti berikut untuk mengontrol ekstraksi arsip:

  • ArchiveSkillsDirectory - Direktori dasar untuk arsip yang diekstrak. Secara bawaan menggunakan subdirektori unik di bawah direktori kerja saat ini, yang dibuat untuk setiap instans sumber guna mencegah bentrokan antara beberapa sumber.
  • ArchiveResourceExtensions - Ekstensi yang diizinkan untuk sumber daya dalam arsip yang diekstrak. Defaultnya adalah .md, .json, .yaml, .yml, .csv, .xml, .txt.
  • ArchiveResourceSearchDepth - Seberapa dalam untuk mencari sumber daya dalam setiap direktori keterampilan yang diekstrak. Secara default menjadi 2.
  • ArchiveMaxFileCount - File maksimum per arsip. Arsip yang melebihi batas ini akan dilewati. Secara default menjadi 20.
  • ArchiveMaxSizeBytes - Ukuran unduhan maksimum per arsip. Secara default menjadi 1 MB.
  • ArchiveMaxUncompressedSizeBytes - Ukuran total maksimum yang tidak dikompresi per arsip. Secara default menjadi 1 MB.

Important

Skrip yang dibundel dalam skill tipe arsip tidak pernah dijalankan. Ini adalah langkah keamanan yang disarankan - konten yang dapat dieksekusi dari server MCP jarak jauh memerlukan kepercayaan eksplisit.

Keterampilan berbasis MCP

Nota

Keterampilan berbasis MCP bersifat eksperimental dan dapat berubah dalam rilis mendatang. Menggunakan MCPSkillsSource menghasilkan FutureWarning di bawah flag fitur MCP_SKILLS.

Keterampilan dapat ditemukan pada server MCP (Model Context Protocol) yang menyediakan sumber daya keterampilan di bawah skema URI skill://. Server MCP mengumumkan keterampilan melalui dokumen penemuan skill://index.json, dan framework mengambil isi SKILL.md setiap keterampilan saat diperlukan melalui resources/read.

Bungkus MCP ClientSession dalam MCPSkillsSource, lalu teruskan ke 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("...")

Nota

Python MCPSkillsSource hanya mendukung entri indeks skill-md (entri indeks dari jenis lain diam-diam dilewati). Tidak seperti implementasi .NET, ini tidak mendukung keterampilan jenis arsip. Jika skill://index.json tidak ada, tidak dapat dibaca, kosong, atau gagal diurai, sumber mengembalikan daftar kosong.

Important

Server MCP eksternal mengontrol konten keterampilan apa saja—termasuk instruksi dan skrip yang dapat dijalankan oleh agen—yang sampai ke agen. Hanya terhubung MCPSkillsSource ke server yang telah Anda periksa dan percayai, dan perlakukan responsnya sebagai input yang tidak tepercaya.

Sumber keterampilan

Sebuah AgentSkillsProvider mengambil kemampuan dari satu atau beberapa sumber - objek yang mengimplementasikan AgentSkillsSource. Sumber terbagi dalam dua kategori: sumber leaf yang menemukan atau berisi skill (seperti AgentFileSkillsSource untuk skill berbasis file), dan dekorator yang mengubah keluaran sumber lain (agregasi, deduplikasi, penyimpanan cache, dan penyaringan). Anda juga dapat membuat sumber kustom.

Setiap sumber mengimplementasikan satu metode - GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default). AgentSkillsSourceContext memuat informasi tentang permintaan saat ini:

  • Agent - AIAgent instans yang meminta keterampilan.
  • Session - AgentSession yang terkait dengan pemanggilan tersebut, atau null ketika tidak ada sesi.

Konteks ini tersedia di seluruh alur sumber, sehingga FilteringAgentSkillsSource predikat atau sumber kustom dapat mendasarkan logikanya di atasnya - misalnya, mengembalikan serangkaian keterampilan yang berbeda tergantung pada agen yang meminta.

Sumber daun

AgentFileSkillsSource

Menemukan keterampilan dari SKILL.md file di disk. Menerima satu atau beberapa jalur direktori, eksekutor skrip opsional, serta AgentFileSkillsSourceOptions opsional (dijelaskan dalam keterampilan berbasis file).

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

AgentInMemorySkillsSource

Membungkus instans AgentSkill (ditentukan kode atau berbasis kelas) dalam memori.

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

Combinator

AggregatingAgentSkillsSource

Menggabungkan beberapa sumber menjadi satu. Keahlian dikembalikan sesuai urutan pendaftaran tanpa deduplikasi atau pemfilteran.

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

Decorators

Dekorator membungkus sumber internal dan mengubah keluarannya. Mereka dapat dirangkai untuk membentuk pipeline.

DeduplicatingAgentSkillsSource

Menghapus nama keterampilan duplikat (tidak peka huruf besar/kecil, kemunculan pertama menang). Duplikat dicatat sebagai peringatan.

var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);

CachingAgentSkillsSource

Menyimpan daftar keterampilan yang dikembalikan oleh sumber internal ke dalam cache. Pemanggil bersamaan diproses secara serial per kunci cache sehingga hanya satu operasi pengambilan yang berjalan pada satu waktu. Menerima opsional CachingAgentSkillsSourceOptions:

  • RefreshInterval (TimeSpan?) - ketika diatur, hasil cache kedaluwarsa setelah interval ini dan sumber dalam dipanggil kembali. Ketika null (default), hasil cache tidak pernah kedaluwarsa.
  • CacheIsolationKeySelector (Func<AgentSkillsSourceContext, string?>?) - mengembalikan kunci cache untuk mengisolasi hasil cache berdasarkan konteks (misalnya, per penyewa). Saat null, semua pemanggil berbagi satu bucket cache.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
    RefreshInterval = TimeSpan.FromMinutes(5)
});

FilteringAgentSkillsSource

Menerapkan predikat untuk menyertakan atau mengecualikan keterampilan. Predikat menerima keterampilan dan sebuah AgentSkillsSourceContext.

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

Sumber kustom

Ketika sumber bawaan tidak mencakup skenario Anda, terapkan sumber Anda sendiri. Subkelas AgentSkillsSource untuk sumber daun (yang menghasilkan keterampilan dari asal baru seperti database atau layanan jarak jauh), atau subkelas DelegatingAgentSkillsSource untuk dekorator yang mengubah output sumber lain.

Sumber daun

Berasal dari AgentSkillsSource dan terapkan GetSkillsAsync. Argumen AgentSkillsSourceContext memungkinkan sumber menyesuaikan hasilnya dengan permintaan saat ini - misalnya, mengembalikan serangkaian keterampilan yang berbeda tergantung pada agen yang meminta. Ambil alih Dispose(bool) jika sumber memiliki sumber daya seperti klien atau koneksi.

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 khusus

Berasal dari DelegatingAgentSkillsSource, panggil InnerSource.GetSkillsAsync, dan ubah atau amati hasilnya. Ini adalah pola yang sama dengan yang digunakan oleh dekorator cache, deduplikasi, dan penyaringan bawaan. Misalnya, dekorator yang mencatat berapa banyak keterampilan yang dikembalikan per permintaan tanpa mengubah hasilnya:

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

Kedua sumber kustom dapat diteruskan ke AgentSkillsProvider langsung atau bersarang di dalam alur yang lebih besar, sama seperti sumber bawaan.

Konstruksi penyedia

AgentSkillsProvider adalah komponen yang mengekspos keterampilan ke agen. Ini membungkus satu atau beberapa sumber dan mendaftarkan alat load_skill, read_skill_resource, dan run_skill_script. Ada tiga cara untuk membuatnya:

  1. AgentSkillsProviderBuilder - menggabungkan beberapa jenis skill ke dalam satu penyedia dengan agregasi otomatis, deduplikasi, penyimpanan cache, dan penyaringan opsional. Paling cocok untuk skenario yang menggabungkan keterampilan berbasis file, yang didefinisikan dalam kode, berbasis kelas, dan berbasis MCP.
  2. Komposisi sumber langsung - buat alur sumber sendiri menggunakan kelas publik AgentSkillsSource . Tidak ada cache otomatis atau deduplikasi yang diterapkan - Anda mengontrol seluruh pipeline. Paling cocok saat Anda memerlukan kendali atas urutan, logika bersyarat, atau perilaku dekorator kustom.
  3. Konstruktor praktis - membuat penyedia langsung dari jalur file atau satu atau beberapa instans skill. Menerapkan deduplikasi dan penyimpanan cache secara otomatis. Terbaik untuk skenario sumber tunggal.

Menggunakan AgentSkillsProviderBuilder

Gunakan AgentSkillsProviderBuilder saat Anda memerlukan salah satu hal berikut:

  • Jenis keterampilan campuran - menggabungkan keterampilan berbasis file, yang ditentukan kode (AgentInlineSkill), berbasis kelas (AgentClassSkill), dan berbasis MCP dalam satu penyedia.
  • Penyaringan keterampilan - menyertakan atau mengecualikan keterampilan menggunakan predikat.

Jenis keterampilan campuran

Gabungkan beberapa jenis keterampilan dalam satu penyedia dengan merangkai UseFileSkill, UseSkill, UseMcpSkills, dan 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();

Penyaringan keterampilan

Gunakan UseFilter untuk hanya menyertakan keterampilan yang memenuhi kriteria Anda - misalnya, untuk memuat keterampilan dari direktori bersama tetapi mengecualikan yang eksperimental:

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

Menyusun sumber secara langsung

Ketika penyusun tidak menawarkan kontrol yang Anda butuhkan, buat kelas sumber sendiri dan teruskan alur yang dihasilkan ke AgentSkillsProvider. Lihat Sumber keterampilan untuk daftar lengkap sumber yang tersedia dan opsinya.

Contoh berikut membangun alur multi-sumber yang sebanding, tetapi memberi Anda kontrol eksplisit atas setiap dekorator:

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

Nota

Ketika ownsSource adalah true, membuang penyedia juga membuang seluruh alur sumber. Atur ke false jika Anda mengelola siklus hidup sumber sendiri.

Konstruktor kenyamanan

Untuk skenario sumber tunggal, gunakan langsung konstruktor AgentSkillsProvider. Ini secara otomatis menerapkan deduplikasi dan penyimpanan cache tanpa memerlukan alat penyusun atau penyusunan sumber secara manual.

Dari jalur file:

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

Dari instans keterampilan:

var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);

Sumber keterampilan

Sebuah SkillsProvider mengambil keahlian dari satu atau beberapa sumber - objek yang diturunkan dari SkillsSource. Sumber terbagi dalam dua kategori: sumber leaf yang menemukan atau berisi skill (seperti FileSkillsSource untuk skill berbasis file), dan dekorator yang mengubah keluaran sumber lain (agregasi, deduplikasi, penyimpanan cache, dan penyaringan). Anda juga dapat membuat sumber kustom.

Setiap sumber mengimplementasikan satu metode - async def get_skills(self, context: SkillsSourceContext) -> list[Skill]. SkillsSourceContext memuat informasi tentang permintaan saat ini:

  • agent - agen (SupportsAgentRun) meminta keterampilan.
  • session - AgentSession yang terkait dengan pemanggilan tersebut, atau None ketika tidak ada sesi.

Konteks ini mengalir melalui seluruh alur sumber, sehingga FilteringSkillsSource predikat atau sumber kustom dapat mendasarkan logikanya di atasnya - misalnya, mengembalikan serangkaian keterampilan yang berbeda tergantung pada agen yang meminta.

Sumber daun

  • FileSkillsSource - menemukan skill dari file SKILL.md di disk. Menerima satu atau beberapa jalur direktori, script_runner opsional, dan opsi penemuan (resource_extensions, script_extensions, search_depth, resource_filter, script_filter) yang didokumentasikan dalam Keahlian berbasis file.
  • InMemorySkillsSource - membungkus instans Skill (didefinisikan kode atau berbasis kelas) dalam memori.
  • MCPSkillsSource - menemukan keterampilan dari server MCP (lihat keterampilan berbasis 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])

Combinator

AggregatingSkillsSource menggabungkan beberapa sumber menjadi satu. Keahlian dikembalikan sesuai urutan pendaftaran tanpa deduplikasi atau pemfilteran.

from agent_framework import AggregatingSkillsSource

aggregated = AggregatingSkillsSource([file_source, in_memory_source])

Decorators

Dekorator membungkus sumber internal dan mengubah keluarannya. Mereka dapat dirangkai untuk membentuk pipeline.

  • DeduplicatingSkillsSource - menghapus nama keterampilan duplikat (tidak peka huruf besar/kecil, kemunculan pertama menang). Duplikat dicatat sebagai peringatan.
  • CachingSkillsSource - menyimpan daftar keterampilan yang dikembalikan oleh sumber internal dalam cache. Pemanggil serentak untuk kunci cache yang sama berbagi satu pengambilan yang sedang berlangsung, sehingga sumber internal diminta paling banyak satu kali untuk setiap kunci. Menerima dua argumen kata kunci opsional:
    • refresh_interval (timedelta | None) - ketika diatur, daftar dalam cache dianggap kedaluwarsa jika usianya melebihi interval tersebut, sehingga pemanggilan berikutnya akan melakukan kueri ulang ke sumber internal. Ketika None (default), hasil cache tidak pernah kedaluwarsa. Berguna untuk sumber dalam yang keterampilannya berubah selama masa pakai proses, seperti MCPSkillsSource.
    • cache_isolation_key_selector (Callable[[SkillsSourceContext], str | None]) - memperoleh kunci cache dari konteks untuk mengisolasi hasil cache (misalnya, per agen atau penyewa). Kunci harus rendah kardinalitas dan stabil. Mengembalikan None (atau membiarkannya None) akan menggunakan satu bucket cache bersama.
  • FilteringSkillsSource - menerapkan predikat untuk menyertakan atau mengecualikan keterampilan. Predikat menerima keterampilan danSkillsSourceContext: 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",
)

Sumber kustom

Ketika sumber bawaan tidak mencakup skenario Anda, terapkan sumber Anda sendiri. Subkelas SkillsSource untuk sumber daun (yang menghasilkan keterampilan dari asal baru seperti database atau layanan jarak jauh), atau subkelas DelegatingSkillsSource untuk dekorator yang mengubah output sumber lain.

Sumber daun

Berasal dari SkillsSource dan terapkan get_skills. Argumen SkillsSourceContext memungkinkan sumber menyesuaikan hasilnya dengan permintaan saat ini - misalnya, mengembalikan serangkaian keterampilan yang berbeda tergantung pada agen yang meminta:

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 khusus

Berasal dari DelegatingSkillsSource, panggil self.inner_source.get_skills(context), dan ubah atau amati hasilnya. Ini adalah pola yang sama dengan yang digunakan oleh dekorator cache, deduplikasi, dan penyaringan bawaan. Misalnya, dekorator yang mencatat berapa banyak keterampilan yang dikembalikan per permintaan tanpa mengubah hasilnya:

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

Kedua sumber kustom dapat diteruskan ke SkillsProvider langsung atau bersarang di dalam alur yang lebih besar, sama seperti sumber bawaan.

Konstruksi penyedia

SkillsProvider adalah komponen yang mengekspos keterampilan ke agen. Ini membungkus satu atau beberapa sumber dan mendaftarkan alat load_skill, read_skill_resource, dan run_skill_script. Ada tiga cara untuk membuatnya:

  1. Dari instans keterampilan - berikan satu Skill atau urutan keterampilan ke konstruktor. Terbaik untuk keterampilan yang didefinisikan dengan kode dan berbasis kelas. Menerapkan deduplikasi dan penyimpanan cache secara otomatis.
  2. Dari jalur file - gunakan SkillsProvider.from_paths() factory. Paling cocok untuk keterampilan berbasis file dari satu sumber. Menerapkan deduplikasi dan penyimpanan cache secara otomatis.
  3. Komposisi sumber langsung - buat alur sumber sendiri menggunakan kelas publik SkillsSource dan teruskan ke konstruktor. Anda mengendalikan seluruh alur proses. Paling cocok saat Anda memerlukan kontrol atas urutan, logika bersyarat, kunci cache, atau perilaku dekorator kustom.

Dari instans keterampilan

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

Dari jalur file

from pathlib import Path
from agent_framework import SkillsProvider

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

Menyusun sumber secara langsung

Ketika Anda membutuhkan kontrol penuh, buat kelas sumber sendiri dan teruskan alur yang dihasilkan ke SkillsProvider. Lihat Sumber keterampilan untuk daftar lengkap sumber yang tersedia dan opsinya.

Contoh di bawah ini membangun alur multi-sumber dengan kontrol eksplisit atas setiap dekorator. Contoh ini menggunakan objek placeholder:

  • volume_converter_skill - instans apa pun InlineSkill , dibuat seperti yang ditunjukkan dalam keterampilan yang ditentukan kode.
  • temperature_converter_skill - instans apa pun ClassSkill , dibangun seperti yang ditunjukkan dalam keterampilan berbasis Kelas.
  • my_runner - sebuah SkillScriptRunner yang dapat dipanggil, didefinisikan seperti yang ditunjukkan dalam Eksekusi Skrip.
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

SkillsSource yang disediakan pemanggil digunakan apa adanya: tidak secara otomatis dideduplikasi atau dibungkus dalam CachingSkillsSource. Penyimpanan cache otomatis pada sumber yang peka terhadap konteks dalam satu bucket bersama dapat menyebabkan keterampilan milik satu agen atau penyewa digunakan kembali untuk agen atau penyewa lain. Susun DeduplicatingSkillsSource dan CachingSkillsSource (opsional menggunakan cache_isolation_key_selector) sendiri saat Anda memerlukannya. Deduplikasi otomatis dan penyimpanan cache hanya berlaku jika Anda memberikan keterampilan atau jalur file secara langsung (opsi 1 dan 2 di atas).

Jenis keterampilan campuran

Gabungkan keterampilan berbasis file, berbasis kode, dan berbasis kelas dalam satu penyedia menggunakan 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]),
        ])
    )
)

Penyaringan keterampilan

Gunakan FilteringSkillsSource untuk mengontrol keterampilan mana yang dilihat agen. Fungsi predikat menerima setiap Skill dan SkillsSourceContext, lalu mengembalikan True agar keterampilan disertakan. Misalnya, untuk memuat keterampilan dari direktori bersama tetapi menyembunyikan yang masih bersifat eksperimental:

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

Perilaku cache

Secara default, penyusun membungkus alur sumber dengan CachingAgentSkillsSource yang menyimpan daftar keterampilan yang dikembalikan oleh sumber yang mendasar. Setelah skill berhasil ditentukan pada permintaan pertama, permintaan-permintaan berikutnya menggunakan kembali daftar yang tersimpan dalam cache tanpa melakukan kueri ulang ke sumber data. Untuk menonaktifkan cache (misalnya, saat pengembangan ketika definisi skill sering berubah), gunakan DisableCaching() pada builder:

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

Nota

Menonaktifkan cache berguna selama pengembangan ketika konten skill sering berubah. Dalam produksi, pertahankan pencaching diaktifkan sebagai pengaturan default untuk kinerja yang lebih baik.

Perilaku cache

Secara default, alat keterampilan dan instruksi di-cache setelah build pertama. Atur disable_caching=True untuk memaksa pembangunan ulang pada setiap pemanggilan:

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

disable_caching juga tersedia pada konstruktor SkillsProvider untuk skill yang ditentukan melalui kode dan yang berbasis kelas.

Untuk tetap mengaktifkan cache tetapi menemukan ulang skill secara berkala (misalnya, ketika sumber berbasis file atau MCP berubah selama masa aktif proses), teruskan cache_refresh_interval. Cache bawaan diperlakukan sebagai basi setelah lebih lama dari interval, sehingga eksekusi berikutnya mengkueri ulang sumber:

from datetime import timedelta

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

cache_refresh_interval hanya memengaruhi cache yang dibangun secara internal oleh penyedia (dari skill atau jalur file); diabaikan ketika disable_caching=True dan tidak berpengaruh pada SkillsSource yang disediakan pemanggil (susun CachingSkillsSource Anda sendiri dengan refresh_interval untuk itu).

Nota

Menonaktifkan cache berguna selama pengembangan ketika konten skill sering berubah. Dalam produksi, pertahankan pencaching diaktifkan sebagai pengaturan default untuk kinerja yang lebih baik.

Persetujuan alat

Semua alat yang diekspos oleh AgentSkillsProvider (load_skill, read_skill_resource, run_skill_script) memerlukan persetujuan secara default. Saat panggilan alat memerlukan persetujuan, agen berhenti sejenak dan mengembalikan ToolApprovalRequestContent alih-alih langsung mengeksekusinya. Gunakan UseToolApproval middleware dengan aturan persetujuan otomatis untuk secara selektif melewati perintah untuk operasi tepercaya:

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

Untuk menyetujui secara otomatis semua alat skill, termasuk eksekusi skrip:

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

Menonaktifkan persetujuan untuk alat tertentu

Gunakan AgentSkillsProviderOptions untuk menonaktifkan persetujuan untuk alat individual, menghapusnya dari alur persetujuan sepenuhnya:

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

Ketika beberapa alat memerlukan persetujuan dan yang lain tidak dalam respons yang sama, model dapat memanggil kedua jenis secara bersamaan. Atur EnableNonApprovalRequiredFunctionBypassing agar alat yang tidak memerlukan persetujuan langsung dijalankan, sementara pengguna hanya akan diminta persetujuan untuk alat lainnya:

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

Menangani permintaan persetujuan

Ketika alat memerlukan persetujuan (dan tidak ada aturan persetujuan otomatis yang cocok), agen mengembalikan ToolApprovalRequestContent item yang harus disetujui atau ditolak sebelum melanjutkan:

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

Detail kesalahan skrip

Secara bawaan, ketika eksekusi skrip skill gagal, pengecualian diteruskan ke FunctionInvokingChatClient yang mendasarinya. Jika propertinya IncludeDetailedErrors diatur ke true, pesan pengecualian diteruskan ke model, memungkinkannya untuk mengoreksi sendiri dengan mencoba kembali dengan argumen yang berbeda:

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

Jika Anda tidak dapat mengonfigurasi FunctionInvokingChatClient secara langsung, atur AgentSkillsProviderOptions.IncludeDetailedErrors sebagai gantinya. Ini menangkap pengecualian di tingkat penyedia keterampilan dan mengembalikan pesan kesalahan langsung ke model:

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

Peringatan

Kedua pendekatan tersebut dapat mengungkap detail mentah tentang pengecualian kepada model. Pesan pengecualian dapat berisi informasi sensitif seperti string koneksi, jalur file, atau nama layanan internal. Selain itu, jika skill atau skrip berasal dari sumber yang tidak tepercaya, skrip yang dirancang secara berbahaya dapat memicu pengecualian dengan pesan yang menyisipkan muatan injeksi prompt.

Semua alat yang diekspos oleh SkillsProvider (load_skill, read_skill_resource, dan run_skill_script) memerlukan persetujuan secara default. Ketika pemanggilan alat memerlukan persetujuan, agen berhenti sejenak dan mengembalikan permintaan persetujuan melalui result.user_input_requests alih-alih langsung mengeksekusinya. Anda menyetujui atau menolak setiap permintaan dengan request.to_function_approval_response(approved=...) dan mengirim respons kembali:

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)

Ketika panggilan alat ditolak (approved=False), agen diberitahu bahwa pengguna menolak dan dapat merespons dengan sesuai.

Menyetujui alat tepercaya secara otomatis

Alih-alih meminta konfirmasi untuk setiap panggilan, instal ToolApprovalMiddleware dengan salah satu aturan persetujuan otomatis statis yang disediakan oleh SkillsProvider. Ini memungkinkan alat baca-saja berjalan secara otomatis sambil tetap meminta eksekusi skrip:

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

Dua aturan tersedia:

  • SkillsProvider.read_only_tools_auto_approval_rule - hanya menyetujui alat hanya-baca (load_skill, read_skill_resource) namun tetap meminta run_skill_script.
  • SkillsProvider.all_tools_auto_approval_rule - menyetujui semua alat skill, termasuk run_skill_script (tidak memerlukan proses persetujuan manual).

Kedua aturan menolak panggilan apa pun yang menyertakan server_label, sehingga cakupannya tetap terbatas pada alat lokal milik penyedia ini dan tidak pernah menyetujui secara otomatis alat terhosting dengan nama yang sama. Aturan ini hanya berlaku untuk alat yang masih memerlukan persetujuan - alat yang dikecualikan melalui argumen disable_*_approval di bawah ini tetap dijalankan tanpa persetujuan.

Menonaktifkan persetujuan untuk alat tertentu

Untuk skill tepercaya, teruskan disable_load_skill_approval, disable_read_skill_resource_approval, dan/atau disable_run_skill_script_approval untuk mengecualikan masing-masing alat sepenuhnya dari alur persetujuan (alat tersebut didaftarkan dengan 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
)

Argumen ini juga tersedia di SkillsProvider.from_paths().

Peringatan

Hanya nonaktifkan persetujuan, atau setujui eksekusi skrip secara otomatis, untuk keterampilan dan skrip dari sumber yang Anda percayai. Instruksi keterampilan disuntikkan ke dalam konteks agen, dan run_skill_script menjalankan kode yang disediakan oleh sumber.

Prompt sistem kustom

Secara default, penyedia keterampilan menyuntikkan permintaan sistem yang mencantumkan keterampilan yang tersedia dan menginstruksikan agen untuk menggunakan load_skill dan read_skill_resource. Anda dapat menyesuaikan perintah ini:

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

Nota

Templat kustom harus berisi {skills} sebagai tempat penampung untuk daftar keterampilan yang dihasilkan. Kurung kurawal literal harus di-escape sebagai {{ dan }}.

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

Nota

Templat kustom harus berisi placeholder {skills} untuk daftar keterampilan yang dihasilkan. Ini dapat berisi placeholder {resource_instructions} (petunjuk alat sumber daya) dan {runner_instructions} (petunjuk alat skrip) secara opsional; saat tersedia, placeholder tersebut diisi dengan panduan bawaan, dan saat dihilangkan, placeholder tersebut tidak ditampilkan (alat terkait tetap terdaftar). Kurung kurawal literal harus di-escape sebagai {{ dan }}.

Menyuntikkan layanan dan argumen saat proses berjalan

Sumber daya keterampilan dan fungsi skrip dapat menerima konteks aplikasi eksternal yang disediakan saat runtime.

Sumber daya keterampilan dan delegasi skrip dapat mendeklarasikan parameter IServiceProvider yang secara otomatis disuntikkan oleh Kerangka Kerja Agen. Ini memungkinkan keterampilan menyelesaikan layanan aplikasi terdaftar sesuai permintaan.

Siapkan

Daftarkan layanan aplikasi Anda dan teruskan hasil kompilasi IServiceProvider ke agen melalui parameter 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);

Keterampilan yang ditentukan kode dengan DI

Nyatakan IServiceProvider sebagai parameter dalam AddResource atau AddScript delegasi - kerangka kerja menyelesaikan dan menyuntikkannya secara otomatis saat agen membaca sumber daya atau menjalankan skrip:

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

Keterampilan berbasis kelas dengan DI

Anotasi metode dengan [AgentSkillResource] atau [AgentSkillScript] dan deklarasikan IServiceProvider parameter - kerangka kerja menemukan anggota ini melalui pantulan dan menyuntikkan penyedia layanan secara otomatis:

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

Tip

Keterampilan berbasis kelas juga dapat menyelesaikan dependensi melalui konstruktornya. Daftarkan kelas kemampuan di ServiceCollection dan panggil dari kontainer alih-alih memanggil new secara langsung:

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

Ini berguna ketika kelas keterampilan itu sendiri membutuhkan layanan yang disuntikkan di luar apa yang digunakan oleh delegasi sumber daya dan skrip.

Fungsi sumber daya dan skrip yang menerima **kwargs secara otomatis menerima argumen kata kunci runtime yang diteruskan ke agent.run(). Ini memungkinkan fungsi keterampilan mengakses konteks aplikasi - seperti konfigurasi, identitas pengguna, atau klien layanan - tanpa mengkodekannya secara permanen ke dalam definisi keterampilan.

Meneruskan argumen runtime

Teruskan function_invocation_kwargs ke agent.run() untuk menyediakan argumen kata kunci yang diteruskan kerangka kerja ke fungsi sumber daya dan skrip:

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

Keterampilan yang ditentukan oleh kode dengan kwargs

Ketika fungsi sumber daya mendeklarasikan **kwargs, kerangka kerja meneruskan argumen kata kunci runtime setiap kali agen membaca sumber daya:

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

Fungsi sumber daya tanpa **kwargs dipanggil tanpa argumen dan tidak menerima konteks runtime.

Ketika fungsi skrip mendeklarasikan **kwargs, kerangka kerja meneruskan argumen kata kunci runtime bersama args yang disediakan oleh agen:

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

Agen menyediakan value dan factor melalui panggilan alat args; aplikasi menyediakan precision melalui function_invocation_kwargs. Fungsi skrip tanpa **kwargs hanya menerima argumen yang disediakan agen.

Keterampilan berbasis kelas dengan kwargs

Metode keterampilan berbasis kelas juga dapat menerima **kwargs untuk menerima argumen runtime. Pola bekerja dengan cara yang sama - nyatakan **kwargs pada metode sumber daya atau metode skrip:

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

Praktik terbaik keamanan

Keterampilan Agen harus diperlakukan seperti kode pihak ketiga yang Anda bawa ke dalam proyek Anda. Karena instruksi keterampilan disuntikkan ke dalam konteks agen - dan keterampilan dapat mencakup skrip - menerapkan tingkat peninjauan dan tata kelola yang sama yang Anda lakukan pada dependensi sumber terbuka sangat penting.

  • Tinjau sebelum digunakan - Baca semua konten keterampilan (SKILL.md, skrip, dan sumber daya) sebelum menyebarkan. Verifikasi bahwa perilaku aktual skrip cocok dengan niat yang dinyatakan. Periksa instruksi adversarial yang mencoba melewati pedoman keselamatan, menyelundupkan data, atau memodifikasi file konfigurasi agen.
  • Kepercayaan terhadap sumber - Hanya instal keterampilan dari penulis tepercaya atau kontributor internal yang telah diverifikasi. Lebih suka kemampuan dengan sumber yang jelas, kontrol versi, dan pemeliharaan aktif. Waspadai nama kemampuan yang menyerupai nama paket populer.
  • Sandboxing - Jalankan keterampilan yang menyertakan skrip yang dapat dieksekusi di lingkungan terisolasi. Batasi sistem file, jaringan, dan akses tingkat sistem hanya untuk apa yang dibutuhkan keterampilan. Memerlukan konfirmasi pengguna eksplisit sebelum menjalankan operasi yang berpotensi sensitif.
  • Audit dan pengelogan - Catat keterampilan mana yang dimuat, sumber daya mana yang dibaca, dan skrip mana yang dijalankan. Ini memberi Anda jejak audit untuk menelusuri tingkah laku agen hingga ke konten keterampilan tertentu jika terjadi kesalahan.

Kapan menggunakan keterampilan vs. alur kerja

Keterampilan Agen dan Alur Kerja Kerangka Kerja Agen memperluas apa yang dapat dilakukan agen, tetapi mereka bekerja dengan cara yang pada dasarnya berbeda. Pilih pendekatan yang paling sesuai dengan kebutuhan Anda:

  • Kontrol - Dengan keterampilan, AI memutuskan cara menjalankan instruksi. Ini sangat ideal ketika Anda ingin agen menjadi kreatif atau adaptif. Dengan alur kerja, Anda secara eksplisit menentukan jalur eksekusi. Gunakan alur kerja saat Anda memerlukan perilaku deterministik dan dapat diprediksi.
  • Ketahanan - Keterampilan berjalan dalam satu giliran agen. Jika terjadi kegagalan, seluruh operasi harus dicoba kembali. Alur kerja mendukung checkpointing, sehingga dapat dilanjutkan dari langkah terakhir yang berhasil setelah kegagalan. Pilih alur kerja saat biaya eksekusi ulang seluruh proses tinggi.
  • Efek samping - Skill cocok digunakan saat operasi bersifat idempoten atau berisiko rendah. Lebih suka alur kerja ketika langkah-langkah menghasilkan efek samping (mengirim email, menagih pembayaran) yang tidak boleh diulang saat mencoba kembali.
  • Kompleksitas - Keterampilan adalah yang terbaik untuk tugas domain tunggal terfokus yang dapat ditangani oleh satu agen. Alur kerja lebih cocok untuk proses bisnis multi-langkah yang mengoordinasikan beberapa agen, persetujuan manusia, atau integrasi sistem eksternal.

Tip

Sebagai aturan praktis: jika Anda ingin AI mencari tahu cara menyelesaikan tugas, gunakan keterampilan. Jika Anda perlu menjamin langkah-langkah apa yang dijalankan dan dalam urutan apa, gunakan alur kerja.

Langkah selanjutnya