Partekatu honen bidez:


Aptitudes del agente

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:

  • Empaquetar el dominio de la experiencia: capte conocimientos especializados (políticas de gastos, flujos de trabajo legales, pipelines de análisis de datos) como paquetes reutilizables y portátiles.
  • Ampliar las funcionalidades del agente : proporcione nuevas capacidades a los agentes 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 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 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: la compatibilidad puede variar entre las implementaciones del agente.

El cuerpo de Markdown después de la frontmatter contiene las instrucciones de habilidades, instrucciones paso a paso, ejemplos de entradas y salidas, casos límite 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.

  1. Publicidad (~100 tokens por aptitud): los nombres y las descripciones de las aptitudes se insertan en la indicación del sistema al principio de cada ejecución, de modo que el agente sepa qué aptitudes están disponibles.
  2. Cargar (< 5000 tokens recomendados): cuando una tarea coincide con el dominio de una aptitud, el agente llama a la load_skill herramienta para recuperar el cuerpo completo del SKILL.md con instrucciones detalladas.
  3. Recursos de lectura (según sea necesario): el agente llama a la read_skill_resource herramienta para capturar archivos complementarios (referencias, plantillas, recursos) solo cuando sea necesario.
  4. Ejecutar scripts (según sea necesario): el agente llama a la herramienta run_skill_script para ejecutar scripts agrupados con 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 detectadas a partir de SKILL.md archivos en directorios del sistema de archivos
  • Código definido: aptitudes definidas en línea en el código mediante AgentInlineSkill (C#) o Skill (Python)
  • Basado en clases — habilidades encapsuladas en una clase de C# derivada de AgentClassSkill<T> (solo C#)

Para mezclar varios orígenes en un proveedor, use AgentSkillsProviderBuilder (solo C#, consulte Generador: escenarios avanzados de varios orígenes).

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 apuntar el proveedor a un único directorio primario: 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;

static async Task<string> RunAsync(AgentSkill skill, AgentSkillScript script, IDictionary<string, object?>? args)
{
    var psi = new ProcessStartInfo("python3")
    {
        RedirectStandardOutput = true,
        UseShellExecute = false,
    };
    psi.ArgumentList.Add(Path.Combine(skill.Path, script.Path));
    if (args != null)
    {
        foreach (var (key, value) in args)
        {
            if (value is not null)
            {
                psi.ArgumentList.Add($"--{key}");
                psi.ArgumentList.Add(value.ToString()!);
            }
        }
    }
    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 y reenvía los argumentos JSON proporcionados por el agente como marcas de línea de comandos.

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

Cree un SkillsProvider que apunte a un directorio que contenga sus aptitudes y agréguelo a los proveedores de contexto del agente:

import os
from pathlib import Path
from agent_framework import SkillsProvider
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity.aio import AzureCliCredential

# Discover skills from the 'skills' directory
skills_provider = SkillsProvider(
    skill_paths=Path(__file__).parent / "skills"
)

# Create an agent with the skills provider
agent = OpenAIChatCompletionClient(
    model=os.environ["AZURE_OPENAI_CHAT_COMPLETION_MODEL"],
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
    credential=AzureCliCredential(),
).as_agent(
    name="SkillsAgent",
    instructions="You are a helpful assistant.",
    context_providers=[skills_provider],
)

Varios directorios de aptitudes

Puede dirigir al proveedor a una sola carpeta principal: cada subcarpeta que contiene un SKILL.md se detecta automáticamente como una habilidad.

skills_provider = SkillsProvider(
    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(
    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

De forma predeterminada, SkillsProvider reconoce los recursos con extensiones .md, , .json.yaml, .yml, .csv, .xmly .txt. Examina todos los subdirectorios dentro de cada carpeta de aptitudes. Pase resource_extensions para cambiar los tipos de archivo reconocidos:

skills_provider = SkillsProvider(
    skill_paths=Path(__file__).parent / "skills",
    resource_extensions=(".md", ".txt"),
)

Ejecución de scripts

Para habilitar la ejecución de scripts basados en archivos, pase un script_runner a SkillsProvider. 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 Skill, SkillScript, SkillsProvider

def my_runner(skill: Skill, script: SkillScript, args: dict | None = None) -> str:
    """Run a file-based script as a subprocess."""
    import subprocess, sys
    cmd = [sys.executable, str(Path(skill.path) / script.path)]
    if args:
        for key, value in args.items():
            if value is not None:
                cmd.extend([f"--{key}", str(value)])
    result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
    return result.stdout.strip()

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

El corredor recibe el objeto resuelto Skill, SkillScript y un diccionario opcional args. Los scripts basados en archivos se detectan automáticamente a partir de .py archivos en directorios de aptitudes.

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, o firejail)
  • 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 habilidades basadas en archivos con scripts, pero no se establece script_runner, SkillsProvider genera un ValueError.

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.

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, consulte AgentSkillsProviderBuilderBuilder: escenarios avanzados de varios orígenes.

Además de las competencias basadas en archivos detectadas a partir de SKILL.md, puede definir competencias puramente en código Python. 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.

Aptitud de código básico

Cree una Skill instancia con un nombre, una descripción y un contenido de instrucciones. Opcionalmente, adjunte SkillResource instancias con contenido estático:

from textwrap import dedent
from agent_framework import Skill, SkillResource, SkillsProvider

code_style_skill = Skill(
    name="code-style",
    description="Coding style guidelines and conventions for the team",
    content=dedent("""\
        Use this skill when answering questions about coding style,
        conventions, or best practices for the team.
    """),
    resources=[
        SkillResource(
            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(skills=[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 Skill

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

@project_info_skill.resource
def environment() -> Any:
    """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() -> Any:
    """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 script. Se admiten las funciones de sincronización y asincrónica:

from agent_framework import Skill

unit_converter_skill = Skill(
    name="unit-converter",
    description="Convert between common units using a conversion factor",
    content="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.

Combinación de aptitudes basadas en archivos y definidas por código

Pase tanto skill_paths como skills a un solo SkillsProvider. Primero se detectan aptitudes basadas en archivos; si una aptitud definida por código tiene el mismo nombre que una aptitud basada en archivos existente, se omite la aptitud definida por código:

from pathlib import Path
from agent_framework import Skill, SkillsProvider

my_skill = Skill(
    name="my-code-skill",
    description="A code-defined skill",
    content="Instructions for the skill.",
)

skills_provider = SkillsProvider(
    skill_paths=Path(__file__).parent / "skills",
    skills=[my_skill],
)

Habilidades basadas en clases

Las aptitudes basadas en clases permiten agrupar todos los componentes de aptitud (nombre, descripción, instrucciones, recursos y scripts) en una sola clase de C#. 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.

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

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 pausa y devuelve solicitudes de aprobación:

from agent_framework import Agent, Skill, SkillsProvider

# Create provider with approval enabled
skills_provider = SkillsProvider(
    skills=[my_skill],
    require_script_approval=True,
)

# Run the agent — script calls pause for approval
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)

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(
    skill_paths=Path(__file__).parent / "skills",
    instruction_template=(
        "You have skills available. Here they are:\n{skills}\n"
        "Use the `load_skill` function to get skill instructions.\n"
        "Use the `read_skill_resource` function to read skill files."
    ),
)

Nota:

La plantilla personalizada debe contener un {skills} marcador de posición donde se inserta la lista de aptitudes y un {runner_instructions} marcador de posición donde se insertan instrucciones relacionadas con scripts.

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.

Inserción de dependencia

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 clientes de base de datos, configuración o lógica empresarial, 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 e 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"},
)

Funciones de recursos 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:

from typing import Any
from agent_framework import Skill

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

@project_info_skill.resource(name="environment", description="Current environment configuration")
def environment(**kwargs: Any) -> Any:
    """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.

Funciones de script con kwargs

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 Skill

converter_skill = Skill(
    name="unit-converter",
    description="Convert between common units using a conversion factor",
    content="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.

Procedimientos recomendados de seguridad

Las habilidades del agente deben tratarse como cualquier código de terceros que incorpore en su proyecto. Dado que las instrucciones de habilidades se insertan en el contexto del agente, y las habilidades pueden incluir scripts, es esencial aplicar el mismo nivel de revisión y gobernanza que aplicaría a una dependencia de código abierto.

  • 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.
  • Sandboxing — Ejecute 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.
  • Resistencia — Se ejecuta una habilidad dentro de un solo turno de 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 aptitudes 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.

Pasos siguientes