Habilidades do Agente

As Habilidades do Agente são pacotes portáteis de instruções, scripts e recursos que fornecem aos agentes recursos especializados e experiência de domínio. As habilidades seguem uma especificação aberta e implementam um padrão de divulgação progressiva para que os agentes carreguem apenas o contexto necessário, quando precisarem.

Use as habilidades do agente quando quiser:

  • Empacote o conhecimento de domínio - Capture conhecimento especializado (políticas de despesas, fluxos de trabalho jurídicos, pipelines de análise de dados) como pacotes reutilizáveis e portáteis.
  • Estender as funcionalidades do agente – dê aos agentes novas habilidades sem alterar suas instruções principais.
  • Garantir a consistência – transforme tarefas de várias etapas em fluxos de trabalho repetíveis e auditáveis.
  • Habilitar a interoperabilidade – reutilize a mesma habilidade em diferentes produtos compatíveis com habilidades de agente.

Estrutura de habilidades

Uma habilidade é um diretório que contém um SKILL.md arquivo com subdiretórios opcionais para recursos:

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

formato SKILL.md

O SKILL.md arquivo deve conter o frontmatter YAML seguido pelo conteúdo de markdown:

---
name: expense-report
description: File and validate employee expense reports according to company policy. Use when asked about expense submissions, reimbursement rules, or spending limits.
license: Apache-2.0
compatibility: Requires python3
metadata:
  author: contoso-finance
  version: "2.1"
---
Campo Obrigatório DESCRIÇÃO
name Yes Máximo de 64 caracteres. Letras minúsculas, números e hifens somente. Não deve iniciar ou terminar com um hífen ou conter hifens consecutivos. Deve corresponder ao nome do diretório pai.
description Yes O que a habilidade faz e quando usá-la. Máximo de 1024 caracteres. Deve incluir palavras-chave que ajudam os agentes a identificar tarefas relevantes.
license Não Nome da licença ou referência a um arquivo de licença empacotado.
compatibility Não Máximo de 500 caracteres. Indica os requisitos de ambiente (produto pretendido, pacotes do sistema, acesso à rede etc.).
metadata Não Mapeamento arbitrário de chave-valor para metadados adicionais.
allowed-tools Não Lista delimitada por espaço de ferramentas pré-aprovadas que a habilidade pode usar. Experimental – o suporte pode variar entre implementações de agente.

O corpo de markdown após o frontmatter contém as instruções de habilidade – orientação passo a passo, exemplos de entradas e saídas, casos de borda comuns ou qualquer conteúdo que ajude o agente a executar a tarefa. Mantenha SKILL.md com menos de 500 linhas e transfira o material detalhado de referência para arquivos separados.

Divulgação progressiva

As Habilidades do Agente usam um padrão de divulgação progressiva de quatro estágios para minimizar o uso de contexto:

  1. Anunciar (aproximadamente 100 tokens por habilidade) – nomes de habilidade e descrições são injetados no prompt do sistema no início de cada execução, para que o agente saiba quais habilidades estão disponíveis.
  2. Carga (< 5000 tokens recomendados) - Quando uma tarefa corresponde ao domínio de uma habilidade, o agente chama a ferramenta load_skill para recuperar o conteúdo completo do SKILL.md com instruções detalhadas.
  3. Ler recursos (conforme necessário) – O agente chama a read_skill_resource ferramenta para buscar arquivos suplementares (referências, modelos, ativos) somente quando necessário.
  4. Executar scripts (conforme necessário) - o agente chama a ferramenta run_skill_script para executar scripts incluídos em uma habilidade.

Esse padrão mantém a janela de contexto do agente enxuta, dando-lhe acesso ao conhecimento profundo do domínio sob demanda.

Observação

load_skill é sempre anunciado. read_skill_resource é anunciado somente quando pelo menos uma habilidade tem recursos. run_skill_script é anunciado somente quando pelo menos uma habilidade tem scripts.

Fornecendo habilidades a um agente

