Menghasilkan Output Terstruktur dengan Agen

Langkah tutorial ini menunjukkan kepada Anda cara menghasilkan output terstruktur dengan agen, di mana agen dibangun di Azure layanan OpenAI Chat Completion.

Penting

Tidak semua jenis agen mendukung output terstruktur secara asli. ChatClientAgent mendukung output terstruktur saat digunakan dengan klien obrolan yang kompatibel.

Prasyarat

Untuk prasyarat dan menginstal paket NuGet, lihat langkah Membuat dan menjalankan agen sederhana dalam tutorial ini.

Menentukan jenis untuk output terstruktur

Pertama, tentukan jenis yang mewakili struktur output yang Anda inginkan dari agen.

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

Membuat agen

Buat ChatClientAgent menggunakan Klien Proyek AI 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.");

Peringatan

DefaultAzureCredential nyaman untuk pengembangan tetapi membutuhkan pertimbangan yang cermat dalam produksi. Dalam produksi, pertimbangkan untuk menggunakan kredensial tertentu (misalnya, ManagedIdentityCredential) untuk menghindari masalah latensi, pemeriksaan kredensial yang tidak diinginkan, dan potensi risiko keamanan dari mekanisme fallback.

Keluaran terstruktur dengan RunAsync<T>

Metode RunAsync<T> ini tersedia di AIAgent kelas dasar. Ini menerima parameter jenis generik yang menentukan jenis output terstruktur. Pendekatan ini berlaku ketika jenis output terstruktur diketahui pada waktu kompilasi dan instans hasil yang ditik diperlukan. Ini mendukung primitif, array, dan jenis kompleks.

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

Output terstruktur dengan ResponseFormat

Output terstruktur dapat dikonfigurasi dengan mengatur properti ResponseFormat pada AgentRunOptions pada saat pemanggilan, atau saat inisialisasi agen untuk agen yang mendukungnya, seperti ChatClientAgent dan Agen Foundry.

Pendekatan ini berlaku ketika:

  • Jenis output terstruktur tidak diketahui pada waktu kompilasi.
  • Skema diwakili sebagai JSON mentah.
  • Output terstruktur hanya dapat dikonfigurasi pada saat pembuatan agen.
  • Hanya teks JSON mentah yang diperlukan tanpa deserialisasi.
  • Kolaborasi antar-agen digunakan.

Berbagai opsi untuk ResponseFormat tersedia:

Nota

Primitif dan array tidak didukung oleh pendekatan ResponseFormat. Jika Anda perlu bekerja dengan primitif atau array, gunakan pendekatan RunAsync<T> atau buat tipe pembungkus.

// 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 juga dapat ditentukan menggunakan string skema JSON mentah, yang berguna ketika tidak ada jenis .NET yang sesuai yang tersedia, seperti untuk agen deklaratif atau skema yang dimuat dari konfigurasi eksternal:

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

Output terstruktur melalui streaming

Saat streaming, respons agen dialirkan sebagai serangkaian pembaruan, dan Anda hanya dapat mendeserialisasi respons setelah semua pembaruan diterima. Anda harus merakit semua pembaruan menjadi satu respons sebelum mendeserialisasinya.

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

Output terstruktur dengan agen yang tidak memiliki kemampuan output terstruktur

Beberapa agen tidak secara asli mendukung output terstruktur, baik karena itu bukan bagian dari protokol atau karena agen menggunakan model bahasa tanpa kemampuan output terstruktur. Salah satu pendekatan yang mungkin adalah membuat agen dekorator kustom yang membungkus apa pun AIAgent dan menggunakan panggilan LLM tambahan melalui klien obrolan untuk mengonversi respons teks agen menjadi JSON terstruktur.

Nota

Karena pendekatan ini bergantung pada panggilan LLM tambahan untuk mengubah respons, keandalannya mungkin tidak cukup untuk semua skenario.

