Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Esta etapa do tutorial mostra como produzir saídas estruturadas com um agente, em que o agente é criado no serviço de conclusão de chat do Azure OpenAI.
Importante
Nem todos os tipos de agente dão suporte a saídas estruturadas nativamente. O ChatClientAgent suporta saídas estruturadas quando usado com clientes de bate-papo compatíveis.
Pré-requisitos
Para pré-requisitos e instalação de pacotes NuGet, consulte a etapa Criar e executar um agente simples neste tutorial.
Definir um tipo para saídas estruturadas
Primeiro, defina um tipo que represente a estrutura da saída desejada do agente.
public class PersonInfo
{
public string? Name { get; set; }
public int? Age { get; set; }
public string? Occupation { get; set; }
}
Criar o agente
Crie um ChatClientAgent usando o cliente de projetos de IA 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.");
Aviso
DefaultAzureCredential é conveniente para o desenvolvimento, mas requer uma consideração cuidadosa na produção. Em produção, considere o uso de uma credencial específica (por exemplo, ManagedIdentityCredential) para evitar problemas de latência, investigação de credenciais não intencionais e possíveis riscos de segurança de mecanismos de fallback.
Saídas estruturadas com RunAsync<T>
O RunAsync<T> método está disponível na AIAgent classe base. Ele aceita um parâmetro de tipo genérico que especifica o tipo de saída estruturada.
Essa abordagem é aplicável quando o tipo de saída estruturada é conhecido no momento de compilação e uma instância de resultado com tipagem é necessária. Ele dá suporte a primitivos, matrizes e tipos complexos.
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}");
Saídas estruturadas com ResponseFormat
As saídas estruturadas podem ser configuradas definindo a propriedade ResponseFormat no AgentRunOptions no momento da invocação ou no momento da inicialização do agente para agentes que suportam esse recurso, como ChatClientAgent e o Foundry Agent.
Essa abordagem é aplicável quando:
- O tipo de saída estruturada não é conhecido no momento da compilação.
- O esquema é representado como JSON bruto.
- As saídas estruturadas só podem ser configuradas no momento da criação do agente.
- Somente o texto JSON bruto é necessário sem desserialização.
- A colaboração entre agentes é usada.
Várias opções ResponseFormat estão disponíveis.
- Uma propriedade interna ChatResponseFormat.Text: a resposta será texto sem formatação.
- Uma propriedade interna ChatResponseFormat.Json : a resposta será um objeto JSON sem nenhum esquema específico.
- Uma instância personalizada ChatResponseFormatJson : a resposta será um objeto JSON que está em conformidade com um esquema específico.
Observação
Primitivas e matrizes não são compatíveis com a ResponseFormat abordagem. Se você precisar trabalhar com primitivas ou matrizes, use a RunAsync<T> abordagem ou crie um tipo de 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}");
O ResponseFormat também pode ser especificado usando uma cadeia de caracteres de esquema JSON bruta, que é útil quando não há nenhum tipo de .NET correspondente disponível, como para agentes declarativos ou esquemas carregados da configuração externa:
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()}");
Saídas estruturadas com streaming
Ao transmitir, a resposta do agente é transmitida como uma série de atualizações e você só pode desserializar a resposta depois que todas as atualizações forem recebidas. Você deve agrupar todas as atualizações em uma única resposta antes de desserializá-la.
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}");
Saídas estruturadas com agentes que não possuem capacidades de saídas estruturadas
Alguns agentes não dão suporte nativo a saídas estruturadas, seja porque ela não faz parte do protocolo ou porque os agentes usam modelos de linguagem sem recursos de saída estruturados. Uma abordagem possível é criar um agente decorador de funções personalizado que encapsula qualquer AIAgent e usa uma chamada LLM adicional através de um cliente de chat para converter a resposta de texto do agente em JSON estruturado.
Observação
Como essa abordagem depende de uma chamada adicional de LLM para transformar a resposta, sua confiabilidade pode não ser adequada para todos os cenários.
Para obter uma implementação de referência desse padrão que você pode adaptar aos seus próprios requisitos, consulte o exemplo StructuredOutputAgent.
Tip
Consulte os exemplos .NET para obter exemplos executáveis completos.
Exemplo de streaming
Tip
Consulte os exemplos .NET para obter exemplos executáveis completos.
Esta etapa do tutorial mostra como produzir saídas estruturadas com um agente, em que o agente é criado no serviço de conclusão de chat do Azure OpenAI.
Importante
Nem todos os tipos de agente dão suporte a saídas estruturadas. O Agent suporta saídas estruturadas quando usado com clientes de chat compatíveis.
Pré-requisitos
Para pré-requisitos e instalação de pacotes, consulte a etapa Criar e executar um agente simples neste tutorial.
Criar o agente com saídas estruturadas
Agent é baseado em qualquer implementação de cliente de chat que dê suporte a saídas estruturadas.
O Agent usa a chave response_format no dicionário options para especificar o esquema de saída desejado.
Quando executar o agente, você pode fornecer:
- Um modelo Pydantic que define a estrutura da saída esperada.
- Um mapeamento de esquema JSON (
dict) quando você deseja analisar JSON sem definir uma classe de modelo.
Você pode passar o options dicionário em tempo de execução via agent.run(..., options={"response_format": ...}), ou defini-lo no momento da criação do agente por meio do default_options dicionário.
Há suporte para vários formatos de resposta com base nos recursos subjacentes do cliente de chat.
O primeiro exemplo cria um agente que produz saídas estruturadas na forma de um objeto JSON que está em conformidade com um esquema de modelo Pydantic.
Primeiro, defina um modelo Pydantic que represente a estrutura da saída desejada do agente:
from pydantic import BaseModel
class PersonInfo(BaseModel):
"""Information about a person."""
name: str | None = None
age: int | None = None
occupation: str | None = None
Agora você pode criar um agente usando o cliente de chat 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."
)
Agora você pode executar o agente com algumas informações textuais e especificar o formato de saídas estruturadas usando a chave response_format no dicionário options.
response = await agent.run(
"Please provide information about John Smith, who is a 35-year-old software engineer.",
options={"response_format": PersonInfo},
)
Para um formato de resposta de modelo Pydantic, a resposta do agente contém as saídas estruturadas na propriedade value como uma instância de modelo.
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")
Usar um mapeamento de esquema JSON
Se você já tiver um esquema JSON como um mapeamento de Python, passe esse esquema diretamente como o valor response_format no ditado options. Nesse modo, response.value contém o valor JSON analisado (normalmente um dict ou list) em vez de uma instância de modelo 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']}")
Ao transmitir, agent.run(..., stream=True) retorna um ResponseStream. O finalizador interno do fluxo lida automaticamente com a análise de saídas estruturadas, para que você possa iterar para atualizações em tempo real e, em seguida, chamar get_final_response() para obter o resultado analisado:
# 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}")
A mesma regra se aplica quando response_format for um mapeamento de esquema JSON: final_response.value contém JSON analisado em vez de uma instância de modelo Pydantic.
Se você não precisar processar atualizações de streaming individuais, poderá ignorar totalmente a iteração – get_final_response() consumirá automaticamente o fluxo:
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}")
Exemplo 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())