Nástroje prostředí

Balíček beta agent-framework-tools Python poskytuje nástroje pro spouštění prostředí a sledování prostředí prostřednictvím agent_framework.tools oboru názvů.

nástroj Použijte ji, když
LocalShellTool Příkazy jsou důvěryhodné nebo jednotlivě schválené a měly by se spouštět v hostitelském prostředí procesu agenta.
DockerShellTool Příkazy prostředí generované modelem vyžadují izolaci kontejneru OCI.
ShellEnvironmentProvider Model potřebuje aktivní řadu prostředí, operační systém, pracovní adresář a nainstalované verze rozhraní příkazového řádku.
ShellPolicy Před schválením nebo provedením chcete před schválením nebo spuštěním předfiltrovat seznam povolených nebo odepřít.

Warning

Spouštění prostředí může upravovat soubory, spouštět procesy, přistupovat k přihlašovacím údajům a komunikovat s externími systémy. Použijte úroveň spouštění s nejnižšími oprávněními, která podporuje úlohu.

Nainstalujte balíček

dotnet add package Microsoft.Agents.AI.Tools.Shell --prerelease

Použití místního prostředí a povědomí o prostředí

LocalShellExecutor podporuje bezstavové a trvalé režimy. ShellEnvironmentProvider testuje aktivní prostředí a přidá autoritativní pokyny prostředí do kontextu agenta.

using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Tools.Shell;
using Microsoft.Extensions.AI;

