Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las aptitudes del agente son paquetes portátiles de instrucciones, scripts y recursos que proporcionan a los agentes funcionalidades especializadas y conocimientos sobre dominios. Las aptitudes siguen una especificación abierta e implementan un patrón de divulgación progresiva para que los agentes carguen solo el contexto que necesitan, cuando lo necesiten.
Utilice habilidades del agente cuando las necesite:
- Empaquete la experiencia de dominio: capture conocimientos especializados (políticas de gastos, flujos de trabajo jurídicos, canalizaciones de análisis de datos) en forma de paquetes reutilizables y portables.
- Ampliar las funcionalidades del agente : proporcione a los agentes nuevas capacidades sin cambiar sus instrucciones principales.
- Garantizar la coherencia : convierta las tareas de varios pasos en flujos de trabajo repetibles y auditables.
- Habilitar la interoperabilidad : reutilice la misma aptitud en diferentes productos compatibles con aptitudes del agente.
Estructura de aptitudes
Una aptitud es un directorio que contiene un SKILL.md archivo con subdirectorios opcionales para los 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
El SKILL.md archivo debe contener el frontmatter de YAML seguido del contenido 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 | Obligatorio | Description |
|---|---|---|
name |
Sí | Máximo de 64 caracteres. Solo se permiten letras minúsculas, números y guiones. No debe iniciar ni terminar con un guión o contener guiones consecutivos. Debe coincidir con el nombre del directorio primario. |
description |
Sí | Qué hace la aptitud y cuándo usarla. Máximo de 1024 caracteres. Debe incluir palabras clave que ayuden a los agentes a identificar las tareas pertinentes. |
license |
No | Nombre de licencia o referencia a un archivo de licencia agrupado. |
compatibility |
No | Máximo de 500 caracteres. Indica los requisitos del entorno (producto previsto, paquetes del sistema, acceso a la red, etc.). |
metadata |
No | Mapeo arbitrario de clave-valor para metadatos adicionales. |
allowed-tools |
No | Lista delimitada por espacios de herramientas pre-aprobadas que la habilidad puede usar. Experimental: el soporte puede variar entre las implementaciones de agentes. |
El cuerpo de Markdown después de la frontmatter contiene las instrucciones de aptitud: instrucciones paso a paso, ejemplos de entradas y salidas, casos perimetrales comunes o cualquier contenido que ayude al agente a realizar la tarea. Mantenga SKILL.md en menos de 500 líneas y mueva el material de referencia detallado a archivos independientes.
Divulgación progresiva
Las capacidades del agente usan un modelo de revelación progresiva a lo largo de cuatro etapas para reducir al mínimo el uso del contexto.
- Anunciar (~100 tokens por habilidad) - Los nombres y las descripciones de las habilidades se insertan en el prompt del sistema al comienzo de cada ejecución, para que el agente sepa qué habilidades están disponibles.
-
Cargar (< se recomiendan 5000 tokens) - Cuando una tarea coincide con el dominio de una habilidad, el agente llama a la herramienta
load_skillpara recuperar el contenido completo de SKILL.md con instrucciones detalladas. -
Recursos de lectura (según sea necesario): el agente llama a la
read_skill_resourceherramienta para capturar archivos complementarios (referencias, plantillas, recursos) solo cuando sea necesario. -
Ejecutar scripts (según sea necesario) - El agente usa la herramienta
run_skill_scriptpara ejecutar scripts incluidos en una habilidad.
Este patrón mantiene la ventana de contexto del agente ligera al tiempo que proporciona acceso a conocimientos profundos de dominio bajo demanda.
Nota:
load_skill siempre se anuncia.
read_skill_resource se anuncia solo cuando al menos una habilidad tiene recursos.
run_skill_script solo se anuncia cuando al menos una habilidad tiene scripts.
Proporcionar aptitudes a un agente
AgentSkillsProvider (C#) y SkillsProvider (Python) son proveedores de contexto que hacen que las aptitudes estén disponibles para los agentes. Admiten tres orígenes de aptitudes:
-
Basado en archivos - habilidades descubiertas a partir de archivos
SKILL.mden directorios del sistema de archivos -
Código definido: aptitudes definidas en línea en el código mediante
AgentInlineSkill(C#) oInlineSkill(Python) -
Basado en clases - habilidades encapsuladas en una clase que deriva de
AgentClassSkill<T>(C#) oClassSkill(Python)
Para mezclar varios orígenes en un proveedor, use AgentSkillsProviderBuilder (C#) o componga clases de origen como AggregatingSkillsSource, FilteringSkillsSource y DeduplicatingSkillsSource (Python): consulte Builder: escenarios avanzados de varios orígenes (C#) o Source composition: escenarios avanzados de varios orígenes (Python).
Habilidades basadas en archivos
Cree un AgentSkillsProvider que apunte a un directorio que contenga sus aptitudes y agréguelo a los proveedores de contexto del agente. Pase un ejecutor de scripts para habilitar la ejecución de scripts basados en archivos que se encuentran en directorios de aptitudes:
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);
Advertencia
DefaultAzureCredential es conveniente para el desarrollo, pero requiere una consideración cuidadosa en producción. En producción, considere usar una credencial específica (por ejemplo, ManagedIdentityCredential) para evitar problemas de latencia, sondeos de credenciales no deseados y posibles riesgos de seguridad de los mecanismos de respaldo.
Varios directorios de aptitudes
Puede hacer que el proveedor apunte a un único directorio principal: cada subdirectorio que contiene un SKILL.md se detecta automáticamente como una habilidad:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "all-skills"));
O bien, pase una lista de rutas de acceso para buscar varios directorios raíz:
var skillsProvider = new AgentSkillsProvider(
[
Path.Combine(AppContext.BaseDirectory, "company-skills"),
Path.Combine(AppContext.BaseDirectory, "team-skills"),
]);
El proveedor busca hasta dos niveles en profundidad.
Personalización de la detección de recursos
De forma predeterminada, el proveedor reconoce los recursos con extensiones .md, .json, .yaml, .yml, .csv, .xml y .txt en los subdirectorios references y assets. Use AgentFileSkillsSourceOptions para cambiar estos valores predeterminados:
var fileOptions = new AgentFileSkillsSourceOptions
{
AllowedResourceExtensions = [".md", ".txt"],
ResourceDirectories = ["docs", "templates"],
};
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
fileOptions: fileOptions);
Ejecución de scripts
Pase SubprocessScriptRunner.RunAsync como segundo argumento a AgentSkillsProvider para habilitar la ejecución de scripts basados en archivos:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync);
SubprocessScriptRunner.RunAsync es aproximadamente equivalente a lo siguiente:
// Simplified equivalent of what SubprocessScriptRunner.RunAsync does internally
using System.Diagnostics;
using System.Text.Json;
static async Task<string> RunAsync(
AgentFileSkill skill,
AgentFileSkillScript script,
JsonElement? args,
IServiceProvider? serviceProvider)
{
var psi = new ProcessStartInfo("python3")
{
RedirectStandardOutput = true,
UseShellExecute = false,
};
psi.ArgumentList.Add(Path.Combine(skill.Path, script.Path));
if (args is { ValueKind: JsonValueKind.Array } json)
{
foreach (var element in json.EnumerateArray())
{
psi.ArgumentList.Add(element.GetString()!);
}
}
using var process = Process.Start(psi)!;
string output = await process.StandardOutput.ReadToEndAsync();
await process.WaitForExitAsync();
return output.Trim();
}
El ejecutor ejecuta cada script detectado como un subproceso local. Los scripts basados en archivos esperan argumentos como una matriz JSON de cadenas: cada elemento de matriz se convierte en un argumento de línea de comandos posicional.
Advertencia
SubprocessScriptRunner solo se proporciona con fines de demostración. Para su uso en producción, considere la posibilidad de agregar:
- Sandboxing (por ejemplo, contenedores o entornos de ejecución aislados)
- Límites de recursos (CPU, memoria, tiempo de espera del reloj)
- Validación de entrada y lista de permitidos de scripts ejecutables
- Registros estructurados y seguimientos de auditoría
Personalización de la detección de scripts
De forma predeterminada, el proveedor reconoce scripts con extensiones.py, , .js.sh, .ps1, .cs, y .csx en el scripts subdirectorio. Use AgentFileSkillsSourceOptions para cambiar estos valores predeterminados:
Pase AgentFileSkillsSourceOptions al AgentSkillsProvider constructor o al UseFileSkill / UseFileSkills generador:
var fileOptions = new AgentFileSkillsSourceOptions
{
AllowedScriptExtensions = [".py"],
ScriptDirectories = ["scripts", "tools"],
};
// Via constructor
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
fileOptions: fileOptions);
// Via builder
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"), options: fileOptions)
.Build();
Habilidades basadas en archivos
Use la factoría SkillsProvider.from_paths() para descubrir habilidades de directorios que contienen archivos SKILL.md, y agregue el proveedor a los proveedores de contexto del 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],
)
Varios directorios de aptitudes
Puede hacer que el proveedor apunte a un único directorio principal: cada subdirectorio que contiene un SKILL.md se detecta automáticamente como una habilidad:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "all-skills"
)
O bien, pase una lista de rutas de acceso para buscar varios directorios raíz:
skills_provider = SkillsProvider.from_paths(
skill_paths=[
Path(__file__).parent / "company-skills",
Path(__file__).parent / "team-skills",
]
)
El proveedor busca hasta dos niveles en profundidad.
Personalización de la detección de recursos y scripts
De forma predeterminada, los recursos se detectan en los subdirectorios references/ y assets/, y los scripts en scripts/, según la especificación de agentskills.io. Las extensiones de recursos reconocidas son .md, .json, .yaml, .yml.csv, , .xmly .txt. Use resource_directories, script_directoriesy resource_extensions para personalizar estos valores predeterminados:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
resource_extensions=(".md", ".txt"),
resource_directories=["docs", "templates"],
script_directories=["scripts", "tools"],
)
Usa "." para incluir archivos en el nivel raíz de la skill, además de en los subdirectorios.
Ejecución de scripts
Para habilitar la ejecución de scripts basados en archivos, pase un script_runner a SkillsProvider.from_paths(). Se puede usar cualquier función que sea una llamada síncrona o asíncrona que satisfaga el protocolo SkillScriptRunner.
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,
)
El ejecutador recibe los valores resueltos FileSkill, FileSkillScript y un argumento opcional args. Los scripts basados en archivos esperan argumentos como una matriz JSON de cadenas: cada elemento de matriz se convierte en un argumento de línea de comandos posicional. Los scripts se descubren automáticamente en los archivos .py del subdirectorio scripts/ de cada directorio de habilidad.
Advertencia
El runner arriba solo se proporciona con fines de demostración. Para su uso en producción, considere la posibilidad de agregar:
- Sandboxing (por ejemplo, contenedores,
seccomp, ofirejail) - Límites de recursos (CPU, memoria, tiempo de espera del reloj)
- Validación de entrada y lista de permitidos de scripts ejecutables
- Registros estructurados y seguimientos de auditoría
Nota:
Si se proporcionan capacidades basadas en archivos con scripts, pero no se establece script_runner, SkillsProvider produce un error al intentar ejecutar el script.
Aptitudes definidas por código
Además de las aptitudes basadas en archivos detectadas a partir de SKILL.md archivos, puede definir aptitudes por completo en el código mediante AgentInlineSkill. Las aptitudes definidas por código son útiles cuando:
- El contenido de la aptitud se genera dinámicamente (por ejemplo, leer desde una base de datos o un entorno).
- Quiere mantener las definiciones de habilidades junto con el código de aplicación que las usa.
- Necesita recursos que ejecuten lógica en tiempo de lectura en lugar de servir archivos estáticos.
- Las definiciones de aptitudes deben crearse en tiempo de ejecución a partir de datos ; por ejemplo, crear una aptitud personalizada para cada sesión de usuario en función de su rol o permisos.
- Una habilidad debe capturar el estado en el punto de llamada (variables locales, clausuras) en lugar de resolver servicios desde un contenedor de inyección de dependencias.
Aptitud de código básico
Cree un AgentInlineSkill con un nombre, una descripción e instrucciones. Adjuntar recursos mediante .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
Pase un delegado de fábrica a .AddResource() para calcular el contenido en tiempo de ejecución. El delegado se invoca cada vez que el agente lee el 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 un delegado como un script ejecutable. Los scripts definidos por código se ejecutan en proceso como llamadas de delegado directas. No se necesita ningún ejecutor de scripts. Los parámetros tipados del delegado se convierten automáticamente en un esquema JSON que el agente utiliza para pasar 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);
Nota:
Para combinar aptitudes definidas por código con aptitudes basadas en archivos o basadas en clases en un único proveedor, use AgentSkillsProviderBuilder : consulte Generador: escenarios avanzados de varios orígenes.
Además de las habilidades basadas en archivos detectadas en archivos SKILL.md, puede definir habilidades íntegramente en código Python mediante InlineSkill. Las aptitudes definidas por código son útiles cuando:
- El contenido de la aptitud se genera dinámicamente (por ejemplo, leer desde una base de datos o un entorno).
- Quiere mantener las definiciones de habilidades junto con el código de aplicación que las usa.
- Necesita recursos que ejecuten lógica en tiempo de lectura en lugar de servir archivos estáticos.
- Las definiciones de aptitudes deben crearse en tiempo de ejecución a partir de datos ; por ejemplo, crear una aptitud personalizada para cada sesión de usuario en función de su rol o permisos.
- Una habilidad debe capturar el estado del sitio de llamada (variables locales, clausuras) en lugar de resolver servicios a través de
**kwargs.
Aptitud de código básico
Cree una InlineSkill instancia con un SkillFrontmatter (que contiene el nombre y la descripción) y el contenido de instrucciones. Opcionalmente, adjunte InlineSkillResource instancias con contenido 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 el @skill.resource decorador para registrar una función como un recurso. La función se llama cada vez que el agente lee el recurso, por lo que puede devolver datos actualizados. Se admiten las funciones de sincronización y asincrónica:
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)"
Cuando el decorador se usa sin argumentos (@skill.resource), el nombre de la función se convierte en el nombre del recurso y docstring se convierte en la descripción. Use @skill.resource(name="...", description="...") para establecerlos explícitamente.
Scripts definidos por código
Use el decorador @skill.script para registrar una función como un script ejecutable en una habilidad. Los scripts definidos por código se ejecutan en proceso y no requieren un ejecutor de scripts. Se admiten las funciones de sincronización y asincrónica:
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})
Cuando el decorador se usa sin argumentos (@skill.script), el nombre de la función se convierte en el nombre del script y docstring se convierte en la descripción. Los parámetros tipificados de la función se convierten automáticamente en un esquema JSON que el agente utiliza para el paso de argumentos.
Habilidades basadas en clases
Las aptitudes basadas en clases permiten agrupar todos los componentes de aptitudes ( nombre, descripción, instrucciones, recursos y scripts) en una sola clase de C#. Esto hace que sean fáciles de empaquetar y distribuir como paquetes NuGet: los equipos pueden crear y enviar aptitudes de forma independiente, y los consumidores los agregan con dotnet add package y una sola .UseSkill() llamada. Derive de AgentClassSkill<T> (donde T es la clase ), anote las propiedades con [AgentSkillResource] y los métodos con [AgentSkillScript] para la detección 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 });
}
}
Registra la habilidad basada en clases con AgentSkillsProvider
var skill = new UnitConverterSkill();
var skillsProvider = new AgentSkillsProvider(skill);
Cuando el [AgentSkillResource] atributo se aplica a una propiedad o método, su valor devuelto se usa como contenido del recurso cuando el agente lee el recurso: use un método cuando el contenido se necesite calcular en tiempo de lectura. Cuando [AgentSkillScript] se aplica a un método, se invoca el método cuando el agente llama al script. Use [Description] desde System.ComponentModel para describir cada recurso y script para el agente.
Nota:
AgentClassSkill<T> también admite la sobrescritura de Resources y Scripts como colecciones para escenarios en los que la detección basada en atributos no es adecuada.
Habilidades basadas en clases
Las aptitudes basadas en clases permiten agrupar todos los componentes de aptitudes (nombre, descripción, instrucciones, recursos y scripts) en una sola clase Python. Esto hace que sea fácil empaquetarlas y distribuirlas como paquetes de PyPI: los equipos pueden crear y publicar habilidades de forma independiente, y los usuarios pueden agregarlas con pip install y una sola llamada a SkillsProvider(). Cree una subclase de ClassSkill y luego use los decoradores @ClassSkill.resource y @ClassSkill.script para la detección 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})
Registra la habilidad basada en clases con SkillsProvider
from agent_framework import SkillsProvider
skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)
Cuando @ClassSkill.resource se aplica como decorador completo (sin argumentos), el nombre del método se convierte en el nombre del recurso (con caracteres de subrayado convertidos en guiones) y la docstring se convierte en la descripción. Use @ClassSkill.resource(name="...", description="...") para establecerlos explícitamente. El mismo patrón se aplica a @ClassSkill.script.
Los recursos se pueden definir como métodos o @property descriptores normales. Cuando se usa @property, coloque @property primero y @ClassSkill.resource segundo. Los valores devueltos de recursos se almacenan en caché después del primer acceso.
Nota:
ClassSkill también admite sobrescribir explícitamente las propiedades resources y scripts para devolver directamente instancias de InlineSkillResource y InlineSkillScript, en aquellos casos en los que la detección basada en decoradores no se ajusta.
Generador: escenarios avanzados de varios orígenes
Para escenarios sencillos y de origen único, use los AgentSkillsProvider constructores directamente. Use AgentSkillsProviderBuilder cuando necesite cualquiera de las siguientes opciones:
-
Tipos de aptitudes mixtas: combine aptitudes basadas en archivos, definidas por código (
AgentInlineSkill) y basadas en clases (AgentClassSkill) en un único proveedor. - Filtrado de aptitudes : incluya o excluya aptitudes mediante un predicado.
Tipos de aptitudes mixtas
Combina los tres tipos de habilidades de un proveedor mediante el encadenamiento de UseFileSkill, UseSkill y UseFileScriptRunner.
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills")) // file-based skills
.UseSkill(volumeConverterSkill) // AgentInlineSkill
.UseSkill(temperatureConverter) // AgentClassSkill
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync) // runner for file scripts
.Build();
Filtrado de aptitudes
Use UseFilter para incluir solo las aptitudes que cumplan los criterios; por ejemplo, para cargar aptitudes desde un directorio compartido, pero excluir las experimentales:
var approvedSkillNames = new HashSet<string> { "expense-report", "code-style" };
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseFilter(skill => approvedSkillNames.Contains(skill.Frontmatter.Name))
.Build();
Composición de origen: escenarios avanzados de varios orígenes
Para escenarios sencillos con una sola aptitud o una lista de aptitudes, páselos directamente al SkillsProvider constructor. En el caso de las aptitudes basadas en archivos, use el SkillsProvider.from_paths() generador. En escenarios avanzados, cree clases de origen para controlar la detección, el filtrado y la desduplicación:
-
FileSkillsSource- descubre habilidades en archivosSKILL.mddel disco. -
InMemorySkillsSource: encapsula cualquierSkillinstancia (definida por código o basada en clases) en memoria. -
AggregatingSkillsSource: combina varios orígenes en uno. -
FilteringSkillsSource: aplica un predicado para incluir o excluir aptitudes. -
DeduplicatingSkillsSource: quita nombres de aptitud duplicados (sin distinción entre mayúsculas y minúsculas, primeros victorias).
Tipos de aptitudes mixtas
Combine habilidades basadas en archivos, definidas mediante código y basadas en clases en un único proveedor con AggregatingSkillsSource. En el ejemplo siguiente se usan objetos de marcador de posición:
-
volume_converter_skill: cualquierInlineSkillinstancia, creada como se muestra en Aptitudes definidas por código. -
TemperatureConverterSkill: cualquierClassSkillsubclase, creada como se muestra en Aptitudes basadas en clases. -
my_runner: unSkillScriptRunnerinvocable, definido como se muestra en Ejecución 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]),
])
)
)
Filtrado de aptitudes
Use FilteringSkillsSource para controlar qué aptitudes ve el agente. El predicado recibe cada Skill y devuelve True para incluirlo. Por ejemplo, para cargar habilidades desde un directorio compartido pero ocultar una 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",
)
)
)
Aprobación de scripts
Utiliza AgentSkillsProviderOptions.ScriptApproval para bloquear toda la ejecución de scripts hasta que haya aprobación humana. Cuando está habilitado, el agente pausa y devuelve una solicitud de aprobación en lugar de ejecutarse inmediatamente:
var skillsProvider = new AgentSkillsProvider(
skillPath: Path.Combine(AppContext.BaseDirectory, "skills"),
options: new AgentSkillsProviderOptions
{
ScriptApproval = true,
});
Para habilitar la aprobación de scripts en un proveedor configurado por el generador, use UseScriptApproval:
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseScriptApproval(true)
.Build();
Use require_script_approval=True en SkillsProvider para controlar toda la ejecución de scripts con aprobación humana. En lugar de ejecutarse inmediatamente, el agente hace una pausa y devuelve solicitudes de aprobación a travé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)
Cuando se rechaza un script (approved=False), se informa al agente de que el usuario ha rechazado y que puede responder en consecuencia.
Mensaje del sistema personalizado
De forma predeterminada, el proveedor de aptitudes inserta una solicitud del sistema que enumera las aptitudes disponibles e indica al agente que use load_skill y read_skill_resource. Puede personalizar este mensaje:
var skillsProvider = new AgentSkillsProvider(
skillPath: Path.Combine(AppContext.BaseDirectory, "skills"),
options: new AgentSkillsProviderOptions
{
SkillsInstructionPrompt = """
You have skills available. Here they are:
{skills}
{resource_instructions}
{script_instructions}
"""
});
Nota:
La plantilla personalizada debe contener los marcadores de posición {skills} (lista de habilidades), {resource_instructions} (sugerencia de herramienta de recursos) y {script_instructions} (sugerencia de herramienta de script). Las llaves literales deben ser de escape como {{ y }}.
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
instruction_template=(
"You have skills available. Here they are:\n{skills}\n"
"{resource_instructions}\n"
"{runner_instructions}"
),
)
Nota:
La plantilla personalizada debe contener los marcadores de posición {skills} (lista de habilidades), {resource_instructions} (sugerencia de herramienta de recursos) y {runner_instructions} (sugerencia de herramienta de script). Las llaves literales deben ser de escape como {{ y }}.
Comportamiento del almacenamiento en caché
De forma predeterminada, las herramientas de aptitud y las instrucciones se almacenan en caché después de la primera compilación. Establezca DisableCaching = true en AgentSkillsProviderOptions para forzar una recompilación en cada invocación:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
options: new AgentSkillsProviderOptions
{
DisableCaching = true,
});
Nota:
Deshabilitar el almacenamiento en caché es útil durante el desarrollo cuando el contenido de la aptitud cambia con frecuencia. En producción, deje habilitado el almacenamiento en caché (valor predeterminado) para mejorar el rendimiento.
Comportamiento del almacenamiento en caché
De forma predeterminada, las herramientas de aptitud y las instrucciones se almacenan en caché después de la primera compilación. Establezca disable_caching=True para forzar una reconstrucción en cada invocación:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
disable_caching=True,
)
disable_caching también está disponible en el SkillsProvider constructor para aptitudes definidas por código y basadas en clases.
Nota:
Deshabilitar el almacenamiento en caché es útil durante el desarrollo cuando el contenido de la aptitud cambia con frecuencia. En producción, deje habilitado el almacenamiento en caché (valor predeterminado) para mejorar el rendimiento.
Los delegados de script y de recursos de aptitud pueden incluir un parámetro IServiceProvider que el Framework del Agente inserta automáticamente. Esto permite que las aptitudes resuelvan los servicios de aplicación , como los clientes de base de datos, la configuración o la lógica de negocios, sin codificarlos de forma rígida en la definición de la aptitud.
Configuración
Registre los servicios de aplicación y pase el compilado IServiceProvider al agente mediante el 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);
Aptitudes definidas por código con DI
Declarar IServiceProvider como parámetro en los delegados AddResource o AddScript: el framework lo resuelve y lo inyecta automáticamente cuando el agente lee un recurso o ejecuta un 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 basadas en clases con inyección de dependencias
Anotación de métodos con [AgentSkillResource] o [AgentSkillScript] y declaración de un IServiceProvider parámetro: el marco detecta estos miembros a través de la reflexión e inserta automáticamente el proveedor de servicios:
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);
}
}
Sugerencia
Las habilidades basadas en clases también pueden resolver las dependencias a través de su constructor. Registre la clase de aptitud en ServiceCollection y la resuelva desde el contenedor en lugar de llamar directamente a new :
services.AddSingleton<WeightConverterSkill>();
var weightSkill = serviceProvider.GetRequiredService<WeightConverterSkill>();
Esto resulta útil cuando la propia clase de habilidad necesita servicios inyectados más allá de aquellos utilizados por los delegados de recursos y scripts.
Las funciones de recursos y scripts que aceptan **kwargs reciben automáticamente los argumentos de palabras clave en tiempo de ejecución que se pasan a agent.run(). Esto permite que las funciones de aptitud accedan al contexto de la aplicación , como la configuración, la identidad del usuario o los clientes de servicio, sin codificarlos de forma rígida en la definición de la aptitud.
Pasar argumentos en tiempo de ejecución
Pase function_invocation_kwargs a agent.run() para proporcionar argumentos de palabra clave que el marco reenvía a las funciones de recurso y script:
response = await agent.run(
"How many kilometers is 26.2 miles?",
function_invocation_kwargs={"precision": 2, "user_id": "alice"},
)
Habilidades definidas mediante código con kwargs
Cuando una función de recurso declara **kwargs, el marco reenvía los argumentos de palabra clave en tiempo de ejecución cada vez que el agente lee el 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}"
Las funciones de recursos sin **kwargs se llaman sin argumentos y no reciben contexto en tiempo de ejecución.
Cuando una función de script declara **kwargs, el marco reenvía los argumentos de palabra clave en tiempo de ejecución junto con el args proporcionado por el 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})
El agente proporciona value y factor a través de la llamada a la herramienta args; la aplicación proporciona precision a través de function_invocation_kwargs. Funciones de script sin **kwargs reciben solo los argumentos que el agente proporciona.
Habilidades basadas en clases con kwargs
Los métodos de habilidad basados en clases también pueden aceptar **kwargs para recibir argumentos en tiempo de ejecución. El patrón funciona de la misma manera: declarar **kwargs en métodos de recursos o 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})
Procedimientos recomendados de seguridad
Las aptitudes del agente deben tratarse como cualquier código de terceros que incorpore al proyecto. Dado que las instrucciones de aptitudes se insertan en el contexto del agente( y las aptitudes pueden incluir scripts), aplicar el mismo nivel de revisión y gobernanza que haría con una dependencia de código abierto es esencial.
-
Revisar antes de usar : lea todo el contenido de las aptitudes (
SKILL.md, scripts y recursos) antes de la implementación. Compruebe que el comportamiento real de un script coincide con su intención indicada. Busque instrucciones adversarias que intenten omitir las directrices de seguridad, exfiltrar datos o modificar archivos de configuración de agentes. - Confianza de origen : instale solo aptitudes de autores de confianza o colaboradores internos examinados. Prefiere aptitudes con un claro origen, control de versiones y mantenimiento activo. Esté atento a los nombres de habilidades suplantados que imitan paquetes de software populares.
- Aislamiento - Ejecutar habilidades que incluyan scripts ejecutables en entornos aislados. Limite el acceso del sistema de archivos, la red y el nivel de sistema solo a lo que requiere la aptitud. Requerir confirmación explícita del usuario antes de ejecutar operaciones potencialmente confidenciales.
- Auditoría y registro : registre qué aptitudes se cargan, qué recursos se leen y qué scripts se ejecutan. Esto le proporciona una pista de auditoría para rastrear el comportamiento del agente hasta contenido específico de habilidades si algo sale mal.
Cuándo usar aptitudes frente a flujos de trabajo
Los flujos de trabajo de Agent Skills y Agent Framework amplían lo que pueden hacer los agentes, pero funcionan de maneras fundamentalmente diferentes. Elija el enfoque que mejor se adapte a sus requisitos:
- Control : con una aptitud, la inteligencia artificial decide cómo ejecutar las instrucciones. Esto es ideal cuando quieres que el agente sea creativo o adaptable. Con un flujo de trabajo, se define explícitamente la trayectoria de ejecución. Use flujos de trabajo cuando necesite un comportamiento determinista y predecible.
- Resiliencia - Una habilidad se ejecuta en un único turno del agente. Si se produce un error en algo, se debe reintentar toda la operación. Los flujos de trabajo admiten puntos de control, por lo que pueden reanudarse desde el último paso exitoso después de una falla. Elija flujos de trabajo cuando el costo de volver a ejecutar todo el proceso sea alto.
- Efectos secundarios - Las habilidades son adecuadas cuando las operaciones son idempotentes o de bajo riesgo. Prefiere flujos de trabajo cuando los pasos producen efectos secundarios (enviar correos electrónicos, cobrar pagos) que no deben repetirse en el reintento.
- Complejidad : las aptitudes son las mejores para las tareas centradas y de dominio único que un agente puede controlar. Los flujos de trabajo son más adecuados para los procesos empresariales de varios pasos que coordinan varios agentes, aprobaciones humanas o integraciones de sistemas externos.
Sugerencia
Como regla general: si desea que la inteligencia artificial descubra cómo realizar una tarea, use una aptitud. Si necesita garantizar qué pasos se ejecutan y en qué orden, use un flujo de trabajo.