Partilhar via


Guia de Atualização: Opções de Chat como TypedDict com Generics

Este guia ajuda-o a atualizar o seu código Python para o novo sistema baseado Options em TypedDict introduzido na versão 1.0.0b260114 do Microsoft Agent Framework. Esta é uma alteração que proporciona maior segurança de tipos, autocompletamento do IDE e extensibilidade em tempo de execução.

Visão geral das alterações

Esta versão introduz uma grande refatoração da forma 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 diretos por palavras-chave em métodos como get_response(), get_streaming_response(), run(), e construtores agentes:

# 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 como 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 instructions parâmetros e tools continuam disponíveis como argumentos diretos de palavras-chave em ChatAgent.__init__() e client.as_agent(). Para agent.run(), apenas tools está disponível como 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 mudanças

  1. Parâmetro de Opções Consolidadas: A maioria dos argumentos de palavras-chave (model_id, temperature, etc.) são agora passados através de um único options dicionário.
  2. Exceção para Criação de Agente: instructions e tools permanecem disponíveis como argumentos diretos de palavras-chave em ChatAgent.__init__() e create_agent()
  3. Exceção para Agent Run: tools permanece disponível como argumento direto de palavra-chave em agent.run()
  4. Opções baseadas em TypedDict: As opções são definidas como TypedDict classes para segurança de tipos
  5. Suporte a Tipos Genéricos: Clientes e agentes de chat oferecem suporte a tipos genéricos para opções específicas de fornecedores, permitindo sobrecargas em tempo de execução.
  6. Opções específicas do fornecedor: Cada fornecedor tem o seu próprio TypedDict por defeito (por exemplo, OpenAIChatOptions, OllamaChatOptions)
  7. No More additional_properties: Os parâmetros específicos do fornecedor são agora campos tipados de primeira classe

Benefícios

  • Segurança de Tipo: Preenchimento automático e verificação de tipos do IDE para todas as opções
  • Flexibilidade do Prestador: Suporte para parâmetros específicos do prestador no primeiro dia
  • Código mais limpo: Passagem consistente de parâmetros baseada em ditados
  • Extensão mais fácil: Criar opções personalizadas para casos de uso especializados (por exemplo, modelos de raciocínio ou outros backends de API)

Guia de migração

1. Converter argumentos de palavras-chave em dito de opções

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

Antes (argumentos por palavras-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="")

Depois (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 passar opções que não são adequadas para aquele cliente, receberá um erro de tipos no seu IDE.

2. Usar opções específicas do fornecedor (Sem propriedades_adicionais)

Anteriormente, para passar parâmetros específicos do fornecedor que não faziam parte do conjunto base de argumentos de palavras-chave, era necessário 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 (subclasse personalizada para novos parâmetros):

Ou, se for um parâmetro que ainda não faz parte do Agent Framework (porque é novo, ou porque é personalizado para um backend compatível com OpenAI), pode agora subclassificar 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 fornecedor faz agora parte do dicionário de opções tipadas, proporcionando-lhe:

  • O IDE preencheu automaticamente para todas as opções disponíveis
  • Verificação de tipos para detetar chaves ou valores inválidos
  • Não há necessidade de additional_properties para parâmetros conhecidos do fornecedor
  • Extensão fácil para parâmetros personalizados ou novos

3. Atualização da configuração do ChatAgent

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

Antes (argumentos-chave sobre construtor e 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 Fornecedor

Cada fornecedor agora tem o seu próprio TypedDict para opções, que são ativadas por padrão. Isto permite-lhe utilizar parâmetros específicos do fornecedor com total segurança de tipo:

Exemplo da 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 também podes tornar 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. Criação de Opções Personalizadas para Modelos Especializados

Uma funcionalidade poderosa do novo sistema é a capacidade de criar opções personalizadas de TypedDict para modelos especializados. Isto é particularmente útil para modelos que têm parâmetros únicos, 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 podes especificar o genérico tanto no cliente como no agente, por isso isto 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 de Clientes de Chat

Se implementou um cliente de chat personalizado ao estender 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 Simples de Parâmetro

# 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: Múltiplos 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 entra no 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 criação de agentes, tools e instructions podem permanecer como argumentos de palavras-chave. Para run(), apenas 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 Mudanças Recentes

Aspeto Antes Depois
Opções do cliente de chat Argumentos individuais de palavras-chave (temperature=0.7) Ditado único options (options={"temperature": 0.7})
Ferramentas de cliente de chat tools=[...] Argumento de palavra-chave options={"tools": [...]}
Criação tools de agentes e instructions Argumentos de palavras-chave Ainda argumentos de palavras-chave (inalterados)
Agente run()tools Argumento da palavra-chave Ainda argumento da palavra-chave (inalterado)
Agente run()instructions Argumento da palavra-chave Transferido para options={"instructions": ...}
Opções específicas para cada fornecedor additional_properties={...} Incluído diretamente no options dicionário
Opções padrão do agente Argumentos de palavras-chave no construtor default_options={...}
Opções de execução do agente Argumentos de palavras-chave em run() parâmetro options={...}
Cliente a digitar OpenAIChatClient() OpenAIChatClient[CustomOptions]() (opcional)
Agente a digitar ChatAgent(...) ChatAgent[CustomOptions](...) (opcional)

Testando sua migração

Atualizações do ChatClient

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

Atualizações do ChatAgent

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

Atualizações do Cliente de Chat Personalizado

  1. Atualize as assinaturas dos métodos _inner_get_response() e _inner_get_streaming_response(): altere o parâmetro de chat_options: ChatOptions para options: dict[str, Any]
  2. Atualizar o acesso a atributos (por exemplo, chat_options.model_id) para acesso a ditados (por exemplo, options.get("model_id"))
  3. (Opcional) Se usar parâmetros não padrão: Defina um TypedDict personalizado
  4. Adicione parâmetros genéricos de tipo à sua classe cliente

Para Todos

  1. Executar Verificador de Tipos: Usar mypy ou pyright para apanhar erros de tipo
  2. Teste de ponta a ponta: Execute a sua aplicação para verificar a funcionalidade

Suporte IDE

O novo sistema baseado em TypedDict oferece excelente suporte a IDE:

  • Autocompletar: Obtenha sugestões para todas as opções disponíveis
  • Verificação de Tipos: Detetar chaves de opção inválidas no momento do desenvolvimento
  • Documentação: Passe o rato sobre as teclas para ver as descrições
  • Específico do fornecedor: As opções de cada fornecedor mostram apenas parâmetros relevantes

Próximas Etapas

Para ver os ditos digitados em ação no caso de utilização de Modelos de Raciocínio OpenAI com a API Chat Completing, explore este exemplo

Após concluir a migração:

  1. Explore opções específicas do fornecedor na documentação da API
  2. Revisão de exemplos atualizados
  3. Saiba como criar clientes de chat personalizados

Para ajuda adicional, consulte a documentação do Agent Framework ou contacte a comunidade.