Compartilhar via


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 fornece 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_id="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_id="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_id": "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 ChatAgent.__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 = ChatAgent(
    chat_client=client,
    tools=[my_function],
    instructions="You are a helpful assistant.",
    default_options={"model_id": "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_id, 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 ChatAgent.__init__() e create_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 argumentos de palavra-chave em dic 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_id="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_id="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_id": "gpt-4",
        "temperature": 0.7,
        "max_tokens": 1000,
    },
)

# Same pattern for streaming
async for chunk in client.get_streaming_response(
    "Tell me a story",
    options={
        "model_id": "gpt-4",
        "temperature": 0.9,
    },
):
    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 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_id="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_id": "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_id": "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.

  • 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 a Configuração do ChatAgent

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

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

from agent_framework import ChatAgent
from agent_framework.openai import OpenAIChatClient

client = OpenAIChatClient()

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

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

After:

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

client = OpenAIChatClient()
agent = ChatAgent(
    chat_client=client,
    name="assistant",
    default_options={ # <- type checkers will verify this dict
        "model_id": "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 tem 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_id": "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_id": "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_id": "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 ChatAgent
from agent_framework.openai import OpenAIChatClient

agent = ChatAgent(
    chat_client=OpenAIChatClient[OpenAIReasoningChatOptions](),
    default_options={
        "model_id": "o3",
        "max_tokens": 100,
        "allow_multiple_tool_calls": True,
        "reasoning_effort": "medium",
    },
)

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

from agent_framework import ChatAgent
from agent_framework.openai import OpenAIChatClient

agent = ChatAgent[OpenAIReasoningChatOptions](
    chat_client=OpenAIChatClient(),
    default_options={
        "model_id": "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, ChatMessage, ChatOptions, ChatResponse

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

After:

from typing import Generic
from agent_framework import BaseChatClient, ChatMessage, 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[ChatMessage],
        options: dict[str, Any],  # Note: parameter renamed and just a dict
        **kwargs: Any,
    ) -> ChatResponse:
        # Access options via dict access
        model = options.get("model_id")
        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_id="gpt-4",
    temperature=0.7,
    max_tokens=1000,
)

# After - all in options dict
await client.get_response(
    "Hello",
    options={
        "model_id": "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_id="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_id": "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 = ChatAgent(
    chat_client=client,
    name="assistant",
    tools=[my_function],
    instructions="You are helpful.",
    model_id="gpt-4",
)

# After - tools and instructions stay as keyword args on creation
agent = ChatAgent(
    chat_client=client,
    name="assistant",
    tools=[my_function],  # Still a keyword argument!
    instructions="You are helpful.",  # Still a keyword argument!
    default_options={"model_id": "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_id="o3",
    additional_properties={"reasoning_effort": "high"},
)

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

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

# Define reusable options
my_options: OpenAIChatOptions = {
    "model_id": "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) Ditado único options (options={"temperature": 0.7})
Ferramentas de cliente de chat tools=[...] argumento de palavra-chave options={"tools": [...]}
Criação de tools agentes 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 ChatAgent(...) ChatAgent[CustomOptions](...) (opcional)

Testando sua migração

Atualizações do ChatClient

  1. Localize todas as chamadas para get_response() e get_streaming_response() que usam argumentos de palavra-chave como model_id=, 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 ChatAgent

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

Atualizações personalizadas do cliente de chat

  1. Atualizar as assinaturas dos métodos _inner_get_response() e _inner_get_streaming_response(): alterar o parâmetro chat_options: ChatOptions para options: dict[str, Any]
  2. Atualizar o acesso de atributo (por exemplo, chat_options.model_id) para dict access (por exemplo, options.get("model_id"))
  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.