Бөлісу құралы:


Навыки агента

Навыки агента — это переносимые пакеты инструкций, скриптов и ресурсов, которые предоставляют агентам специализированные возможности и опыт работы с доменом. Навыки соответствуют открытой спецификации и реализуют прогрессивный шаблон раскрытия, чтобы агенты загружали только нужный контекст, когда им нужен.

Используйте навыки агента, если требуется:

  • Опыт в области пакетов — захват специализированных знаний (политики расходов, юридических рабочих процессов, конвейеров анализа данных) в качестве многократно используемых переносимых пакетов.
  • Расширение возможностей агента— предоставление агентам новых возможностей без изменения основных инструкций.
  • Обеспечение согласованности — преобразование многофакторных задач в повторяемые, проверяемые рабочие процессы.
  • Включение интероперабельности — повторное использование одного и того же навыка в различных продуктах, совместимых с Agent Skills.

Структура навыка

Умение — это каталог, в котором находится SKILL.md файл с необязательными подкаталогами для ресурсов:

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

Файл SKILL.md должен содержать метаинформацию YAML, за которой следует содержимое 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"
---
Поле Обязательно Description
name Да Максимум 64 символов. Только строчные буквы, цифры и дефисы. Не должно начинаться или заканчиваться дефисом или содержать последовательные дефисы. Должно соответствовать имени родительского каталога.
description Да Что делает навык и когда его использовать. Максимум 1024 символов. Следует включать ключевые слова, помогающие агентам определять соответствующие задачи.
license нет Имя лицензии или ссылка на пакетный файл лицензии.
compatibility нет Максимум 500 символов. Указывает требования к среде (предназначенный продукт, системные пакеты, сетевой доступ и т. д.).
metadata нет Произвольное сопоставление значений ключа для дополнительных метаданных.
allowed-tools нет Список предварительно утвержденных инструментов, разделённый пробелами, которые могут использоваться умением. Экспериментально — уровень поддержки может варьироваться в зависимости от реализации агента.

Текст markdown после вступительной части содержит инструкции по выполнению навыка: пошаговые указания, примеры входных и выходных данных, распространенные крайние случаи или любое другое содержимое, которое помогает агенту выполнять задачу. Держите SKILL.md в пределах 500 строк и перемещайте подробные справочные материалы в отдельные файлы.

Прогрессивное раскрытие информации

Навыки агента используют четырехэтапный прогрессивный шаблон раскрытия для минимизации использования контекста:

  1. Объявление (~100 токенов на навык) — имена и описания навыков внедряются в системный запрос в начале каждого запуска, поэтому агент знает, какие навыки доступны.
  2. Загрузка (< рекомендуется 5000 токенов) — когда задача соответствует сфере навыка, агент вызывает load_skill инструмент для получения полного текста SKILL.md с подробными инструкциями.
  3. Чтение ресурсов (по мере необходимости) — агент вызывает read_skill_resource средство для получения дополнительных файлов (ссылок, шаблонов, ресурсов) только при необходимости.
  4. Выполнение скриптов (по мере необходимости) — агент вызывает run_skill_script средство для выполнения скриптов в составе навыка.

Этот паттерн сохраняет окно контекста агента компактным, предоставляя ему доступ к обширным специальным знаниям по требованию.

Замечание

load_skill всегда рекламируется. read_skill_resource рекламируется только в том случае, если хотя бы у одного навыка есть ресурсы. run_skill_script объявляется только в том случае, если по крайней мере один навык имеет скрипты.

Предоставление навыков агенту