var endpoint = Environment.GetEnvironmentVariable("FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("FOUNDRY_PROJECT_ENDPOINT is not set.");
var deploymentName = Environment.GetEnvironmentVariable("FOUNDRY_MODEL") ?? "gpt-5.4-mini";

// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
var aiProjectClient = new AIProjectClient(new Uri(endpoint), new DefaultAzureCredential());

const string Instructions = """
    You are an agent with a single tool: run_shell. Use it to satisfy the
    user's request. Do not describe what you would do — actually run the
    commands. Reply with the final answer derived from real output.
    """;

// --------------------------------------------------------------------
// 1. Stateless mode — each call gets a fresh shell.
// --------------------------------------------------------------------
Console.WriteLine("### Stateless mode\n");
await using (var statelessShell = new LocalShellExecutor(new() { Mode = ShellMode.Stateless, AcknowledgeUnsafe = true }))
{
    var envProvider = new ShellEnvironmentProvider(statelessShell);
    var statelessAgent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
    {
        ChatOptions = new()
        {
            ModelId = deploymentName,
            Instructions = Instructions,
            Tools = [statelessShell.AsAIFunction(requireApproval: false)],
        },
        AIContextProviders = [envProvider],
    });
// --------------------------------------------------------------------
// 2. Persistent mode — one shell, reused across calls. State carries.
// --------------------------------------------------------------------
Console.WriteLine("\n### Persistent mode\n");
await using (var persistentShell = new LocalShellExecutor(new() { Mode = ShellMode.Persistent, AcknowledgeUnsafe = true }))
{
    var envProvider = new ShellEnvironmentProvider(persistentShell);
    var persistentAgent = aiProjectClient.AsAIAgent(new ChatClientAgentOptions
    {
        ChatOptions = new()
        {
            ModelId = deploymentName,
            Instructions = Instructions,
            Tools = [persistentShell.AsAIFunction(requireApproval: false)],
        },
        AIContextProviders = [envProvider],
    });

    var persistentSession = await persistentAgent.CreateSessionAsync();

    // State carries across calls in persistent mode: cd into temp, then
    // verify the next call sees the new CWD.
    Console.WriteLine(await persistentAgent.RunAsync("Change directory into the system temp folder, then print the current working directory.", persistentSession));
    Console.WriteLine();
    Console.WriteLine(await persistentAgent.RunAsync("In a NEW shell call, print the current working directory again. Tell me whether it still matches the temp folder.", persistentSession));
    Console.WriteLine();

    // Same idea with an exported variable: set in one call, read in the next.
    Console.WriteLine(await persistentAgent.RunAsync("Set the environment variable DEMO_TOKEN to the value 'hello-world'.", persistentSession));
    Console.WriteLine();
    Console.WriteLine(await persistentAgent.RunAsync("Print the current value of DEMO_TOKEN. Tell me exactly what value the shell reports.", persistentSession));
    Console.WriteLine();

    PrintSnapshot(envProvider.CurrentSnapshot!);
}

ShellPolicy je také k dispozici pro předběžné filtrování příkazů. Vyhrazená spustitelná DockerShellExecutor ukázka není aktuálně publikovaná.

Nainstalujte balíček

pip install agent-framework-tools --pre

Balíček se nainstaluje tak, aby ukončil stromy psutil podřízených procesů, když vyprší časový limit provádění.

Použijte LocalShellTool

LocalShellTool spustí příkazy přímo na hostiteli. Výchozí hodnota je trvalé prostředí, 30sekundový časový limit, zkrácení výstupu 64 KiB, omezení pracovního adresáře a schválení pro každý příkaz.

import asyncio
from typing import Any

from agent_framework import Agent, Message
from agent_framework.openai import OpenAIChatClient
from agent_framework.tools import LocalShellTool
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()
async def main() -> None:
    print("=== OpenAI Agent with LocalShellTool Example ===")
    print("NOTE: Commands will execute on your local machine.\n")

    client = OpenAIChatClient(model="gpt-5.4-nano")

    async with LocalShellTool() as shell:
        agent = Agent(
            client=client,
            instructions="You are a helpful assistant that can run shell commands to help the user.",
            tools=[client.get_shell_tool(func=shell.as_function())],
        )

        query = "Use the shell tool to execute `python --version` and show only the command output."
        print(f"User: {query}")
        result = await run_with_approvals(query, agent)
        if isinstance(result, str):
            print(f"Agent: {result}\n")
            return
        if result.text:
            print(f"Agent: {result.text}\n")
        else:
            printed = False
            for message in result.messages:
                for content in message.contents:
                    if content.type == "function_result" and content.result:
                        print(f"Agent (tool output): {content.result}\n")
                        printed = True
            if not printed:
                print("Agent: (no text output returned)\n")


async def run_with_approvals(query: str, agent: Agent) -> Any:
    """Run the agent and handle shell approvals outside tool execution."""
    current_input: str | list[Any] = query

    while True:
        result = await agent.run(current_input)
        if not result.user_input_requests:
            return result

        next_input: list[Any] = [query]
        rejected = False
        for user_input_needed in result.user_input_requests:
            if user_input_needed.function_call is None:
                continue
            print(
                f"\nShell request: {user_input_needed.function_call.name}"
                f"\nArguments: {user_input_needed.function_call.arguments}"
            )
            user_approval = await asyncio.to_thread(input, "\nApprove shell command? (y/n): ")
            approved = user_approval.strip().lower() == "y"
            next_input.append(Message("assistant", [user_input_needed]))
            next_input.append(Message("user", [user_input_needed.to_function_approval_response(approved)]))
            if not approved:
                rejected = True
                break
        if rejected:
            print("\nShell command rejected. Stopping without additional approval prompts.")
            return "Shell command execution was rejected by user."
        current_input = next_input


if __name__ == "__main__":
    asyncio.run(main())

Použijte mode="stateless" , když by se každé volání mělo spustit v novém procesu. AGENT_FRAMEWORK_SHELL K přepsání přeloženého prostředí použijte proměnnou prostředí nebo shell argument konstruktoru.

Important

LocalShellTool není sandbox. Schválení je primární hranicí zabezpečení. Zakázání schválení vyžaduje acknowledge_unsafe=True.

Omezení příkazů pomocí ShellPolicy

ShellPolicy použije seznam povolených a odepříných regulárních výrazů před spuštěním. Pravidla zamítnutí mají přednost.

import asyncio

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from agent_framework.tools import LocalShellTool, ShellPolicy
from dotenv import load_dotenv
load_dotenv()
async def main() -> None:
    client = OpenAIChatClient(model="gpt-5.4-nano")

    shell = LocalShellTool(
        mode="stateless",
        approval_mode="never_require",
        acknowledge_unsafe=True,
        policy=ShellPolicy(
            allowlist=[
                r"^ls(\s|$)",
                r"^pwd$",
                r"^cat\s[^|;&]+$",
                r"^git\s+(status|log|diff)(\s|$)",
                r"^python\s+--version$",
            ],
        ),
        timeout=10,
    )

    agent = Agent(
        client=client,
        instructions=(
            "You can run a narrow set of read-only shell commands (ls, pwd, cat, "
            "git status/log/diff, python --version). Anything else will be rejected."
        ),
        tools=[client.get_shell_tool(func=shell.as_function())],
    )

    query = "Summarise the current directory and print the Python version."
    print(f"User: {query}")
    result = await agent.run(query)
    print(f"Agent: {result.text}")

Warning

Zásady příkazů jsou předfiltrovatelnost, nikoli hranice zabezpečení. Syntaxe prostředí, aliasy, proměnné, interprety a zakódované datové části můžou obejít jednoduché porovnávání vzorů.

Přidejte ShellEnvironmentProvider

ShellEnvironmentProvider testuje řadu prostředí, verzi, operační systém, pracovní adresář a vybrané verze rozhraní příkazového řádku a potom před spuštěním agenta vloží informace. Výchozí seznam testů je git, node, pythona docker.

import asyncio

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient
from agent_framework.tools import (
    LocalShellTool,
    ShellEnvironmentProvider,
    ShellEnvironmentProviderOptions,
)
from dotenv import load_dotenv
load_dotenv()
def _print_snapshot(label: str, provider: ShellEnvironmentProvider) -> None:
    snapshot = provider.current_snapshot
    if snapshot is None:
        print(f"[{label}] no snapshot captured")
        return
    print(f"\n[{label}] snapshot:")
    print(f"  family            = {snapshot.family.value}")
    print(f"  os                = {snapshot.os_description}")
    print(f"  shell_version     = {snapshot.shell_version}")
    print(f"  working_directory = {snapshot.working_directory}")
    for tool, version in snapshot.tool_versions.items():
        print(f"  {tool:<17} = {version}")


async def _ask(agent: Agent, query: str) -> None:
    print(f"\nUser: {query}")
    result = await agent.run(query)
    if result.text:
        print(f"Agent: {result.text}")


async def main() -> None:
    client = OpenAIChatClient(model="gpt-5.4-nano")
    options = ShellEnvironmentProviderOptions(
        probe_tools=("git", "python", "uv", "node"),
    )

    print("=== stateless mode ===")
    async with LocalShellTool(
        mode="stateless",
        approval_mode="never_require",
        acknowledge_unsafe=True,
    ) as shell:
        provider = ShellEnvironmentProvider(shell, options)
        agent = Agent(
            client=client,
            instructions="Use the shell tool to answer the user's question.",
            tools=[client.get_shell_tool(func=shell.as_function())],
            context_providers=[provider],
        )
        await _ask(agent, "Show me the current working directory.")
        await _ask(agent, "Now `cd ..` then show the working directory again.")
        await _ask(agent, "Show the working directory once more — did `cd` persist?")
        _print_snapshot("stateless", provider)

    print("\n=== persistent mode ===")
    async with LocalShellTool(
        mode="persistent",
        confine_workdir=False,
        approval_mode="never_require",
        acknowledge_unsafe=True,
    ) as shell:
        provider = ShellEnvironmentProvider(shell, options)
        agent = Agent(
            client=client,
            instructions="Use the shell tool to answer the user's question.",
            tools=[client.get_shell_tool(func=shell.as_function())],
            context_providers=[provider],
        )
        await _ask(agent, "Show me the current working directory.")
        await _ask(agent, "Now `cd ..` then show the working directory again.")
        await _ask(agent, "Show the working directory once more — did `cd` persist?")
        _print_snapshot("persistent", provider)

Použijte DockerShellTool

DockerShellTool vyžaduje Docker nebo Podman na PATH. Ve výchozím nastavení se sítě zakazují, běží jako uživatel, který není uživatelem root, používá kořenový systém souborů jen pro čtení, možnosti vyřazení, omezí paměť na 512 MiB a omezí kontejner na 256 procesů.

from agent_framework.tools import DockerShellTool

async with DockerShellTool(
    image="mcr.microsoft.com/azurelinux/base/core:3.0",
    approval_mode="never_require",
) as shell:
    result = await shell.run("uname -a && id")
    print(result.stdout)

Výchozí obrázek je mcr.microsoft.com/azurelinux/base/core:3.0. Předejte docker_binary="podman" použití podmana. Vyhrazená spustitelná DockerShellTool ukázka není aktuálně publikovaná.

Volba úrovně spuštění

Scénář nástroj Hranice izolace
Důvěryhodné vývojové příkazy LocalShellTool Schválení v hostitelském procesu
Nedůvěryhodné příkazy prostředí DockerShellTool Kontejner OCI s výchozími příznaky izolace
Nedůvěryhodný vygenerovaný kód bez prostředí Hyperlight CodeAct Hyperlight microVM

Go poskytuje spouštění místního prostředí a testování prostředí prostřednictvím tool/shelltool. Viz Použití místního nástroje prostředí.

DockerShellTool Pokyny nejsou aktuálně k dispozici pro Go.

Použití nástrojů prostředí s využitím agenta

Plain agents and HarnessAgent use the same two-part shell setup: register the executor's function as a tool, and add ShellEnvironmentProvider when the model should receive shell, operating-system, working-directory, and CLI-version context. HarnessAgent nevytvoří ani nevlastní exekutor prostředí:

using System.IO;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Tools.Shell;
using Microsoft.Extensions.AI;

await using var shell = new LocalShellExecutor(new LocalShellExecutorOptions
{
    WorkingDirectory = Directory.GetCurrentDirectory(),
    Timeout = LocalShellExecutor.DefaultTimeout,
});

AIAgent agent = chatClient.AsHarnessAgent(new HarnessAgentOptions
{
    AIContextProviders = [new ShellEnvironmentProvider(shell)],
    ChatOptions = new ChatOptions
    {
        Tools = [shell.AsAIFunction(requireApproval: true)],
    },
});

AsAIFunction výchozí hodnota je název run_shell a requireApproval: true. LocalShellExecutor výchozí hodnota pro trvalý režim, limit 64 KiB na výstupní datový proud a bez časového limitu; příklad explicitně používá doporučenou 30sekundundu LocalShellExecutor.DefaultTimeout. ShellEnvironmentProviderOptionsvýchozí hodnota pro sondu git, , dotnet, nodepython, a docker, s pětisekundovým časovým limitem na sondu.

Vytvořte jeden trvalý exekutor pro každou uživatelskou relaci a vyřaďte ho po skončení relace. Nesdílejte ho mezi uživateli ani souběžnými konverzacemi, protože se sdílí pracovní adresář, prostředí, historie prostředí, úlohy na pozadí a fronta příkazů. ShellPolicy je pouze předfiltr; zachovat povolení schválení, používat nejméně privilegované přihlašovací údaje a preferovat DockerShellExecutor , když příkazy vyžadují silnější hranici izolace.

Nástroje prostředí jsou k dispozici v předběžné verzi Microsoft.Agents.AI.Tools.Shell balíčku. HarnessAgent je k dispozici na webu Microsoft.Agents.AI.Harness.

Pro prostého agenta vytvořte funkci prostředí a client.get_shell_tool(func=shell.as_function()) přidejte ShellEnvironmentProvider ji samostatně. create_harness_agent provede oba kroky, když předáte shell_executor:

from agent_framework import create_harness_agent
from agent_framework.tools import LocalShellTool, ShellEnvironmentProviderOptions

async with LocalShellTool() as shell:
    agent = create_harness_agent(
        client=client,
        shell_executor=shell,
        shell_environment_provider_options=ShellEnvironmentProviderOptions(
            probe_tools=("git", "python"),
        ),
    )

    session = agent.create_session()
    response = await agent.run("Inspect the current repository.", session=session)

shell_executor je opt-in a musí zveřejnit as_function(). Továrna přidá nástroj prostředí a ShellEnvironmentProvider pouze když klient implementuje SupportsShellTool; jinak zaznamená upozornění a přeskočí obojí. shell_environment_provider_options je nepovinný a používá se pouze s shell_executor.

LocalShellTool výchozí hodnota pro trvalý režim, 30sekundový časový limit, kombinovaný výstup 64-KiB, opětovné ukotvení pracovního adresáře a approval_mode="always_require". Vzhledem k tomu, že je ve výchozím nastavení povoleno schválení nástroje Použádek, předat AgentSession do run. Volající vlastní životní cyklus exekutoru; použijte async with nebo zavolejte close()a vytvořte jeden trvalý nástroj pro každou uživatelskou relaci. Nesdílejte proměnlivý stav prostředí mezi uživateli ani souběžnými konverzacemi.

Hostitelské prostředí není sandbox. Povolte schválení, používejte nejméně privilegované přihlašovací údaje a používejte DockerShellTool je pro izolaci kontejnerů. Zakázání schválení vyžaduje approval_mode="never_require" a acknowledge_unsafe=TrueShellPolicy není to hranice zabezpečení.

create_harness_agent je vydán v agent-framework-core. Integrace prostředí je poskytována předběžným agent-framework-tools balíčkem a generuje ExperimentalWarning , když je povolená.

Balíček Go Postroj není v současné době k dispozici. Vytvořte nástroj místního prostředí a poskytovatele prostředí přímo v prostém agentu Go.