AgentSkillsProvider (C#) e SkillsProvider (Python) são provedores de contexto que disponibilizam habilidades aos agentes. Eles dão suporte a três fontes de habilidade:

  • Baseado em arquivos - habilidades descobertas a partir de arquivos SKILL.md em diretórios no sistema de arquivos
  • Definido no código - habilidades definidas diretamente no código usando AgentInlineSkill (C#) ou InlineSkill (Python)
  • Class-based - habilidades encapsuladas em uma classe derivada de AgentClassSkill<T> (C#) ou ClassSkill (Python)

Para misturar várias fontes em um provedor, use AgentSkillsProviderBuilder (C#) ou compor classes de origem, como AggregatingSkillsSource, FilteringSkillsSource e DeduplicatingSkillsSource (Python) – consulte Builder: cenários avançados de várias fontes (C#) ou A composição de fonte: cenários avançados de várias fontes (Python).

Habilidades baseadas em arquivo

Crie um AgentSkillsProvider apontando para um diretório que contenha suas habilidades e adicione-o aos provedores de contexto do agente. Passe um executor de script para habilitar a execução de scripts baseados em arquivo encontrados em diretórios de habilidades:

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

Aviso

DefaultAzureCredential é conveniente para o desenvolvimento, mas requer uma consideração cuidadosa na produção. Em produção, considere o uso de uma credencial específica (por exemplo, ManagedIdentityCredential) para evitar problemas de latência, investigação de credenciais não intencionais e possíveis riscos de segurança de mecanismos de fallback.

Vários diretórios de habilidades

Você pode apontar o provedor para um único diretório pai - cada subdiretório que contém um SKILL.md é descoberto automaticamente como uma habilidade:

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

Ou passe uma lista de caminhos para pesquisar vários diretórios raiz:

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

O provedor pesquisa em até dois níveis de profundidade.

Personalizando a descoberta de recursos

Por padrão, o provedor reconhece recursos com extensões .md, .json, .yaml, .yml, .csv, .xml e .txt em subdiretórios references e assets. Use AgentFileSkillsSourceOptions para alterar esses padrões:

var fileOptions = new AgentFileSkillsSourceOptions
{
    AllowedResourceExtensions = [".md", ".txt"],
    ResourceDirectories = ["docs", "templates"],
};

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

Execução do script

Passe SubprocessScriptRunner.RunAsync como o segundo argumento para AgentSkillsProvider habilitar a execução de scripts baseados em arquivos:

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

SubprocessScriptRunner.RunAsync é aproximadamente equivalente ao seguinte:

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

static async Task<string> RunAsync(
    AgentFileSkill skill,
    AgentFileSkillScript script,
    JsonElement? args,
    IServiceProvider? serviceProvider)
{
    var psi = new ProcessStartInfo("python3")
    {
        RedirectStandardOutput = true,
        UseShellExecute = false,
    };
    psi.ArgumentList.Add(Path.Combine(skill.Path, script.Path));
    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();
    await process.WaitForExitAsync();
    return output.Trim();
}

O executor executa cada script descoberto como um subprocesso local. Os scripts baseados em arquivo esperam argumentos como uma matriz JSON de cadeias de caracteres – cada elemento de matriz se torna um argumento de linha de comando posicional.

Aviso

SubprocessScriptRunner é fornecido somente para fins de demonstração. Para uso em produção, considere adicionar:

  • Sandboxing (por exemplo, contêineres ou ambientes de execução isolados)
  • Limites de recursos (CPU, memória, tempo limite do relógio de parede)
  • Validação de entrada e lista de permissões de scripts executáveis
  • Registros e trilhas de auditoria estruturadas

Personalizando a descoberta de script

Por padrão, o provedor reconhece scripts com extensões.py, .js, .sh, , .ps1e .cs.csx no scripts subdiretório. Use AgentFileSkillsSourceOptions para alterar esses padrões:

Passe AgentFileSkillsSourceOptions para o AgentSkillsProvider construtor ou para UseFileSkill / UseFileSkills o construtor:

var fileOptions = new AgentFileSkillsSourceOptions
{
    AllowedScriptExtensions = [".py"],
    ScriptDirectories = ["scripts", "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();

Habilidades baseadas em arquivo

Use a fábrica SkillsProvider.from_paths() para descobrir habilidades em diretórios que contêm arquivos SKILL.md e adicione o provedor aos provedores de contexto do agente:

import os
from pathlib import Path
from agent_framework import Agent, SkillsProvider
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential

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

Vários diretórios de habilidades

Você pode apontar o provedor para um único diretório pai - cada subdiretório que contém um SKILL.md é descoberto automaticamente como uma habilidade:

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

Ou passe uma lista de caminhos para pesquisar vários diretórios raiz:

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

O provedor pesquisa em até dois níveis de profundidade.

Personalizando a descoberta de recursos e scripts

Por padrão, os recursos são descobertos nos subdiretórios references/ e assets/, e os scripts em scripts/, conforme a especificação agentskills.io. As extensões de recurso reconhecidas são .md, .json, .yaml, .yml, .csv, .xml e .txt. Use resource_directories, script_directories e resource_extensions para personalizar esses padrões:

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    resource_extensions=(".md", ".txt"),
    resource_directories=["docs", "templates"],
    script_directories=["scripts", "tools"],
)

Use "." para incluir arquivos no nível raiz da habilidade, além de subdiretórios.

Execução do script

Para habilitar a execução de scripts baseados em arquivo, passe um script_runner para SkillsProvider.from_paths(). Qualquer sincronização ou chamada assíncrona que atenda ao SkillScriptRunner protocolo pode ser usada:

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

O executor recebe os argumentos resolvidos FileSkill, FileSkillScript e um argumento opcional args. Os scripts baseados em arquivo esperam argumentos como uma matriz JSON de cadeias de caracteres – cada elemento de matriz se torna um argumento de linha de comando posicional. Os scripts são descobertos automaticamente a partir de .py arquivos no scripts/ subdiretório de cada diretório de habilidades.

Aviso

O executor acima é fornecido somente para fins de demonstração. Para uso em produção, considere adicionar:

  • Sandboxing (por exemplo, contêineres seccomp ou firejail)
  • Limites de recursos (CPU, memória, tempo limite do relógio de parede)
  • Validação de entrada e lista de permissões de scripts executáveis
  • Registros e trilhas de auditoria estruturadas

Observação

Se habilidades baseadas em arquivos com scripts forem fornecidas, mas script_runner não estiver definido, SkillsProvider gerará um erro quando se tentar executar o script.

Habilidades definidas por código

Além das habilidades baseadas em arquivo descobertas nos SKILL.md arquivos, você pode definir habilidades inteiramente no código usando AgentInlineSkill. As habilidades definidas por código são úteis quando:

  • O conteúdo da habilidade é gerado dinamicamente (por exemplo, leitura de um banco de dados ou ambiente).
  • Você deseja manter definições de habilidade junto com o código do aplicativo que as usa.
  • Você precisa de recursos que executem a lógica em tempo de leitura em vez de servir arquivos estáticos.
  • As definições de habilidades precisam ser construídas em runtime a partir de dados , por exemplo, criar uma habilidade personalizada para cada sessão de usuário com base em sua função ou permissões.
  • Uma habilidade precisa ser fechada sobre o estado do site de chamada (variáveis locais, fechamentos) em vez de resolver serviços de um contêiner de DI.

Habilidade básica de código

Crie um AgentInlineSkill com um nome, uma descrição e instruções. Anexar recursos usando .AddResource():

using Microsoft.Agents.AI;

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

var skillsProvider = new AgentSkillsProvider(codeStyleSkill);

Recursos dinâmicos

Passe um delegado de fábrica para .AddResource() calcular o conteúdo em runtime. O delegado é invocado sempre que o agente lê o recurso:

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

Scripts definidos por código

Use .AddScript() para registrar um delegado como um script executável. Scripts definidos por código são executados em processo como chamadas de delegado direto. Nenhum executor de script é necessário. Os parâmetros digitados do delegado são automaticamente convertidos em um esquema JSON que o agente usa para passar argumentos:

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

Observação

Para combinar habilidades definidas por código com habilidades baseadas em arquivo ou baseadas em classe em um único provedor, use AgentSkillsProviderBuilder - consulte Builder: cenários avançados de várias fontes.

Além das habilidades baseadas em arquivos descobertas em arquivos SKILL.md, você pode definir habilidades inteiramente em código Python usando InlineSkill. As habilidades definidas por código são úteis quando:

  • O conteúdo da habilidade é gerado dinamicamente (por exemplo, leitura de um banco de dados ou ambiente).
  • Você deseja manter definições de habilidade junto com o código do aplicativo que as usa.
  • Você precisa de recursos que executem a lógica em tempo de leitura em vez de servir arquivos estáticos.
  • As definições de habilidades precisam ser construídas em runtime a partir de dados , por exemplo, criar uma habilidade personalizada para cada sessão de usuário com base em sua função ou permissões.
  • Uma habilidade precisa capturar o estado no local da chamada (variáveis locais, closures) em vez de resolver serviços por meio de **kwargs.

Habilidade básica de código

Crie uma InlineSkill instância com um SkillFrontmatter (contendo o nome e a descrição) e o conteúdo da instrução. Opcionalmente, anexe InlineSkillResource instâncias com conteúdo estático:

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)

Recursos dinâmicos

Use o @skill.resource decorador para registrar uma função como um recurso. A função é chamada cada vez que o agente lê o recurso, para que possa retornar dados atualizados. Há suporte para funções de sincronização e assíncronas:

import os
from agent_framework import InlineSkill, SkillFrontmatter

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

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

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

Quando o decorador é usado sem argumentos (@skill.resource), o nome da função se torna o nome do recurso e o docstring se torna a descrição. Use @skill.resource(name="...", description="...") para defini-los explicitamente.

Scripts definidos por código

Use o @skill.script decorador para registrar uma função como um script executável em uma habilidade. Os scripts definidos por código são executados em processo e não exigem um executor de script. Há suporte para funções de sincronização e assíncronas:

from agent_framework import InlineSkill, SkillFrontmatter

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

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

Quando o decorador é usado sem argumentos (@skill.script), o nome da função se torna o nome do script e o docstring se torna a descrição. Os parâmetros tipados da função são convertidos automaticamente num esquema JSON que o agente usa para passar argumentos.

Habilidades baseadas em classe

As habilidades baseadas em classe permitem que você agrupe todos os componentes de habilidades – nome, descrição, instruções, recursos e scripts – em uma única classe C#. Isso os torna fáceis de empacotar e distribuir como pacotes NuGet - as equipes podem criar e enviar habilidades de forma independente, e os consumidores as adicionam com dotnet add package e uma única .UseSkill() chamada. Derivar de AgentClassSkill<T> (onde T é sua classe), em seguida, anotar propriedades com [AgentSkillResource] e métodos com [AgentSkillScript] para descoberta automática.

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

Registre a habilidade baseada em classe com AgentSkillsProvider:

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

Quando o [AgentSkillResource] atributo é aplicado a uma propriedade ou método, seu valor retornado é usado como o conteúdo do recurso quando o agente lê o recurso – use um método quando o conteúdo precisar ser computado em tempo de leitura. Quando [AgentSkillScript] é aplicado a um método, o método é invocado quando o agente chama o script. Use [Description] de System.ComponentModel para descrever cada recurso e script para o agente.

Observação

AgentClassSkill<T> também oferece suporte à substituição de Resources e Scripts como coleções para cenários em que a descoberta baseada em atributos não é adequada.

Habilidades baseadas em classe

As habilidades baseadas em classe permitem agrupar todos os componentes de habilidade - nome, descrição, instruções, recursos e scripts - em uma única classe Python. Isso os torna fáceis de empacotar e distribuir como pacotes PyPI - as equipes podem criar e enviar habilidades de forma independente, e os consumidores as adicionam com pip install e uma única SkillsProvider() chamada. Crie uma subclasse de ClassSkill e, em seguida, use os decoradores @ClassSkill.resource e @ClassSkill.script para descoberta automática:

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

Registre a habilidade baseada em classe com SkillsProvider:

from agent_framework import SkillsProvider

skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)

Quando @ClassSkill.resource é aplicado como um decorador nu (sem argumentos), o nome do método se torna o nome do recurso (com sublinhados convertidos em hifens) e o docstring se torna a descrição. Use @ClassSkill.resource(name="...", description="...") para defini-los explicitamente. O mesmo padrão se aplica a @ClassSkill.script.

Os recursos podem ser definidos como métodos regulares ou @property descritores. Ao usar @property, coloque @property o primeiro e @ClassSkill.resource o segundo. Os valores de retorno de recurso são armazenados em cache após o primeiro acesso.

Observação

ClassSkill também oferece suporte à substituição explícita das propriedades resources e scripts para retornar instâncias de InlineSkillResource e InlineSkillScript diretamente, em cenários nos quais a descoberta baseada em decoradores não é adequada.

Gerador: cenários avançados de múltiplas fontes

Para cenários simples de origem única, use os AgentSkillsProvider construtores diretamente. Use AgentSkillsProviderBuilder quando precisar de qualquer um dos seguintes:

  • Tipos de habilidades mistas – combinar habilidades baseadas em arquivo, definidas por código (AgentInlineSkill) e baseadas em classe (AgentClassSkill) em um único provedor.
  • Filtragem de habilidades – incluir ou excluir habilidades usando um predicado.

Tipos de habilidades mistas

Combine todos os três tipos de competência em um provedor encadeando UseFileSkill, UseSkill e UseFileScriptRunner:

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

Filtragem de habilidades

Use UseFilter para incluir apenas as habilidades que atendem aos seus critérios , por exemplo, para carregar habilidades de um diretório compartilhado, mas excluir as experimentais:

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

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

Composição de origem: cenários avançados de várias fontes

Para cenários simples com uma única habilidade ou uma lista de habilidades, passe-os diretamente para o SkillsProvider construtor. Para habilidades baseadas em arquivo, use a SkillsProvider.from_paths() fábrica. Para cenários avançados, redigir classes de origem para controlar a descoberta, a filtragem e a eliminação de duplicação:

  • FileSkillsSource – descobre habilidades a partir de arquivos SKILL.md no disco.
  • InMemorySkillsSource - encapsula todas Skill as instâncias (definidas por código ou baseadas em classe) na memória.
  • AggregatingSkillsSource – combina várias fontes em uma.
  • FilteringSkillsSource – aplica um predicado para incluir ou excluir habilidades.
  • DeduplicatingSkillsSource - remove nomes de habilidades duplicados (sem diferenciar maiúsculas de minúsculas, mantendo a primeira ocorrência).

Tipos de habilidades mistas

Combine habilidades baseadas em arquivo, definidas por código e baseadas em classe em um provedor usando AggregatingSkillsSource. O exemplo abaixo usa objetos marcadores:

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

Filtragem de habilidades

Use FilteringSkillsSource para controlar quais habilidades o agente vê. O predicado recebe cada Skill e retorna True para incluí-lo. Por exemplo, para carregar habilidades de um diretório compartilhado, mas ocultar uma experimental:

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: skill.frontmatter.name != "experimental-tools",
        )
    )
)

