Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
As Competências do Agente são pacotes portáteis de instruções, scripts e recursos que conferem aos agentes capacidades especializadas e conhecimento de domínio. As competências seguem uma especificação aberta e implementam um padrão progressivo de divulgação para que os agentes carreguem apenas o contexto de que precisam, quando precisam.
Use as Habilidades de Agente quando quiser:
- Especialização no domínio dos pacotes - Capturar conhecimento especializado (políticas de despesas, fluxos de trabalho legais, pipelines de análise de dados) como pacotes reutilizáveis e portáteis.
- Estender as capacidades dos agentes - Dar aos agentes novas habilidades sem alterar as suas instruções principais.
- Garanta consistência – Transforme tarefas em vários passos em fluxos de trabalho repetíveis e auditáveis.
- Permitir a interoperabilidade - Reutilizar a mesma competência em diferentes produtos compatíveis com Competências de Agente.
Estrutura de competências
Uma habilidade é um diretório que contém um SKILL.md ficheiro 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
SKILL.md formato
O SKILL.md ficheiro deve conter material inicial YAML seguido de conteúdo marcado:
---
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 | Description |
|---|---|---|
name |
Yes | No máximo 64 caracteres. Apenas letras minúsculas, números e hífens. Não deve começar nem terminar com um hífen, nem conter hífens consecutivos. Deve corresponder ao nome do diretório principal. |
description |
Yes | O que a habilidade faz e quando a usar. Máximo 1024 caracteres. Deve incluir palavras-chave que ajudem os agentes a identificar tarefas relevantes. |
license |
Não | Nome da licença ou referência a um ficheiro de licença agrupado. |
compatibility |
Não | No máximo 500 caracteres. Indica os requisitos do ambiente (produto pretendido, pacotes do sistema, acesso à rede, etc.). |
metadata |
Não | Mapeamento chave-valor arbitrário para metadados adicionais. |
allowed-tools |
Não | Lista delimitada por espaço de ferramentas pré-aprovadas que a competência pode usar. Experimental - o suporte pode variar entre implementações de agentes. |
O corpo de markdown após o frontmatter contém as instruções de competência – orientação passo a passo, exemplos de entradas e saídas, casos excecionais comuns ou qualquer conteúdo que ajude o agente a realizar a tarefa. Mantenha SKILL.md com menos de 500 linhas e transfira o material de referência detalhado para ficheiros separados.
Divulgação progressiva
As Competências do Agente utilizam um padrão progressivo de divulgação em quatro etapas para minimizar o uso do contexto:
- Publicitar (~100 tokens por habilidade) - Os nomes e descrições das habilidades são inseridos no prompt do sistema no início de cada run, para que o agente saiba que habilidades estão disponíveis.
-
Load (< 5000 tokens recomendados) - Quando uma tarefa corresponde ao domínio de uma skill, o agente invoca a ferramenta
load_skillpara obter o conteúdo completo do ficheiro SKILL.md com instruções detalhadas. -
Ler recursos (conforme necessário) - O agente chama a
read_skill_resourceferramenta para obter ficheiros suplementares (referências, templates, assets) apenas quando necessário. -
Executar scripts (conforme necessário) - O agente chama a ferramenta
run_skill_scriptpara executar scripts fornecidos com uma competência.
Este padrão mantém a janela de contexto do agente enxuta, ao mesmo tempo que lhe dá acesso a conhecimento profundo do domínio sob demanda.
Observação
load_skill é sempre anunciado.
read_skill_resource é anunciada apenas quando pelo menos uma habilidade tem recursos.
run_skill_script é anunciado apenas quando pelo menos uma habilidade contém scripts.
Fornecer competências a um agente
Trabalhar com competências envolve três blocos de construção:
-
Fornecedor -
AgentSkillsProvider(C#) ouSkillsProvider(Python) é um fornecedor de contexto que expõe competências a um agente. Anuncia as competências disponíveis no prompt do sistema e regista as ferramentas que o agente usa para carregar competências, ler recursos e executar scripts. -
Fontes - uma fonte fornece competências ao prestador. As competências podem vir de vários tipos de fontes:
-
Baseado em ficheiros - competências descobertas a partir de
SKILL.mdficheiros em diretórios de sistemas de ficheiros. -
Definido por código - competências definidas em linha em código usando
AgentInlineSkill(C#) ouInlineSkill(Python). -
Baseado em classes - competências encapsuladas numa classe derivada de
AgentClassSkill<T>(C#) ouClassSkill(Python). -
Baseado em MCP - competências descobertas em servidores MCP (Model Context Protocol) via
UseMcpSkills(C#) ouMCPSkillsSource(Python).
-
Baseado em ficheiros - competências descobertas a partir de
-
Construtor -
AgentSkillsProviderBuilder(C#) reúne múltiplas fontes num único fornecedor, aplicando agregação, deduplicação, cache e filtragem opcional. Em Python, compõe classes fonte comoAggregatingSkillsSource,FilteringSkillsSource, eDeduplicatingSkillsSourcediretamente.
As secções seguintes mostram como criar competências para cada tipo de fonte, depois como combinar fontes e construir um fornecedor a partir delas.
Competências baseadas em ficheiros
Cria um AgentSkillsProvider que aponte para um diretório que contenha as suas competências e adicione-o aos fornecedores de contexto do agente. Passe um script runner para permitir a execução de scripts baseados em ficheiros encontrados em diretórios de competências:
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);
Advertência
DefaultAzureCredential é conveniente para o desenvolvimento, mas requer uma consideração cuidadosa na produção. Em produção, considere usar uma credencial específica (por exemplo, ManagedIdentityCredential) para evitar problemas de latência, sondagens não intencionais de credenciais e potenciais riscos de segurança provenientes de mecanismos de recurso.
Múltiplos diretórios de competências
Pode apontar o provedor para um único diretório principal — cada subdiretório que contém um SKILL.md é automaticamente detetado como uma capacidade:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "all-skills"));
Ou passar uma lista de caminhos para pesquisar em múltiplos diretórios raiz:
var skillsProvider = new AgentSkillsProvider(
[
Path.Combine(AppContext.BaseDirectory, "company-skills"),
Path.Combine(AppContext.BaseDirectory, "team-skills"),
]);
O prestador pesquisa até dois níveis de profundidade.
Personalização da descoberta de recursos e scripts
Por predefinição, o fornecedor reconhece recursos com extensões .md, .json, .yaml, .yml, .csv, .xml e .txt, e scripts com extensões .py, .js, .sh, .ps1, .cs e .csx. Pesquisa até dois níveis de profundidade em cada diretório de competências. Use AgentFileSkillsSourceOptions para alterar estes predefinidos:
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 recebe um AgentFileSkillFilterContext com o nome da habilidade e o caminho relativo do ficheiro, permitindo-te restringir ficheiros por localização, convenção de nomes ou qualquer lógica personalizada.
Execução de scripts
Passe SubprocessScriptRunner.RunAsync como executor de scripts para permitir a execução de scripts baseados em ficheiros:
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 runner executa cada script descoberto como um subprocesso local. Os scripts baseados em ficheiros esperam argumentos sob a forma de um array JSON de cadeias de caracteres - cada elemento do array corresponde a um argumento posicional da linha de comandos.
Advertência
SubprocessScriptRunner é fornecido apenas para fins demonstrativos. Para uso em produção, considere adicionar:
- Sandboxing (por exemplo, contentores ou ambientes de execução isolados)
- Limites de recursos (limites de CPU, limites de memória, tempo limite de execução)
- Validação de entrada e listagem de scripts executáveis
- Registos estruturados e trilhas de auditoria
Competências baseadas em ficheiros
Utilize a fábrica SkillsProvider.from_paths() para descobrir competências em diretórios que contêm ficheiros SKILL.md e adicione o fornecedor aos fornecedores 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],
)
Múltiplos diretórios de competências
Pode apontar o provedor para um único diretório principal — cada subdiretório que contém um SKILL.md é automaticamente detetado como uma capacidade:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "all-skills"
)
Ou passar uma lista de caminhos para pesquisar em múltiplos diretórios raiz:
skills_provider = SkillsProvider.from_paths(
skill_paths=[
Path(__file__).parent / "company-skills",
Path(__file__).parent / "team-skills",
]
)
O prestador pesquisa até dois níveis de profundidade.
Personalização da descoberta de recursos e scripts
Por defeito, os recursos são detetados nos subdiretórios references/ e assets/, e os scripts em scripts/, de acordo com a especificação agentskills.io. Extensões de recursos 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/"),
)
Utilize "." para incluir ficheiros na raiz da skill, para além dos subdiretórios.
Execução de scripts
Para permitir a execução de scripts baseados em ficheiros, passe a script_runner para SkillsProvider.from_paths(). Qualquer função síncrona ou assíncrona que satisfaça o protocolo SkillScriptRunner 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 FileSkill e FileSkillScript já resolvidos, e um argumento args opcional. Os scripts baseados em ficheiros esperam argumentos sob a forma de um array JSON de cadeias de caracteres - cada elemento do array corresponde a um argumento posicional da linha de comandos. Os scripts são detetados automaticamente nos ficheiros .py do subdiretório scripts/ de cada diretório de skill.
Advertência
O corredor acima é fornecido apenas para fins de demonstração. Para uso em produção, considere adicionar:
- Sandboxing (por exemplo, contentores,
seccomp, oufirejail) - Limites de recursos (limites de CPU, limites de memória, tempo limite de execução)
- Validação de entrada e listagem de scripts executáveis
- Registos estruturados e trilhas de auditoria
Observação
Se forem fornecidas competências baseadas em ficheiros com scripts, mas nenhuma script_runner estiver definida, SkillsProvider gera um erro quando é tentada a execução do script.
Competências definidas por código
Para além das competências baseadas em ficheiros descobertas a partir de SKILL.md ficheiros, podes definir competências inteiramente em código usando AgentInlineSkill. Competências definidas pelo código são úteis quando:
- O conteúdo de competências é gerado dinamicamente (por exemplo, leitura de uma base de dados ou ambiente).
- Deves manter as definições de competências juntamente com o código da aplicação que as utiliza.
- Precisas de recursos que executem lógica em tempo de leitura em vez de servirem ficheiros estáticos.
- As definições de competências precisam de ser construídas em tempo de execução a partir de dados – por exemplo, criar uma competência personalizada para cada sessão do utilizador com base no seu papel ou permissões.
- Uma competência precisa de fechar sobre o estado do site da chamada (variáveis locais, encerramentos) em vez de resolver serviços a partir de um contentor DI.
Competências básicas de programação
Cria um AgentInlineSkill com nome, descrição e instruções. Anexe 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() a fim de calcular o conteúdo durante o tempo de execução. O delegado é invocado cada vez 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 registar um delegado como script executável. Scripts definidos por código são executados dentro do processo como chamadas diretas a delegados. Não é necessário um script runner. Os parâmetros tipados pelo delegado são automaticamente convertidos num Esquema JSON que o agente utiliza para passar os 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 competências definidas por código com competências baseadas em ficheiros ou classes num único fornecedor, use AgentSkillsProviderBuilder - veja Construção do Fornecedor.
Para além das competências baseadas em ficheiros descobertas a partir de ficheiros SKILL.md, podes definir competências inteiramente em código Python usando InlineSkill. Competências definidas pelo código são úteis quando:
- O conteúdo de competências é gerado dinamicamente (por exemplo, leitura de uma base de dados ou ambiente).
- Deves manter as definições de competências juntamente com o código da aplicação que as utiliza.
- Precisas de recursos que executem lógica em tempo de leitura em vez de servirem ficheiros estáticos.
- As definições de competências precisam de ser construídas em tempo de execução a partir de dados – por exemplo, criar uma competência personalizada para cada sessão do utilizador com base no seu papel ou permissões.
- Uma capacidade precisa de capturar o estado do local de chamada (variáveis locais, fechos) em vez de resolver serviços através de
**kwargs.
Competências básicas de programação
Crie uma InlineSkill instância com um SkillFrontmatter (contendo o nome e a descrição) e conteúdo de instruções. 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 registar uma função como recurso. A função é chamada cada vez que o agente lê o recurso, para que possa devolver dados atualizados. São suportadas tanto funções de sincronização como 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 torna-se o nome do recurso e a docstring torna-se a descrição. Use @skill.resource(name="...", description="...") para os definir explicitamente.
Scripts definidos por código
Use o @skill.script decorador para registar uma função como um script executável numa capacidade. Scripts definidos por código correm em processo e não requerem um executor de scripts. São suportadas tanto funções de sincronização como 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 torna-se o nome do script e a docstring torna-se a descrição. Os parâmetros tipados da função são automaticamente convertidos num Esquema JSON que o agente usa para passar argumentos.
Competências baseadas em classes
As competências baseadas em classes permitem-te agrupar todos os componentes de competência – nome, descrição, instruções, recursos e scripts – numa única classe de C#. Isto torna-os fáceis de empacotar e distribuir como pacotes NuGet – as equipas podem criar e disponibilizar capacidades de forma independente, e os consumidores adicionam-nas com dotnet add package e uma única chamada .UseSkill(). Derive de AgentClassSkill<T> (onde T é a sua classe), depois anote 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 });
}
}
Registe a competência 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, o seu valor de retorno é usado como conteúdo de recurso quando o agente lê o recurso – use um método quando o conteúdo precisa de ser calculado em tempo de leitura. Quando [AgentSkillScript] é aplicado a um método, o método é invocado quando o agente chama o script. Use [Description] from System.ComponentModel para descrever cada recurso e script para o agente.
Observação
AgentClassSkill<T> também suporta sobrescrever Resources e Scripts como coleções para cenários onde a descoberta baseada em atributos não é adequada.
Competências baseadas em classes
As competências baseadas em aulas permitem-te agrupar todos os componentes de competências – nome, descrição, instruções, recursos e scripts – numa única aula de Python. Isto torna-os fáceis de empacotar e distribuir como pacotes PyPI – as equipas podem criar e disponibilizar competências de forma independente, e os utilizadores adicionam-nas com pip install e uma única chamada SkillsProvider(). Subclasse ClassSkill, então usa os @ClassSkill.resource e @ClassSkill.script decoradores 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})
Registe a competência baseada em classe com SkillsProvider:
from agent_framework import SkillsProvider
skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)
Quando @ClassSkill.resource é aplicado como decorador simples (sem argumentos), o nome do método torna-se o nome do recurso (com sublinhados convertidos em hífens) e o docstring torna-se a descrição. Use @ClassSkill.resource(name="...", description="...") para os definir explicitamente. O mesmo padrão aplica-se a @ClassSkill.script.
Os recursos podem ser definidos como métodos regulares ou @property descritores. Ao usar @property, coloca @property primeiro e @ClassSkill.resource segundo. Os valores de retorno de recursos são armazenados em cache após o primeiro acesso.
Observação
ClassSkill também permite substituir explicitamente as propriedades resources e scripts para devolver diretamente instâncias de InlineSkillResource e InlineSkillScript, em cenários em que a deteção baseada em decoradores não é adequada.
Competências baseadas em MCP
Observação
As competências baseadas em MCP requerem o pacote Microsoft.Agents.AI.Mcp NuGet. A API de competências MCP é experimental e pode mudar em futuras versões.
As competências podem ser descobertas a partir de servidores MCP (Model Context Protocol) que disponibilizam recursos de competências no esquema de URI skill://. O servidor MCP divulga competências através de um skill://index.json documento de descoberta, e o framework obtém conteúdo de competências sob demanda.
As competências baseadas em MCP suportam dois tipos de entrada de índice:
-
skill-md- Os recursos da habilidadeSKILL.mde os recursos associados são obtidos consoante necessário a partir do servidor MCP. -
archive- A competência é distribuída como um único arquivo empacotado (ZIP, TAR ou TAR comprimido em gzip) que é descarregado e desempacotado localmente.
Utilização básica
Utilize o método de extensão UseMcpSkills em AgentSkillsProviderBuilder para adicionar uma origem de competências 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);
Competências do tipo arquivo
Para competências do tipo arquivo, use AgentMcpSkillsSourceOptions (a partir do Microsoft.Agents.AI.Mcp pacote) 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. Por predefinição, é utilizado um subdiretório único no diretório de trabalho atual, gerado para cada instância de origem para evitar colisões entre múltiplas origens. -
ArchiveResourceExtensions- Permitiu extensões para recursos em arquivos extraídos. Por defeito,.md,.json,.yaml,.yml,.csv,.xml,.txt. -
ArchiveResourceSearchDepth- A profundidade da pesquisa de recursos em cada diretório de aptidões extraído. O valor padrão é2. -
ArchiveMaxFileCount- Número máximo de ficheiros por arquivo. Arquivos que excedam este limite são ignorados. O valor padrão é20. -
ArchiveMaxSizeBytes- Tamanho máximo de download por arquivo. O valor padrão é1 MB. -
ArchiveMaxUncompressedSizeBytes- Tamanho máximo total não comprimido por arquivo. O valor padrão é1 MB.
Importante
Scripts incluídos em competências do tipo arquivo nunca são executados. Esta é uma medida de segurança deliberada – conteúdos executáveis provenientes de servidores MCP requerem confiança explícita.
Fontes de habilidade
Um AgentSkillsProvider obtém capacidades de uma ou mais origens - objetos que implementam AgentSkillsSource. As fontes dividem-se em duas categorias: fontes de base que descobrem ou contêm competências (como AgentFileSkillsSource para competências baseadas em ficheiros) e decoradores que transformam a saída de outra fonte (agregação, deduplicação, armazenamento em cache e filtragem). Também podes criar uma fonte personalizada.
Cada fonte implementa um único método - GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default). O AgentSkillsSourceContext contém informações sobre o pedido atual:
-
Agent- aAIAgentinstância que solicita competências. -
Session- oAgentSessionassociado à invocação, ounullquando não há sessão.
Este contexto está disponível em todo o pipeline de origem, pelo que um predicado FilteringAgentSkillsSource ou uma origem personalizada pode basear nele a sua lógica — por exemplo, devolvendo um conjunto diferente de competências consoante o agente que faz o pedido.
Fontes foliares
AgentFileSkillsSource
Descobre competências a partir de SKILL.md ficheiros em disco. Aceita um ou mais caminhos de diretório, um executor de scripts opcional e opcional AgentFileSkillsSourceOptions (documentado em competências baseadas em ficheiros).
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 classe).
var source = new AgentInMemorySkillsSource([volumeConverterSkill, temperatureConverter]);
Combinadores
AggregatingAgentSkillsSource
Combina várias fontes numa só. As competências são devolvidas por ordem de registo, sem aplicação de deduplicação ou filtragem.
var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);
Decorators
Os decoradores envolvem uma fonte interna e transformam o seu resultado. Podem ser encadeados para construir um oleoduto.
DeduplicatingAgentSkillsSource
Remove nomes de perícias duplicados (sem distinção entre maiúsculas e minúsculas; prevalece a primeira ocorrência). Os duplicados são registados ao nível de aviso.
var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);
CachingAgentSkillsSource
Armazena em cache a lista de habilidades devolvida pela fonte interna. Os chamadores concorrentes são serializados por chave de cache, pelo que apenas uma busca é executada de cada vez. Aceita CachingAgentSkillsSourceOptions opcionalmente:
-
RefreshInterval(TimeSpan?) - quando definidos, os resultados em cache expiram após este intervalo e a fonte interna é invocada novamente. Quandonull(o padrão), os resultados em cache nunca expiram. -
CacheIsolationKeySelector(Func<AgentSkillsSourceContext, string?>?) - devolve uma chave de cache para isolar os resultados em cache por contexto (por exemplo, por inquilino). Quandonull, todos os chamadores partilham um único bucket de cache.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
RefreshInterval = TimeSpan.FromMinutes(5)
});
FilteringAgentSkillsSource
Aplica um predicado para incluir ou excluir competências. 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 incorporadas não cobrirem o seu cenário, implemente as suas próprias. Subclasse AgentSkillsSource para uma fonte folha (uma que produz competências a partir de uma nova origem, como uma base de dados ou serviço remoto), ou subclasse DelegatingAgentSkillsSource para um decorador que transforma a saída de outra fonte.
Fonte foliar
Derive de AgentSkillsSource e implemente GetSkillsAsync. O AgentSkillsSourceContext argumento permite que a fonte adapte o seu resultado ao pedido atual – por exemplo, devolvendo um conjunto diferente de competências dependendo do agente requerente. Redefina Dispose(bool) se a origem 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 de cache, deduplicação e filtragem incorporados usam. Por exemplo, um decorador que regista quantas competências foram devolvidas por pedido 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 dentro de um pipeline maior, tal como as fontes integradas.
Construção do fornecedor
AgentSkillsProvider é o componente que expõe competências a um agente. Encapsula uma ou mais origens e regista as ferramentas load_skill, read_skill_resource e run_skill_script. Existem três formas de criar um:
-
AgentSkillsProviderBuilder- Compõe múltiplos tipos de competências num único fornecedor com agregação automática, deduplicação, cache e filtragem opcional. Ideal para cenários que combinam competências baseadas em ficheiros, definidas por código, por classes e MCP. -
Composição direta de fonte - constrói tu próprio o pipeline de código-fonte usando as classes públicas
AgentSkillsSource. Não é aplicado cache automático nem deduplicação – controlas todo o pipeline. É melhor quando precisas de controlo sobre a encomenda, lógica condicional ou comportamento personalizado do decorador. - Construtores de conveniência – criem um fornecedor a partir de um caminho de ficheiro ou instância(s) de competência(s) diretamente. Aplica automaticamente deduplicação e cache. Ideal para cenários de fonte única.
Usando o AgentSkillsProviderBuilder
Use AgentSkillsProviderBuilder quando precisar de algum dos seguintes:
-
Tipos de competências mistas - combinam competências baseadas em ficheiros, definidas por código (
AgentInlineSkill), baseadas em classes (AgentClassSkill) e baseadas em MCP num único fornecedor. - Filtragem de competências - incluir ou excluir competências usando um predicado.
Tipos de habilidades mistas
Combine vários tipos de competências num único fornecedor, encadeando 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 competências
Use UseFilter para incluir apenas as competências que cumprem os seus critérios – por exemplo, para carregar competências de um diretório partilhado 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();
Compor diretamente as fontes
Quando o construtor não oferece o controlo de que precisa, compõe as classes de origem por ti próprio e passa o pipeline resultante para AgentSkillsProvider.
Consulte Fontes de Competências para a lista completa de fontes disponíveis e as suas opções.
O exemplo seguinte cria um pipeline comparável de múltiplas fontes, mas permite-lhe ter controlo 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, eliminar o fornecedor também elimina todo o pipeline de código-fonte. Defina-o como false se gerir você mesmo o ciclo de vida da origem.
Construtores de conveniência
Para cenários de fonte única, use diretamente os AgentSkillsProvider construtores. Estes aplicam automaticamente deduplicação e cache sem necessidade de um construtor ou composição manual de código-fonte.
A partir de um caminho de ficheiro:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
scriptRunner: SubprocessScriptRunner.RunAsync);
De exemplos de habilidade:
var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);
Composição de fonte: cenários avançados multi-fonte
Para cenários simples com uma única habilidade ou uma lista de competências, passa-os diretamente para o SkillsProvider construtor. Para competências baseadas em ficheiros, utilize o elemento SkillsProvider.from_paths() factory. Para cenários avançados, compõe classes fonte para controlar a descoberta, filtragem e deduplicação:
-
FileSkillsSource- descobre competências a partir deSKILL.mdficheiros no disco. -
InMemorySkillsSource- envolve quaisquerSkillinstâncias (definidas por código ou baseadas em classes) em memória. -
AggregatingSkillsSource- combina múltiplas fontes numa só. -
FilteringSkillsSource- aplica um predicado para incluir ou excluir competências. -
DeduplicatingSkillsSource- remove nomes de competências duplicados (sem distinção entre maiúsculas e minúsculas, prevalece a primeira).
Tipos de habilidades mistas
Combine competências baseadas em ficheiros, definidas por código e baseadas em classes num único fornecedor usando AggregatingSkillsSource. O exemplo abaixo utiliza objetos provisórios:
-
volume_converter_skill- qualquerInlineSkillinstância, construída conforme mostrado nas competências definidas pelo código. -
TemperatureConverterSkill- qualquer subclasse deClassSkill, criada como mostrado em Competências baseadas em classes. -
my_runner- umSkillScriptRunnerchamável, definido conforme mostrado na execução do 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 competências
Use FilteringSkillsSource para controlar quais as competências que o agente vê. O predicado recebe cada Skill e devolve True para o incluir. Por exemplo, para carregar competências de um diretório partilhado 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 predefinição, o builder envolve o pipeline de origem com um CachingAgentSkillsSource que coloca em cache a lista de competências devolvida pelas fontes subjacentes. Depois de as capacidades serem resolvidas na primeira solicitação, as solicitações subsequentes reutilizam a lista na cache sem voltar a consultar as fontes. Para desativar o cache (por exemplo, durante o desenvolvimento, quando as definições de habilidades mudam frequentemente), use DisableCaching() no construtor:
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
.DisableCaching()
.Build();
Observação
Desativar o cache é útil durante o desenvolvimento, quando o conteúdo das habilidades muda frequentemente. Em produção, deixe a cache ativada (o padrão) para melhor desempenho.
Comportamento de cache
Por padrão, as ferramentas de competências e as instruções são armazenadas em cache após a primeira construção. Definir disable_caching=True para forçar uma reconstrução em cada invocação:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
disable_caching=True,
)
disable_caching está também disponível no SkillsProvider construtor para competências definidas por código e baseadas em classes.
Observação
Desativar o cache é útil durante o desenvolvimento, quando o conteúdo das habilidades muda frequentemente. Em produção, deixe a cache ativada (o padrão) para melhor desempenho.
Aprovação de ferramentas
Todas as ferramentas expostas por AgentSkillsProvider (load_skill, read_skill_resource, run_skill_script) requerem aprovação por defeito. Quando uma chamada de ferramenta requer aprovação, o agente pausa e retorna a ToolApprovalRequestContent em vez de executar imediatamente. Utilize o UseToolApproval middleware com regras de aprovação automática para ignorar seletivamente os pedidos de confirmação para operações fidedignas:
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 competência, incluindo a execução de scripts:
.UseToolApproval(new ToolApprovalAgentOptions
{
AutoApprovalRules = [AgentSkillsProvider.AllToolsAutoApprovalRule],
})
Desativar a aprovação para ferramentas específicas
Use AgentSkillsProviderOptions para desativar a aprovação de ferramentas individuais, removendo-as completamente 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 algumas ferramentas requerem aprovação e outras não, na mesma resposta, o modelo pode chamar ambos os tipos simultaneamente. Defina EnableNonApprovalRequiredFunctionBypassing para que as ferramentas que não requerem aprovação sejam executadas imediatamente, enquanto ao utilizador só seja solicitada aprovação para as restantes:
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();
Gestão de pedidos de aprovação
Quando as ferramentas requerem aprovação (e nenhuma regra de aprovação automática se aplica), o agente devolve ToolApprovalRequestContent itens que têm de 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 defeito, quando a execução de um script de skill falha, a exceção é propagada para o FunctionInvokingChatClient subjacente. Se a sua IncludeDetailedErrors propriedade for definida para true, a mensagem de exceção é encaminhada para o modelo, permitindo-lhe autocorrigir-se ao tentar novamente 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 não conseguir configurar FunctionInvokingChatClient diretamente, defina AgentSkillsProviderOptions.IncludeDetailedErrors em vez disso. Isto capta a exceção no nível do fornecedor de competências e devolve a mensagem de erro diretamente ao modelo:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync,
options: new AgentSkillsProviderOptions
{
IncludeDetailedErrors = true,
});
Advertência
Qualquer abordagem pode revelar detalhes brutos das exceções no modelo. As mensagens de exceção podem conter informações sensíveis, como cadeias de ligação, caminhos de ficheiros ou nomes de serviços internos. Além disso, se as competências ou scripts provierem de fontes não confiáveis, um script concebido de forma maliciosa pode lançar uma exceção cuja mensagem contém uma carga útil de injeção de prompt.
Use require_script_approval=True em SkillsProvider para colocar toda execução de scripts atrás de aprovação humana. Em vez de executar de imediato, o agente faz uma pausa e devolve pedidos de aprovação através de 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 utilizador recusou e pode responder em conformidade.
Indicação de sistema personalizada
Por defeito, o fornecedor de competências insere um prompt do sistema que lista as competências disponíveis e instrui o agente a usar load_skill e read_skill_resource. 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 marcador de posição para a lista de competências gerada. Os parênteses literais devem ser escapados 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 {skills} (lista de competências), {resource_instructions} (sugestão de ferramenta de recursos) e {runner_instructions} (sugestão de ferramenta de script) espaços reservados. Os parênteses literais devem ser escapados como {{ e }}.
Injeção de serviços e argumentos em tempo de execução
As funções de recursos de skill e script podem receber contexto externo de aplicação fornecido em tempo de execução.
Os delegados de recursos de competências e scripts podem declarar um IServiceProvider parâmetro que o Agent Framework injeta automaticamente. Isto permite que as competências resolvam serviços de aplicação registados sob demanda.
Configuração
Registe os seus serviços de aplicação e passe o build IServiceProvider ao agente através do parâmetro services:
using Microsoft.Extensions.DependencyInjection;
// Register application services
ServiceCollection services = new();
services.AddSingleton<ConversionService>();
IServiceProvider serviceProvider = services.BuildServiceProvider();
// Create the agent and pass the service provider
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(
options: new ChatClientAgentOptions
{
Name = "ConverterAgent",
ChatOptions = new() { Instructions = "You are a helpful assistant." },
AIContextProviders = [skillsProvider],
},
model: deploymentName,
services: serviceProvider);
Competências definidas por código com DI
Declare IServiceProvider como um parâmetro em delegados AddResource ou AddScript - a framework resolve-o e injeta-o 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);
});
Competências baseadas em classes com DI
Anote métodos com [AgentSkillResource] ou [AgentSkillScript] e declare um IServiceProvider parâmetro – o framework descobre estes membros através de reflexão e injeta automaticamente o fornecedor de serviço:
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);
}
}
Sugestão
Competências baseadas em classes também podem resolver dependências por meio do seu construtor. Registe a classe de habilidade no ServiceCollection e resolve-a a partir do contentor em vez de chamar new diretamente:
services.AddSingleton<WeightConverterSkill>();
var weightSkill = serviceProvider.GetRequiredService<WeightConverterSkill>();
Isto é útil quando a própria classe de habilidades precisa de serviços injetados além daqueles utilizados pelos delegados de recursos e scripts.
As funções de recursos e scripts que aceitam **kwargs recebem automaticamente argumentos de palavra-chave em tempo de execução passados para agent.run(). Isto permite que as funções de competência acedam ao contexto da aplicação – como configuração, identidade do utilizador ou clientes de serviço – sem os codificar diretamente na definição da competência.
Passagem de argumentos de tempo de execução
Passe function_invocation_kwargs a agent.run() para fornecer argumentos de palavras-chave que o framework 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"},
)
Competências definidas por código com kwargs
Quando uma função de recurso declara **kwargs, a estrutura encaminha os argumentos das palavras-chave em tempo de execução cada vez 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}"
Funções de recurso sem **kwargs são chamadas sem argumentos e não recebem contexto em tempo de execução.
Quando uma função de script declara **kwargs, a estrutura encaminha os argumentos de palavras-chave em tempo de execução juntamente com os args que são fornecidos 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 à ferramenta args; a aplicação fornece precision através de function_invocation_kwargs. Funções de script sem **kwargs recebem apenas os argumentos fornecidos pelo agente.
Competências baseadas em classes com kwargs
Os métodos de competências baseados em classes também podem aceitar **kwargs para receber argumentos em tempo de execução. O padrão funciona da mesma forma - declarar **kwargs em 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})
Práticas recomendadas de segurança
As Competências do Agente devem ser tratadas como qualquer código de terceiros que incorpora no seu projeto. Como as instruções das competências são inseridas no contexto do agente — e as competências podem incluir scripts — é essencial aplicar o mesmo nível de revisão e governação que aplicaria a uma dependência de código aberto.
-
Revise antes de usar - Leia todo o conteúdo de competências (
SKILL.mdscripts e recursos) antes de implementar. Verifique se o comportamento real de um script corresponde à sua intenção declarada. Verifique instruções adversariais que tentem contornar as diretrizes de segurança, exfiltrar dados ou modificar ficheiros de configuração do agente. - Source trust - Só instale competências de autores de confiança ou colaboradores internos verificados. Prefiro competências com proveniência clara, controlo de versões e manutenção ativa. Fique atento a nomes de habilidades typosquatted que imitam pacotes populares.
- Sandboxing - Executar competências que incluam scripts executáveis em ambientes isolados. Limite o acesso ao sistema de ficheiros, rede e sistema apenas ao que a competência exige. Exija confirmação explícita do utilizador antes de executar operações potencialmente sensíveis.
- Auditoria e registo de eventos - Regista que competências são carregadas, que recursos são lidos e que scripts são executados. Isto dá-te um registo de auditoria para rastrear o comportamento dos agentes até ao conteúdo específico de competências caso algo corra mal.
Quando usar competências vs. fluxos de trabalho
As Competências do Agente e os Fluxos de Trabalho do Framework do Agente estendem o que os agentes podem fazer, mas funcionam de formas fundamentalmente diferentes. Escolha a abordagem que melhor se adeque às suas necessidades:
- Controlo - Com uma habilidade, a IA decide como executar as instruções. Isto é ideal quando se quer que o agente seja criativo ou adaptativo. Com um fluxo de trabalho, defines explicitamente o caminho de execução. Use fluxos de trabalho quando precisar de comportamento determinístico e previsível.
- Resiliência - Uma habilidade é executada num único turno de agente. Se algo falhar, toda a operação tem de ser tentada novamente. Os fluxos de trabalho suportam o armazenamento de pontos de verificação, para que possam retomar a partir do último passo bem-sucedido após uma falha. Escolha fluxos de trabalho quando o custo de reexecutar todo o processo for elevado.
- Efeitos secundários - As competências são adequadas quando as operações são idempotentes ou de baixo risco. Prefira fluxos de trabalho quando as etapas produzem efeitos secundários (envio de emails, cobrança de pagamentos) que não devam ser repetidos numa nova tentativa.
- Complexidade - As competências são melhores para tarefas focadas e de domínio único que um agente pode gerir. Os fluxos de trabalho são mais adequados para processos empresariais em múltiplas etapas que coordenam múltiplos agentes, aprovações humanas ou integrações de sistemas externos.
Sugestão
Como regra geral: se quiseres que a IA descubra como realizar uma tarefa, usa uma habilidade. Se precisares de garantir que passos são executados e em que ordem, usa um fluxo de trabalho.