AgentSkillsProvider (C#) и SkillsProvider (Python) — это поставщики контекстов, которые делают навыки доступными для агентов. Они поддерживают три источника навыков:

  • На основе файлов — навыки, выявленные из SKILL.md файлов в директориях файловой системы
  • Code-defined — навыки, определенные в коде с помощью AgentInlineSkill (C#) или Skill (Python)
  • На основе классов — навыки, инкапсулированные в класс C#, производный только от AgentClassSkill<T> (только C#)

Для смешивания нескольких источников в одном поставщике используйте AgentSkillsProviderBuilder (только C# — см. построитель: расширенные сценарии с несколькими источниками).

Навыки, связанные с файлами

Создайте указатель AgentSkillsProvider на каталог, содержащий ваши навыки, и добавьте его в контекстные поставщики агента. Передайте средство выполнения скрипта, чтобы включить выполнение скриптов на основе файлов, найденных в каталогах навыков:

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

Предупреждение

DefaultAzureCredential удобно для разработки, но требует тщательного рассмотрения в рабочей среде. В рабочей среде рекомендуется использовать определенные учетные данные (например, ManagedIdentityCredential), чтобы избежать проблем с задержкой, непреднамеренной проверки данных аутентификации и потенциальных рисков безопасности из-за резервных механизмов.

Несколько каталогов навыков

Вы можете указать поставщику один родительский каталог — каждый подкаталог, содержащий SKILL.md, автоматически обнаруживается как навык.

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

Или передайте список путей для поиска нескольких корневых каталогов:

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

Поставщик выполняет поиск до глубины двух уровней.

Настройка обнаружения ресурсов

По умолчанию поставщик распознает ресурсы с расширениями.md, .json, .yaml, .yml, .csvи .xml.txt в referencesassets подкаталогах. Используйте AgentFileSkillsSourceOptions для изменения этих значений по умолчанию:

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

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

Выполнение сценария

Передайте SubprocessScriptRunner.RunAsync как второй аргумент в AgentSkillsProvider, чтобы включить выполнение скриптов на основе файлов.

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

SubprocessScriptRunner.RunAsync примерно эквивалентен следующему:

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

Раннер запускает каждый обнаруженный скрипт как локальный подпроцесс и пересылает аргументы JSON, которые агент предоставляет в виде флагов командной строки.

Предупреждение

SubprocessScriptRunner предоставляется только для демонстрационных целей. Для использования в рабочей среде рекомендуется добавить:

  • Сэндбоксинг (например, контейнеры или изолированные среды выполнения)
  • Ограничения ресурсов (процессор, память, тайм-аут по времени)
  • Проверка входных данных и перечисление исполняемых скриптов
  • Структурированные журналы и следы аудита

Настройка обнаружения скриптов

По умолчанию поставщик распознает скрипты с расширениями.py, , .js.sh, , .ps1и .cs.csx в подкаталогеscripts. Используйте AgentFileSkillsSourceOptions для изменения этих значений по умолчанию:

Передайте AgentFileSkillsSourceOptions конструктору или AgentSkillsProviderUseFileSkill / UseFileSkills в построителе:

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

Навыки, связанные с файлами

Создайте SkillsProvider, указывающий на каталог, содержащий ваши навыки, и добавьте его в контекстные провайдеры агента:

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

Несколько каталогов навыков

Вы можете указать поставщику одну родительскую папку — каждая вложенная папка, содержащая SKILL.md, автоматически обнаруживается как навык.

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

Или передайте список путей для поиска нескольких корневых каталогов:

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

Поставщик выполняет поиск до глубины двух уровней.

Настройка обнаружения ресурсов

По умолчанию SkillsProvider распознает ресурсы с расширениями.md, , .json.yaml, .yml.csvи .xml.txt. Он сканирует все вложенные каталоги в каждой папке навыка. Передайте resource_extensions , чтобы изменить распознанные типы файлов:

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

Выполнение сценария

Чтобы включить выполнение скриптов на основе файлов, передайте script_runner в SkillsProvider. Может быть использован любой синхронный или асинхронный вызываемый объект, удовлетворяющий протоколу 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,
)

Исполнитель получает разрешенные Skill, SkillScript, и необязательный args словарь. Скрипты на основе файлов автоматически обнаруживаются из .py файлов в каталогах навыков.

Предупреждение

Приведенный выше бегун предоставляется только для демонстрационных целей. Для использования в рабочей среде рекомендуется добавить:

  • Sandboxing (например, контейнеры, seccomp или firejail)
  • Ограничения ресурсов (процессор, память, тайм-аут по времени)
  • Проверка входных данных и перечисление исполняемых скриптов
  • Структурированные журналы и следы аудита

Замечание

Если навыки на основе файлов с скриптами предоставляются, но не script_runner заданы, SkillsProvider вызывает значение ValueError.

Определяемые кодом навыки

Помимо файловых навыков, полученных из SKILL.md файлов, можно определять навыки исключительно в коде с помощью AgentInlineSkill. Определяемые кодом навыки полезны при следующих случаях:

  • Содержимое навыка создается динамически (для примера, чтение из базы данных или окружающей среды).
  • Вы хотите сохранить определения навыков вместе с кодом приложения, который использует их.
  • Вам нужны ресурсы, выполняющие логику во время чтения, а не обслуживающие статические файлы.

Базовый навык кода

Создайте AgentInlineSkill с именем, описанием и инструкциями. Присоедините ресурсы с помощью .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);

Динамические ресурсы

Передайте делегат фабрики в .AddResource(), чтобы вычислить содержимое во время выполнения. Делегат вызывается каждый раз, когда агент считывает ресурс:

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

Скрипты, определяемые кодом

Используйте .AddScript(), чтобы зарегистрировать делегата в качестве исполняемого скрипта. Скрипты, определённые кодом, выполняются внутри процесса в качестве прямых вызовов делегатов. Инструмент исполнения скриптов не требуется. Типизированные параметры делегата автоматически преобразуются в схему JSON, которую агент использует для передачи аргументов:

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

Замечание

Чтобы объединить навыки, определённые кодом, с навыками на основе файлов или на основе классов в одном поставщике, используйте AgentSkillsProviderBuilder — см. дополнительные сценарии с несколькими источниками.

Помимо навыков, обнаруживаемых из файлов SKILL.md, вы можете полностью определить навыки в Python коде. Определяемые кодом навыки полезны при следующих случаях:

  • Содержимое навыка создается динамически (для примера, чтение из базы данных или окружающей среды).
  • Вы хотите сохранить определения навыков вместе с кодом приложения, который использует их.
  • Вам нужны ресурсы, выполняющие логику во время чтения, а не обслуживающие статические файлы.

Базовый навык кода

Skill Создайте экземпляр с именем, описанием и содержимым инструкций. При необходимости присоединяйте экземпляры SkillResource со статическим контентом:

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

Динамические ресурсы

Используйте декоратор @skill.resource для регистрации функции в качестве ресурса. Функция вызывается каждый раз, когда агент считывает ресурс, поэтому она может возвращать актуальные данные. Поддерживаются обе функции синхронизации и асинхронной синхронизации:

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

Если декоратор используется без аргументов (@skill.resource), имя функции становится именем ресурса, а докстринг становится описанием. Используйте @skill.resource(name="...", description="..."), чтобы задать их явно.

Скрипты, определяемые кодом

Используйте декоратор @skill.script, чтобы зарегистрировать функцию в качестве исполняемого скрипта в навыке. Кодовые скрипты выполняются в процессе и не требуют исполнителя скрипта. Поддерживаются обе функции синхронизации и асинхронной синхронизации:

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

Если декоратор используется без аргументов (@skill.script), имя функции становится именем скрипта, а docstring превращается в описание. Типизированные параметры функции автоматически преобразуются в схему JSON, которую агент использует для передачи аргументов.

Объединение навыков на основе файлов и определенных кодом навыков

Передайте оба skill_paths и skills в один SkillsProvider. Сначала обнаруживаются навыки на основе файлов; Если определяемый кодом навык имеет то же имя, что и существующий навык на основе файлов, то кодовый навык пропускается:

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

Навыки на базе классов

Навыки на основе классов позволяют объединить все компоненты навыка — имя, описание, инструкции, ресурсы и скрипты — в один класс C#. Наследуйте от AgentClassSkill<T> (где T является вашим классом), затем аннотируйте свойства с [AgentSkillResource] и методы с [AgentSkillScript] для автоматического обнаружения.

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

Регистрация навыка на основе класса с помощью AgentSkillsProvider:

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

[AgentSkillResource] Если атрибут применяется к свойству или методу, его возвращаемое значение используется в качестве содержимого ресурса, когда агент считывает ресурс, используйте метод, когда содержимое необходимо вычислить во время чтения. При применении [AgentSkillScript] к методу, метод будет вызван, когда агент вызывает скрипт. Используйте [Description] из System.ComponentModel для описания каждого ресурса и скрипта для агента.

Замечание

AgentClassSkill<T> также поддерживает переопределение Resources и Scripts в качестве коллекций для случаев, когда обнаружение на основе атрибутов не подходит.

Конструктор: расширенные сценарии с несколькими источниками

Для простых сценариев с одним исходным кодом используйте AgentSkillsProvider конструкторы напрямую. Используйте AgentSkillsProviderBuilder, если вам потребуется следующее:

  • Смешанные типы навыков — объединение навыков на основе файлов, определяемых кодом (AgentInlineSkill) и навыков на основеAgentClassSkill классов в одном поставщике.
  • Фильтрация навыков — включение или исключение навыков с помощью предиката.

Смешанные типы навыков

Объедините все три типа навыков в одном поставщике, используя UseFileSkill, UseSkill и 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();

Фильтрация навыков

Используйте UseFilter , чтобы включить только навыки, соответствующие вашим критериям, например для загрузки навыков из общего каталога, но исключить экспериментальные:

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

Утверждение скрипта

Используйте AgentSkillsProviderOptions.ScriptApproval, чтобы ограничить выполнение всех скриптов до получения одобрения человека. Если этот параметр включен, агент приостанавливается и отправляет запрос на утверждение вместо немедленного выполнения.

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

Чтобы включить утверждение скрипта на поставщике, сконфигурированном построителем, используйте UseScriptApproval:

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

Используйте require_script_approval=True на SkillsProvider для ограничения всех выполнения скриптов человеком. Вместо немедленного выполнения агент приостанавливает и возвращает запросы на утверждение:

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)