Aprovação de script

Use AgentSkillsProviderOptions.ScriptApproval para bloquear toda a execução de script por trás da aprovação humana. Quando habilitado, o agente pausa e retorna uma solicitação de aprovação em vez de executar imediatamente:

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

Para habilitar a aprovação de script em um provedor configurado pelo construtor, use UseScriptApproval:

var skillsProvider = new AgentSkillsProviderBuilder()
    .UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
    .UseScriptApproval(true)
    .Build();

Use require_script_approval=True no SkillsProvider para condicionar toda a execução de script à aprovação humana. Em vez de executar imediatamente, o agente faz uma pausa e envia solicitações de aprovação via result.user_input_requests:

from textwrap import dedent
from agent_framework import Agent, InlineSkill, 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}"

skills_provider = SkillsProvider(deployment_skill, require_script_approval=True)

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

    # Handle approval requests
    while result.user_input_requests:
        for request in result.user_input_requests:
            print(f"Script: {request.function_call.name}")
            print(f"Args: {request.function_call.arguments}")

            approval = request.to_function_approval_response(approved=True)
            result = await agent.run(approval, session=session)

    print(result)

Quando um script é rejeitado (approved=False), o agente é informado de que o usuário recusou e pode responder adequadamente.

Prompt personalizado do sistema

