Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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 página inicial 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:
- 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.
-
Carga (< 5000 tokens recomendados), quando uma tarefa corresponde ao domínio de uma habilidade, o agente chama a ferramenta
load_skillpara recuperar o conteúdo completo do SKILL.md com instruções detalhadas. -
Ler recursos (conforme necessário) – O agente chama a
read_skill_resourceferramenta para buscar arquivos suplementares (referências, modelos, ativos) somente quando necessário. -
Executar os scripts (conforme necessário), o agente chama a ferramenta
run_skill_scriptpara 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 apenas quando pelo menos uma habilidade tem recursos.
run_skill_script é anunciado apenas quando pelo menos uma habilidade tem scripts.
Fornecendo habilidades a um agente
Trabalhar com habilidades envolve três blocos de construção:
-
Provedor -
AgentSkillsProvider(C#) ouSkillsProvider(Python) é um provedor de contexto que expõe habilidades a um agente. Ele anuncia as habilidades disponíveis no prompt do sistema e registra as ferramentas que o agente usa para carregar habilidades, ler recursos e executar scripts. -
Fontes – uma fonte fornece habilidades para o provedor. As habilidades podem vir de vários tipos de origem:
-
Baseado em arquivos - habilidades descobertas em arquivos
SKILL.mdem diretórios do sistema de arquivos. -
Definido por código – habilidades definidas embutidas no código usando
AgentInlineSkill(C#) ouInlineSkill(Python). -
Baseado em classe – habilidades encapsuladas em uma classe derivada de
AgentClassSkill<T>(C#) ouClassSkill(Python). -
Baseadas em MCP - habilidades descobertas a partir de servidores MCP (Model Context Protocol) por meio de
UseMcpSkills(C#) ouMCPSkillsSource(Python).
-
Baseado em arquivos - habilidades descobertas em arquivos
-
Construtor -
AgentSkillsProviderBuilder(C#) reúne várias fontes em um único provedor, aplicando agregação, eliminação de duplicação, cache e filtragem opcional. Em Python, redigir classes de origem, comoAggregatingSkillsSource,FilteringSkillsSourceeDeduplicatingSkillsSourcediretamente.
As seções a seguir mostram como criar habilidades de cada tipo de origem e, em seguida, como combinar fontes e construir um provedor a partir delas.
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 e scripts
Por padrão, o provedor reconhece recursos com extensões .md, , .json, .yaml, .yml, .csv, .xmle .txt scripts com extensões .py, .js, .sh, , .ps1, .cse .csx. Ele pesquisa até dois níveis profundos em cada diretório de habilidades. Use AgentFileSkillsSourceOptions para alterar esses padrões:
var fileOptions = new AgentFileSkillsSourceOptions
{
AllowedResourceExtensions = [".md", ".txt"],
AllowedScriptExtensions = [".py"],
SearchDepth = 3, // Search up to 3 levels deep (default is 2)
ResourceFilter = context => context.RelativeFilePath.StartsWith("references/"),
ScriptFilter = context => context.RelativeFilePath.StartsWith("scripts/")
|| context.RelativeFilePath.StartsWith("tools/"),
};
// Via constructor
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
fileOptions: fileOptions);
// Via builder
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"), options: fileOptions)
.Build();
ResourceFilter e ScriptFilter receba um AgentFileSkillFilterContext com o nome da habilidade e o caminho relativo do arquivo, permitindo que você restrinja arquivos por local, convenção de nomenclatura ou qualquer lógica personalizada.
Execução do script
Passe SubprocessScriptRunner.RunAsync como o executor de script para habilitar a execução de scripts baseados em arquivo:
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<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();
}
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
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_extensions, script_extensions, resource_filter e script_filter para personalizar a descoberta:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
resource_extensions=(".md", ".txt"),
script_extensions=(".py", ".sh"),
resource_filter=lambda skill_name, path: path.startswith("references/"),
script_filter=lambda skill_name, path: path.startswith("scripts/"),
)
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 apenas para fins de demonstração. Para uso em produção, considere adicionar:
- Sandboxing (por exemplo, contêineres
seccompoufirejail) - 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 a construção do provedor.
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.
Habilidades baseadas em MCP
Observação
As habilidades baseadas em MCP exigem o Microsoft.Agents.AI.Mcp pacote NuGet. A API de habilidades do MCP é experimental e pode mudar em versões futuras.
As habilidades podem ser descobertas em servidores MCP (Protocolo de Contexto do Modelo) que expõem recursos de habilidades no esquema de URI skill://. O servidor MCP anuncia habilidades por meio de um skill://index.json documento de descoberta e a estrutura busca conteúdo de habilidade sob demanda.
As habilidades baseadas em MCP dão suporte a dois tipos de entrada de índice:
-
skill-md- OSKILL.mdda habilidade e os recursos relacionados são obtidos sob demanda do servidor MCP. -
archive- A habilidade é distribuída como um único arquivo empacotado (ZIP, TAR ou TAR compactado por gzip) que é baixado e descompactado localmente.
Uso Básico
Use o método de extensão UseMcpSkills em AgentSkillsProviderBuilder para adicionar uma fonte de habilidades do 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);
Habilidades do tipo arquivo
Para habilidades do tipo arquivo, use AgentMcpSkillsSourceOptions (do pacote Microsoft.Agents.AI.Mcp) para configurar o comportamento de extração:
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 expõe as seguintes propriedades para controlar a extração de arquivos:
-
ArchiveSkillsDirectory- Diretório base para arquivos extraídos. Usa como padrão um subdiretório exclusivo no diretório de trabalho atual, gerado por instância de origem para evitar colisões entre várias fontes. -
ArchiveResourceExtensions- Extensões permitidas para recursos em arquivos extraídos. O padrão é.md,.json,.yaml,.yml,.csv,.xml,.txt. -
ArchiveResourceSearchDepth- Qual é a profundidade da pesquisa de recursos em cada diretório de habilidades extraído. Usa2como padrão. -
ArchiveMaxFileCount- Número máximo de arquivos por arquivo compactado. Os arquivos que excedem esse limite são ignorados. Usa20como padrão. -
ArchiveMaxSizeBytes- Tamanho máximo de download por arquivo compactado. Usa1 MBcomo padrão. -
ArchiveMaxUncompressedSizeBytes- Tamanho total máximo não compactado por arquivo compactado. Usa1 MBcomo padrão.
Importante
Scripts incluídos em habilidades do tipo arquivo compactado nunca são executados. Essa é uma medida de segurança deliberada – o conteúdo executável de servidores MCP remotos requer confiança explícita.
Fontes de habilidades
Uma AgentSkillsProvider recupera habilidades de uma ou mais fontes – objetos que implementam AgentSkillsSource. As fontes se enquadram em duas categorias: fontes de folha que descobrem ou contêm habilidades (como AgentFileSkillsSource para habilidades baseadas em arquivo), e decoradores que transformam a saída de outra fonte (agregação, eliminação de duplicatas, armazenamento em cache e filtragem). Você também pode criar uma fonte personalizada.
Cada origem implementa um único método – GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default). O AgentSkillsSourceContext contém informações sobre a solicitação atual:
-
Agent- a instânciaAIAgentque solicita habilidades. -
Session- oAgentSessionassociado à invocação ounullquando não há sessão.
Esse contexto está disponível em todo o pipeline de origem, portanto, um FilteringAgentSkillsSource predicado ou uma fonte personalizada pode basear sua lógica nele – por exemplo, retornando um conjunto diferente de habilidades dependendo do agente solicitante.
Fontes de folha
AgentFileSkillsSource
Descobre competências de arquivos SKILL.md no disco. Aceita um ou mais caminhos de diretório, um executor de script opcional e um AgentFileSkillsSourceOptions opcional (documentado em habilidades baseadas em arquivos).
var source = new AgentFileSkillsSource(
[Path.Combine(AppContext.BaseDirectory, "skills")],
scriptRunner: SubprocessScriptRunner.RunAsync,
options: new AgentFileSkillsSourceOptions { SearchDepth = 3 });
AgentInMemorySkillsSource
Encapsula em memória instâncias AgentSkill definidas por código ou baseadas em classes.
var source = new AgentInMemorySkillsSource([volumeConverterSkill, temperatureConverter]);
Combinadores
AggregatingAgentSkillsSource
Combina várias fontes em uma. As habilidades são retornadas na ordem de registro, sem remoção de duplicatas nem aplicação de filtragem.
var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);
Decoradores
Decoradores encapsulam uma fonte interna e transformam sua saída. Eles podem ser encadeados para criar um pipeline.
DeduplicatingAgentSkillsSource
Remove nomes de habilidade duplicados (não diferencia maiúsculas de minúsculas, a primeira ocorrência vence). As duplicatas são registradas no nível de aviso.
var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);
CachingAgentSkillsSource
Armazena em cache a lista de habilidades retornada pela fonte interna. Chamadores simultâneos são serializados por chave de cache, portanto, apenas uma busca é executada por vez. Aceita opcionalmente CachingAgentSkillsSourceOptions:
-
RefreshInterval(TimeSpan?) - quando definidos, os resultados armazenados em cache expiram após esse intervalo e a origem interna é invocada novamente. Quandonull(o padrão), os resultados armazenados em cache nunca expiram. -
CacheIsolationKeySelector(Func<AgentSkillsSourceContext, string?>?) – retorna uma chave de cache para isolar os resultados armazenados em cache por contexto (por exemplo, por locatário). Quandonull, todos os chamadores compartilham um único bucket de cache.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
RefreshInterval = TimeSpan.FromMinutes(5)
});
FilteringAgentSkillsSource
Aplica um predicado para incluir ou excluir habilidades. O predicado recebe a habilidade e um AgentSkillsSourceContext.
var filtered = new FilteringAgentSkillsSource(
innerSource,
(skill, context) => skill.Frontmatter.Name != "experimental-skill");
Fontes personalizadas
Quando as fontes internas não abrangem seu cenário, implemente o seu próprio. Subclasse AgentSkillsSource para uma fonte folha (que produz habilidades de uma nova origem, como um banco de dados ou serviço remoto), ou subclasse DelegatingAgentSkillsSource para um decorador que transforma a saída de outra fonte.
Origem da folha
Derivar de AgentSkillsSource e implementar GetSkillsAsync. O AgentSkillsSourceContext argumento permite que a origem adapte seu resultado à solicitação atual , por exemplo, retornando um conjunto diferente de habilidades, dependendo do agente solicitante. Sobrescreva Dispose(bool) se a fonte tiver recursos como um cliente ou uma conexão.
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);
}
}
Decorador personalizado
Derive de DelegatingAgentSkillsSource, chame InnerSource.GetSkillsAsync e transforme ou observe o resultado. Este é o mesmo padrão que os decoradores integrados de cache, deduplicação e filtragem usam. Por exemplo, um decorador que registra quantas habilidades foram retornadas por solicitação sem alterar o resultado:
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;
}
}
Ambas as fontes personalizadas podem ser passadas diretamente para AgentSkillsProvider ou aninhadas em um pipeline maior, assim como as fontes integradas.
Construção do provedor
AgentSkillsProvider é o componente que expõe habilidades a um agente. Ele encapsula uma ou mais fontes e registra as ferramentas load_skill, read_skill_resource e run_skill_script. Há três maneiras de criar uma:
-
AgentSkillsProviderBuilder- compõe vários tipos de competência em um provedor com agregação automática, remoção de duplicatas, cache e filtragem opcional. Melhor para cenários que combinam habilidades baseadas em arquivo, definidas por código, baseadas em classe e baseadas em MCP. -
Composição de origem direta – construa o pipeline de origem por conta própria usando as classes públicas
AgentSkillsSource. Nenhum cache automático ou eliminação de duplicação é aplicado – você controla o pipeline completo. Melhor quando você precisa de controle sobre ordenação, lógica condicional ou comportamento personalizado do decorador. - Construtores de conveniência – crie um provedor diretamente de um caminho de arquivo ou instâncias de habilidade. Aplica automaticamente a eliminação de duplicação e o cache. Melhor para cenários de origem única.
Usando AgentSkillsProviderBuilder
Use AgentSkillsProviderBuilder quando precisar de qualquer um dos seguintes:
-
Tipos de habilidades mistas – combinam habilidades baseadas em arquivo, definidas por código (
AgentInlineSkill), baseadas em classe (AgentClassSkill) e baseadas em MCP em um único provedor. - Filtragem de habilidades – incluir ou excluir habilidades usando um predicado.
Tipos de habilidades mistas
Combine vários tipos de habilidades em um provedor ao encadear UseFileSkill, UseSkill, UseMcpSkills e 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();
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, context) => approvedSkillNames.Contains(skill.Frontmatter.Name))
.Build();
Redigindo fontes diretamente
Quando o construtor não oferecer o controle de que você precisa, componha você mesmo as classes de origem e passe o pipeline resultante para AgentSkillsProvider. Consulte as fontes do Skill para obter a lista completa de fontes disponíveis e suas opções.
O exemplo a seguir cria um pipeline comparável com múltiplas fontes, mas permite controle explícito sobre cada decorador:
// 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);
Observação
Quando ownsSource é true, descartar o provedor também descarta todo o pipeline de origem. Defina-o como false se você mesmo gerenciar o ciclo de vida da origem.
Construtores de conveniência
Para cenários de origem única, use os AgentSkillsProvider construtores diretamente. Elas aplicam automaticamente a eliminação de duplicatas e cache sem exigir um builder nem uma composição manual da origem.
A partir de um caminho de arquivo:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
scriptRunner: SubprocessScriptRunner.RunAsync);
A partir de instâncias de habilidade:
var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);
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 as 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 arquivosSKILL.mdno disco. -
InMemorySkillsSource- encapsula todasSkillas 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. -
DeduplicatingSkillsSourceremove os 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:
-
volume_converter_skill- qualquerInlineSkillinstância, criada conforme mostrado em habilidades definidas por código. -
TemperatureConverterSkill- qualquerClassSkillsubclasse, criada conforme mostrado em habilidades baseadas em classe. -
my_runner, umSkillScriptRunnerque pode ser chamado, definido como mostrado em execução de script.
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",
)
)
)
Comportamento de cache
Por padrão, o construtor encapsula o pipeline de origem com um CachingAgentSkillsSource que armazena em cache a lista de habilidades retornadas pelas fontes subjacentes. Depois que as habilidades forem resolvidas na primeira solicitação, as solicitações subsequentes reutilizarão a lista armazenada em cache sem consultar novamente as fontes. Para desabilitar o cache (por exemplo, durante o desenvolvimento, quando as definições de habilidade são alteradas com frequência), use DisableCaching() no construtor:
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
.DisableCaching()
.Build();
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.
Aprovação da ferramenta
Todas as ferramentas expostas por AgentSkillsProvider (load_skill, read_skill_resource, run_skill_script) exigem aprovação por padrão. Quando uma chamada de ferramenta requer aprovação, o agente pausa e retorna um ToolApprovalRequestContent em vez de executar imediatamente. Use o middleware UseToolApproval com regras de aprovação automática para ignorar seletivamente as solicitações em operações confiáveis:
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();
Para aprovar automaticamente todas as ferramentas de habilidade, incluindo a execução de scripts:
.UseToolApproval(new ToolApprovalAgentOptions
{
AutoApprovalRules = [AgentSkillsProvider.AllToolsAutoApprovalRule],
})
Desabilitando a aprovação para ferramentas específicas
Use AgentSkillsProviderOptions para desabilitar a aprovação de ferramentas individuais, removendo-as totalmente do fluxo de aprovação:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync,
options: new AgentSkillsProviderOptions
{
DisableLoadSkillApproval = true,
DisableReadSkillResourceApproval = true,
// DisableRunSkillScriptApproval remains false - scripts still require approval
});
Quando, na mesma resposta, algumas ferramentas exigem aprovação e outras não, o modelo pode invocar os dois tipos de ferramenta simultaneamente. Defina EnableNonApprovalRequiredFunctionBypassing para que as ferramentas que não exigem aprovação sejam executadas imediatamente, enquanto o usuário receba solicitação apenas para as demais:
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();
Gerenciando solicitações de aprovação
Quando as ferramentas exigem aprovação (e nenhuma regra de aprovação automática se aplica), o agente retorna ToolApprovalRequestContent itens que precisam ser aprovados ou rejeitados antes de continuar:
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();
}
Detalhes do erro de script
Por padrão, quando a execução de um script de habilidade falha, a exceção é propagada para o FunctionInvokingChatClient subjacente. Se sua IncludeDetailedErrors propriedade estiver definida como true, a mensagem de exceção será encaminhada para o modelo, permitindo que ela se auto-corrija repetindo com argumentos diferentes:
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(
options: new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant.",
},
AIContextProviders = [skillsProvider],
},
model: deploymentName,
clientFactory: client => client
.AsBuilder()
.UseFunctionInvocation(configure: (c) => c.IncludeDetailedErrors = true)
.Build());
Se você não puder configurar FunctionInvokingChatClient diretamente, defina AgentSkillsProviderOptions.IncludeDetailedErrors em vez disso. Isso captura a exceção no nível do provedor de habilidades e retorna a mensagem de erro diretamente para o modelo:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync,
options: new AgentSkillsProviderOptions
{
IncludeDetailedErrors = true,
});
Aviso
Qualquer abordagem pode divulgar detalhes brutos de exceção para o modelo. As mensagens de exceção podem conter informações confidenciais, como cadeias de conexão, caminhos de arquivo ou nomes de serviço internos. Além disso, se as habilidades ou scripts se originarem de fontes não confiáveis, um script maliciosamente elaborado poderá lançar uma exceção cuja mensagem incorpore uma carga maliciosa de injeção de prompt.
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}
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.
"""
});
Observação
O modelo personalizado deve conter {skills} como espaço reservado para a lista de habilidades gerada. 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 }}.
Injetando serviços e argumentos de runtime
As funções de script e os recursos de habilidade podem receber contexto externo do aplicativo fornecido em tempo de execução.
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 os serviços de aplicativos registrados sob demanda.
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 utilizam.
Funções de recurso e script que aceitam **kwargs recebem automaticamente os 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 com base 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.