エージェント のスキル

エージェント スキル は、エージェントに特化した機能とドメインの専門知識を提供する、命令、スクリプト、リソースの移植可能なパッケージです。 スキルはオープン仕様に従い、段階的な開示パターンを実装して、エージェントが必要なときに必要なコンテキストのみを読み込みます。

次の状況では、エージェント スキルを使用します。

  • パッケージ ドメインの専門知識 - 再利用可能なポータブル パッケージとして、専門的な知識 (経費ポリシー、法的ワークフロー、データ分析パイプライン) をキャプチャします。
  • エージェントの機能を拡張する - コア命令を変更することなく、エージェントに新しい機能を提供します。
  • 一貫性を確保 する - 複数ステップのタスクを反復可能で監査可能なワークフローに変換します。
  • 相互運用性を有効にする - 異なるエージェント スキル互換製品間で同じスキルを再利用します。

スキルの構造

スキルは、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 frontmatter とそれに続くマークダウン コンテンツが含まれている必要があります。

---
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"
---
Field 必須 [説明]
name イエス 最大 64 文字。 小文字、数字、ハイフンのみ。 先頭または末尾にハイフンを使用したり、連続するハイフンを含めたりすることはできません。 親ディレクトリ名と一致する必要があります。
description イエス スキルが実行する内容と、それを使用するタイミング。 最大 1024 文字。 エージェントが関連するタスクを識別するのに役立つキーワードを含める必要があります。
license いいえ バンドルされたライセンス ファイルへのライセンス名または参照。
compatibility いいえ 最大 500 文字。 環境要件 (目的の製品、システム パッケージ、ネットワーク アクセスなど) を示します。
metadata いいえ 追加のメタデータに対するキーと値の任意のマッピング。
allowed-tools いいえ スキルが使用する可能性がある、事前に承認されたツールのスペースで区切られた一覧。 試験段階 - サポートは、エージェントの実装によって異なる場合があります。

フロントマッターの後のマークダウン本文には、スキル命令 (ステップ バイ ステップ ガイダンス、入力と出力の例、一般的なエッジ ケース、エージェントがタスクを実行するのに役立つコンテンツ) が含まれています。 SKILL.md 500 行以下にし、詳細な参照マテリアルを別のファイルに移動します。

段階的な開示

エージェント スキルは、コンテキストの使用を最小限に抑えるために、4 段階のプログレッシブ開示パターンを使用します。

  1. アドバタイズ (スキルあたり最大 100 トークン) - スキル名と説明は、各実行の開始時にシステム プロンプトに挿入されるため、エージェントは使用可能なスキルを認識します。
  2. 読み込み (< 5,000 トークンを推奨) - タスクがスキルのドメインと一致すると、エージェントは load_skill ツールを呼び出して、詳細な手順で完全な SKILL.md 本文を取得します。
  3. リソースの読み取り (必要に応じて) - エージェントは read_skill_resource ツールを呼び出して、必要な場合にのみ補助ファイル (参照、テンプレート、資産) をフェッチします。
  4. スクリプトの実行 (必要に応じて) - エージェントは run_skill_script ツールを呼び出して、スキルにバンドルされたスクリプトを実行します。

必要に応じてドメインの深い知識にアクセスできるようにしつつ、このパターンはエージェントのコンテキスト ウィンドウを簡素に保ちます。

load_skill は常にアドバタイズされます。 read_skill_resource は、少なくとも 1 つのスキルにリソースがある場合にのみアドバタイズされます。 run_skill_script は、少なくとも 1 つのスキルにスクリプトがある場合にのみアドバタイズされます。

エージェントにスキルを提供する