Если скрипт отклоняется (approved=False), агент уведомляется о том, что пользователь отказался и может отвечать соответствующим образом.

Пользовательская системная подсказка

По умолчанию поставщик навыков внедряет системный запрос, который перечисляет доступные навыки и указывает агенту использовать load_skill и read_skill_resource. Этот запрос можно настроить:

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

Замечание

Настраиваемый шаблон должен содержать {skills} (местоимения списка навыков), {resource_instructions} (подсказка инструментов ресурсов) и {script_instructions} (подсказка инструментов сценариев). Литеральные фигурные скобки должны быть экранированы как {{ и }}.

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

Замечание

Пользовательский шаблон должен содержать {skills} заполнитель, в который вставляется список навыков, и {runner_instructions} заполнитель, в котором вставляются инструкции, связанные с скриптом.

Поведение кэширования

По умолчанию инструменты навыков и инструкции сохраняются в кэше после первой сборки. Установите DisableCaching = true на AgentSkillsProviderOptions, чтобы принудительно перестраивать с каждым вызовом:

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

Замечание

Отключение кэширования полезно во время разработки при частом изменении контента навыка. В рабочей среде оставьте кэширование включено (по умолчанию) для повышения производительности.

Внедрение зависимостей

Делегаты ресурсов и скриптов навыка могут объявлять IServiceProvider параметр, который Agent Framework автоматически внедряет. Это позволяет навыкам разрешать службы приложений, такие как клиенты базы данных, конфигурация или бизнес-логика, без жесткого написания их в определении навыка.