Por padrão, o provedor de habilidades injeta um prompt do sistema que lista as habilidades disponíveis e instrui o agente a usar load_skill e read_skill_resource. Você pode personalizar este prompt:

var skillsProvider = new AgentSkillsProvider(
    skillPath: Path.Combine(AppContext.BaseDirectory, "skills"),
    options: new AgentSkillsProviderOptions
    {
        SkillsInstructionPrompt = """
            You have skills available. Here they are:
            {skills}
            {resource_instructions}
            {script_instructions}
            """
    });

Observação

O modelo personalizado deve conter os espaços reservados {skills} (lista de habilidades), {resource_instructions} (dica de ferramenta de recurso) e {script_instructions} (dica de ferramenta de script). Chaves literais devem ser escapadas como {{ e }}.

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

Observação

O modelo personalizado deve conter os espaços reservados {skills} (lista de habilidades), {resource_instructions} (dica de ferramenta de recurso) e {runner_instructions} (dica de ferramenta de script). Chaves literais devem ser escapadas como {{ e }}.

Comportamento de cache

Por padrão, as ferramentas de habilidade e as instruções são armazenadas em cache após o primeiro build. Defina DisableCaching = true em AgentSkillsProviderOptions para forçar uma recompilação a cada invocação:

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

Observação