AgentSkillsProvider (C#) と SkillsProvider (Python) は、エージェントがスキルを使用できるようにするコンテキスト プロバイダーです。 次の 3 つのスキル ソースがサポートされています。

  • ファイル ベース - ファイル システム ディレクトリ内の SKILL.md ファイルから検出されたスキル
  • Code-defined - AgentInlineSkill (C#) または InlineSkill (Python) を使用してコード内でインラインで定義されたスキル
  • Class-based - AgentClassSkill<T> (C#) または ClassSkill (Python) から派生するクラスにカプセル化されたスキル

1 つのプロバイダーで複数のソースを混在させる場合は、AgentSkillsProviderBuilder (C#) を使用するか、AggregatingSkillsSource などのソース クラスを作成します。 FilteringSkillsSource、および DeduplicatingSkillsSource (Python) - Builder: 高度なマルチソース シナリオ (C#) または Source コンポジション: 高度なマルチソース シナリオ (Python) を参照してください。

ファイル ベースのスキル

スキルを含むディレクトリを指す 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);

Warnung

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

プロバイダーは、最大 2 つのレベルの深さまで検索します。

リソース検出のカスタマイズ

既定では、プロバイダーは、拡張機能の .md.json.yaml.yml.csv.xml、および .txt を持つリソースを references および assets サブディレクトリで認識します。 AgentFileSkillsSourceOptionsを使用して、次の既定値を変更します。

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

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

スクリプトの実行

SubprocessScriptRunner.RunAsyncを 2 番目の引数として渡して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;
using System.Text.Json;

static async Task<string> RunAsync(
    AgentFileSkill skill,
    AgentFileSkillScript script,
    JsonElement? args,
    IServiceProvider? serviceProvider)
{
    var psi = new ProcessStartInfo("python3")
    {
        RedirectStandardOutput = true,
        UseShellExecute = false,
    };
    psi.ArgumentList.Add(Path.Combine(skill.Path, script.Path));
    if (args is { ValueKind: JsonValueKind.Array } json)
    {
        foreach (var element in json.EnumerateArray())
        {
            psi.ArgumentList.Add(element.GetString()!);
        }
    }
    using var process = Process.Start(psi)!;
    string output = await process.StandardOutput.ReadToEndAsync();
    await process.WaitForExitAsync();
    return output.Trim();
}

ランナーは、検出された各スクリプトをローカル サブプロセスとして実行します。 ファイル ベースのスクリプトでは、引数が文字列の JSON 配列として想定されます。各配列要素は位置指定コマンド ライン引数になります。

Warnung

SubprocessScriptRunner はデモ目的 でのみ提供されます。 運用環境で使用する場合は、次の追加を検討してください。

  • サンドボックス (コンテナーや分離された実行環境など)
  • リソース制限 (CPU、メモリ、ウォール クロック タイムアウト)
  • 実行可能スクリプトの入力検証と許可リスト
  • 構造化されたログ記録と監査証跡

スクリプト検出のカスタマイズ

既定では、プロバイダーは、.py サブディレクトリ内の拡張機能.js.sh.ps1.cs.csx、およびscriptsを持つスクリプトを認識します。 AgentFileSkillsSourceOptionsを使用して、次の既定値を変更します。

AgentFileSkillsSourceOptionsAgentSkillsProviderコンストラクターまたはビルダーのUseFileSkill / 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.from_paths() ファクトリを使用して、SKILL.md ファイルを含むディレクトリからスキルを検出し、エージェントのコンテキスト プロバイダーにプロバイダーを追加します。

import os
from pathlib import Path
from agent_framework import Agent, SkillsProvider
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential

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

# Create an agent with the skills provider
endpoint = os.environ["FOUNDRY_PROJECT_ENDPOINT"]
deployment = os.environ.get("FOUNDRY_MODEL", "gpt-4o-mini")

client = FoundryChatClient(
    project_endpoint=endpoint,
    model=deployment,
    credential=AzureCliCredential(),
)

agent = Agent(
    client=client,
    instructions="You are a helpful assistant.",
    context_providers=[skills_provider],
)

複数のスキル ディレクトリ

プロバイダーを単一の親ディレクトリにポイントできます。 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",
    ]
)

プロバイダーは、最大 2 つのレベルの深さまで検索します。

リソースとスクリプトの検出のカスタマイズ

既定では、リソースは agentskills.io 仕様に従って、 references/ および assets/ サブディレクトリから検出され、 scripts/からスクリプトが検出 されます。 認識されるリソース拡張機能は、 .md.json.yaml.yml.csv.xml、および .txtです。 resource_directoriesscript_directories、およびresource_extensionsを使用して、これらの既定値をカスタマイズします。

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    resource_extensions=(".md", ".txt"),
    resource_directories=["docs", "templates"],
    script_directories=["scripts", "tools"],
)

