عوامل التشغيل

يعرض تجريد العامل الأساسي خيارات مختلفة لتشغيل العامل. يمكن للمتصلين اختيار توفير صفر أو رسالة إدخال واحدة أو العديد من رسائل الإدخال. يمكن للمتصلين أيضا الاختيار بين البث وعدم البث. دعونا نتعمق في سيناريوهات الاستخدام المختلفة.

الدفق وعدم الدفق

يدعم Microsoft Agent Framework كلا من طرق الدفق وغير المتدفقة لتشغيل عامل.

بالنسبة إلى عدم الدفق، استخدم RunAsync الأسلوب .

Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?"));

للبث، استخدم RunStreamingAsync الأسلوب .

await foreach (var update in agent.RunStreamingAsync("What is the weather like in Amsterdam?"))
{
    Console.Write(update);
}

بالنسبة إلى عدم الدفق، استخدم run الأسلوب .

result = await agent.run("What is the weather like in Amsterdam?")
print(result.text)

للبث، استخدم run الأسلوب مع stream=True. يؤدي ذلك إلى إرجاع كائن ResponseStream يمكن تكراره بشكل غير متزامن:

async for update in agent.run("What is the weather like in Amsterdam?", stream=True):
    if update.text:
        print(update.text, end="", flush=True)

ResponseStream

ResponseStream يدعم الكائن الذي تم إرجاعه بواسطة run(..., stream=True) نمطي استهلاك:

النمط 1: التكرار غير المتزامن — معالجة التحديثات عند وصولها للعرض في الوقت الحقيقي:

response_stream = agent.run("Tell me a story", stream=True)
async for update in response_stream:
    if update.text:
        print(update.text, end="", flush=True)

النمط 2: الإكمال المباشر — تخطي التكرار والحصول على الاستجابة الكاملة:

response_stream = agent.run("Tell me a story", stream=True)
final = await response_stream.get_final_response()
print(final.text)

النمط 3: مدمج — تكرار العرض في الوقت الحقيقي، ثم الحصول على النتيجة المجمعة:

response_stream = agent.run("Tell me a story", stream=True)

# First, iterate to display streaming output
async for update in response_stream:
    if update.text:
        print(update.text, end="", flush=True)

# Then get the complete response (uses already-collected updates, does not re-iterate)
final = await response_stream.get_final_response()
print(f"\n\nFull response: {final.text}")
print(f"Messages: {len(final.messages)}")

في Go، RunText ترجع ResponseStream - مكرر أزواج (ResponseUpdate, error) .

بالنسبة إلى عدم الدفق، اتصل Collect() على الدفق لجمع جميع التحديثات في استجابة واحدة:

resp, err := a.RunText(ctx, "What is the weather like in Amsterdam?").Collect()
fmt.Println(resp, err)

للبث، كرر الدفق مباشرة باستخدام range حلقة:

for update, err := range a.RunText(ctx, "What is the weather like in Amsterdam?", agent.Stream(true)) {
    fmt.Print(update, err)
}

خيارات تشغيل العامل

يسمح تجريد العامل الأساسي بتمرير عنصر خيارات لكل تشغيل عامل، ولكن القدرة على تخصيص تشغيل على مستوى التجريد محدودة جدا. يمكن أن يختلف الوكلاء بشكل كبير وبالتالي لا توجد خيارات تخصيص شائعة حقا.

بالنسبة للحالات التي يعرف فيها المتصل نوع العامل الذي يعمل معه، من الممكن تمرير خيارات محددة للنوع للسماح بتخصيص التشغيل.

على سبيل المثال، هنا يكون العامل هو ChatClientAgent ومن الممكن تمرير كائن ChatClientAgentRunOptions يرث من AgentRunOptions. يسمح هذا للمتصل بتوفير مخصص ChatOptions يتم دمجه مع أي خيارات على مستوى العامل قبل تمريره إلى IChatClient الذي ChatClientAgent تم إنشاء عليه.

var chatOptions = new ChatOptions() { Tools = [AIFunctionFactory.Create(GetWeather)] };
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?", options: new ChatClientAgentRunOptions(chatOptions)));

يدعم وكلاء Python تخصيص كل تشغيل عبر المعلمة options . يتم تمرير الخيارات ك TypedDict ويمكن تعيينها في كل من وقت البناء (عبر default_options) وكل تشغيل (عبر options). لكل موفر فئة TypedDict الخاصة به التي توفر الإكمال التلقائي الكامل ل IDE والتحقق من النوع للإعدادات الخاصة بالموفر.