Setup

Зарегистрируйте службы приложений и передайте созданный IServiceProvider агенту через параметр 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);

Определяемые кодом навыки с помощью DI

Объявите IServiceProvider в качестве параметра в AddResource или AddScript делегатах — фреймворк разрешает и внедряет его автоматически, когда агент считывает ресурс или запускает скрипт:

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

Навыки на основе классов с помощью DI

Аннотируйте методы с помощью [AgentSkillResource] или [AgentSkillScript], и объявите параметр IServiceProvider — платформа обнаруживает эти элементы с помощью рефлексии и автоматически внедряет поставщика услуг.

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

Подсказка

Навыки на основе классов также могут устранять зависимости с помощью конструктора. Зарегистрируйте класс навыка в ServiceCollection контейнере и устраните его из контейнера, а не вызывая new напрямую:

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

Это полезно, если сам класс навыка нуждается в внедренных службах, которые выходят за пределы тех, которые используют делегаты ресурсов и скриптов.

Функции ресурсов и скриптов, принимающие **kwargs, автоматически получают переданные agent.run() аргументы ключевых слов среды выполнения. Это позволяет функциям навыка получать доступ к контексту приложения: например, к конфигурации, удостоверению пользователя или клиентам службы без жесткого кодирования в определении навыка.

Передача аргументов среды выполнения

