إشعار
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تسجيل الدخول أو تغيير الدلائل.
يتطلب الوصول إلى هذه الصفحة تخويلاً. يمكنك محاولة تغيير الدلائل.
توفر حزمة Python بيتا agent-framework-tools أدوات تنفيذ shell والتوعية بالبيئة agent_framework.tools من خلال مساحة الاسم.
| الأداة | استخدمه عندما |
|---|---|
LocalShellTool |
الأوامر موثوق بها أو معتمدة بشكل فردي ويجب تشغيلها في بيئة مضيف عملية العامل. |
DockerShellTool |
تحتاج أوامر shell التي تم إنشاؤها بواسطة النموذج إلى عزل حاوية OCI. |
ShellEnvironmentProvider |
يحتاج النموذج إلى عائلة shell النشطة ونظام التشغيل ودليل العمل وإصدارات CLI المثبتة. |
ShellPolicy |
تريد تصفية مسبقة لقائمة السماح أو قائمة الرفض قبل الموافقة أو التنفيذ. |
تحذير
يمكن لتنفيذ Shell تعديل الملفات، وتشغيل العمليات، والوصول إلى بيانات الاعتماد، والتواصل مع الأنظمة الخارجية. استخدم طبقة التنفيذ الأقل امتيازا التي تدعم المهمة.
تثبيت الحزمة
dotnet add package Microsoft.Agents.AI.Tools.Shell --prerelease
استخدام shell المحلي والوعي بالبيئة
LocalShellExecutor يدعم الأوضاع عديمة الحالة والمستمرة.
ShellEnvironmentProvider فحص البيئة النشطة وإضافة إرشادات shell موثوقة إلى سياق العامل.
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 يتوفر أيضا للتصفية المسبقة للأمر. عينة مخصصة قابلة للتشغيل DockerShellExecutor غير منشورة حاليا.
تثبيت الحزمة
pip install agent-framework-tools --pre
يتم تثبيت الحزمة psutil لإنهاء أشجار المعالجة التابعة عند انتهاء مهلة التنفيذ.
استخدام LocalShellTool
LocalShellTool تشغيل الأوامر مباشرة على المضيف. يتم تعيينه افتراضيا إلى shell مستمر، ومهلة 30 ثانية، واقتطاع إخراج 64 كيبيبايت، وإعادة ارتساء دليل العمل. تتطلب استدعاءات العامل من خلال as_function() الموافقة بشكل افتراضي. المكالمات المباشرة ل run() لا تطلب الموافقة.
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())
استدعاءات مباشرة لإرجاع مع حقول منفصلة exit_codetimed_outstderrtruncatedstdoutduration_msو.run()ShellResult عند تشغيل shell من خلال استجابات OpenAI أو استضافة Foundry، يحافظ إطار عمل العامل على الإخراج القياسي والخطأ القياسي ونتائج الخروج ونتائج المهلة عبر متابعة الموفر. تظل المخارج غير الصفرية حالات فشل، ويظل الخطأ القياسي منفصلا، ولا تظهر المهلة كإنهاء ناجح.
تظل عناصر نص shell المستضافة من قبل موفر OpenAI إعلامية، حتى عند تكوين منفذ shell محلي. يدخل فقط مكالمة shell أو local_shell_callأو مكالمة shell التي تم تشكيلها environment.type="local"بشكل جيد بالدالة المحلية ومسار الموافقة. لا يؤدي التكوين LocalShellTool وحده إلى تنفيذ استدعاءات shell المستضافة من قبل الموفر على المضيف.
استخدم mode="stateless" عندما يجب تشغيل كل مكالمة في عملية جديدة.
AGENT_FRAMEWORK_SHELL استخدم متغير البيئة أو وسيطة الدالة shell الإنشائية لتجاوز shell الذي تم حله.
Important
LocalShellTool ليس بيئة الاختبار المعزولة. تضيف الموافقة البشرية بوابة مراجعة، ولكنها لا تعزل shell. يتطلب تعطيل الموافقة على استدعاءات acknowledge_unsafe=Trueالعامل .
تقييد الأوامر باستخدام ShellPolicy
ShellPolicy تطبيق قوائم السماح بالتعبير العادي ورفضها على نص الأمر قبل التنفيذ. قواعد الرفض لها الأسبقية. لا يفحص ما ينفذه shell في النهاية أو يقيد الوصول إلى الملفات.
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",
# Unsafe for production as shown: these filters do not replace human approval or isolation.
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=("Use only these shell commands: ls, pwd, cat, git status/log/diff, python --version."),
tools=[client.get_shell_tool(func=shell.as_function())],
)
تحذير
العينة تعطل الموافقة البشرية وهي مناسبة فقط لبيئة معزولة يمكن التخلص منها دون أسرار أو بيانات قيمة. يمكن أن تمر عمليات استبدال الأوامر، مثل $(...) و backticks، بأنماط قائمة السماح البسيطة. يمكن أن تسمح الأنماط التي تطابق بداية الأمر فقط بعمليات إضافية. استخدم العزل المفروض بشكل منفصل والأذونات المقيدة للإنتاج. يمكن أن تضيف المراجعة البشرية فحصا، ولكنها لا تعزل shell.
تفضل أنماط السلسلة. يقوم Python بتجميع السلاسل مع regex المحرك وتطبيق ميزانية ثانية واحدة على كل تطابق. ترفض مهلة قائمة الرفض الأمر، ولا تمنح مهلة قائمة السماح الإذن. يستخدم التحويل regex.Pattern البرمجي المسبق نفس الربط. تحتفظ المكتبة القياسية مسبقة re.Pattern التحويل البرمجي بعلاماتها ولكن لا يمكن مقاطعتها، لذا تجنب التعبيرات المكلفة أو الغامضة في هذا النموذج.
إضافة ShellEnvironmentProvider
ShellEnvironmentProvider فحص عائلة shell، والإصدار، ونظام التشغيل، ودليل العمل، وإصدارات CLI المحددة، ثم إدخال هذه المعلومات قبل تشغيل العامل. قائمة التحقيق الافتراضية هي gitو nodepythonو و.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)
استخدام DockerShellTool
DockerShellTool يتطلب Docker أو Podman على PATH. تقوم الإعدادات الافتراضية بتعطيل الشبكات، وتشغيلها كمستخدم غير جذر، واستخدام نظام ملفات جذر للقراءة فقط، وإفلات الإمكانات، والحد من الذاكرة إلى 512 ميجابايت، والحد الأقصى للحاوية عند 256 عملية.
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)
الصورة الافتراضية هي mcr.microsoft.com/azurelinux/base/core:3.0. تمرير docker_binary="podman" لاستخدام Podman. عينة مخصصة قابلة للتشغيل DockerShellTool غير منشورة حاليا.
استخدم extra_run_args فقط لخيارات Docker التي لا تضعف حدود العزل أو الموارد المكونة. يتعرف التحقق من الصحة على العلامات الطويلة والعلامات القصيرة والقيم المرفقة والعلامات القصيرة المجمعة. يرفض التجاوزات مثل -u--user / و.--pids-limit-m / --memory-v / --volume--network استخدم خيار الدالة الإنشائية المطابقة DockerShellTool بدلا من ذلك.
اختيار مستوى تنفيذ
| السيناريو | الأداة | حد العزل |
|---|---|---|
| أوامر التطوير الموثوق بها | LocalShellTool |
بلا؛ يتم تمكين الموافقة البشرية بشكل افتراضي |
| أوامر shell غير موثوق بها | DockerShellTool |
حاوية OCI مع علامات العزل الافتراضية |
| التعليمات البرمجية التي تم إنشاؤها غير موثوق بها بدون shell | Hyperlight CodeAct | Hyperlight microVM |
يوفر Go تنفيذ shell المحلي وتصفح البيئة من خلال tool/shelltool. راجع استخدام أداة shell المحلية.
DockerShellTool الإرشادات غير متوفرة حاليا ل Go.
استخدام أدوات shell مع Harness Agent
وكلاء عاديون HarnessAgent ويستخدمون نفس إعداد shell المكون من جزئين: تسجيل وظيفة المنفذ كأداة، وإضافة ShellEnvironmentProvider متى يجب أن يتلقى النموذج shell ونظام التشغيل ودليل العمل وسياق إصدار CLI.
HarnessAgent لا يقوم بإنشاء أو امتلاك منفذ shell:
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 الإعدادات الافتراضية للاسم run_shell و requireApproval: true.
LocalShellExecutor الإعدادات الافتراضية إلى الوضع الثابت، وقبعة 64 كيبيبايت لكل دفق إخراج، وبدون مهلة؛ يستخدم المثال بشكل صريح 30 ثانية LocalShellExecutor.DefaultTimeoutالموصى بها .
ShellEnvironmentProviderOptionsافتراضيات فحص gitو pythondotnetnodeو dockerمع مهلة خمس ثوان لكل مسبار.
إنشاء منفذ ثابت واحد لكل جلسة عمل مستخدم والتخلص منه عند انتهاء جلسة العمل. لا تشاركه عبر المستخدمين أو المحادثات المتزامنة لأنه تتم مشاركة دليل العمل والبيئة ومحفوظات shell ووظائف الخلفية وقوائم انتظار الأوامر.
ShellPolicy هو فقط عامل تصفية مسبق؛ حافظ على تمكين الموافقة، واستخدم بيانات الاعتماد الأقل امتيازا، وتفضل DockerShellExecutor عندما تتطلب الأوامر حدود عزل أقوى.
تتوفر أدوات Shell من حزمة الإصدار التجريبي Microsoft.Agents.AI.Tools.Shell .
HarnessAgent متوفر من Microsoft.Agents.AI.Harness.
بالنسبة إلى عامل عادي، قم بإنشاء دالة shell مع client.get_shell_tool(func=shell.as_function()) وإضافتها ShellEnvironmentProvider بشكل منفصل.
create_harness_agent ينفذ كلا الخطوتين عند اجتياز 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 هو الاشتراك ويجب أن يعرض as_function(). يضيف المصنع أداة shell وفقط ShellEnvironmentProvider عندما ينفذ SupportsShellToolالعميل ؛ وإلا فإنه يسجل تحذيرا ويتخطى كليهما.
shell_environment_provider_options اختياري ويستخدم فقط مع shell_executor.
LocalShellTool الإعدادات الافتراضية إلى الوضع الثابت، ومهلة 30 ثانية، وإخراج مجمع 64 كيبيبايت، وإعادة إرساء دليل العمل، و approval_mode="always_require". نظرا لأن الموافقة على أداة Harness ممكنة بشكل افتراضي، قم بتمرير AgentSession إلى run. يمتلك المتصل دورة حياة المنفذ؛ استخدم async with أو استدع close()، وأنشئ أداة ثابتة واحدة لكل جلسة عمل مستخدم. لا تشارك حالة shell القابلة للتغيير عبر المستخدمين أو المحادثات المتزامنة.
واجهة المضيف ليست بيئة الاختبار المعزولة. حافظ على تمكين الموافقة، واستخدم بيانات الاعتماد الأقل امتيازا، واستخدم DockerShellTool لعزل الحاوية. يتطلب تعطيل الموافقة approval_mode="never_require" و acknowledge_unsafe=True؛ ShellPolicy وحده ليس حد أمان.
create_harness_agent تم إصداره في agent-framework-core. يتم توفير تكامل Shell بواسطة حزمة ما قبل الإصدار agent-framework-tools ويصدر ExperimentalWarning عند التمكين.
لا تتوفر حاليا حزمة Go Harness. قم بإنشاء أداة shell المحلية وموفر البيئة مباشرة على عامل Go عادي.