تشمل الخيارات الشائعة ما يلي:

  • max_tokens: الحد الأقصى لعدد الرموز المميزة التي يجب إنشاؤها
  • temperature: يتحكم في العشوائية في إنشاء الاستجابة
  • model: تجاوز النموذج لهذا التشغيل المحدد
  • top_p: معلمة أخذ عينات Nucleus
  • response_format: حدد تنسيق الاستجابة (على سبيل المثال، المخرجات المنظمة)

Note

tools تظل المعلمات و instructions كوسيطات كلمات أساسية مباشرة ولا يتم تمريرها عبر options القاموس.

from agent_framework.openai import OpenAIChatClient, OpenAIChatOptions

# Set default options at construction time
agent = OpenAIChatClient().as_agent(
    instructions="You are a helpful assistant",
    default_options={
        "temperature": 0.7,
        "max_tokens": 500
    }
)

# Run with custom options (overrides defaults)
# OpenAIChatOptions provides IDE autocomplete for all OpenAI-specific settings
options: OpenAIChatOptions = {
    "temperature": 0.3,
    "max_tokens": 150,
    "model": "gpt-4o",
    "presence_penalty": 0.5,
    "frequency_penalty": 0.3
}

result = await agent.run(
    "What is the weather like in Amsterdam?",
    options=options
)

# Streaming with custom options
async for update in agent.run(
    "Tell me a detailed weather forecast",
    stream=True,
    options={"temperature": 0.7, "top_p": 0.9},
    tools=[additional_weather_tool]  # tools is still a keyword argument
):
    if update.text:
        print(update.text, end="", flush=True)

كل موفر لديه فئة TypedDict الخاصة به (على سبيل المثال، OpenAIChatOptions، ، AnthropicChatOptions، OllamaChatOptions) التي تعرض المجموعة الكاملة من الخيارات التي يدعمها هذا الموفر.

عند توفير كل من default_options و لكل تشغيل options ، تكون لخيارات التشغيل الأسبقية ويتم دمجها مع الإعدادات الافتراضية.

يتم تمرير الخيارات كوسيطات variadic agent.Option . تتضمن الخيَارَات المُتَاحة الآتي:

  • agent.Stream(true) - تمكين الدفق
  • agent.WithSession(session) - إرفاق جلسة عمل للمحادثات متعددة الأدوار
  • agent.WithStructuredOutput(&v) - طلب إخراج منظم في قيمة مكتوبة
  • agent.WithResponseFormat(format) - تحديد تنسيق الاستجابة
  • agent.WithTool(tool) - إضافة أداة لهذا التشغيل
  • agent.AllowBackgroundResponses(true) - تمكين استجابات الخلفية
resp, err := a.RunText(ctx, "Tell me a joke.",
    agent.Stream(true),
    agent.WithSession(session),
).Collect()

أنواع الاستجابة

تحتوي الاستجابات المتدفقة وغير المتدفقة من الوكلاء على جميع المحتويات التي ينتجها العامل. قد يتضمن المحتوى بيانات ليست النتيجة (أي الإجابة على سؤال المستخدم) من العامل. تتضمن أمثلة البيانات الأخرى التي تم إرجاعها استدعاءات أداة الدالة والنتائج من استدعاءات أداة الدالة ونص المنطق وتحديثات الحالة وغيرها الكثير.

نظرا لأن المحتوى الذي تم إرجاعه ليس هو النتيجة، فمن المهم البحث عن أنواع محتويات معينة عند محاولة عزل النتيجة عن المحتوى الآخر.

لاستخراج نتيجة النص من استجابة، يجب تجميع كافة TextContent العناصر من كافة ChatMessages العناصر. لتبسيط هذا، Text تتوفر خاصية على جميع أنواع الاستجابة التي تجمع جميع TextContent.

بالنسبة للحالة غير المتدفقة، يتم إرجاع كل شيء في كائن واحد AgentResponse . AgentResponse يسمح بالوصول إلى الرسائل المنتجة عبر الخاصية Messages .

var response = await agent.RunAsync("What is the weather like in Amsterdam?");
Console.WriteLine(response.Text);
Console.WriteLine(response.Messages.Count);

بالنسبة لحالة الدفق، AgentResponseUpdate يتم دفق الكائنات أثناء إنتاجها. قد يحتوي كل تحديث على جزء من النتيجة من العامل، بالإضافة إلى عناصر محتوى أخرى مختلفة. على غرار حالة عدم الدفق، من الممكن استخدام الخاصية Text للحصول على جزء من النتيجة الواردة في التحديث، والتعمق في التفاصيل عبر الخاصية Contents .

await foreach (var update in agent.RunStreamingAsync("What is the weather like in Amsterdam?"))
{
    Console.WriteLine(update.Text);
    Console.WriteLine(update.Contents.Count);
}

