Guia de atualização: opções de chat como TypedDict com genéricos

Este guia ajuda você a atualizar seu código Python para o novo sistema baseado em Options TypedDict introduzido na versão 1.0.0b260114 do Microsoft Agent Framework. Essa é uma alteração significativa que oferece segurança de tipo aprimorada, preenchimento automático do IDE e extensibilidade de runtime.

Visão geral das alterações

Esta versão apresenta uma grande refatoração de como as opções são passadas para clientes de chat e agentes de chat.

Como funcionava antes

Anteriormente, as opções eram passadas como argumentos de palavra-chave direta em métodos como get_response(), get_streaming_response()e run()construtores de agente:

# Options were individual keyword arguments
response = await client.get_response(
    "Hello!",
    model="gpt-4",
    temperature=0.7,
    max_tokens=1000,
)

# For provider-specific options not in the base set, you used additional_properties
response = await client.get_response(
    "Hello!",
    model="gpt-4",
    additional_properties={"reasoning_effort": "medium"},
)

Como funciona agora

A maioria das opções agora é passada através de um único parâmetro options na forma de um dicionário tipado.

# Most options go in a single typed dict
response = await client.get_response(
    "Hello!",
    options={
        "model": "gpt-4",
        "temperature": 0.7,
        "max_tokens": 1000,
        "reasoning_effort": "medium",  # Provider-specific options included directly
    },
)

Nota: Para Agentes, os parâmetros instructions e tools permanecem disponíveis como argumentos de palavra-chave diretos em Agent.__init__() e client.as_agent(). Para agent.run(), só tools está disponível como um argumento de palavra-chave:

# Agent creation accepts both tools and instructions as keyword arguments
agent = Agent(
    client=client,
    tools=[my_function],
    instructions="You are a helpful assistant.",
    default_options={"model": "gpt-4", "temperature": 0.7},
)

# agent.run() only accepts tools as a keyword argument
response = await agent.run(
    "Hello!",
    tools=[another_function],  # Can override tools per-run
)

Principais alterações

  1. Parâmetro de opções consolidadas: a maioria dos argumentos de palavra-chave (model, temperatureetc.) agora são passados por meio de um único options ditado
  2. Exceção para criação de agente: instructions e tools permanecer disponível como argumentos de palavra-chave diretos em Agent.__init__() e as_agent()
  3. Exceção para execução do agente: tools permanece disponível como um argumento de palavra-chave direta em agent.run()
  4. Opções baseadas em TypedDict: as opções são definidas como TypedDict classes para segurança de tipo
  5. Suporte a tipos genéricos: clientes e agentes de chat dão suporte a genéricos para opções específicas do provedor, para permitir sobrecargas de runtime
  6. Opções específicas do provedor: cada provedor tem seu próprio TypedDict padrão (por exemplo, , OpenAIChatOptions) OllamaChatOptions
  7. Não há mais additional_properties: parâmetros específicos do provedor agora são campos tipados de primeira classe

Benefícios

  • Segurança do Tipo: preenchimento automático do IDE e verificação de tipo para todas as opções
  • Flexibilidade do provedor: suporte para parâmetros específicos do provedor no primeiro dia
  • Código mais limpo: uso consistente de parâmetros baseados em dicionário
  • Extensão mais fácil: criar opções personalizadas para casos de uso especializados (por exemplo, modelos de raciocínio ou outros back-ends de API)

Guia de migração

1. Converter os argumentos de palavra-chave em dicionário de opções

A alteração mais comum é converter argumentos de palavra-chave individuais para o options dicionário.

Antes (argumentos de palavra-chave):

from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()

# Options passed as individual keyword arguments
response = await client.get_response(
    "Hello!",
    model="gpt-4",
    temperature=0.7,
    max_tokens=1000,
)

# Streaming also used keyword arguments
async for chunk in client.get_streaming_response(
    "Tell me a story",
    model="gpt-4",
    temperature=0.9,
):
    print(chunk.text, end="")

Após (dicionário de opções):

from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()

# All options now go in a single 'options' parameter
response = await client.get_response(
    "Hello!",
    options={
        "model": "gpt-4",
        "temperature": 0.7,
        "max_tokens": 1000,
    },
)

# Same pattern for streaming
async for chunk in client.get_response(
    "Tell me a story",
    options={
        "model": "gpt-4",
        "temperature": 0.9,
    },
    stream=True,
):
    print(chunk.text, end="")

