إنتاج المخرجات المنظمة مع العوامل

توضح لك خطوة البرنامج التعليمي هذه كيفية إنتاج مخرجات منظمة مع عامل، حيث يتم بناء العامل على خدمة إكمال دردشة OpenAI Azure.

Important

لا تدعم جميع أنواع الوكلاء المخرجات المنظمة في الأصل. ChatClientAgent يدعم المخرجات المنظمة عند استخدامها مع عملاء الدردشة المتوافقين.

المتطلبات الأساسية

للحصول على المتطلبات الأساسية وتثبيت حزم NuGet، راجع خطوة إنشاء وتشغيل عامل بسيط في هذا البرنامج التعليمي.

تعريف نوع للمخرجات المنظمة

أولا، حدد نوعا يمثل بنية الإخراج الذي تريده من العامل.

public class PersonInfo
{
    public string? Name { get; set; }
    public int? Age { get; set; }
    public string? Occupation { get; set; }
}

أنشئ الوكيل

ChatClientAgent إنشاء باستخدام عميل مشاريع الذكاء الاصطناعي Azure.

using System;
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;

AIAgent agent = new AIProjectClient(
    new Uri("<your-foundry-project-endpoint>"),
    new DefaultAzureCredential())
        .AsAIAgent(
            model: "gpt-4o-mini",
            name: "HelpfulAssistant",
            instructions: "You are a helpful assistant.");

تحذير

DefaultAzureCredential مناسب للتنمية ولكنه يتطلب دراسة متأنية في الإنتاج. في الإنتاج، ضع في اعتبارك استخدام بيانات اعتماد محددة (على سبيل المثال، ManagedIdentityCredential) لتجنب مشكلات زمن الانتقال، وبحث بيانات الاعتماد غير المقصودة، والمخاطر الأمنية المحتملة من الآليات الاحتياطية.

المخرجات المنظمة باستخدام RunAsync<T>

RunAsync<T> يتوفر الأسلوب في AIAgent الفئة الأساسية. يقبل معلمة نوع عام تحدد نوع المخرجات المنظمة. ينطبق هذا الأسلوب عندما يكون نوع المخرجات المنظمة معروفا في وقت التحويل البرمجي وتحتاج إلى مثيل نتيجة مكتوبة. وهو يدعم البدائيات والصفائف والأنواع المعقدة.

AgentResponse<PersonInfo> response = await agent.RunAsync<PersonInfo>("Please provide information about John Smith, who is a 35-year-old software engineer.");

Console.WriteLine($"Name: {response.Result.Name}, Age: {response.Result.Age}, Occupation: {response.Result.Occupation}");

المخرجات المنظمة مع ResponseFormat

يمكن تكوين المخرجات المنظمة عن طريق تعيين ResponseFormat الخاصية في AgentRunOptions وقت استدعاء، أو في وقت تهيئة العامل للوكلاء الذين يدعمونها، مثل ChatClientAgent و Foundry Agent.

ينطبق هذا النهج عندما:

  • لا يعرف نوع المخرجات المنظمة في وقت التحويل البرمجي.
  • يتم تمثيل المخطط ك JSON أولي.
  • يمكن تكوين المخرجات المنظمة فقط في وقت إنشاء العامل.
  • مطلوب فقط نص JSON الخام دون إلغاء التسلسل.
  • يتم استخدام التعاون بين الوكلاء.

تتوفر خيارات مختلفة ل ResponseFormat :

  • خاصية مضمنة ChatResponseFormat.Text : ستكون الاستجابة نصا عاديا.
  • خاصية مضمنة ChatResponseFormat.Json : ستكون الاستجابة كائن JSON دون أي مخطط معين.
  • مثيل مخصص ChatResponseFormatJson : ستكون الاستجابة كائن JSON يتوافق مع مخطط معين.

Note

لا يدعم ResponseFormat النهج البدائيات والصفائف. إذا كنت بحاجة إلى العمل مع البدائيات أو الصفائف، فاستخدم RunAsync<T> الأسلوب أو أنشئ نوع برنامج تضمين.

// Instead of using List<string> directly, create a wrapper type:
public class MovieListWrapper
{
    public List<string> Movies { get; set; }
}
using System.Text.Json;
using Microsoft.Extensions.AI;

AgentRunOptions runOptions = new()
{
    ResponseFormat = ChatResponseFormat.ForJsonSchema<PersonInfo>()
};