Desabilitar o cache é útil durante o desenvolvimento quando o conteúdo da habilidade é alterado com frequência. Na produção, deixe o cache habilitado (o padrão) para melhorar o desempenho.

Comportamento de cache

Por padrão, as ferramentas de habilidade e as instruções são armazenadas em cache após o primeiro build. Defina disable_caching=True para forçar uma reconstrução a cada invocação:

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

disable_caching também está disponível no construtor SkillsProvider para habilidades definidas por código e baseadas em classes.

Observação

Desabilitar o cache é útil durante o desenvolvimento quando o conteúdo da habilidade é alterado com frequência. Na produção, deixe o cache habilitado (o padrão) para melhorar o desempenho.

Os representantes de script e recursos de habilidade podem declarar um IServiceProvider parâmetro que o Agent Framework injeta automaticamente. Isso permite que as habilidades resolvam serviços de aplicativo - como clientes de banco de dados, configuração ou lógica de negócios - sem codificá-los na definição de habilidade.

Configuração

Registre seus serviços de aplicativo e passe o compilado IServiceProvider para o agente por meio do services parâmetro:

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

Habilidades definidas por código com DI

Declare IServiceProvider como um parâmetro em delegates AddResource ou AddScript — o framework o resolve e injeta automaticamente quando o agente lê um recurso ou executa um script:

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

