Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo passaggio dell'esercitazione illustra come produrre output strutturati con un agente, in cui l'agente è basato sul servizio di completamento chat OpenAI di Azure.
Importante
Non tutti i tipi di agente supportano output strutturati in modo nativo.
ChatClientAgent supporta output strutturati se usati con client di chat compatibili.
Prerequisiti
Per i prerequisiti e l'installazione dei pacchetti NuGet, vedere il passaggio Creare ed eseguire un agente semplice in questa esercitazione.
Definire un tipo per gli output strutturati
Definire innanzitutto un tipo che rappresenta la struttura dell'output desiderato dall'agente.
public class PersonInfo
{
public string? Name { get; set; }
public int? Age { get; set; }
public string? Occupation { get; set; }
}
Creare l'agente
Creare un ChatClientAgent usando il client di progetti di intelligenza artificiale 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.");
Avvertimento
DefaultAzureCredential è utile per lo sviluppo, ma richiede un'attenta considerazione nell'ambiente di produzione. Nell'ambiente di produzione prendere in considerazione l'uso di credenziali specifiche ,ad esempio ManagedIdentityCredential, per evitare problemi di latenza, probe di credenziali indesiderate e potenziali rischi per la sicurezza dai meccanismi di fallback.
Risultati strutturati con RunAsync<T>
Il RunAsync<T> metodo è disponibile nella AIAgent classe base. Accetta un parametro di tipo generico che specifica il tipo di output strutturati.
Questo approccio è applicabile quando il tipo di output strutturati è noto in fase di compilazione e è necessaria un'istanza del risultato tipizzata. Supporta primitive, matrici e tipi complessi.
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 strutturati con ResponseFormat
Gli output strutturati possono essere configurati impostando la ResponseFormat proprietà su AgentRunOptions in fase di chiamata o in fase di inizializzazione dell'agente per gli agenti che lo supportano, ad esempio ChatClientAgent e Foundry Agent.
Questo approccio è applicabile quando:
- Il tipo di output strutturati non è noto in fase di compilazione.
- Lo schema è rappresentato come JSON non elaborato.
- Gli output strutturati possono essere configurati solo in fase di creazione dell'agente.
- Solo il testo JSON non elaborato è necessario senza deserializzazione.
- Viene usata la collaborazione tra agenti.
Sono disponibili varie opzioni per ResponseFormat :
- Proprietà predefinita ChatResponseFormat.Text : la risposta sarà testo normale.
- Una proprietà predefinita ChatResponseFormat.Json : la risposta sarà un oggetto JSON senza uno schema specifico.
- Istanza personalizzata ChatResponseFormatJson : la risposta sarà un oggetto JSON conforme a uno schema specifico.
Annotazioni
Le primitive e le matrici non sono supportate dall'approccio ResponseFormat . Se è necessario usare primitive o matrici, usare l'approccio RunAsync<T> o creare un tipo wrapper.
// 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}");
È anche possibile specificare la ResponseFormat usando una stringa di schema JSON non elaborata, utile quando non è disponibile alcun tipo di .NET corrispondente, ad esempio per gli agenti dichiarativi o gli schemi caricati dalla configurazione esterna:
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 strutturati con trasmissione in streaming
Quando si esegue lo streaming, la risposta dell'agente viene trasmessa come una serie di aggiornamenti ed è possibile deserializzare la risposta solo dopo che tutti gli aggiornamenti sono stati ricevuti. È necessario assemblare tutti gli aggiornamenti in una singola risposta prima di deserializzarlo.
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 strutturati con agenti senza funzionalità di output strutturati
Alcuni agenti non supportano in modo nativo output strutturati, perché non fanno parte del protocollo o perché gli agenti usano modelli linguistici senza funzionalità di output strutturati. Un approccio possibile consiste nel creare un agente decorator personalizzato che esegue il wrapping di qualsiasi AIAgent e usa una chiamata LLM aggiuntiva tramite un client di chat per convertire la risposta di testo dell'agente in JSON strutturato.
Annotazioni
Poiché questo approccio si basa su una chiamata LLM aggiuntiva per trasformare la risposta, l'affidabilità potrebbe non essere sufficiente per tutti gli scenari.
Per un'implementazione di riferimento di questo modello che è possibile adattare ai propri requisiti, vedere l'esempio StructuredOutputAgent.
Suggerimento
Vedere gli esempi .NET per esempi eseguibili completi.
Esempio di streaming
Suggerimento
Vedere gli esempi .NET per esempi eseguibili completi.
Questo passaggio dell'esercitazione illustra come generare output strutturati con un agente, in cui l'agente è basato sul servizio di completamento chat Azure OpenAI.
Importante
Non tutti i tipi di agente supportano output strutturati.
Agent supporta output strutturati se usati con client di chat compatibili.
Prerequisiti
Per i prerequisiti e l'installazione dei pacchetti, vedere il passaggio Creare ed eseguire un agente semplice in questa esercitazione.
Creare l'agente con output strutturati
Agent è basato su qualsiasi implementazione client di chat che supporta output strutturati.
Agent usa la response_format chiave nel options dict per specificare lo schema di output desiderato.
Quando si esegue l'agente, è possibile specificare una delle seguenti opzioni:
- Modello Pydantic che definisce la struttura dell'output previsto.
- Mapping dello schema JSON (
dict) quando si vuole analizzare JSON senza definire una classe modello.
È possibile passare il options dict in fase di esecuzione tramite agent.run(..., options={"response_format": ...})o impostarlo in fase di creazione dell'agente tramite il default_options dict.
Diversi formati di risposta sono supportati in base alle funzionalità client di chat sottostanti.
Il primo esempio crea un agente che produce output strutturati sotto forma di oggetto JSON conforme a uno schema del modello Pydantic.
Prima di tutto, definire un modello Pydantic che rappresenta la struttura dell'output desiderato dall'agente:
from pydantic import BaseModel
class PersonInfo(BaseModel):
"""Information about a person."""
name: str | None = None
age: int | None = None
occupation: str | None = None
È ora possibile creare un agente usando il 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."
)
È ora possibile eseguire l'agente con alcune informazioni testuali e specificare il formato degli output strutturati usando la response_format chiave nel options dict:
response = await agent.run(
"Please provide information about John Smith, who is a 35-year-old software engineer.",
options={"response_format": PersonInfo},
)
Per un formato di risposta del modello Pydantic, la risposta dell'agente contiene gli output strutturati nella value proprietà come istanza del modello:
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")
Usare un mapping dello schema JSON
Se si dispone già di uno schema JSON come mapping Python, passare tale schema direttamente come valore response_format nel dizionario options. In questa modalità response.value contiene il valore JSON analizzato (in genere o dictlist) anziché un'istanza del modello 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']}")
Quando si esegue lo streaming, agent.run(..., stream=True) restituisce un ResponseStream. Il finalizzatore predefinito del flusso gestisce automaticamente l'analisi degli output strutturati, in modo da poter eseguire l'iterazione per gli aggiornamenti in tempo reale e quindi chiamare get_final_response() per ottenere il risultato analizzato:
# 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}")
La stessa regola si applica quando response_format si tratta di un mapping dello schema JSON: final_response.value contiene json analizzato anziché un'istanza del modello Pydantic.
Se non devi elaborare i singoli aggiornamenti in streaming, puoi saltare completamente l'iterazione: get_final_response() consumerà automaticamente il flusso.
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}")
Esempio completo
# 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())