Se você passar opções que não são apropriadas para esse cliente, receberá um erro de tipo em seu IDE.

2. Usando as opções de Provider-Specific (não há mais additional_properties)

Anteriormente, para passar parâmetros específicos do provedor que não eram parte do conjunto base de argumentos de palavra-chave, você precisava usar o additional_properties parâmetro:

Antes (usando additional_properties):

from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()
response = await client.get_response(
    "What is 2 + 2?",
    model="gpt-4",
    temperature=0.7,
    additional_properties={
        "reasoning_effort": "medium",  # No type checking or autocomplete
    },
)

Depois (opções diretas com TypedDict):

from agent_framework.openai import OpenAIChatClient

# Provider-specific options are now first-class citizens with full type support
client = OpenAIChatClient()
response = await client.get_response(
    "What is 2 + 2?",
    options={
        "model": "gpt-4",
        "temperature": 0.7,
        "reasoning_effort": "medium",  # Type checking or autocomplete
    },
)

Depois (para novos parâmetros, subclasse personalizada):

Ou se for um parâmetro que ainda não faz parte do Agent Framework (porque ele é novo ou porque é personalizado para um back-end compatível com OpenAI), agora você pode subclasse as opções e usar o suporte genérico:

from typing import Literal
from agent_framework.openai import OpenAIChatOptions, OpenAIChatClient

class MyCustomOpenAIChatOptions(OpenAIChatOptions, total=False):
    """Custom OpenAI chat options with additional parameters."""

    # New or custom parameters
    custom_param: str

# Use with the client
client = OpenAIChatClient[MyCustomOpenAIChatOptions]()
response = await client.get_response(
    "Hello!",
    options={
        "model": "gpt-4",
        "temperature": 0.7,
        "custom_param": "my_value",  # IDE autocomplete works!
    },
)

O principal benefício é que a maioria dos parâmetros específicos do provedor agora fazem parte do dicionário de opções tipado, fornecendo:

  • Preenchimento automático do IDE para todas as opções disponíveis
  • Verificação de tipo para capturar chaves ou valores inválidos
  • Não há necessidade de additional_properties para parâmetros de provedor conhecidos
  • Extensão fácil para parâmetros personalizados ou novos

3. Atualizar configuração do agente

Os métodos de inicialização e execução do agente seguem o mesmo padrão:

Antes (argumentos de palavra-chave no construtor e em execução):

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()

# Default options as keyword arguments on constructor
agent = Agent(
    client=client,
    name="assistant",
    model="gpt-4",
    temperature=0.7,
)

# Run also took keyword arguments
response = await agent.run(
    "Hello!",
    max_tokens=1000,
)

After:

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient, OpenAIChatOptions

client = OpenAIChatClient()
agent = Agent(
    client=client,
    name="assistant",
    default_options={ # <- type checkers will verify this dict
        "model": "gpt-4",
        "temperature": 0.7,
    },
)

response = await agent.run("Hello!", options={ # <- and this dict too
    "max_tokens": 1000,
})

4. Opções Específicas do Provedor

Cada provedor agora possui o seu próprio TypedDict para opções, eles são habilitados por padrão. Isso permite que você use parâmetros específicos do provedor com segurança de tipo completo:

Exemplo do OpenAI:

from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()
response = await client.get_response(
    "Hello!",
    options={
        "model": "gpt-4",
        "temperature": 0.7,
        "reasoning_effort": "medium",
    },
)

Mas você também pode torná-lo explícito:

from agent_framework_anthropic import AnthropicClient, AnthropicChatOptions

client = AnthropicClient[AnthropicChatOptions]()
response = await client.get_response(
    "Hello!",
    options={
        "model": "claude-3-opus-20240229",
        "max_tokens": 1000,
    },
)

5. Criando opções personalizadas para modelos especializados

Um recurso poderoso do novo sistema é a capacidade de criar opções personalizadas do TypedDict para modelos especializados. Isso é particularmente útil para modelos que têm parâmetros exclusivos, como modelos de raciocínio com OpenAI:

from typing import Literal
from agent_framework.openai import OpenAIChatOptions, OpenAIChatClient

class OpenAIReasoningChatOptions(OpenAIChatOptions, total=False):
    """Chat options for OpenAI reasoning models (o1, o3, o4-mini, etc.)."""

    # Reasoning-specific parameters
    reasoning_effort: Literal["none", "minimal", "low", "medium", "high", "xhigh"]

    # Unsupported parameters for reasoning models (override with None)
    temperature: None
    top_p: None
    frequency_penalty: None
    presence_penalty: None
    logit_bias: None
    logprobs: None
    top_logprobs: None
    stop: None