AgentResponse response = await agent.RunAsync("Please provide information about John Smith, who is a 35-year-old software engineer.", options: runOptions);

PersonInfo personInfo = JsonSerializer.Deserialize<PersonInfo>(response.Text, JsonSerializerOptions.Web)!;

Console.WriteLine($"Name: {personInfo.Name}, Age: {personInfo.Age}, Occupation: {personInfo.Occupation}");

ResponseFormat يمكن أيضا تحديد باستخدام سلسلة مخطط JSON الأولية، وهو أمر مفيد عندما لا يتوفر نوع .NET مطابق، مثل العوامل التعريفية أو المخططات المحملة من التكوين الخارجي:

string jsonSchema = """
{
    "type": "object",
    "properties": {
        "name": { "type": "string" },
        "age": { "type": "integer" },
        "occupation": { "type": "string" }
    },
    "required": ["name", "age", "occupation"]
}
""";

AgentRunOptions runOptions = new()
{
    ResponseFormat = ChatResponseFormat.ForJsonSchema(JsonElement.Parse(jsonSchema), "PersonInfo", "Information about a person")
};

AgentResponse response = await agent.RunAsync("Please provide information about John Smith, who is a 35-year-old software engineer.", options: runOptions);

JsonElement result = JsonSerializer.Deserialize<JsonElement>(response.Text);

Console.WriteLine($"Name: {result.GetProperty("name").GetString()}, Age: {result.GetProperty("age").GetInt32()}, Occupation: {result.GetProperty("occupation").GetString()}");

المخرجات المنظمة مع الدفق

عند الدفق، يتم دفق استجابة العامل كسلسلة من التحديثات، ويمكنك فقط إلغاء تسلسل الاستجابة بمجرد تلقي جميع التحديثات. يجب تجميع جميع التحديثات في استجابة واحدة قبل إلغاء تسلسلها.

using System.Text.Json;
using Microsoft.Extensions.AI;

AIAgent agent = new AIProjectClient(
    new Uri("<your-foundry-project-endpoint>"),
    new DefaultAzureCredential())
        .AsAIAgent(new ChatClientAgentOptions()
        {
            Name = "HelpfulAssistant",
            ChatOptions = new()
            {
                ModelId = "gpt-4o-mini",
                Instructions = "You are a helpful assistant.",
                ResponseFormat = ChatResponseFormat.ForJsonSchema<PersonInfo>()
            }
        });