Habilidades baseadas em classe com DI

Anote métodos com [AgentSkillResource] ou [AgentSkillScript] e declare um parâmetro IServiceProvider — o framework descobre esses membros por reflexão e injeta o provedor de serviços automaticamente:

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

As habilidades baseadas em classe também podem resolver dependências através de seu construtor. Registre a classe de habilidade no ServiceCollection contêiner e resolva-a em vez de chamar new diretamente:

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

Isso é útil quando a classe de habilidade em si precisa de serviços injetados além do que os delegados de script e de recurso usam.

Funções de recurso e script que aceitam **kwargs recebem automaticamente argumentos de palavra-chave de tempo de execução passados para agent.run(). Isso permite que as funções de habilidade acessem o contexto do aplicativo - como configuração, identidade do usuário ou clientes de serviço - sem codificá-las na definição de habilidade.

Passando argumentos de tempo de execução

Passe function_invocation_kwargs para agent.run() fornecer argumentos de palavra-chave que a estrutura encaminha para funções de recurso e script:

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

Habilidades definidas por código com kwargs

Quando uma função de recurso é declarada **kwargs, a estrutura encaminha os argumentos de palavra-chave de runtime sempre que o agente lê o recurso:

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

As funções de recurso sem **kwargs são chamadas sem argumentos e não recebem contexto de runtime.