# Use with the client
client = OpenAIChatClient[OpenAIReasoningChatOptions]()
response = await client.get_response(
    "What is 2 + 2?",
    options={
        "model": "o3",
        "max_tokens": 100,
        "allow_multiple_tool_calls": True,
        "reasoning_effort": "medium",  # IDE autocomplete works!
        # "temperature": 0.7,  # Would raise a type error, because the value is not None
    },
)

6. Agentes de chat com opções

A configuração genérica também foi estendida aos Agentes de Chat:

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient

agent = Agent(
    client=OpenAIChatClient[OpenAIReasoningChatOptions](),
    default_options={
        "model": "o3",
        "max_tokens": 100,
        "allow_multiple_tool_calls": True,
        "reasoning_effort": "medium",
    },
)

e você pode especificar o genérico no cliente e no agente, então, isso também é válido:

from agent_framework import Agent
from agent_framework.openai import OpenAIChatClient

agent = Agent[OpenAIReasoningChatOptions](
    client=OpenAIChatClient(),
    default_options={
        "model": "o3",
        "max_tokens": 100,
        "allow_multiple_tool_calls": True,
        "reasoning_effort": "medium",
    },
)

6. Atualizar implementações personalizadas do cliente de chat

Se você implementou um cliente de chat personalizado estendendo BaseChatClient, atualize os métodos internos:

Before:

from agent_framework import BaseChatClient, Message, ChatOptions, ChatResponse

class MyCustomClient(BaseChatClient):
    async def _inner_get_response(
        self,
        *,
        messages: MutableSequence[Message],
        chat_options: ChatOptions,
        **kwargs: Any,
    ) -> ChatResponse:
        # Access options via class attributes
        model = chat_options.model
        temp = chat_options.temperature
        # ...

After:

from typing import Generic
from agent_framework import BaseChatClient, Message, ChatOptions, ChatResponse

# Define your provider's options TypedDict
class MyCustomChatOptions(ChatOptions, total=False):
    my_custom_param: str

# This requires the TypeVar from Python 3.13+ or from typing_extensions, so for Python 3.13+:
from typing import TypeVar

TOptions = TypeVar("TOptions", bound=TypedDict, default=MyCustomChatOptions, covariant=True)

class MyCustomClient(BaseChatClient[TOptions], Generic[TOptions]):
    async def _inner_get_response(
        self,
        *,
        messages: MutableSequence[Message],
        stream: bool,
        options: dict[str, Any],  # Note: parameter renamed and just a dict
        **kwargs: Any,
    ) -> ChatResponse:
        # Access options via dict access
        model = options.get("model")
        temp = options.get("temperature")
        # ...

Padrões Comuns de Migração

Padrão 1: atualização de parâmetro simples

# Before - keyword arguments
await client.get_response("Hello", temperature=0.7)

# After - options dict
await client.get_response("Hello", options={"temperature": 0.7})

Padrão 2: vários parâmetros

# Before - multiple keyword arguments
await client.get_response(
    "Hello",
    model="gpt-4",
    temperature=0.7,
    max_tokens=1000,
)

# After - all in options dict
await client.get_response(
    "Hello",
    options={
        "model": "gpt-4",
        "temperature": 0.7,
        "max_tokens": 1000,
    },
)

Padrão 3: Cliente de Chat com Ferramentas

Para clientes de chat, tools agora vai para o dicionário de opções:

# Before - tools as keyword argument on chat client
await client.get_response(
    "What's the weather?",
    model="gpt-4",
    tools=[my_function],
    tool_choice="auto",
)

# After - tools in options dict for chat clients
await client.get_response(
    "What's the weather?",
    options={
        "model": "gpt-4",
        "tools": [my_function],
        "tool_choice": "auto",
    },
)

Padrão 4: Agente com Ferramentas e Instruções

Para a criação do agente, tools e instructions podem permanecer como argumentos nomeados. Para run(), só tools está disponível:

# Before
agent = Agent(
    client=client,
    name="assistant",
    tools=[my_function],
    instructions="You are helpful.",
    model="gpt-4",
)