> [!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.

IAsyncEnumerable<AgentResponseUpdate> updates = agent.RunStreamingAsync("Please provide information about John Smith, who is a 35-year-old software engineer.");

AgentResponse response = await updates.ToAgentResponseAsync();

PersonInfo personInfo = JsonSerializer.Deserialize<PersonInfo>(response.Text)!;

Console.WriteLine($"Name: {personInfo.Name}, Age: {personInfo.Age}, Occupation: {personInfo.Occupation}");

مخرجات منظمة مع عوامل بدون قدرات مخرجات منظمة

لا يدعم بعض العوامل في الأصل المخرجات المنظمة، إما لأنها ليست جزءا من البروتوكول أو لأن الوكلاء يستخدمون نماذج اللغة دون قدرات مخرجات منظمة. أحد النهج المحتملة هو إنشاء عامل مصمم مخصص يلتف أي AIAgent ويستخدم مكالمة LLM إضافية عبر عميل دردشة لتحويل استجابة نص العامل إلى JSON منظم.

Note

نظرا لأن هذا النهج يعتمد على استدعاء LLM إضافي لتحويل الاستجابة، فقد لا تكون موثوقيتها كافية لجميع السيناريوهات.

للحصول على تنفيذ مرجعي لهذا النمط الذي يمكنك تكييفه مع متطلباتك الخاصة، راجع نموذج StructuredOutputAgent.

Tip

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

مثال الدفق

Tip

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

توضح لك خطوة البرنامج التعليمي هذه كيفية إنتاج مخرجات منظمة مع عامل، حيث يتم بناء العامل على خدمة إكمال دردشة OpenAI Azure.

Important

لا تدعم جميع أنواع الوكلاء المخرجات المنظمة. Agent يدعم المخرجات المنظمة عند استخدامها مع عملاء الدردشة المتوافقين.

المتطلبات الأساسية

للحصول على المتطلبات الأساسية وتثبيت الحزم، راجع خطوة إنشاء وتشغيل عامل بسيط في هذا البرنامج التعليمي.

إنشاء العامل بمخرجات منظمة

Agent تم بناء على أي تنفيذ لعميل الدردشة يدعم المخرجات المنظمة. Agent يستخدم response_format المفتاح في الإملاء options لتحديد مخطط الإخراج المطلوب.

عند تشغيل العامل، يمكنك توفير إما:

  • نموذج Pydantic الذي يحدد بنية الإخراج المتوقع.
  • تعيين مخطط JSON (dict) عندما تريد تحليل JSON دون تعريف فئة نموذج.

يمكنك تمرير options الإملاء في وقت التشغيل عبر agent.run(..., options={"response_format": ...})، أو تعيينه في وقت إنشاء العامل عبر default_options الإملاء.

يتم دعم تنسيقات الاستجابة المختلفة استنادا إلى قدرات عميل الدردشة الأساسية.

ينشئ المثال الأول عامل ينتج مخرجات منظمة في شكل كائن JSON يتوافق مع مخطط نموذج Pydantic.

أولا، حدد نموذج Pydantic الذي يمثل بنية الإخراج الذي تريده من العامل:

from pydantic import BaseModel

class PersonInfo(BaseModel):
    """Information about a person."""
    name: str | None = None
    age: int | None = None
    occupation: str | None = None

الآن يمكنك إنشاء عامل باستخدام عميل دردشة Azure OpenAI:

import os
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity import AzureCliCredential

# Create the agent using Azure OpenAI Chat Client
agent = OpenAIChatCompletionClient(
    model=os.environ["AZURE_OPENAI_CHAT_COMPLETION_MODEL"],
    azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
    api_version=os.getenv("AZURE_OPENAI_API_VERSION"),
    credential=AzureCliCredential(),
).as_agent(
    name="HelpfulAssistant",
    instructions="You are a helpful assistant that extracts person information from text."
)

الآن يمكنك تشغيل العامل مع بعض المعلومات النصية وتحديد تنسيق المخرجات المنظمة باستخدام response_format المفتاح في options الإملاء:

response = await agent.run(
    "Please provide information about John Smith, who is a 35-year-old software engineer.",
    options={"response_format": PersonInfo},
)

بالنسبة لتنسيق استجابة نموذج Pydantic، تحتوي استجابة العامل على المخرجات المنظمة في الخاصية value كمثيل نموذج:

if response.value:
    person_info = response.value
    print(f"Name: {person_info.name}, Age: {person_info.age}, Occupation: {person_info.occupation}")
else:
    print("No structured data found in response")

استخدام تعيين مخطط JSON

إذا كان لديك بالفعل مخطط JSON كمخطط Python، فمرر هذا المخطط مباشرة كقيمة response_formatoptions في الإملاء. في هذا الوضع، response.value يحتوي على قيمة JSON التي تم تحليلها (عادة أو listdict ) بدلا من مثيل نموذج Pydantic.

person_info_schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer"},
        "occupation": {"type": "string"},
    },
    "required": ["name", "age", "occupation"],
}

response = await agent.run(
    "Please provide information about John Smith, who is a 35-year-old software engineer.",
    options={"response_format": person_info_schema},
)

if response.value:
    person_info = response.value
    print(f"Name: {person_info['name']}, Age: {person_info['age']}, Occupation: {person_info['occupation']}")

عند الدفق، agent.run(..., stream=True) ترجع ResponseStream. تعالج أداة الإنهاء المضمنة للدفق تلقائيا تحليل المخرجات المنظمة، بحيث يمكنك التكرار للتحديثات في الوقت الفعلي ثم الاتصال get_final_response() للحصول على النتيجة التي تم تحليلها:

# Stream updates in real time, then get the structured result
stream = agent.run(query, stream=True, options={"response_format": PersonInfo})
async for update in stream:
    print(update.text, end="", flush=True)

# get_final_response() returns the AgentResponse with the parsed value
final_response = await stream.get_final_response()

if final_response.value:
    person_info = final_response.value
    print(f"Name: {person_info.name}, Age: {person_info.age}, Occupation: {person_info.occupation}")

تنطبق نفس القاعدة عندما response_format تكون تعيين مخطط JSON: final_response.value يحتوي على JSON محلل بدلا من مثيل نموذج Pydantic.