Quando uma função de script é declarada **kwargs, a estrutura encaminha os argumentos de palavra-chave de runtime junto com o args fornecido pelo agente:

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

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

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

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

O agente fornece value e factor através da chamada de ferramenta args; o aplicativo fornece precision através do function_invocation_kwargs. Funções de script sem **kwargs recebem apenas os argumentos fornecidos pelo agente.

Habilidades baseadas em classe com kwargs

Os métodos de habilidade baseados em classe também podem aceitar **kwargs para receber argumentos em tempo de execução. O padrão funciona da mesma maneira : declare **kwargs sobre métodos de recurso ou métodos de script:

from typing import Any
from agent_framework import ClassSkill, SkillFrontmatter

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

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

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

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

Melhores práticas de segurança

As habilidades do agente devem ser tratadas como qualquer código de terceiros que você colocar em seu projeto. Como as instruções de habilidade são injetadas no contexto do agente - e as habilidades podem incluir scripts - aplicar o mesmo nível de revisão e governança que você faria a uma dependência de software livre é essencial.

  • Revise antes de usar - Leia todo o conteúdo da skill (SKILL.md, scripts e recursos) antes de implantar. Verifique se o comportamento real de um script corresponde à sua intenção declarada. Verifique se há instruções adversárias que tentam ignorar diretrizes de segurança, exfiltrar dados ou modificar arquivos de configuração do agente.
  • Confiança de origem – instale apenas habilidades de autores confiáveis ou colaboradores internos examinados. Prefira habilidades com procedência clara, controle de versão e manutenção ativa. Fique atento aos nomes de funcionalidades com erros de digitação que imitam pacotes populares.
  • Área restrita – executar habilidades que incluem scripts executáveis em ambientes isolados. Limite o sistema de arquivos, a rede e o acesso no nível do sistema apenas ao que a habilidade exige. Exigir confirmação explícita do usuário antes de executar operações potencialmente confidenciais.
  • Auditoria e registro - Registra quais habilidades são carregadas, quais recursos são lidos e quais scripts são executados. Isso oferece uma trilha de auditoria para rastrear o comportamento do agente de volta ao conteúdo de habilidade específico se algo der errado.

Quando usar habilidades versus fluxos de trabalho

As habilidades do agente e os fluxos de trabalho do Agent Framework estendem o que os agentes podem fazer, mas funcionam de maneiras fundamentalmente diferentes. Escolha a abordagem que melhor corresponda aos seus requisitos:

  • Controle – Com uma habilidade, a IA decide como executar as instruções. Isso é ideal quando você deseja que o agente seja criativo ou adaptável. Com um fluxo de trabalho, você define explicitamente o caminho de execução. Use fluxos de trabalho quando precisar de um comportamento determinístico e previsível.
  • Resiliência - Uma habilidade é executada durante um único turno do agente. Se algo falhar, toda a operação deverá ser repetida. Os fluxos de trabalho dão suporte ao ponto de verificação, para que possam ser retomados da última etapa bem-sucedida após uma falha. Escolha fluxos de trabalho quando o custo de executar novamente todo o processo for alto.
  • Efeitos colaterais – as habilidades são adequadas quando as operações são idempotentes ou de baixo risco. Prefira fluxos de trabalho quando as etapas produzem efeitos colaterais (enviar emails, cobrar pagamentos) que não devem ser repetidos na repetição.
  • Complexidade – as habilidades são melhores para tarefas de domínio único e focadas que um agente pode lidar. Os fluxos de trabalho são mais adequados para processos de negócios de várias etapas que coordenam vários agentes, aprovações humanas ou integrações externas do sistema.

Tip

Como regra geral: se você quiser que a IA descubra como realizar uma tarefa, use uma habilidade. Se você precisar garantir quais etapas são executadas e em que ordem, use um fluxo de trabalho.

Próximas etapas