"."を使用して、サブディレクトリに加えてスキル ルート レベルでファイルを含めます。

スクリプトの実行

ファイル ベースのスクリプトの実行を有効にするには、 script_runnerSkillsProvider.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,
)

ランナーは、解決された FileSkillFileSkillScript、および省略可能な args 引数を受け取ります。 ファイル ベースのスクリプトでは、引数が文字列の JSON 配列として想定されます。各配列要素は位置指定コマンド ライン引数になります。 スクリプトは、各スキル ディレクトリの .py サブディレクトリ内のscripts/ ファイルから自動的に検出されます。

Warnung

上記のランナーはデモンストレーション目的 でのみ提供されます。 運用環境で使用する場合は、次の追加を検討してください。

  • サンドボックス (コンテナー、 seccompfirejailなど)
  • リソース制限 (CPU、メモリ、ウォール クロック タイムアウト)
  • 実行可能スクリプトの入力検証と許可リスト
  • 構造化されたログ記録と監査証跡

スクリプトを含むファイル ベースのスキルが提供されていても、 script_runner が設定されていない場合、 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);

コード定義スキルとファイル ベースまたはクラスベースのスキルを 1 つのプロバイダーで組み合わせるには、 AgentSkillsProviderBuilder を使用します。 ビルダー: 高度なマルチソース シナリオを参照してください。

SKILL.md ファイルから検出されたファイル ベースのスキルに加えて、InlineSkill を使用して、Python コードでスキルを完全に定義できます。 コード定義スキルは、次の場合に役立ちます。

  • スキル コンテンツは動的に生成されます (データベースや環境からの読み取りなど)。
  • スキル定義は、それらを使用するアプリケーション コードと共に保持する必要があります。
  • 静的ファイルを提供するのではなく、読み取り時にロジックを実行するリソースが必要です。
  • スキル定義は、実行時に データから構築 する必要があります。たとえば、ロールやアクセス許可に基づいてユーザー セッションごとにパーソナライズされたスキルを作成します。
  • スキルは、呼び出し元の状態(ローカル変数、クロージャ)をキャプチャする必要があり、**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) なしでデコレーターを使用すると、関数名がリソース名になり、docstring が説明になります。 @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 スキーマに自動的に変換されます。

クラスベースのスキル

クラスベースのスキルを使用すると、すべてのスキル コンポーネント (名前、説明、命令、リソース、スクリプト) を 1 つの C# クラスにバンドルできます。 これにより、NuGet パッケージとしてのパッケージ化と配布が簡単になります。チームは個別にスキルを作成して出荷することができ、コンシューマーは dotnet add package と 1 回の .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> では、属性ベースの検出が適合しないシナリオのコレクションとして、 ResourcesScripts のオーバーライドもサポートされています。

クラスベースのスキル

クラスベースのスキルを使用すると、名前、説明、命令、リソース、スクリプトなど、すべてのスキル コンポーネントを 1 つのPython クラスにバンドルできます。 これにより、PyPI パッケージとしてのパッケージ化と配布が簡単になります。チームは、スキルを個別に作成して出荷することができ、コンシューマーは pip install と 1 回の 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がベア デコレーター (引数なし) として適用されている場合、メソッド名はリソース名になり (アンダースコアはハイフンに変換されます)、docstring は説明になります。 @ClassSkill.resource(name="...", description="...")を使用して明示的に設定します。 @ClassSkill.scriptにも同じパターンが適用されます。

リソースは、通常のメソッドまたは @property 記述子として定義できます。 @propertyを使用する場合は、@propertyを最初に配置し、@ClassSkill.resourceを2番目に配置します。 リソースの戻り値は、最初のアクセス後にキャッシュされます。

ClassSkillまた、デコレータベースの検出が適合しないシナリオでは、resourcesおよびscriptsインスタンスを直接返すために、InlineSkillResourceプロパティとInlineSkillScriptプロパティを明示的にオーバーライドすることもできます。

ビルダー: 高度なマルチソース シナリオ