Untuk implementasi referensi pola ini yang dapat Anda adaptasi dengan persyaratan Anda sendiri, lihat sampel StructuredOutputAgent.

Tip

Lihat sampel .NET untuk contoh lengkap yang dapat dijalankan.

Contoh streaming

Tip

Lihat sampel .NET untuk contoh lengkap yang dapat dijalankan.

Langkah tutorial ini menunjukkan kepada Anda cara menghasilkan output terstruktur dengan agen, di mana agen dibangun di Azure layanan OpenAI Chat Completion.

Penting

Tidak semua jenis agen mendukung output terstruktur. Agent mendukung output terstruktur saat digunakan dengan klien obrolan yang kompatibel.

Prasyarat

Untuk prasyarat dan penginstalan paket, lihat langkah Buat dan jalankan agen sederhana dalam tutorial ini.

Membuat agen dengan output terstruktur

Agent dibangun di atas implementasi klien obrolan apa pun yang mendukung output terstruktur. Agent menggunakan response_format kunci dalam options dict untuk menentukan skema output yang diinginkan.

Saat menjalankan agen, Anda dapat menyediakan salah satu dari berikut ini:

  • Model Pydantic yang menentukan struktur output yang diharapkan.
  • Pemetaan skema JSON (dict) saat Anda ingin mengurai JSON tanpa menentukan kelas model.

Anda dapat meneruskan options dict saat runtime melalui agent.run(..., options={"response_format": ...}), atau mengaturnya pada saat pembuatan agen melalui default_options dict.

Berbagai format respons didukung berdasarkan kemampuan klien obrolan yang mendasar.

Contoh pertama membuat agen yang menghasilkan output terstruktur dalam bentuk objek JSON yang sesuai dengan skema model Pydantic.

Pertama, tentukan model Pydantic yang mewakili struktur output yang Anda inginkan dari agen:

from pydantic import BaseModel

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

Sekarang Anda dapat membuat agen menggunakan Azure OpenAI Chat Client:

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

Sekarang Anda dapat menjalankan agen dengan beberapa informasi tekstual dan menentukan format output terstruktur menggunakan response_format kunci dalam dict options :

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

Untuk format respons model Pydantic, respons agen berisi output terstruktur di properti value sebagai instans model.

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

Menggunakan pemetaan skema JSON

Jika Anda sudah memiliki skema JSON sebagai pemetaan Python, teruskan skema tersebut langsung sebagai nilai response_format di dict options. Dalam mode ini, response.value berisi nilai JSON yang diurai (biasanya atau dictlist) alih-alih instans model 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']}")

Saat streaming, agent.run(..., stream=True) mengembalikan ResponseStream. Finalizer bawaan stream secara otomatis menangani penguraian output terstruktur, sehingga Anda dapat melakukan iterasi untuk pembaruan real-time lalu memanggil get_final_response() untuk mendapatkan hasil yang diurai:

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

Aturan yang sama berlaku ketika response_format adalah pemetaan skema JSON: final_response.value berisi JSON yang diurai alih-alih instans model Pydantic.

Jika Anda tidak perlu memproses pembaruan streaming individu, Anda dapat sepenuhnya melewati iterasi — get_final_response() akan secara otomatis mengonsumsi aliran tersebut.

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

Contoh lengkap

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

Output terstruktur

Agen Go mendukung output terstruktur melalui agent.WithStructuredOutput opsi . Definisikan struct Go dan kerangka kerja akan secara otomatis menghasilkan skema JSON serta melakukan unmarshal pada respons.

Tentukan jenis output

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

Meminta output terstruktur

Gunakan pembantu generik untuk memanggil agen dan membatalkan respon:

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)

Tentukan format respons di tingkat agen

Anda juga dapat mengatur format respons pada konfigurasi agen sehingga semua eksekusi menghasilkan output terstruktur:

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

Lihat sampel lengkap untuk contoh lengkap yang dapat dijalankan.

Langkah berikutnya