Strukturált kimenetek előállítása ügynökökkel

Ez az oktatóanyag lépés bemutatja, hogyan hozhat létre strukturált kimeneteket egy ügynökkel, ahol az ügynök az OpenAI-csevegés befejezésének Azure szolgáltatásra épül.

Important

Nem minden ügynöktípus támogatja natív módon a strukturált kimeneteket. A ChatClientAgent kompatibilis csevegési ügyfelekkel való használat esetén a strukturált kimenetek támogatottak.

Prerequisites

Az előfeltételekről és a NuGet-csomagok telepítéséről lásd az egyszerű ügynök létrehozása és futtatása lépést ebben az oktatóanyagban.

Strukturált kimenetek típusának meghatározása

Először adjon meg egy típust, amely az ügynök által kívánt kimenet szerkezetét jelöli.

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

Az ügynök létrehozása

A ChatClientAgent létrehozása az Azure AI Projects kliens használatával.

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.");

Warning

DefaultAzureCredential a fejlesztéshez kényelmes, de a termelési környezetben gondos megfontolást igényel. Éles környezetben fontolja meg egy adott hitelesítő adat (pl. ManagedIdentityCredential) használatát a késési problémák elkerülése, a hitelesítő adatok nem szándékos próbálgatásának és a tartalék mechanizmusokból eredő esetleges biztonsági kockázatok elkerülése érdekében.

Strukturált kimenetek RunAsync<T használatával>

A RunAsync<T> metódus az alaposztályban AIAgent érhető el. Elfogad egy általános típusparamétert, amely meghatározza a strukturált kimenet típusát. Ez a megközelítés akkor alkalmazható, ha a strukturált kimenetek típusa fordításkor ismert, és begépelt eredménypéldányra van szükség. Támogatja a primitíveket, tömböket és összetett típusokat.

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}");

Strukturált kimenetek a ResponseFormat használatával

A strukturált kimenetek konfigurálhatók úgy, hogy a ResponseFormat tulajdonságot beállítjuk a AgentRunOptions meghívási idejénél, vagy az azokat támogató ügynökök, például a ChatClientAgent és a Foundry Agent inicializálásakor.

Ez a megközelítés akkor alkalmazható, ha:

  • A strukturált kimenetek típusa fordításkor nem ismert.
  • A séma nyers JSON-ként jelenik meg.
  • A strukturált kimenetek csak az ügynöklétrehozáskor konfigurálhatók.
  • Deszerializálás nélkül csak a nyers JSON-szövegre van szükség.
  • Ügynökközi együttműködést használunk.

Különböző lehetőségek ResponseFormat állnak rendelkezésre:

Megjegyzés:

A ResponseFormat megközelítés nem támogatja a primitíveket és a tömböket. Ha primitívekkel vagy tömbökkel kell dolgoznia, használja a RunAsync<T> módszert, vagy hozzon létre egy burkolótípust.

// 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}");

A ResponseFormat nyers JSON-sémasztring használatával is megadható, ami akkor hasznos, ha nincs megfelelő .NET típus, például külső konfigurációból betöltött deklaratív ügynökök vagy sémák esetén:

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()}");

Strukturált kimenetek streameléssel

Streameléskor az ügynök válasza frissítéssorozatként lesz streamelve, és a válasz csak az összes frissítés beérkezése után deszerializálható. Az összes frissítést a deszerializálás előtt egyetlen válaszba kell összeállítania.

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}");

Strukturált kimenetek strukturált kimeneti képességekkel nem rendelkező ügynökökkel

Egyes ügynökök natív módon nem támogatják a strukturált kimeneteket, vagy azért, mert nem része a protokollnak, vagy mert az ügynökök strukturált kimeneti képességek nélkül használnak nyelvi modelleket. Az egyik lehetséges módszer egy egyéni dekoráló ügynök létrehozása, amely becsomagolja bármelyik AIAgent, és egy további LLM-hívást használ egy csevegési ügyfélen keresztül az ügynök szöveges válaszának strukturált JSON formátummá alakításához.

Megjegyzés:

Mivel ez a megközelítés egy további LLM-hívásra támaszkodik a válasz átalakításához, a megbízhatósága nem feltétlenül elegendő minden forgatókönyvhöz.