単一ソースの単純なシナリオでは、 AgentSkillsProvider コンストラクターを直接使用します。 次のいずれかが必要な場合は、 AgentSkillsProviderBuilder を使用します。

  • 混合スキルの種類 - ファイル ベース、コード定義 (AgentInlineSkill)、クラスベース (AgentClassSkill) のスキルを 1 つのプロバイダーで結合します。
  • スキルのフィルター処理 - 述語を使用してスキルを含めるか除外します。

混合スキルの種類

UseFileSkillUseSkillUseFileScriptRunnerを連結して、1 つのプロバイダーに 3 つのスキルの種類をすべて結合します。

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

ソース構成: 高度なマルチソース シナリオ

1 つのスキルまたはスキルの一覧を使用する単純なシナリオでは、 SkillsProvider コンストラクターに直接渡します。 ファイル ベースのスキルについては、 SkillsProvider.from_paths() ファクトリを使用します。 高度なシナリオでは、検出、フィルター処理、重複除去を制御するソース クラスを作成します。

  • FileSkillsSource - ディスク上の SKILL.md ファイルからスキルを検出します。
  • InMemorySkillsSource - メモリ内の Skill インスタンス (コード定義またはクラスベース) をラップします。
  • AggregatingSkillsSource - 複数のソースを 1 つに結合します。
  • FilteringSkillsSource - スキルを含めるか除外する述語を適用します。
  • DeduplicatingSkillsSource - 重複するスキル名を削除します(大文字と小文字を区別せず、最初のものを優先)。

混合スキルの種類

AggregatingSkillsSourceを使用して、1 つのプロバイダーでファイル ベース、コード定義、クラスベースのスキルを組み合わせます。 次の例では、プレースホルダー オブジェクトを使用します。

  • volume_converter_skill- InlineSkillに示すように構築された任意の インスタンス。
  • TemperatureConverterSkill- ClassSkillに示すように構築された任意のサブクラス。
  • my_runner - SkillScriptRunner 呼び出し可能オブジェクト。スクリプトの実行に示すように定義されます。
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 を受け取り、それを含める 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: skill.frontmatter.name != "experimental-tools",
        )
    )
)

スクリプトの承認

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=TrueSkillsProviderを使用して、人間の承認の背後にあるすべてのスクリプト実行をゲートします。 エージェントは、すぐに実行するのではなく、一時停止し、 result.user_input_requests経由で承認要求を返します。

from textwrap import dedent
from agent_framework import Agent, InlineSkill, SkillFrontmatter, SkillsProvider

deployment_skill = InlineSkill(
    frontmatter=SkillFrontmatter(
        name="deployment",
        description="Tools for deploying application versions to production",
    ),
    instructions=dedent("""\
        Use this skill when the user asks to deploy an application.
        Run the deploy script with the version and environment parameters.
    """),
)

@deployment_skill.script
def deploy(version: str, environment: str = "staging") -> str:
    """Deploy the application to the specified environment."""
    return f"Deployed version {version} to {environment}"

skills_provider = SkillsProvider(deployment_skill, require_script_approval=True)

async with Agent(
    client=client,
    instructions="You are a deployment assistant.",
    context_providers=[skills_provider],
) as agent:
    # Use a session so the agent retains context across approval round-trips
    session = agent.create_session()

    result = await agent.run(
        "Deploy version 2.5.0 to production",
        session=session,
    )

    # Handle approval requests
    while result.user_input_requests:
        for request in result.user_input_requests:
            print(f"Script: {request.function_call.name}")
            print(f"Args: {request.function_call.arguments}")

            approval = request.to_function_approval_response(approved=True)
            result = await agent.run(approval, session=session)

    print(result)

スクリプトが拒否されると (approved=False)、エージェントはユーザーが辞退したことを通知され、それに応じて応答できます。

カスタム システム プロンプト

既定では、スキル プロバイダーは、使用可能なスキルを一覧表示するシステム プロンプトを挿入し、 load_skillread_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.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} (スクリプト ツール ヒント) プレースホルダーが含まれている必要があります。 リテラルの中括弧は{{および}}としてエスケープする必要があります。

キャッシュ動作

既定では、スキル ツールと命令は最初のビルドの後にキャッシュされます。 DisableCaching = trueAgentSkillsProviderOptionsを設定して、すべての呼び出しで強制的に再構築します。

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