function_invocation_kwargs Передайте agent.run() для предоставления ключевых аргументов, которые фреймворк перенаправит в функции ресурсов и скриптов:

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

Функции ресурсов с kwargs

Когда функция ресурса объявляет **kwargs, платформа пересылает аргументы ключевых слов среды выполнения каждый раз, когда агент считывает ресурс:

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

Функции объектов без **kwargs вызываются без аргументов и не получают контекст выполнения.

Функции скрипта с kwargs

Когда функция скрипта **kwargsобъявляет, платформа перенаправит аргументы ключевых слов среды выполнения вместе с args предоставленным агентом:

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

Агент предоставляет value и factor через вызов инструмента args; приложение предоставляет precision через function_invocation_kwargs. Функции скрипта без **kwargs получают только аргументы, предоставленные агентом.

Рекомендации по обеспечению безопасности

Навыки агента должны рассматриваться как любой сторонний код, который вы вносите в проект. Поскольку инструкции по навыку внедряются в контекст агента — и навыки могут включать скрипты— применение того же уровня проверки и управления, что и зависимость с открытым кодом, является важной.

  • Просмотрите перед использованием всё содержимое навыка (скрипты, SKILL.md и ресурсы) перед развертыванием. Убедитесь, что фактическое поведение скрипта соответствует указанному намерению. Проверьте враждебные инструкции, которые пытаются обойти рекомендации по безопасности, эксфильтровать данные или изменить файлы конфигурации агента.
  • Доверие к источнику — установка навыков только доверенных авторов или проверенных внутренних участников. Предпочитайте навыки с четким происхождением, управлением версиями и активным обслуживанием. Следите за именами навыков typeosquatted, которые имитируют популярные пакеты.
  • Песочница — выполнение навыков, включающих исполняемые скрипты в изолированных средах. Ограничить доступ к файловой системе, сети и системе только тому, что требуется навыку. Перед выполнением потенциально конфиденциальных операций требуется явное подтверждение пользователя.
  • Аудит и ведение журнала — запись, какие навыки загружаются, какие ресурсы считываются и какие скрипты выполняются. Это дает путь аудита для трассировки поведения агента обратно к определенному содержимому навыка, если что-то пойдет не так.

Когда использовать навыки и рабочие процессы

Навыки агента и рабочие процессы платформы агента расширяют возможности агентов, но они работают по-разному. Выберите подход, который лучше всего соответствует вашим требованиям:

  • Управление — с помощью навыка ИИ решает, как выполнить инструкции. Это идеально, если вы хотите, чтобы агент был творческим или адаптивным. При использовании рабочего процесса вы явно определяете путь выполнения. Используйте рабочие процессы, если требуется детерминированное, прогнозируемое поведение.
  • Стойкость — навык выполняется в пределах одного хода агента. Если что-то завершается сбоем, необходимо повторить всю операцию. Рабочие процессы поддерживают контрольные точки, чтобы они могли возобновить работу с последнего успешного шага после сбоя. Выберите рабочие процессы, когда стоимость повторного выполнения всего процесса высока.
  • Побочные эффекты — навыки подходят, когда операции являются идемпотентными или низкорисковыми. Предпочитайте рабочие процессы, когда шаги создают побочные эффекты (отправка сообщений электронной почты, плата за платежи), которые не должны повторяться при повторных попытках.
  • Сложность — Навыки лучше всего подходят для сконцентрированных задач в одном домене, которые может выполнять один агент. Рабочие процессы лучше подходят для многоэтапных бизнес-процессов, координирующих нескольких агентов, формирование человеческих утверждений и интеграцию с внешними системами.

Подсказка

Как правило, если вы хотите, чтобы ИИ определил, как выполнить задачу, используйте навыки. Если вам нужно гарантировать выполнение шагов и в каком порядке, используйте рабочий процесс.

Дальнейшие шаги