Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
agent-framework-tools Beta-Python-paketet innehåller gränssnittskörnings- och miljömedvetenhetsverktyg via agent_framework.tools namnområdet.
| Verktyg | Använd den när |
|---|---|
LocalShellTool |
Kommandon är betrodda eller individuellt godkända och bör köras i agentprocessens värdmiljö. |
DockerShellTool |
Modellgenererade gränssnittskommandon behöver OCI-containerisolering. |
ShellEnvironmentProvider |
Modellen behöver active shell-serien, operativsystemet, arbetskatalogen och installerade CLI-versioner. |
ShellPolicy |
Du vill ha en lista över tillåtna eller neka listor före godkännande eller körning. |
Varning
Shell-körning kan ändra filer, starta processer, komma åt autentiseringsuppgifter och kommunicera med externa system. Använd den lägsta privilegierade körningsnivån som stöder uppgiften.
Installera paketet
dotnet add package Microsoft.Agents.AI.Tools.Shell --prerelease
Använda lokalt gränssnitt och miljömedvetenhet
LocalShellExecutor stöder tillståndslösa och beständiga lägen.
ShellEnvironmentProvider avsöker den aktiva miljön och lägger till auktoritativ gränssnittsvägledning i agentkontexten.
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 är också tillgängligt för förfiltrering av kommandon. Ett dedikerat körbart DockerShellExecutor exempel publiceras för närvarande inte.
Installera paketet
pip install agent-framework-tools --pre
Paketet installeras för att avsluta underordnade processträd när en körning överskrider psutil tidsgränsen.
Använd LocalShellTool
LocalShellTool kör kommandon direkt på värden. Det är som standard ett beständigt gränssnitt, en tidsgräns på 30 sekunder, trunkering av 64 KiB-utdata, begränsning av arbetskataloger och godkännande för varje kommando.
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())
Använd mode="stateless" när varje anrop ska köras i en ny process.
AGENT_FRAMEWORK_SHELL Använd miljövariabeln eller konstruktorargumentet shell för att åsidosätta det lösta gränssnittet.
Important
LocalShellTool är inte en sandbox-miljö. Godkännande är den primära säkerhetsgränsen. Inaktivering av godkännande kräver acknowledge_unsafe=True.
Begränsa kommandon med ShellPolicy
ShellPolicy använder reguljära uttryck för att tillåta och neka listor före körning. Neka regler har företräde.
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}")
Varning
En kommandoprincip är ett förfilter för användbarhet, inte en säkerhetsgräns. Shell-syntax, alias, variabler, tolkar och kodade nyttolaster kan kringgå enkel mönstermatchning.
Lägg till ShellEnvironmentProvider
ShellEnvironmentProvider avsöker gränssnittsfamiljen, versionen, operativsystemet, arbetskatalogen och valda CLI-versioner och matar sedan in den informationen innan agenten körs. Standardavsökningslistan är git, node, pythonoch 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)
Använd DockerShellTool
DockerShellTool kräver Docker eller Podman på PATH. Standardinställningarna inaktiverar nätverk, körs som en icke-rotanvändare, använder ett skrivskyddat rotfilsystem, släpper funktioner, begränsar minnet till 512 MiB och begränsar containern till 256 processer.
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)
Standardbilden är mcr.microsoft.com/azurelinux/base/core:3.0. Pass docker_binary="podman" för att använda Podman. Ett dedikerat körbart DockerShellTool exempel publiceras för närvarande inte.
Välj en körningsnivå
| Scenario | Verktyg | Isoleringsgräns |
|---|---|---|
| Kommandon för betrodd utveckling | LocalShellTool |
Godkännande i värdprocessen |
| Ej betrodda gränssnittskommandon | DockerShellTool |
OCI-container med standardisoleringsflaggor |
| Ej betrodd genererad kod utan gränssnitt | Hyperlight CodeAct | Hyperlight microVM |
Go tillhandahåller lokal gränssnittskörning och miljösökning via tool/shelltool. Se Använda verktyget lokalt gränssnitt.
DockerShellTool vägledning är för närvarande inte tillgänglig för Go.
Använda shell-verktyg med Harness Agent
Vanliga agenter och HarnessAgent använder samma tvådelade gränssnittskonfiguration: registrera körfunktionen som ett verktyg och lägg till ShellEnvironmentProvider när modellen ska ta emot kontexten shell, operativsystem, arbetskatalog och CLI-version.
HarnessAgent skapar eller äger inte en shell-köre:
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 standardvärdet för namnet run_shell och requireApproval: true.
LocalShellExecutor standardvärdet är beständigt läge, ett 64-KiB-tak per utdataström och ingen tidsgräns. i exemplet används uttryckligen den rekommenderade 30-sekunders LocalShellExecutor.DefaultTimeout.
ShellEnvironmentProviderOptions standardvärdet för avsökning git, dotnet, node, pythonoch docker, med en timeout på fem sekunder per avsökning.
Skapa en beständig köre per användarsession och ta bort den när sessionen avslutas. Dela den inte mellan användare eller samtidiga konversationer eftersom arbetskatalog, miljö, gränssnittshistorik, bakgrundsjobb och kommandokön delas.
ShellPolicy är bara ett förfilter. håll godkännande aktiverat, använd minst privilegierade autentiseringsuppgifter och föredra DockerShellExecutor när kommandon kräver en starkare isoleringsgräns.
Shell-verktyg är tillgängliga från förhandsversionspaketet Microsoft.Agents.AI.Tools.Shell .
HarnessAgent är tillgängligt från Microsoft.Agents.AI.Harness.
För en vanlig agent skapar du shell-funktionen med client.get_shell_tool(func=shell.as_function()) och lägger till ShellEnvironmentProvider separat.
create_harness_agent utför båda stegen när du skickar 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 är opt-in och måste exponera as_function(). Fabriken lägger till shell-verktyget och ShellEnvironmentProvider endast när klienten implementerar SupportsShellTool. Annars loggar den en varning och hoppar över båda.
shell_environment_provider_options är valfritt och används endast med shell_executor.
LocalShellTool standardvärdet är beständigt läge, en 30-sekunders timeout, 64-KiB-kombinerade utdata, återankring av arbetskataloger och approval_mode="always_require". Eftersom Godkännande av användningsverktyget är aktiverat som standard skickar du ett AgentSession till run. Anroparen äger körlivscykeln. använd async with eller anropa close()och skapa ett beständigt verktyg per användarsession. Dela inte skaltillstånd som kan ändras mellan användare eller samtidiga konversationer.
Värdgränssnittet är inte en sandbox-miljö. Håll godkännande aktiverat, använd autentiseringsuppgifter med minst privilegier och använd DockerShellTool för containerisolering. Inaktivering av godkännande kräver approval_mode="never_require" och acknowledge_unsafe=True; ShellPolicy ensam är inte en säkerhetsgräns.
create_harness_agent släpps i agent-framework-core. Shell-integrering tillhandahålls av förhandsversionspaketet agent-framework-tools och genererar en ExperimentalWarning när den är aktiverad.
En paketerad Go-sele är inte tillgänglig för närvarande. Skapa det lokala gränssnittet och miljöprovidern direkt på en vanlig Go-agent.