# After - tools and instructions stay as keyword args on creation
agent = Agent(
    client=client,
    name="assistant",
    tools=[my_function],  # Still a keyword argument!
    instructions="You are helpful.",  # Still a keyword argument!
    default_options={"model": "gpt-4"},
)

# For run(), only tools is available as keyword argument
response = await agent.run(
    "Hello!",
    tools=[another_function],  # Can override tools
    options={"max_tokens": 100},
)
# Before - using additional_properties
await client.get_response(
    "Solve this problem",
    model="o3",
    additional_properties={"reasoning_effort": "high"},
)

# After - directly in options
await client.get_response(
    "Solve this problem",
    options={
        "model": "o3",
        "reasoning_effort": "high",
    },
)

Padrão 5: Parâmetros Específicos do Provedor

# Define reusable options
my_options: OpenAIChatOptions = {
    "model": "gpt-4",
    "temperature": 0.7,
}

# Use with different messages
await client.get_response("Hello", options=my_options)
await client.get_response("Goodbye", options=my_options)

# Extend options using dict merge
extended_options = {**my_options, "max_tokens": 500}

Resumo das alterações interruptivas

Aspecto Antes Após
Opções do cliente de chat Argumentos de palavra-chave individuais (temperature=0.7) Dicionário único options (options={"temperature": 0.7})
Ferramentas de cliente de chat tools=[...] argumento de palavra-chave options={"tools": [...]}
Criação de agentes tools e instructions Argumentos de palavra-chave Ainda argumentos de palavra-chave (inalterados)
Agente run()tools Argumento de palavra-chave Ainda argumento de palavra-chave (inalterado)
Agente run()instructions Argumento de palavra-chave Movido para options={"instructions": ...}
Opções específicas do provedor additional_properties={...} Incluído diretamente no options dicionário
Opções padrão do agente Argumentos de palavra-chave no construtor default_options={...}
Opções de execução do agente Argumentos de palavra-chave em run() Parâmetro options={...}
Cliente digitando OpenAIChatClient() OpenAIChatClient[CustomOptions]() (opcional)
Digitação de agente Agent(...) Agent[CustomOptions](...) (opcional)

Testando sua migração

Atualizações do ChatClient

  1. Encontre todas as chamadas para get_response() que usem argumentos de palavra-chave como model=, , temperature=etc tools=.
  2. Mover todos os argumentos de palavra-chave para um options={...} dicionário
  3. Mover quaisquer additional_properties valores diretamente para o options dicionário

Atualizações do agente

  1. Localizar todos os Agent construtores e run() chamadas que usam argumentos de palavra-chave
  2. Mover argumentos de palavra-chave em construtores para default_options={...}
  3. Mover os argumentos run() de palavra-chave para options={...}
  4. Exceção: tools e instructions pode permanecer como argumentos de palavra-chave em Agent.__init__() e as_agent()
  5. Exceção: tools pode permanecer como um argumento de palavra-chave em run()

Atualizações personalizadas do cliente de chat

  1. Atualizar a assinatura do _inner_get_response() método: adicionar stream: bool e alterar o parâmetro antigo chat_options: ChatOptions para options: dict[str, Any]
  2. Atualizar o acesso de atributo (por exemplo, chat_options.model) para acessar o dicionário (por exemplo, options.get("model"))
  3. (Opcional) Se estiver usando parâmetros não padrão: defina um TypedDict personalizado
  4. Adicionar parâmetros de tipo genérico à classe cliente

Para Todos

  1. Executar Verificador de Tipo: Usar mypy ou pyright para capturar erros de tipos
  2. Testar de ponta a ponta: executar seu aplicativo para verificar a funcionalidade

Suporte ao IDE

O novo sistema baseado em TypedDict fornece excelente suporte ao IDE:

  • Preenchimento automático: obter sugestões para todas as opções disponíveis
  • Verificação de tipo: capturar chaves de opção inválidas no momento do desenvolvimento
  • Documentação: passe o cursor sobre os itens para ver as descrições
  • Específico do provedor: as opções de cada provedor mostram apenas parâmetros relevantes

Próximas etapas

Para ver os ditados tipados em ação para o caso de uso de Modelos de Raciocínio OpenAI com a API de Conclusão de Chat, explore este exemplo

Depois de concluir a migração:

  1. Explorar opções específicas do provedor na documentação da API
  2. Examinar exemplos atualizados
  3. Saiba mais sobre como criar clientes de chat personalizados

Para obter ajuda adicional, consulte a documentação do Agent Framework ou entre em contato com a comunidade.