Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Навыки агента — это переносимые пакеты инструкций, скриптов и ресурсов, которые предоставляют агентам специализированные возможности и опыт работы с доменом. Навыки соответствуют открытой спецификации и реализуют прогрессивный шаблон раскрытия, чтобы агенты загружали только нужный контекст, когда им нужен.
Используйте навыки агента, если требуется:
- Упакуйте отраслевую экспертизу — представьте специализированные знания (правила учета расходов, юридические процессы, конвейеры анализа данных) в виде многократно используемых переносимых пакетов.
- Расширение возможностей агента— предоставление агентам новых возможностей без изменения основных инструкций.
- Обеспечьте согласованность — превратите многоэтапные задачи в повторяемые рабочие процессы, поддающиеся аудиту.
- Обеспечьте совместимость — Используйте один и тот же навык повторно в разных продуктах, поддерживающих 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 после frontmatter содержит инструкции по навыку— пошаговые инструкции, примеры входных и выходных данных, распространенные пограничные варианты или любое содержимое, которое помогает агенту выполнять задачу. Держите SKILL.md в пределах 500 строк и перемещайте подробные справочные материалы в отдельные файлы.
Прогрессивное раскрытие информации
Навыки агента используют четырехэтапный прогрессивный шаблон раскрытия для минимизации использования контекста:
- Объявление (~100 токенов на навык) — имена и описания навыков внедряются в системный запрос в начале каждого запуска, поэтому агент знает, какие навыки доступны.
-
Загрузка (< рекомендуется 5000 маркеров) — когда задача соответствует домену навыка, агент вызывает
load_skillсредство для получения полного SKILL.md текста с подробными инструкциями. -
Чтение ресурсов (по мере необходимости) — агент вызывает
read_skill_resourceсредство для получения дополнительных файлов (ссылок, шаблонов, ресурсов) только при необходимости. -
Запуск скриптов (при необходимости) — агент вызывает средство
run_skill_scriptдля выполнения скриптов, входящих в состав навыка.
Этот паттерн сохраняет окно контекста агента компактным, предоставляя ему доступ к обширным специальным знаниям по требованию.
Замечание
load_skill всегда рекламируется.
read_skill_resource рекламируется только в том случае, если хотя бы у одного навыка есть ресурсы.
run_skill_script объявляется только в том случае, если по крайней мере один навык имеет скрипты.
Предоставление навыков агенту
Работа с навыками включает три стандартных блока:
-
Поставщик -
AgentSkillsProvider(C#) илиSkillsProvider(Python) — это поставщик контекста, предоставляющий агенту навыки. Он объявляет доступные навыки в системном запросе и регистрирует средства, которые агент использует для загрузки навыков, чтения ресурсов и запуска скриптов. -
Источники — источник предоставляет навыки поставщику. Навыки могут поступать из нескольких исходных типов:
-
На основе файлов — навыки, обнаруженные в
SKILL.mdфайлах в каталогах файловой системы. -
Определяемые кодом навыки — навыки, определенные в коде с помощью
AgentInlineSkillC#илиInlineSkill(Python). -
На основе классов — навыки, инкапсулированные в класс, производный от
AgentClassSkill<T>(C#) илиClassSkill(Python). -
На основе MCP - навыки, обнаруженные с серверов MCP (Model Context Protocol) через
UseMcpSkills(C#) илиMCPSkillsSource(Python).
-
На основе файлов — навыки, обнаруженные в
-
Построитель -
AgentSkillsProviderBuilder(C#) объединяет несколько источников в один поставщик, применяя агрегирование, дедупликацию, кэширование и необязательную фильтрацию. В Python создайте исходные классы, такие какAggregatingSkillsSource,FilteringSkillsSourceиDeduplicatingSkillsSourceнапрямую.
В следующих разделах показано, как создать навыки каждого исходного типа, а затем объединить источники и создать поставщика из них.
Навыки, связанные с файлами
Создайте указатель 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 скриптами с расширениями.py, .js, .sh, .ps1, .csи ..csx Он выполняет поиск до двух уровней в каждом каталоге навыков. Используйте AgentFileSkillsSourceOptions для изменения этих значений по умолчанию:
var fileOptions = new AgentFileSkillsSourceOptions
{
AllowedResourceExtensions = [".md", ".txt"],
AllowedScriptExtensions = [".py"],
SearchDepth = 3, // Search up to 3 levels deep (default is 2)
ResourceFilter = context => context.RelativeFilePath.StartsWith("references/"),
ScriptFilter = context => context.RelativeFilePath.StartsWith("scripts/")
|| context.RelativeFilePath.StartsWith("tools/"),
};
// Via constructor
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
fileOptions: fileOptions);
// Via builder
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"), options: fileOptions)
.Build();
ResourceFilter и ScriptFilter получает имя навыка и относительный AgentFileSkillFilterContext путь файла, позволяя ограничить файлы по расположению, соглашению об именовании или любой пользовательской логике.
Выполнение сценария
Передайте SubprocessScriptRunner.RunAsync в качестве средства выполнения скрипта, чтобы включить выполнение скриптов на основе файлов:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync);
SubprocessScriptRunner.RunAsync примерно эквивалентен следующему:
// Simplified equivalent of what SubprocessScriptRunner.RunAsync does internally
using System.Diagnostics;
using System.Text.Json;
static async Task<object?> RunAsync(
AgentFileSkill skill,
AgentFileSkillScript script,
JsonElement? args,
IServiceProvider? serviceProvider,
CancellationToken cancellationToken)
{
var psi = new ProcessStartInfo("python3")
{
RedirectStandardOutput = true,
UseShellExecute = false,
};
psi.ArgumentList.Add(script.FullPath);
if (args is { ValueKind: JsonValueKind.Array } json)
{
foreach (var element in json.EnumerateArray())
{
psi.ArgumentList.Add(element.GetString()!);
}
}
using var process = Process.Start(psi)!;
string output = await process.StandardOutput.ReadToEndAsync(cancellationToken);
await process.WaitForExitAsync(cancellationToken);
return output.Trim();
}
Выполняющая среда запускает каждый обнаруженный скрипт как локальный подпроцесс. Скрипты на основе файлов ожидают аргументы в виде массива строк JSON— каждый элемент массива становится позициальным аргументом командной строки.
Предупреждение
SubprocessScriptRunner предоставляется только для демонстрационных целей. Для использования в рабочей среде рекомендуется добавить:
- Сэндбоксинг (например, контейнеры или изолированные среды выполнения)
- Ограничения ресурсов (процессор, память, тайм-аут по времени)
- Проверка входных данных и перечисление исполняемых скриптов
- Структурированные журналы и следы аудита
Навыки, связанные с файлами
Используйте фабрику SkillsProvider.from_paths(), чтобы обнаружить навыки в каталогах, содержащих файлы SKILL.md, и добавьте этого поставщика в список поставщиков контекста агента:
import os
from pathlib import Path
# 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],
)
Несколько каталогов навыков
Вы можете указать поставщику путь к одному родительскому каталогу — каждый подкаталог, содержащий SKILL.md, автоматически распознаётся как навык:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "all-skills"
)
Или передайте список путей для поиска нескольких корневых каталогов:
skills_provider = SkillsProvider.from_paths(
skill_paths=[
Path(__file__).parent / "company-skills",
Path(__file__).parent / "team-skills",
]
)
Поставщик выполняет поиск до глубины двух уровней.
Настройка обнаружения ресурсов и скриптов
По умолчанию ресурсы обнаруживаются в подкаталогах references/ и assets/, а скрипты — в scripts/, в соответствии со спецификацией agentskills.io. Распознаваемыми расширениями ресурсов являются .md, .json, .yaml, .yml, .csv, .xml и .txt. Он выполняет поиск до двух уровней в каждом каталоге навыков. Используйте resource_extensions, , script_extensionssearch_depthresource_filterи script_filter для настройки обнаружения:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
resource_extensions=(".md", ".txt"),
script_extensions=(".py", ".sh"),
search_depth=3, # Search up to 3 levels deep (default is 2)
resource_filter=lambda skill_name, path: path.startswith("references/"),
script_filter=lambda skill_name, path: path.startswith("scripts/"),
)
resource_filter И script_filter предикаты получают имя навыка и относительный путь файла, позволяя ограничить файлы по расположению, соглашению об именовании или любой пользовательской логике. Используйте "." для включения файлов на корневом уровне навыка в дополнение к подкаталогам.
Выполнение сценария
Чтобы включить выполнение скриптов на основе файлов, передайте script_runner в SkillsProvider.from_paths(). Может быть использован любой синхронный или асинхронный вызываемый объект, удовлетворяющий протоколу 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,
)
Исполнитель получает обработанные аргументы FileSkill, FileSkillScript и необязательный аргумент args. Скрипты на основе файлов ожидают аргументы в виде массива строк JSON— каждый элемент массива становится позициальным аргументом командной строки. Скрипты автоматически обнаруживаются в файлах .py в подкаталоге scripts/ каждого каталога навыка.
Предупреждение
Приведенный выше бегун предоставляется только для демонстрационных целей. Для использования в рабочей среде рекомендуется добавить:
- Sandboxing (например, контейнеры,
seccompилиfirejail) - Ограничения ресурсов (процессор, память, тайм-аут по времени)
- Проверка входных данных и перечисление исполняемых скриптов
- Структурированные журналы и следы аудита
Замечание
Если предоставляются навыки на основе файлов со скриптами, но значение script_runner не задано, SkillsProvider выдает ошибку при попытке выполнить скрипт.
Навыки, связанные с файлами
Агенты Go поддерживают навыки с помощью пакета agent/skills. Навыки соответствуют тому же прогрессивному шаблону раскрытия: объявление —> загрузка —> чтение ресурсов —> запуск скриптов.
Обнаружение навыков из SKILL.md файлов на диске и регистрация поставщика навыков в качестве поставщика контекста агента:
import (
"os"
"github.com/microsoft/agent-framework-go/agent"
"github.com/microsoft/agent-framework-go/provider/foundryprovider"
"github.com/microsoft/agent-framework-go/agent/skills"
"github.com/microsoft/agent-framework-go/agent/skills/fsskills"
)
skillsRoot, _ := os.OpenRoot("skills")
defer skillsRoot.Close()
skillsProvider := skills.NewContextProvider(skills.ContextProviderOptions{
Sources: []skills.Source{
fsskills.NewSourceOptions(fsskills.SourceOptions{}, skillsRoot.FS()),
},
})
a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
Instructions: "You are a helpful assistant.",
Config: agent.Config{
ContextProviders: []agent.ContextProvider{skillsProvider},
},
})
Определяемые кодом навыки
Помимо файловых навыков, полученных из SKILL.md файлов, можно определять навыки исключительно в коде с помощью AgentInlineSkill. Определяемые кодом навыки полезны при следующих случаях:
- Содержимое навыка создается динамически (для примера, чтение из базы данных или окружающей среды).
- Вы хотите сохранить определения навыков вместе с кодом приложения, который использует их.
- Вам нужны ресурсы, выполняющие логику во время чтения, а не обслуживающие статические файлы.
- Определения навыков необходимо создавать во время выполнения из данных , например создание персонализированного навыка для каждого сеанса пользователя на основе их роли или разрешений.
- Навык должен замыкать состояние места вызова (локальные переменные, замыкания), а не получать сервисы из DI-контейнера.
Базовый навык кода
Создайте 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 с помощью InlineSkill. Определяемые кодом навыки полезны при следующих случаях:
- Содержимое навыка создается динамически (для примера, чтение из базы данных или окружающей среды).
- Вы хотите сохранить определения навыков вместе с кодом приложения, который использует их.
- Вам нужны ресурсы, выполняющие логику во время чтения, а не обслуживающие статические файлы.
- Определения навыков необходимо создавать во время выполнения из данных , например создание персонализированного навыка для каждого сеанса пользователя на основе их роли или разрешений.
- Навык должен закрыть состояние сайта вызова (локальные переменные, закрытия), а не разрешать службы через
**kwargs.
Базовый навык кода
Создайте экземпляр InlineSkill с объектом SkillFrontmatter (содержащим имя и описание) и содержимым инструкций. При необходимости присоединяйте экземпляры InlineSkillResource со статическим контентом:
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)
Динамические ресурсы
Используйте декоратор @skill.resource для регистрации функции в качестве ресурса. Функция вызывается каждый раз, когда агент считывает ресурс, поэтому она может возвращать актуальные данные. Поддерживаются обе функции синхронизации и асинхронной синхронизации:
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)"
Если декоратор используется без аргументов (@skill.resource), имя функции становится именем ресурса, а докстринг становится описанием. Используйте @skill.resource(name="...", description="..."), чтобы задать их явно.
Скрипты, определяемые кодом
Используйте декоратор @skill.script, чтобы зарегистрировать функцию в качестве исполняемого скрипта в навыке. Скрипты, определяемые в коде, выполняются в том же процессе и не требуют отдельного исполнителя скриптов. Поддерживаются обе функции синхронизации и асинхронной синхронизации:
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})
Если декоратор используется без аргументов (@skill.script), имя функции становится именем скрипта, а docstring превращается в описание. Типизированные параметры функции автоматически преобразуются в схему JSON, которую агент использует для передачи аргументов.
Помимо навыков, основанных на файлах и обнаруженных в файлах SKILL.md, можно определять навыки целиком в коде Go:
skill := &skills.Skill{
Frontmatter: skills.Frontmatter{
Name: "unit-converter",
Description: "Convert between common units using a multiplication factor.",
},
GetContent: func(context.Context) (string, error) {
return "Use this skill when the user asks to convert between units.", nil
},
Resources: []skills.Resource{
{
Name: "conversion-table",
Description: "Lookup table of multiplication factors.",
Read: func(context.Context) (any, error) {
return conversionTable, nil
},
},
},
Scripts: []skills.Script{
{
Name: "convert",
Description: "Multiplies a value by a conversion factor. Pass value and factor as positional string arguments: [\"<value>\", \"<factor>\"].",
Run: func(_ context.Context, _ *skills.Skill, args []string) (any, error) {
if len(args) != 2 {
return nil, fmt.Errorf("expected value and factor")
}
value, err := strconv.ParseFloat(args[0], 64)
if err != nil {
return nil, err
}
factor, err := strconv.ParseFloat(args[1], 64)
if err != nil {
return nil, err
}
return map[string]any{
"value": value,
"factor": factor,
"result": value * factor,
}, nil
},
},
},
}
provider := skills.NewContextProvider(skills.ContextProviderOptions{
Skills: []*skills.Skill{skill},
})
GetContent загружает инструкции навыка только когда агент вызывает load_skill. Скрипты получают позиционные строковые аргументы в стиле CLI, например ["26.2", "1.60934"], и могут разбирать эти аргументы так, как требуется скрипту.
Подсказка
См. примеры навыков, чтобы ознакомиться с полными рабочими примерами.
Навыки на базе классов
Навыки на основе классов позволяют объединить все компоненты навыка — имя, описание, инструкции, ресурсы и скрипты — в один класс C#. Это позволяет легко упаковывать и распространять их как пакеты NuGet — команды могут независимо создавать и публиковать навыки, а пользователи добавляют их с помощью dotnet add package и одного вызова .UseSkill(). Наследуйте от 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 в качестве коллекций для случаев, когда обнаружение на основе атрибутов не подходит.
Навыки на базе классов
Навыки на основе классов позволяют объединить все компоненты навыка — имя, описание, инструкции, ресурсы и скрипты — в один класс Python. Это позволяет легко упаковывать и распространять их в виде пакетов PyPI. Команды могут независимо создавать и публиковать навыки, а пользователи — добавлять их с помощью pip install и одного вызова SkillsProvider(). Создайте подкласс ClassSkill, затем используйте декораторы @ClassSkill.resource и @ClassSkill.script для автоматического обнаружения:
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})
Регистрация навыка на основе класса с помощью SkillsProvider:
from agent_framework import SkillsProvider
skill = UnitConverterSkill()
skills_provider = SkillsProvider(skill)
Если @ClassSkill.resource используется как декоратор без аргументов, имя метода становится именем ресурса (где символы подчёркивания заменяются дефисами), а строка документации становится его описанием. Используйте @ClassSkill.resource(name="...", description="..."), чтобы задать их явно. Тот же шаблон применяется к @ClassSkill.script.
Ресурсы могут быть определены либо как обычные методы, либо как @property дескрипторы. При использовании @propertyпоместите @property первое и @ClassSkill.resource второе. Возвращаемые значения ресурсов кешируются после первого обращения.
Замечание
ClassSkill также поддерживает явное переопределение свойств resources и scripts, чтобы они напрямую возвращали экземпляры InlineSkillResource и InlineSkillScript, в случаях, когда обнаружение на основе декораторов не подходит.
Навыки на базе MCP
Замечание
Для навыков на основе MCP требуется пакет Microsoft.Agents.AI.Mcp NuGet. API навыков MCP является экспериментальным и может измениться в будущих выпусках.
Навыки можно обнаружить на серверах MCP (Model Context Protocol), которые предоставляют ресурсы навыков по схеме URI skill://. Сервер MCP публикует сведения о навыках через документ обнаружения skill://index.json, а фреймворк запрашивает содержимое навыка по требованию.
Навыки на основе MCP поддерживают два типа записи индекса:
-
skill-md— Ресурсы навыкаSKILL.mdи связанные с ним ресурсы загружаются по запросу с сервера MCP. -
archive— Навык распространяется как один упакованный архив (ZIP, TAR или gzip-сжатый TAR), скачанный и распакованный локально.
Основное использование
Используйте метод расширения UseMcpSkills для AgentSkillsProviderBuilder, чтобы добавить источник навыков MCP:
using Microsoft.Agents.AI;
using ModelContextProtocol.Client;
// Connect to the MCP server
await using McpClient client = await McpClient.CreateAsync(
new StdioClientTransport(new()
{
Name = "skills-server",
Command = "dotnet",
Arguments = [skillsServerPath, "--server"],
}));
// Build a skills provider that discovers skills over MCP
var skillsProvider = new AgentSkillsProviderBuilder()
.UseMcpSkills(client)
.Build();
// Create an agent with the MCP skills
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant. Use available skills to answer the user.",
},
AIContextProviders = [skillsProvider],
},
model: deploymentName);
Навыки архивного типа
Для навыков архивного типа используйте AgentMcpSkillsSourceOptions (из Microsoft.Agents.AI.Mcp пакета) для настройки поведения извлечения:
var skillsProvider = new AgentSkillsProviderBuilder()
.UseMcpSkills(client, new AgentMcpSkillsSourceOptions
{
ArchiveSkillsDirectory = Path.Combine(AppContext.BaseDirectory, "extracted-skills"),
ArchiveMaxFileCount = 50,
ArchiveMaxSizeBytes = 2 * 1024 * 1024, // 2 MB
})
.Build();
AgentMcpSkillsSourceOptions предоставляет следующие свойства для управления извлечением архива:
-
ArchiveSkillsDirectory— базовый каталог для извлеченных архивов. По умолчанию используется уникальный подкаталог в текущем рабочем каталоге, создаваемый для каждого экземпляра источника, чтобы предотвратить конфликты между несколькими источниками. -
ArchiveResourceExtensions— Разрешенные расширения для ресурсов в распакованных архивах. По умолчанию используется.md,.json,.yaml.yml.csv.xml.txt. -
ArchiveResourceSearchDepth— Как глубоко искать ресурсы в каждом извлеченном каталоге навыков. По умолчанию —2. -
ArchiveMaxFileCount— максимальное количество файлов на архив. Архивы, превышающие это ограничение, пропускаются. По умолчанию —20. -
ArchiveMaxSizeBytes— Максимальный размер загрузки для каждого архива. По умолчанию —1 MB. -
ArchiveMaxUncompressedSizeBytes— максимальный общий несжатый размер для каждого архива. По умолчанию —1 MB.
Important
Скрипты, упакованные в навыки архивного типа , никогда не выполняются. Это преднамеренная мера безопасности— исполняемое содержимое с удаленных серверов MCP требует явного доверия.
Навыки на базе MCP
Замечание
Навыки на основе MCP являются экспериментальными и могут измениться в будущих выпусках. Использование MCPSkillsSource генерирует FutureWarning при включенном флаге функции MCP_SKILLS.
Навыки можно обнаружить на серверах MCP (Model Context Protocol), которые предоставляют ресурсы навыков по схеме URI skill://. Сервер MCP публикует сведения о навыках через документ обнаружения skill://index.json, а фреймворк по запросу получает содержимое SKILL.md каждого навыка через resources/read.
Оберните MCP ClientSession в MCPSkillsSource и передайте его в SkillsProvider:
import os
from agent_framework import Agent, MCPSkillsSource, SkillsProvider, ToolApprovalMiddleware
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamable_http_client
mcp_url = os.environ["MCP_SKILLS_SERVER_URL"]
# Connect to the MCP server over streamable HTTP
async with streamable_http_client(url=mcp_url) as (read, write, _), ClientSession(read, write) as session:
await session.initialize()
# MCPSkillsSource reads skill://index.json and creates one skill per
# skill-md entry; SKILL.md bodies are fetched on demand.
skills_provider = SkillsProvider(MCPSkillsSource(client=session))
client = FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ.get("FOUNDRY_MODEL", "gpt-4o-mini"),
credential=AzureCliCredential(),
)
async with Agent(
client=client,
instructions="You are a helpful assistant. Use available skills to answer the user.",
context_providers=[skills_provider],
middleware=[ToolApprovalMiddleware(auto_approval_rules=[SkillsProvider.all_tools_auto_approval_rule])],
) as agent:
response = await agent.run("...")
Замечание
Python MCPSkillsSource поддерживает только элементы индекса skill-md (элементы индекса любого другого типа пропускаются без уведомления). В отличие от реализации .NET, он не поддерживает навыки архивного типа. Если skill://index.json отсутствует, нечитаемая, пустая или не выполняет синтаксический анализ, источник возвращает пустой список.
Important
Внешний сервер MCP контролирует, какой контент навыка, включая инструкции и сценарии, которые агент может выполнять, попадает к агенту. Подключайтесь только MCPSkillsSource к серверам, которые вы проверили и которым доверяете, и рассматривайте их ответы как недоверенные входные данные.
Источники навыков
AgentSkillsProvider извлекает навыки из одного или нескольких источников — объектов, реализующих AgentSkillsSource. Источники делятся на две категории: листовые источники, которые обнаруживают или содержат навыки (например, AgentFileSkillsSource для навыков на основе файлов), и декораторы, которые преобразуют результаты работы другого источника (агрегирование, дедупликация, кэширование и фильтрация). Вы также можете создать настраиваемый источник.
Каждый источник реализует один метод — GetSkillsAsync(AgentSkillsSourceContext context, CancellationToken cancellationToken = default).
AgentSkillsSourceContext содержит сведения о текущем запросе:
-
Agent— экземплярAIAgent, запрашивающий навыки. -
Session—AgentSession, связанный с вызовом, илиnull, если сеанс отсутствует.
Этот контекст доступен во всем исходном конвейере, поэтому FilteringAgentSkillsSource предикат или пользовательский источник может основывать свою логику на нем, например, возвращая другой набор навыков в зависимости от запрашивающего агента.
Листовые источники
AgentFileSkillsSource
Обнаруживает навыки в файлах SKILL.md на диске. Принимает один или несколько путей к каталогам, необязательный модуль запуска скриптов и необязательный AgentFileSkillsSourceOptions (описанный в разделе Навыки на основе файлов).
var source = new AgentFileSkillsSource(
[Path.Combine(AppContext.BaseDirectory, "skills")],
scriptRunner: SubprocessScriptRunner.RunAsync,
options: new AgentFileSkillsSourceOptions { SearchDepth = 3 });
AgentInMemorySkillsSource
Оборачивает экземпляры AgentSkill (определённые в коде или на основе класса) в памяти.
var source = new AgentInMemorySkillsSource([volumeConverterSkill, temperatureConverter]);
Комбинаторы
AggregatingAgentSkillsSource
Объединяет несколько источников в один. Навыки возвращаются в порядке регистрации без дедупликации или фильтрации.
var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);
Декораторы
Декораторы оборачивают внутренний источник и преобразуют его результат. Их можно связать для создания конвейера.
DeduplicatingAgentSkillsSource
Удаляет повторяющиеся имена навыков (без учета регистра, первое вхождение выигрывает). Дубликаты регистрируются на уровне предупреждения.
var deduplicated = new DeduplicatingAgentSkillsSource(innerSource);
CachingAgentSkillsSource
Кэширует список навыков, возвращаемый внутренним источником. Одновременные обращения сериализуются по ключу кэша, поэтому в каждый момент времени выполняется только один запрос на получение данных. Принимает необязательный параметр CachingAgentSkillsSourceOptions:
-
RefreshInterval(TimeSpan?) — если задано, срок действия кэшированных результатов истекает после этого интервала, а внутренний источник вызывается повторно. Когдаnull(по умолчанию) кэшированные результаты никогда не истекают. -
CacheIsolationKeySelector(Func<AgentSkillsSourceContext, string?>?) — возвращает ключ кэша для изоляции кэшированных результатов по контексту (например, для каждого клиента). Когдаnullвсе вызывающие серверы совместно используют один контейнер кэша.
var cached = new CachingAgentSkillsSource(innerSource, new CachingAgentSkillsSourceOptions
{
RefreshInterval = TimeSpan.FromMinutes(5)
});
FilteringAgentSkillsSource
Применяет предикат для включения или исключения навыков. Предикат получает навык и .AgentSkillsSourceContext
var filtered = new FilteringAgentSkillsSource(
innerSource,
(skill, context) => skill.Frontmatter.Name != "experimental-skill");
Пользовательские источники
Если встроенные источники не охватывают свой сценарий, реализуйте собственные. Подкласс AgentSkillsSource для конечного источника (который создает навыки из нового источника, например базы данных или удаленной службы), или подкласс DelegatingAgentSkillsSource для декоратора, который преобразует выходные данные другого источника.
Листовой источник
Производный от AgentSkillsSource и реализуемого GetSkillsAsync. Аргумент AgentSkillsSourceContext позволяет источнику адаптировать результат к текущему запросу, например возвращая другой набор навыков в зависимости от агента запроса. Переопределите Dispose(bool) , если источник владеет ресурсами, такими как клиент или подключение.
public sealed class TenantSkillsSource : AgentSkillsSource
{
private readonly ISkillStore _store;
public TenantSkillsSource(ISkillStore store)
{
_store = store;
}
public override async Task<IList<AgentSkill>> GetSkillsAsync(
AgentSkillsSourceContext context,
CancellationToken cancellationToken = default)
{
// Use the requesting agent to decide which skills to load.
var tenantId = context.Agent.Name ?? "default";
return await _store.GetSkillsForTenantAsync(tenantId, cancellationToken);
}
}
Пользовательский декоратор
Унаследуйтесь от DelegatingAgentSkillsSource, вызовите InnerSource.GetSkillsAsync и преобразуйте результат или наблюдайте за ним. Это тот же шаблон, который используют встроенные декораторы кэширования, дедупликации и фильтрации. Например, декоратор, который записывает количество навыков, возвращенных для каждого запроса, не изменяя результат:
public sealed class MetricsAgentSkillsSource : DelegatingAgentSkillsSource
{
private readonly ILogger<MetricsAgentSkillsSource> _logger;
public MetricsAgentSkillsSource(
AgentSkillsSource innerSource,
ILogger<MetricsAgentSkillsSource> logger)
: base(innerSource)
{
_logger = logger;
}
public override async Task<IList<AgentSkill>> GetSkillsAsync(
AgentSkillsSourceContext context,
CancellationToken cancellationToken = default)
{
var skills = await base.GetSkillsAsync(context, cancellationToken);
_logger.LogInformation(
"Returned {SkillCount} skills to agent {AgentName}.",
skills.Count,
context.Agent.Name);
return skills;
}
}
Оба пользовательских источника можно передавать напрямую в AgentSkillsProvider или встраивать в более крупный конвейер, так же, как и встроенные источники.
Создание провайдера
AgentSkillsProvider — это компонент, который предоставляет агенту доступ к навыкам. Объединяет один или несколько источника и регистрирует инструменты load_skill, read_skill_resource и run_skill_script. Существует три способа его создания:
-
AgentSkillsProviderBuilder— объединяет несколько типов навыков в рамках одного поставщика с автоматическим агрегированием, устранением дубликатов, кэшированием и необязательной фильтрацией. Лучше всего подходит для сценариев, сочетающих навыки на основе файлов, определяемые кодом, основанные на классах и основанные на MCP. -
Прямая композиция источника — создание исходного конвейера самостоятельно с помощью общедоступных
AgentSkillsSourceклассов. Автоматическое кэширование или дедупликация не применяются. Вы управляете полным конвейером. Лучше всего, если вам нужен контроль над упорядочением, условной логикой или поведением пользовательского декоратора. - Вспомогательные конструкторы — позволяют создать поставщик по пути к файлу или непосредственно из экземпляра навыка или экземпляров навыков. Автоматически применяет дедупликацию и кэширование. Лучше всего подходит для сценариев с одним источником.
Использование AgentSkillsProviderBuilder
Используйте AgentSkillsProviderBuilder, если вам потребуется следующее:
-
Смешанные типы навыков — объединение навыков на основе файлов, определяемых кодом (
AgentInlineSkill), на основе классов (AgentClassSkill) и навыков на основе MCP в одном поставщике. - Фильтрация навыков — включение или исключение навыков с помощью предиката.
Смешанные типы навыков
Объедините несколько типов навыков в одном поставщике, выстроив в цепочку UseFileSkill, UseSkill, UseMcpSkills и UseFileScriptRunner:
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills")) // file-based skills
.UseSkill(volumeConverterSkill) // AgentInlineSkill
.UseSkill(temperatureConverter) // AgentClassSkill
.UseMcpSkills(mcpClient) // MCP-based skills
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync) // runner for file scripts
.Build();
Фильтрация навыков
Используйте UseFilter , чтобы включить только навыки, соответствующие вашим критериям, например для загрузки навыков из общего каталога, но исключить экспериментальные:
var approvedSkillNames = new HashSet<string> { "expense-report", "code-style" };
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseFilter((skill, context) => approvedSkillNames.Contains(skill.Frontmatter.Name))
.Build();
Составление источников напрямую
Если построитель не предлагает необходимый элемент управления, создайте исходные классы самостоятельно и передайте результирующий конвейер AgentSkillsProvider. Полный список доступных источников и их параметров см. в источниках навыков .
В следующем примере создаётся аналогичный конвейер с несколькими источниками, но он даёт вам явный контроль над каждым декоратором:
// 1. Create the leaf sources
var fileSource = new AgentFileSkillsSource(
[Path.Combine(AppContext.BaseDirectory, "skills")],
SubprocessScriptRunner.RunAsync);
var inMemorySource = new AgentInMemorySkillsSource(
[volumeConverterSkill, temperatureConverter]);
// 2. Aggregate them into one source
var aggregated = new AggregatingAgentSkillsSource([fileSource, inMemorySource]);
// 3. Add deduplication and caching decorators
var deduplicated = new DeduplicatingAgentSkillsSource(aggregated);
var cached = new CachingAgentSkillsSource(deduplicated);
// 4. Create the provider, transferring source ownership
var skillsProvider = new AgentSkillsProvider(
cached,
options: new AgentSkillsProviderOptions(),
ownsSource: true);
Замечание
Когда ownsSource имеет значение true, удаление поставщика также приводит к удалению всего исходного конвейера. Задайте для него значение false , если вы управляете жизненным циклом источника самостоятельно.
Вспомогательные конструкторы
Для сценариев с одним исходным кодом используйте AgentSkillsProvider конструкторы напрямую. Они автоматически обеспечивают дедупликацию и кэширование без необходимости использовать builder или вручную компоновать источники.
Из пути к файлу:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
scriptRunner: SubprocessScriptRunner.RunAsync);
Из экземпляров навыков:
var skillsProvider = new AgentSkillsProvider(volumeConverterSkill, temperatureConverter);
Источники навыков
SkillsProvider получает навыки из одного или нескольких источников — объектов, наследующихся от SkillsSource. Источники делятся на две категории: листовые источники, которые обнаруживают или содержат навыки (например, FileSkillsSource для навыков на основе файлов), и декораторы, которые преобразуют результаты работы другого источника (агрегирование, дедупликация, кэширование и фильтрация). Вы также можете создать настраиваемый источник.
Каждый источник реализует один метод — async def get_skills(self, context: SkillsSourceContext) -> list[Skill].
SkillsSourceContext содержит сведения о текущем запросе:
-
agent— агент (SupportsAgentRun) запрашивает навыки. -
session—AgentSession, связанный с вызовом, илиNone, если сеанс отсутствует.
Этот контекст проходит через весь исходный конвейер, поэтому FilteringSkillsSource предикат или пользовательский источник может основывать свою логику на нем, например, возвращая другой набор навыков в зависимости от запрашивающего агента.
Листовые источники
-
FileSkillsSource— обнаруживает навыки изSKILL.mdфайлов на диске. Принимает один или несколько путей к каталогам, необязательныйscript_runnerи параметры обнаружения (resource_extensions,script_extensions,search_depth,resource_filter,script_filter), задокументированные в разделе Навыки на основе файлов. -
InMemorySkillsSource— упаковываетSkillэкземпляры (определяемые кодом или классом) в память. -
MCPSkillsSource— обнаруживает навыки с сервера MCP (см. навыки на основе MCP).
from pathlib import Path
from agent_framework import FileSkillsSource, InMemorySkillsSource
file_source = FileSkillsSource(Path(__file__).parent / "skills", script_runner=my_runner)
in_memory_source = InMemorySkillsSource([volume_converter_skill, temperature_converter_skill])
Комбинатор
AggregatingSkillsSource объединяет несколько источников в один. Навыки возвращаются в порядке регистрации без дедупликации или фильтрации.
from agent_framework import AggregatingSkillsSource
aggregated = AggregatingSkillsSource([file_source, in_memory_source])
Декораторы
Декораторы оборачивают внутренний источник и преобразуют его результат. Их можно связать для создания конвейера.
-
DeduplicatingSkillsSource— удаляет повторяющиеся имена навыков (без учета регистра, первое вхождение выигрывает). Дубликаты регистрируются на уровне предупреждения. -
CachingSkillsSource— кэширует список навыков, возвращаемый внутренним источником. Одновременные запросы для одного и того же ключа кэша используют один общий уже выполняющийся запрос, поэтому к исходному источнику обращаются не более одного раза для каждого ключа. Принимает два необязательных аргумента ключевого слова:-
refresh_interval(timedelta | None) — при установке кэшированный список обрабатывается как устаревший после того, как он старше интервала, поэтому следующий вызов повторно запрашивает внутренний источник. КогдаNone(по умолчанию) кэшированные результаты никогда не истекают. Полезно для внутренних ресурсов, навыки которых изменяются на протяжении жизненного цикла процесса, напримерMCPSkillsSource. -
cache_isolation_key_selector(Callable[[SkillsSourceContext], str | None]) — наследует ключ кэша из контекста для изоляции кэшированных результатов (например, для каждого агента или клиента). Ключи должны иметь низкую кардинальность и быть стабильными. При возврате этого значенияNone(или если оставить егоNone) используется один общий сегмент кэша.
-
-
FilteringSkillsSource— применяет предикат для включения или исключения навыков. Предикат получает навык иSkillsSourceContext:Callable[[Skill, SkillsSourceContext], bool].
from datetime import timedelta
from agent_framework import (
CachingSkillsSource,
DeduplicatingSkillsSource,
FilteringSkillsSource,
)
deduplicated = DeduplicatingSkillsSource(aggregated)
cached = CachingSkillsSource(
deduplicated,
refresh_interval=timedelta(minutes=5),
cache_isolation_key_selector=lambda context: context.agent.name,
)
filtered = FilteringSkillsSource(
cached,
predicate=lambda skill, context: skill.frontmatter.name != "experimental-skill",
)
Пользовательские источники
Если встроенные источники не охватывают свой сценарий, реализуйте собственные. Подкласс SkillsSource для конечного источника (который создает навыки из нового источника, например базы данных или удаленной службы), или подкласс DelegatingSkillsSource для декоратора, который преобразует выходные данные другого источника.
Листовой источник
Производный от SkillsSource и реализуемого get_skills. Аргумент SkillsSourceContext позволяет источнику адаптировать его результат к текущему запросу, например, возвращая другой набор навыков в зависимости от агента запроса:
from agent_framework import Skill, SkillsSource, SkillsSourceContext
class TenantSkillsSource(SkillsSource):
def __init__(self, store: "SkillStore") -> None:
self._store = store
async def get_skills(self, context: SkillsSourceContext) -> list[Skill]:
# Use the requesting agent to decide which skills to load.
tenant_id = context.agent.name or "default"
return await self._store.get_skills_for_tenant(tenant_id)
Пользовательский декоратор
Унаследуйтесь от DelegatingSkillsSource, вызовите self.inner_source.get_skills(context) и преобразуйте результат или наблюдайте за ним. Это тот же шаблон, который используют встроенные декораторы кэширования, дедупликации и фильтрации. Например, декоратор, который записывает в журнал, сколько навыков было возвращено для каждого запроса, не изменяя результат:
import logging
from agent_framework import DelegatingSkillsSource, Skill, SkillsSourceContext
logger = logging.getLogger(__name__)
class MetricsSkillsSource(DelegatingSkillsSource):
async def get_skills(self, context: SkillsSourceContext) -> list[Skill]:
skills = await self.inner_source.get_skills(context)
logger.info("Returned %d skills to agent %s.", len(skills), context.agent.name)
return skills
Оба пользовательских источника можно передавать напрямую в SkillsProvider или встраивать в более крупный конвейер, так же, как и встроенные источники.
Создание провайдера
SkillsProvider — это компонент, который предоставляет агенту доступ к навыкам. Объединяет один или несколько источника и регистрирует инструменты load_skill, read_skill_resource и run_skill_script. Существует три способа его создания:
-
Из экземпляров навыков — передайте в конструктор один
Skillили последовательность навыков. Лучше всего подходит для навыков, определяемых кодом и основанных на классах. Автоматически применяет дедупликацию и кэширование. -
Из путей к файлам — используйте фабрику
SkillsProvider.from_paths(). Лучше всего подходит для навыков на основе файлов с одним исходным кодом. Автоматически применяет дедупликацию и кэширование. -
Прямая композиция источника — создайте исходный конвейер самостоятельно с помощью открытых
SkillsSourceклассов и передайте его конструктору. Вы управляете полным конвейером. Лучше всего подходит, когда нужно управлять порядком, условной логикой, ключами кэширования или поведением пользовательского декоратора.
Из экземпляров навыков
from agent_framework import SkillsProvider
# Single skill or a list of skills - deduplicated and cached automatically.
skills_provider = SkillsProvider(volume_converter_skill)
skills_provider = SkillsProvider([volume_converter_skill, temperature_converter_skill])
Из путей к файлам
from pathlib import Path
from agent_framework import SkillsProvider
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
script_runner=my_runner,
)
Составление источников напрямую
Когда вам нужен полный контроль, создайте исходные классы самостоятельно и передайте результирующий конвейер SkillsProvider. Полный список доступных источников и их параметров см. в источниках навыков .
В приведенном ниже примере показано, как создать конвейер с несколькими источниками с явным управлением каждым декоратором. В примере используются объекты-заполнители:
-
volume_converter_skill— любой экземплярInlineSkill, созданный, как показано в навыках, определяемых кодом. -
temperature_converter_skill— любой экземплярClassSkill, созданный, как показано в Навыки на основе классов. -
my_runner—SkillScriptRunnerвызываемый объект, определённый, как показано в разделе Выполнение скрипта.
from pathlib import Path
from agent_framework import (
AggregatingSkillsSource,
CachingSkillsSource,
DeduplicatingSkillsSource,
FileSkillsSource,
InMemorySkillsSource,
SkillsProvider,
)
# 1. Create the leaf sources
file_source = FileSkillsSource(Path(__file__).parent / "skills", script_runner=my_runner)
in_memory_source = InMemorySkillsSource([volume_converter_skill, temperature_converter_skill])
# 2. Aggregate them, then add deduplication and caching decorators
aggregated = AggregatingSkillsSource([file_source, in_memory_source])
deduplicated = DeduplicatingSkillsSource(aggregated)
cached = CachingSkillsSource(deduplicated)
# 3. Create the provider from the composed pipeline
skills_provider = SkillsProvider(cached)
Important
Переданный вызывающей стороной SkillsSource используется как есть: для него не выполняется автоматическое удаление дубликатов, и он не обёртывается в CachingSkillsSource. Автоматическое кэширование источника с учетом контекста в одном общем контейнере может воспроизводить навыки одного агента или клиента для другого. Создайте DeduplicatingSkillsSource и CachingSkillsSource самостоятельно (при необходимости вместе с cache_isolation_key_selector), когда они вам понадобятся. Автоматическое дедупликация и кэширование применяется только при передаче навыков или путей к файлам напрямую (параметры 1 и 2 выше).
Смешанные типы навыков
Объедините навыки на основе файлов, определяемые кодом и на основе классов в одном поставщике с помощью AggregatingSkillsSource:
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]),
])
)
)
Фильтрация навыков
Используйте FilteringSkillsSource, чтобы управлять тем, какие навыки видит агент. Предикат получает каждый Skill и SkillsSourceContext, и возвращает True, чтобы включить этот навык. Например, чтобы загрузить навыки из общего каталога, но скрыть экспериментальный:
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, context: skill.frontmatter.name != "experimental-tools",
)
)
)
Поведение кэширования
По умолчанию построитель оборачивает исходный конвейер в CachingAgentSkillsSource, который кэширует список навыков, возвращаемый базовыми источниками. После разрешения навыков при первом запросе последующие запросы повторно используют кэшированный список без повторного запроса источников. Чтобы отключить кэширование (например, во время разработки при частом изменении определений навыков), используйте DisableCaching() в построителе:
var skillsProvider = new AgentSkillsProviderBuilder()
.UseFileSkill(Path.Combine(AppContext.BaseDirectory, "skills"))
.UseFileScriptRunner(SubprocessScriptRunner.RunAsync)
.DisableCaching()
.Build();
Замечание
Отключение кэширования полезно во время разработки при частом изменении контента навыка. В рабочей среде оставьте кэширование включено (по умолчанию) для повышения производительности.
Поведение кэширования
По умолчанию инструменты навыков и инструкции сохраняются в кэше после первой сборки. Задайте disable_caching=True, чтобы принудительно выполнять пересборку при каждом вызове:
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
disable_caching=True,
)
disable_caching также доступен в конструкторе SkillsProvider для навыков, определяемых в коде и на основе классов.
Чтобы оставить кэширование включённым, но при этом периодически повторно обнаруживать навыки (например, когда источник на основе файлов или MCP изменяется в течение времени работы процесса), передайте cache_refresh_interval. Встроенный кэш обрабатывается как устаревший после того, как он старше интервала, поэтому следующий запуск повторно запрашивает источник:
from datetime import timedelta
skills_provider = SkillsProvider.from_paths(
skill_paths=Path(__file__).parent / "skills",
cache_refresh_interval=timedelta(minutes=5),
)
cache_refresh_interval влияет только на кэш, который поставщик формирует внутри себя (на основе навыков или путей к файлам); он игнорируется, когда disable_caching=True, и не влияет на SkillsSource, переданный вызывающей стороной (для таких случаев создайте собственный CachingSkillsSource с refresh_interval).
Замечание
Отключение кэширования полезно во время разработки при частом изменении контента навыка. В рабочей среде оставьте кэширование включено (по умолчанию) для повышения производительности.
Утверждение инструмента
Все средства, предоставляемые AgentSkillsProvider (load_skill, read_skill_resource, run_skill_script), требуют утверждения по умолчанию. Когда для вызова инструмента требуется подтверждение, агент приостанавливает работу и возвращает ToolApprovalRequestContent вместо того, чтобы немедленно его выполнить. Используйте UseToolApproval промежуточное ПО с правилами автоматического подтверждения, чтобы выборочно обходить запросы подтверждения для доверенных операций:
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync);
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new() { Instructions = "You are a helpful assistant." },
AIContextProviders = [skillsProvider],
},
model: deploymentName)
.AsBuilder()
.UseToolApproval(new ToolApprovalAgentOptions
{
// Auto-approve read-only skill tools (load_skill, read_skill_resource).
// run_skill_script still requires explicit user approval.
AutoApprovalRules = [AgentSkillsProvider.ReadOnlyToolsAutoApprovalRule],
})
.Build();
Чтобы автоматически утвердить все средства навыка, включая выполнение скрипта, выполните следующие действия:
.UseToolApproval(new ToolApprovalAgentOptions
{
AutoApprovalRules = [AgentSkillsProvider.AllToolsAutoApprovalRule],
})
Отключение утверждения для определенных инструментов
Используйте AgentSkillsProviderOptions для отключения утверждения отдельных средств, полностью удаляя их из потока утверждения:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync,
options: new AgentSkillsProviderOptions
{
DisableLoadSkillApproval = true,
DisableReadSkillResourceApproval = true,
// DisableRunSkillScriptApproval remains false - scripts still require approval
});
Если в одном ответе одни инструменты требуют одобрения, а другие — нет, модель может вызывать оба типа одновременно. Установите EnableNonApprovalRequiredFunctionBypassing так, чтобы инструменты, не требующие утверждения, выполнялись немедленно, а пользователю предлагалось подтвердить только остальные:
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new() { Instructions = "You are a helpful assistant." },
AIContextProviders = [skillsProvider],
EnableNonApprovalRequiredFunctionBypassing = true,
},
model: deploymentName)
.AsBuilder()
.UseToolApproval()
.Build();
Обработка запросов на утверждение
Если инструменты требуют одобрения (и ни одно правило автоматического одобрения не применяется), агент возвращает элементы ToolApprovalRequestContent, которые необходимо одобрить или отклонить, прежде чем продолжить:
AgentSession session = await agent.CreateSessionAsync();
AgentResponse response = await agent.RunAsync("Convert 26.2 miles to kilometers", session);
List<ToolApprovalRequestContent> approvalRequests = response.Messages
.SelectMany(m => m.Contents)
.OfType<ToolApprovalRequestContent>()
.ToList();
while (approvalRequests.Count > 0)
{
List<ChatMessage> userInputResponses = approvalRequests
.ConvertAll(request =>
{
var toolCall = (FunctionCallContent)request.ToolCall;
Console.WriteLine($"Approve {toolCall.Name}? (Y/N)");
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
return new ChatMessage(ChatRole.User, [request.CreateResponse(approved)]);
});
response = await agent.RunAsync(userInputResponses, session);
approvalRequests = response.Messages
.SelectMany(m => m.Contents)
.OfType<ToolApprovalRequestContent>()
.ToList();
}
Сведения об ошибке скрипта
По умолчанию, при сбое выполнения скрипта навыка исключение передаётся дальше в базовый FunctionInvokingChatClient. Если для свойства IncludeDetailedErrors задано значение true, сообщение об исключении передаётся модели, что позволяет ей самостоятельно исправиться, повторив попытку с другими аргументами:
AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential())
.GetResponsesClient()
.AsAIAgent(
options: new ChatClientAgentOptions
{
Name = "SkillsAgent",
ChatOptions = new()
{
Instructions = "You are a helpful assistant.",
},
AIContextProviders = [skillsProvider],
},
model: deploymentName,
clientFactory: client => client
.AsBuilder()
.UseFunctionInvocation(configure: (c) => c.IncludeDetailedErrors = true)
.Build());
Если вы не можете настроить FunctionInvokingChatClient напрямую, задайте вместо этого AgentSkillsProviderOptions.IncludeDetailedErrors. Это перехватывает исключение на уровне поставщика навыков и возвращает сообщение об ошибке непосредственно в модель:
var skillsProvider = new AgentSkillsProvider(
Path.Combine(AppContext.BaseDirectory, "skills"),
SubprocessScriptRunner.RunAsync,
options: new AgentSkillsProviderOptions
{
IncludeDetailedErrors = true,
});
Предупреждение
Любой из этих подходов может раскрыть модели необработанные сведения об исключении. Сообщения об исключениях могут содержать конфиденциальные сведения, такие как строки подключения, пути к файлам или внутренние имена служб. Кроме того, если навыки или сценарии поступают из ненадёжных источников, специально созданный злоумышленником сценарий может сгенерировать исключение, сообщение которого содержит полезную нагрузку для инъекции в промпт.
Все инструменты, доступные через SkillsProvider (load_skill, read_skill_resource и run_skill_script), по умолчанию требуют одобрения. Если для вызова инструмента требуется подтверждение, агент приостанавливается и возвращает запросы на подтверждение через result.user_input_requests вместо того, чтобы немедленно выполнить его. Вы утверждаете или отклоняете каждый запрос с помощью request.to_function_approval_response(approved=...) и отправляете ответы обратно:
from textwrap import dedent
from agent_framework import Agent, Content, InlineSkill, Message, 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}"
# All skill tools require approval by default.
skills_provider = SkillsProvider(deployment_skill)
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)
# Collect a response for every request and send them in one run so the
# loop always makes progress.
while result.user_input_requests:
approval_responses: list[Content] = []
for request in result.user_input_requests:
if request.function_call is None:
approval_responses.append(request.to_function_approval_response(approved=False))
continue
print(f"Approve {request.function_call.name}? Args: {request.function_call.arguments}")
# In a real application, prompt the user here.
approval_responses.append(request.to_function_approval_response(approved=True))
result = await agent.run(Message(role="user", contents=approval_responses), session=session)
print(result)
Если вызов средства отклоняется (approved=False), агент уведомляется о том, что пользователь отказался и может отвечать соответствующим образом.
Автоматическое утверждение доверенных инструментов
Вместо того чтобы запрашивать подтверждение для каждого вызова, установите ToolApprovalMiddleware, используя одно из статических правил автоматического утверждения, предоставляемых SkillsProvider. Это позволяет автоматически запускать инструменты с доступом только для чтения, при этом по-прежнему запрашивая подтверждение на выполнение скрипта:
from agent_framework import Agent, SkillsProvider, ToolApprovalMiddleware
skills_provider = SkillsProvider(deployment_skill)
# Auto-approve read-only skill tools (load_skill, read_skill_resource).
# run_skill_script still requires explicit approval via result.user_input_requests.
approval_middleware = ToolApprovalMiddleware(
auto_approval_rules=[SkillsProvider.read_only_tools_auto_approval_rule],
)
agent = Agent(
client=client,
instructions="You are a deployment assistant.",
context_providers=[skills_provider],
middleware=[approval_middleware],
)
Доступны два правила:
-
SkillsProvider.read_only_tools_auto_approval_rule— одобряет только инструменты только для чтения (load_skill,read_skill_resource), при этом всё равно запрашивая подтверждение дляrun_skill_script. -
SkillsProvider.all_tools_auto_approval_rule— утверждает каждый инструмент навыка, включаяrun_skill_script(цикл утверждения вручную не требуется).
Оба правила отклоняют любой вызов, содержащий server_label, поэтому их действие ограничивается локальными инструментами этого поставщика и они никогда не одобряют автоматически размещённый инструмент с тем же именем. Правила применяются только к инструментам, которые по-прежнему требуют утверждения, — инструменты, исключённые из этого требования с помощью аргументов disable_*_approval, приведённых ниже, запускаются без утверждения в любом случае.
Отключение утверждения для определенных инструментов
Для доверенных навыков передайте disable_load_skill_approval, disable_read_skill_resource_approval и/или disable_run_skill_script_approval, чтобы полностью исключить отдельные инструменты из процесса утверждения (они зарегистрированы с помощью approval_mode="never_require"):
skills_provider = SkillsProvider(
deployment_skill,
disable_load_skill_approval=True,
disable_read_skill_resource_approval=True,
# disable_run_skill_script_approval remains False - scripts still require approval
)
Эти аргументы также доступны в SkillsProvider.from_paths().
Предупреждение
Отключайте подтверждение или включайте автоматическое подтверждение выполнения скриптов только для навыков и скриптов из источников, которым вы доверяете. Инструкции по навыку внедряются в контекст агента и run_skill_script выполняют код, предоставленный источником.
Пользовательская системная подсказка
По умолчанию поставщик навыков внедряет системный запрос, который перечисляет доступные навыки и указывает агенту использовать 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}
When a task matches a skill, use load_skill to retrieve instructions,
then read_skill_resource for referenced resources, and run_skill_script for scripts.
"""
});
Замечание
Настраиваемый шаблон должен содержать {skills} в качестве заполнителя для сгенерированного списка навыков. Литеральные фигурные скобки должны быть экранированы как {{ и }}.
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}"
),
)
Замечание
Настраиваемый шаблон должен содержать заполнитель {skills} для сгенерированного списка навыков. Он также может опционально содержать плейсхолдеры {resource_instructions} (подсказка для инструмента ресурсов) и {runner_instructions} (подсказка для скриптового инструмента); если они присутствуют, в них подставляются встроенные рекомендации, а если отсутствуют, они просто не отображаются (соответствующие инструменты по-прежнему зарегистрированы). Литеральные фигурные скобки должны быть экранированы как {{ и }}.
Внедрение служб и аргументов среды выполнения
Функции ресурса Skill и скрипта могут получать внешний контекст приложения, передаваемый во время выполнения.
Делегаты ресурсов и скриптов навыка могут объявлять 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, платформа пересылает аргументы ключевых слов среды выполнения каждый раз, когда агент считывает ресурс:
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}"
Функции объектов без **kwargs вызываются без аргументов и не получают контекст выполнения.
Когда функция скрипта **kwargsобъявляет, платформа перенаправит аргументы ключевых слов среды выполнения вместе с args предоставленным агентом:
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})
Агент предоставляет value и factor через вызов инструмента args; приложение предоставляет precision через function_invocation_kwargs. Функции скрипта без **kwargs получают только аргументы, предоставленные агентом.
Навыки на основе классов с kwargs
Методы навыков в классах также могут принимать **kwargs, чтобы получать аргументы времени выполнения. Шаблон работает так же — объявить **kwargs в методах ресурсов или в методах скрипта:
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})
Рекомендации по обеспечению безопасности
Навыки агента должны рассматриваться как любой сторонний код, который вы вносите в проект. Так как инструкции по навыку внедряются в контекст агента — и навыки могут включать скрипты— применение того же уровня проверки и управления, что и зависимость с открытым кодом, является важной.
-
Просмотрите перед использованием — перед развертыванием прочитайте всё содержимое навыка (
SKILL.md, скрипты и ресурсы). Убедитесь, что фактическое поведение скрипта соответствует указанному намерению. Проверьте враждебные инструкции, которые пытаются обойти рекомендации по безопасности, эксфильтровать данные или изменить файлы конфигурации агента. - Доверие к источнику — устанавливайте навыки только от доверенных авторов или проверенных внутренних разработчиков. Предпочитайте навыки с четким происхождением, управлением версиями и активным обслуживанием. Следите за именами навыков typeosquatted, которые имитируют популярные пакеты.
- Песочница — выполнение навыков, включающих исполняемые скрипты в изолированных средах. Ограничить доступ к файловой системе, сети и системе только тому, что требуется навыку. Перед выполнением потенциально конфиденциальных операций требуется явное подтверждение пользователя.
- Аудит и ведение журнала — записывайте, какие навыки загружаются, какие ресурсы считываются и какие скрипты выполняются. Это дает путь аудита для трассировки поведения агента обратно к определенному содержимому навыка, если что-то пойдет не так.
Когда использовать навыки и рабочие процессы
Навыки агента и рабочие процессы платформы агента расширяют возможности агентов, но они работают по-разному. Выберите подход, который лучше всего соответствует вашим требованиям:
- Управление . С помощью навыка ИИ решает, как выполнить инструкции. Это идеально, если вы хотите, чтобы агент был творческим или адаптивным. При использовании рабочего процесса вы явно определяете путь выполнения. Используйте рабочие процессы, если требуется детерминированное, прогнозируемое поведение.
- Устойчивость — навык выполняется за один шаг агента. Если что-то завершается сбоем, необходимо повторить всю операцию. Рабочие процессы поддерживают контрольные точки, чтобы они могли возобновить работу с последнего успешного шага после сбоя. Выберите рабочие процессы, когда стоимость повторного выполнения всего процесса высока.
- Побочные эффекты — навыки подходят, когда операции идемпотентны или связаны с низким риском. Предпочитайте рабочие процессы, когда шаги создают побочные эффекты (отправка сообщений электронной почты, плата за платежи), которые не должны повторяться при повторных попытках.
- Сложность — навыки лучше всего подходят для сфокусированных задач в рамках одной предметной области, с которыми может справиться один агент. Рабочие процессы лучше подходят для многоэтапных бизнес-процессов, координирующих нескольких агентов, формирование человеческих утверждений и интеграцию с внешними системами.
Подсказка
Как правило, если вы хотите, чтобы ИИ определил, как выполнить задачу, используйте навыки. Если вам нужно гарантировать выполнение шагов и в каком порядке, используйте рабочий процесс.