إذا لم تكن بحاجة إلى معالجة تحديثات الدفق الفردية، يمكنك تخطي التكرار بالكامل — get_final_response() سيستهلك الدفق تلقائيا:

stream = agent.run(query, stream=True, options={"response_format": PersonInfo})
final_response = await stream.get_final_response()

if final_response.value:
    person_info = final_response.value
    print(f"Name: {person_info.name}, Age: {person_info.age}, Occupation: {person_info.occupation}")

مثال كامل

# Copyright (c) Microsoft. All rights reserved.

import asyncio

from agent_framework.openai import OpenAIChatClient
from pydantic import BaseModel

"""
OpenAI Responses Client with Structured Outputs Example

This sample demonstrates using structured outputs capabilities with OpenAI Responses Client,
showing Pydantic model integration for type-safe response parsing and data extraction.
"""


class OutputStruct(BaseModel):
    """A structured outputs model for testing purposes."""

    city: str
    description: str


async def non_streaming_example() -> None:
    print("=== Non-streaming example ===")

    agent = OpenAIChatClient().as_agent(
        name="CityAgent",
        instructions="You are a helpful agent that describes cities in a structured format.",
    )

    query = "Tell me about Paris, France"
    print(f"User: {query}")

    result = await agent.run(query, options={"response_format": OutputStruct})

    if structured_data := result.value:
        print("Structured Outputs Agent:")
        print(f"City: {structured_data.city}")
        print(f"Description: {structured_data.description}")
    else:
        print(f"Failed to parse response: {result.text}")


async def streaming_example() -> None:
    print("=== Streaming example ===")

    agent = OpenAIChatClient().as_agent(
        name="CityAgent",
        instructions="You are a helpful agent that describes cities in a structured format.",
    )

    query = "Tell me about Tokyo, Japan"
    print(f"User: {query}")

    # Stream updates in real time using ResponseStream
    stream = agent.run(query, stream=True, options={"response_format": OutputStruct})
    async for update in stream:
        if update.text:
            print(update.text, end="", flush=True)
    print()

    # get_final_response() returns the AgentResponse with structured outputs parsed
    result = await stream.get_final_response()

    if structured_data := result.value:
        print("Structured Outputs (from streaming with ResponseStream):")
        print(f"City: {structured_data.city}")
        print(f"Description: {structured_data.description}")
    else:
        print(f"Failed to parse response: {result.text}")


async def main() -> None:
    print("=== OpenAI Responses Agent with Structured Outputs ===")

    await non_streaming_example()
    await streaming_example()


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

الإنتاج المنظم

يدعم وكلاء Go الإخراج المنظم من agent.WithStructuredOutput خلال الخيار . حدد بنية Go وينشئ إطار العمل تلقائيا مخطط JSON ويلغي تحديد الاستجابة.

تعريف نوع الإخراج

type PersonInfo struct {
    Name       string `json:"name"`
    Age        int    `json:"age"`
    Occupation string `json:"occupation"`
}

طلب الإخراج المنظم

استخدم مساعدا عاما لاستدعاء العامل وإلغاء تحديد الاستجابة:

import (
    "context"
    "fmt"

    "github.com/microsoft/agent-framework-go/agent"
)

func runFor[T any](ctx context.Context, a *agent.Agent, message string, opts ...agent.Option) (T, error) {
    var v T
    opts = append(opts, agent.WithStructuredOutput(&v), agent.Stream(false))
    for _, err := range a.RunText(ctx, message, opts...) {
        if err != nil {
            return v, err
        }
    }
    return v, nil
}

person, err := runFor[PersonInfo](ctx, a,
    "Please provide information about John Smith, who is a 35-year-old software engineer.")
fmt.Println("Name:", person.Name)
fmt.Println("Age:", person.Age)

تحديد تنسيق الاستجابة على مستوى العامل

يمكنك أيضا تعيين تنسيق الاستجابة على تكوين العامل بحيث تنتج جميع عمليات التشغيل إخراجا منظما:

import "github.com/microsoft/agent-framework-go/agent/format/jsonformat"

a := foundryprovider.NewAgent(endpoint, token, foundryprovider.ModelDeployment(model), foundryprovider.AgentConfig{
    Instructions: "You are a helpful assistant.",
    Config: agent.Config{
        RunOptions: []agent.Option{
            agent.WithResponseFormat(jsonformat.MustFor[PersonInfo]()),
        },
    },
})

Tip

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

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