Ennek a mintának a referenciális implementációjához, amely a saját igényeihez igazítható, tekintse meg a StructuredOutputAgent mintát.

Tip

A teljes futtatható példákért tekintse meg a .NET-mintákat .

Streamelési példa

Tip

A teljes futtatható példákért tekintse meg a .NET-mintákat .

Ez az oktatóanyag lépés bemutatja, hogyan hozhat létre strukturált kimeneteket egy ügynökkel, ahol az ügynök az OpenAI-csevegés befejezésének Azure szolgáltatásra épül.

Important

Nem minden ügynöktípus támogatja a strukturált kimeneteket. A Agent kompatibilis csevegési ügyfelekkel való használat esetén a strukturált kimenetek támogatottak.

Prerequisites

Az előfeltételekről és a csomagok telepítéséről lásd a Egyszerű ügynök létrehozása és futtatása lépést ebben az oktatóanyagban.

Az ügynök létrehozása strukturált kimenetekkel

A Agent bármilyen, strukturált kimeneteket támogató csevegőügyfél-implementációra épül. Agent A response_format kulcsot használja options a kívánt kimeneti séma megadásához.

Az ügynök futtatásakor a következőkre van lehetőség:

  • Pydantic-modell, amely meghatározza a várt kimenet struktúráját.
  • JSON-sémaleképezés (dict), ha modellosztály definiálása nélkül szeretné elemezni a JSON-t.

A options szótárt futásidőben átadhatja agent.run(..., options={"response_format": ...}), vagy beállíthatja az ügynök létrehozásakor a default_options szótárt.

A különböző válaszformátumok a mögöttes csevegőügyfél képességei alapján támogatottak.

Az első példa létrehoz egy ügynököt, amely strukturált kimeneteket hoz létre egy Pydantic-modellsémának megfelelő JSON-objektum formájában.

Először definiáljon egy Pydantic-modellt, amely az ügynök által kívánt kimenet struktúráját jelöli:

from pydantic import BaseModel

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

Most már létrehozhat egy ügynököt az Azure OpenAI csevegőügyfél használatával:

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."
)

Most már futtathatja az ügynököt szöveges információkkal, és megadhatja a strukturált kimenetek formátumát a response_formatoptions diktálás kulcsával:

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

Pydantic-modell válaszformátuma esetén az ügynök válasza modellpéldányként tartalmazza a value tulajdonság strukturált kimeneteit:

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-sémaleképezés használata

Ha már rendelkezik JSON-sémával Python leképezésként, adja meg ezt a sémát közvetlenül response_format értékként a options szótárban. Ebben a módban response.value a Pydantic-modellpéldány helyett az elemezett JSON-értéket (általában a dict vagy list) tartalmazza.

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']}")

Streameléskor agent.run(..., stream=True) egy ResponseStream. A stream beépített véglegesítője automatikusan kezeli a strukturált kimenetek elemzését, így iterálhatja a valós idejű frissítéseket, majd meghívhatja get_final_response() az elemzési eredményt:

# 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}")

Ugyanez a szabály akkor érvényes, ha response_format egy JSON-sémaleképezés: final_response.value pydantikus modellpéldány helyett elemezett JSON-t tartalmaz.

Ha nem kell feldolgoznia az egyes streamelési frissítéseket, teljesen kihagyhatja az iterációt – get_final_response() automatikusan felhasználja a streamet:

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}")

Teljes példa

# 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())

Strukturált kimenet

A Go-ügynökök a strukturált kimenetet a agent.WithStructuredOutput beállításon keresztül támogatják. Definiáljon egy Go-struktúrát, és a keretrendszer automatikusan létrehozza a JSON-sémát, valamint deszerializálja a választ.

A kimeneti típus meghatározása

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

Strukturált kimenet kérése

Használjon egy általános segédprogramot az ügynök meghívásához és a válasz deszerializálásához:

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)

Válaszformátum megadása ügynökszinten

A válaszformátumot az ügynök konfigurációján is beállíthatja, hogy az összes futtatás strukturált kimenetet állítson elő:

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

A teljes minta egy teljes futtatható példát mutat be.

Következő lépések