キャッシュの無効化は、スキル コンテンツが頻繁に変更される開発時に役立ちます。 運用環境では、パフォーマンスを向上させるためにキャッシュを有効のままにします (既定値)。

キャッシュ動作

既定では、スキル ツールと命令は最初のビルドの後にキャッシュされます。 disable_caching=Trueを設定して、すべての呼び出しで再構築を強制します。

skills_provider = SkillsProvider.from_paths(
    skill_paths=Path(__file__).parent / "skills",
    disable_caching=True,
)

disable_caching は、コード定義およびクラスベースのスキルの SkillsProvider コンストラクターでも使用できます。

キャッシュの無効化は、スキル コンテンツが頻繁に変更される開発時に役立ちます。 運用環境では、パフォーマンスを向上させるためにキャッシュを有効のままにします (既定値)。

スキル リソースとスクリプト デリゲートは、Agent Framework によって自動的に挿入される IServiceProvider パラメーターを宣言できます。 これにより、スキルは、スキル定義にハードコーディングすることなく、アプリケーション サービス (データベース クライアント、構成、ビジネス ロジックなど) を解決できます。

セットアップ

アプリケーション サービスを登録し、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 を使用したコード定義スキル

IServiceProviderAddResource または 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()に渡されたランタイム キーワード引数を自動的に受け取ります。 これにより、スキル関数は、構成、ユーザー ID、サービス クライアントなどのアプリケーション コンテキストにアクセスでき、スキル定義にハードコーディングする必要はありません。

ランタイム引数の受け渡し

function_invocation_kwargsagent.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を介してfactorargsを提供します。アプリケーションは、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、スクリプト、リソース) を読み取ります。 スクリプトの実際の動作が、指定された意図と一致することを確認します。 安全性ガイドラインのバイパス、データの流出、またはエージェント構成ファイルの変更を試みる敵対的な指示を確認します。
  • ソース信頼 - 信頼できる作成者または検証済みの内部共同作成者からのスキルのみをインストールします。 明確な由来、バージョン管理、アクティブなメンテナンスを備えたスキルやツールを優先します。 人気のあるパッケージを模倣する入力ミスのスキル名を警戒してください。
  • サンドボックス - 分離された環境で実行可能スクリプトを含むスキルを実行します。 ファイルシステム、ネットワーク、システム レベルのアクセスを、スキルに必要なもののみに制限します。 機密性の高い操作を実行する前に、明示的なユーザー確認が必要です。
  • 監査とログ 記録 - 読み込まれるスキル、読み取られたリソース、実行されるスクリプトを記録します。 これにより、問題が発生した場合にエージェントの動作を特定のスキル コンテンツに戻す監査証跡が提供されます。

スキルとワークフローを使用するタイミング

エージェント スキルと エージェント フレームワーク ワークフロー はどちらもエージェントが実行できる機能を拡張しますが、基本的に異なる方法で動作します。 要件に最も適したアプローチを選択します。

  • 制御 - スキルを使用して、AI は命令の実行方法を決定します。 これは、エージェントをクリエイティブまたはアダプティブにする場合に最適です。 ワークフローでは、実行パスを明示的に定義します。 確定的で予測可能な動作が必要な場合は、ワークフローを使用します。
  • 回復性 - スキルは 1 つのエージェント ターン内で実行されます。 何かが失敗した場合は、操作全体を再試行する必要があります。 ワークフローは チェックポイント処理をサポートしているため、失敗後に最後に成功した手順から再開できます。 プロセス全体の再実行コストが高い場合は、ワークフローを選択します。
  • 副作用 - スキルは、操作が冪等または低リスクである場合に適しています。 再試行時に繰り返してはならない副作用 (電子メールの送信、支払いの請求) がステップによって発生する場合は、ワークフローを優先します。
  • 複雑さ - スキルは、1 つのエージェントが処理できる集中型の単一ドメイン タスクに最適です。 ワークフローは、複数のエージェント、人間の承認、または外部システム統合を調整する複数ステップのビジネス プロセスに適しています。

ヒント

経験則として、AI にタスクの実行 方法 を把握させる場合は、スキルを使用します。 実行するステップと順序を保証する必要がある場合は、ワークフローを使用します。

次のステップ