بالنسبة للحالة غير المتدفقة، يتم إرجاع كل شيء في كائن واحد AgentResponse . AgentResponse يسمح بالوصول إلى الرسائل المنتجة عبر الخاصية messages .

لاستخراج نتيجة النص من استجابة، يجب تجميع كافة TextContent العناصر من كافة Message العناصر. لتبسيط هذا، Text تتوفر خاصية على جميع أنواع الاستجابة التي تجمع جميع TextContent.

response = await agent.run("What is the weather like in Amsterdam?")
print(response.text)
print(len(response.messages))

# Access individual messages
for message in response.messages:
    print(f"Role: {message.role}, Text: {message.text}")

بالنسبة لحالة الدفق، AgentResponseUpdate يتم دفق الكائنات كما يتم إنتاجها عبر التي ResponseStream تم إرجاعها بواسطة run(..., stream=True). قد يحتوي كل تحديث على جزء من النتيجة من العامل، بالإضافة إلى عناصر محتوى أخرى مختلفة. على غرار حالة عدم الدفق، من الممكن استخدام الخاصية text للحصول على جزء من النتيجة الواردة في التحديث، والتعمق في التفاصيل عبر الخاصية contents .

response_stream = agent.run("What is the weather like in Amsterdam?", stream=True)
async for update in response_stream:
    print(f"Update text: {update.text}")
    print(f"Content count: {len(update.contents)}")

    # Access individual content items
    for content in update.contents:
        if hasattr(content, 'text'):
            print(f"Content: {content.text}")

# Get the aggregated final response after streaming
final = await response_stream.get_final_response()
print(f"Complete text: {final.text}")

ResponseStream ينتج القيم *agent.ResponseUpdate . يحتوي كل تحديث على:

  • Contents - شريحة من message.Content القيم، مثل النص واستدعاءات الدالة والاستخدام
  • Role - دور الرسالة، مثل المساعد أو النظام
  • MessageID / ResponseID - معرفات الرسالة والاستجابة

للحصول على نتيجة النص الكامل من استجابة غير متدفقة، استخدم Collect():

resp, err := a.RunText(ctx, "What is the weather like in Amsterdam?").Collect()
fmt.Println(resp, err)

أنواع الرسائل

يتم تمثيل الإدخال والإخراج من العوامل كرسائل. يتم تقسيم الرسائل إلى عناصر محتوى.

يستخدم Microsoft Agent Framework أنواع الرسائل والمحتوى التي توفرها التجريداتMicrosoft.Extensions.AI. يتم تمثيل الرسائل بواسطة ChatMessage الفئة وترث كافة فئات المحتوى من الفئة الأساسية AIContent .

توجد فئات فرعية مختلفة AIContent تستخدم لتمثيل أنواع مختلفة من المحتوى. يتم توفير بعضها كجزء من التجريدات الأساسية Microsoft.Extensions.AI ، ولكن يمكن للموفرين أيضا إضافة أنواعهم الخاصة، عند الحاجة.

فيما يلي بعض الأنواع الشائعة من Microsoft.Extensions.AI:

Type Description
TextContent المحتوى النصي الذي يمكن أن يكون إدخالا، على سبيل المثال، من مستخدم أو مطور، وإخراج من العامل. عادة ما يحتوي على نتيجة النص من عامل.
DataContent المحتوى الثنائي الذي يمكن أن يكون كلا من الإدخال والإخراج. يمكن استخدامها لتمرير بيانات الصورة أو الصوت أو الفيديو من وإلى العامل (حيثما كان مدعوما).
UriContent عنوان URL يشير عادة إلى المحتوى المستضاف مثل صورة أو صوت أو فيديو.
FunctionCallContent طلب من قبل خدمة استدلال لاستدعاء أداة دالة.
FunctionResultContent نتيجة استدعاء أداة دالة.

يستخدم Python Agent Framework أنواع الرسائل والمحتوى من الحزمةagent_framework. يتم تمثيل الرسائل بواسطة Message الفئة ويتم تمثيل جميع عناصر المحتوى من قبل الفئة التي Content تميزها الخاصية type .

يتم تمثيل كل المحتوى بواسطة الفئة الموحدة Content مع أساليب المصنع لكل نوع محتوى. استخدم الخاصية type للتحقق من نوع المحتوى. تتوفر أنواع المحتويات التالية:

نوع المحتوى أسلوب المصنع Description
"text" Content.from_text() المحتوى النصي للإدخل والإخراج. عادة ما يحتوي على نتيجة النص من عامل.
"text_reasoning" Content.from_text_reasoning() تحليل النص من النماذج التي تدعم تحليل سلسلة التفكير. قد يتضمن بيانات محمية.
"data" Content.from_data()، Content.from_uri() محتوى ثنائي مرمز ك URI للبيانات. يستخدم للصور والصوت والفيديو والمستندات.
"uri" Content.from_uri() عنوان URL يشير إلى محتوى مستضاف مثل صورة أو صوت أو فيديو.
"error" Content.from_error() معلومات الخطأ عند فشل المعالجة. يتضمن رمز الخطأ الاختياري والتفاصيل.
"function_call" Content.from_function_call() طلب من قبل خدمة الذكاء الاصطناعي لاستدعاء أداة وظيفة.
"function_result" Content.from_function_result() نتيجة استدعاء أداة دالة.
"usage" Content.from_usage() استخدام الرمز المميز ومعلومات الفوترة من خدمة الذكاء الاصطناعي.
"hosted_file" Content.from_hosted_file() مرجع إلى ملف مستضاف من قبل الموفر (على سبيل المثال، تم تحميله إلى OpenAI).
"hosted_vector_store" Content.from_hosted_vector_store() مرجع إلى مخزن متجهات يستضيفه الموفر.
"code_interpreter_tool_call" Content.from_code_interpreter_tool_call() طلب من خدمة الذكاء الاصطناعي لتنفيذ التعليمات البرمجية عبر مترجم التعليمات البرمجية.
"code_interpreter_tool_result" Content.from_code_interpreter_tool_result() نتيجة تنفيذ مترجم التعليمات البرمجية.
"image_generation_tool_call" Content.from_image_generation_tool_call() طلب من خدمة الذكاء الاصطناعي لإنشاء صورة.
"image_generation_tool_result" Content.from_image_generation_tool_result() نتيجة طلب إنشاء صورة.
"mcp_server_tool_call" Content.from_mcp_server_tool_call() طلب لاستدعاء أداة على خادم MCP.
"mcp_server_tool_result" Content.from_mcp_server_tool_result() نتيجة استدعاء أداة خادم MCP.
"shell_tool_call" Content.from_shell_tool_call() طلب من خدمة الذكاء الاصطناعي لتنفيذ أوامر shell.
"shell_tool_result" Content.from_shell_tool_result() النتيجة الإجمالية لاستدعاء أداة shell.
"shell_command_output" Content.from_shell_command_output() إخراج تنفيذ أمر shell واحد.
"function_approval_request" Content.from_function_approval_request() طلب موافقة المستخدم قبل تنفيذ استدعاء دالة.
"function_approval_response" Content.from_function_approval_response() استجابة المستخدم لطلب الموافقة على وظيفة.
"oauth_consent_request" Content.from_oauth_consent_request() طلب للمستخدم لإكمال موافقة OAuth عبر ارتباط مقدم.

تظل رفضات الموفر مرئية ك Content(type="text"). عندما يعرض الموفر دلالات الرفض، Python يحافظ على العلامة additional_properties["model_output_kind"] == "refusal"التجريبية القابلة للتسلسل . لا يقوم استخراج الإخراج المنظم بتحليل النص الذي يحمل هذه العلامة.

فيما يلي كيفية العمل مع أنواع محتويات مختلفة:

from agent_framework import Message, Content

# Create a text message
text_message = Message(role="user", contents=["Hello!"])

# Create a message with multiple content types
image_data = b"..."  # your image bytes
mixed_message = Message(
    role="user",
    contents=[
        Content.from_text("Analyze this image:"),
        Content.from_data(data=image_data, media_type="image/png"),
    ]
)

# Access content from responses
response = await agent.run("Describe the image")
for message in response.messages:
    for content in message.contents:
        if content.type == "text":
            print(f"Text: {content.text}")
        elif content.type == "data":
            print(f"Data URI: {content.uri}")
        elif content.type == "uri":
            print(f"External URI: {content.uri}")

يستخدم Go Agent Framework أنواع الرسائل والمحتوى من الحزمة message . يمكن أن تحتوي تحديثات الاستجابة على عناصر محتوى متعددة؛ افحص كل عنصر بحثا عن نوع المحتوى الذي تحتاجه.

للبث، قم بمعالجة التحديثات بشكل فردي عند وصولها:

for update, err := range a.RunText(ctx, "Tell me a story.", agent.Stream(true)) {
    fmt.Print(err)
    for _, c := range update.Contents {
        if text, ok := c.(*message.TextContent); ok {
            fmt.Print(text.Text)
        }
    }
}

Tip

راجع النموذج الكامل للحصول على مثال كامل قابل للتشغيل.

الخطوات التالية