Partager via


Guide de mise à niveau : Options de conversation en tant que TypedDict avec génériques

Ce guide vous aide à mettre à niveau votre code Python vers le nouveau système TypedDict Options introduit dans la version 1.0.0b260114 de Microsoft Agent Framework. Il s’agit d’un changement cassant qui offre une sécurité de type améliorée, la saisie semi-automatique de l’IDE et l’extensibilité du runtime.

Vue d’ensemble des modifications

Cette version introduit une refactorisation majeure de la façon dont les options sont passées aux clients de conversation et aux agents de conversation.

Comment cela fonctionnait avant

Auparavant, les options étaient passées en tant qu’arguments directs de mot-clé dans des méthodes telles que , get_response(), get_streaming_response() et des constructeurs d’agent :

# 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"},
)

Comment ça fonctionne maintenant

La plupart des options sont désormais passées par le biais d’un seul options paramètre en tant que dictionnaire typé :

# 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
    },
)

Note : Pour les agents, les paramètres instructions et tools restent disponibles en tant qu'arguments de mot-clé directs sur ChatAgent.__init__() et client.as_agent(). Pour agent.run(), uniquement tools est disponible en tant qu’argument de mot clé :

# 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
)

Principales modifications

  1. Paramètre Options consolidées : la plupart des arguments de mot clé (model_id, temperatureetc.) sont désormais passés via une seule options dictée
  2. Exception pour la création de l’agent : instructions et tools reste disponible en tant qu’arguments de mot clé direct sur ChatAgent.__init__() et create_agent()
  3. Exception pour l’exécution de l’agent : tools reste disponible en tant qu’argument de mot clé direct sur agent.run()
  4. Options basées sur TypedDict : les options sont définies en tant que TypedDict classes pour la sécurité des types
  5. Prise en charge des types génériques : les clients de conversation et les agents prennent en charge les génériques pour les options spécifiques au fournisseur, afin d’autoriser les surcharges d’exécution
  6. Options spécifiques au fournisseur : chaque fournisseur a son propre TypedDict par défaut (par exemple, OpenAIChatOptions, OllamaChatOptions)
  7. Plus d’additional_properties : les paramètres spécifiques au fournisseur sont désormais des champs typés de première classe

Avantages

  • Sécurité de type : auto-complétion IDE et vérification de type pour toutes les options
  • Flexibilité du fournisseur : prise en charge des paramètres spécifiques au fournisseur le jour 1
  • Code propre : passage cohérent de paramètres basés sur un dictionnaire
  • Extension plus facile : créer des options personnalisées pour des cas d’usage spécialisés (par exemple, des modèles de raisonnement ou d’autres back-ends d’API)

Guide de Migration

1. Convertir des arguments de mot clé en options Dict

La modification la plus courante consiste à convertir des arguments de mot clé individuels au options dictionnaire.

Avant (arguments de mot clé) :

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="")

Après (dictionnaire d'options) :

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="")

Si vous transmettez des options qui ne conviennent pas à ce client, vous obtiendrez une erreur de type dans votre IDE.

2. Utilisation des options spécifiques au fournisseur (plus de propriétés supplémentaires)

Auparavant, pour passer des paramètres spécifiques au fournisseur qui ne faisaient pas partie du jeu de base d’arguments de mot clé, vous deviez utiliser le additional_properties paramètre :

Avant (utilisation de 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
    },
)

Après (options directes avec 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
    },
)

Après (sous-classification personnalisée pour les nouveaux paramètres) :

Ou s’il s’agit d’un paramètre qui ne fait pas encore partie de Agent Framework (car il est nouveau ou parce qu’il est personnalisé pour un back-end compatible OpenAI), vous pouvez désormais sous-classer les options et utiliser la prise en charge générique :

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!
    },
)

L’avantage clé est que la plupart des paramètres spécifiques au fournisseur font désormais partie du dictionnaire d’options typées, ce qui vous donne :

  • Autocomplétion de l'IDE pour toutes les options disponibles
  • Vérification de type pour intercepter des clés ou des valeurs non valides
  • Il n’est pas nécessaire de additional_properties pour les paramètres de fournisseur connus
  • Extension simple pour les paramètres personnalisés ou nouveaux

3. Mettre à jour la configuration chatAgent

L’initialisation chatAgent et les méthodes d’exécution suivent le même modèle :

Avant (arguments de mot clé sur le constructeur et exécution) :

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. Options spécifiques au fournisseur

Chaque fournisseur possède désormais son propre TypedDict pour les options, il est activé par défaut. Cela vous permet d’utiliser des paramètres spécifiques au fournisseur avec une sécurité de type complète :

Exemple 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",
    },
)

Mais vous pouvez également le rendre explicite :

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. Création d’options personnalisées pour les modèles spécialisés

Une fonctionnalité puissante du nouveau système est la possibilité de créer des options TypedDict personnalisées pour les modèles spécialisés. Cela est particulièrement utile pour les modèles qui ont des paramètres uniques, tels que des modèles de raisonnement avec 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. Agents de conversation avec options

La configuration générique a également été étendue aux agents de conversation :

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",
    },
)

et vous pouvez spécifier le générique sur le client et l’agent. Cela est donc également valide :

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. Mettre à jour les implémentations de client conversation personnalisées

Si vous avez implémenté un client de conversation personnalisé en étendant BaseChatClient, mettez à jour les méthodes internes :

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")
        # ...

Modèles de migration courants

Modèle 1 : Mise à jour de paramètres simple

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

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

Modèle 2 : Plusieurs paramètres

# 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,
    },
)

Modèle 3 : Client de discussion avec outils

Pour les clients de chat, tools est maintenant inclus dans le dictionnaire des options :

# 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",
    },
)

Modèle 4 : Agent avec outils et instructions

Pour la création de l’agent, tools et instructions peuvent rester en tant qu’arguments de mot-clé. Pour run(), uniquement tools est disponible :

# 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",
    },
)

Modèle 5 : paramètres spécifiques au fournisseur

# 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}

Résumé des changements cassants

Aspect Avant Après
Options du client de conversation Arguments de mot clé individuels (temperature=0.7) Dictionnaire unique options (options={"temperature": 0.7})
Outils clients de conversation tools=[...] argument de mot clé options={"tools": [...]}
Création d’agent tools et instructions Arguments de mot clé Arguments de mots-clés (inchangés)
Agent run()tools Argument de mot clé Toujours un argument de mot clé (inchangé)
Agent run()instructions Argument de mot clé Déplacé vers options={"instructions": ...}
Options spécifiques au fournisseur additional_properties={...} Inclus directement dans options dict
Options par défaut de l’agent Arguments de mot clé sur le constructeur default_options={...}
Options d’exécution de l’agent Arguments de mot clé sur run() Paramètre options={...}
Saisie du client OpenAIChatClient() OpenAIChatClient[CustomOptions]() (facultatif)
Saisie de l’agent ChatAgent(...) ChatAgent[CustomOptions](...) (facultatif)

Test de votre migration

Mises à jour ChatClient

  1. Recherchez tous les appels vers get_response() et get_streaming_response() qui utilisent des arguments de mot clé tels que model_id=, temperature=, tools=, etc.
  2. Déplacer tous les arguments de mot clé dans un options={...} dictionnaire
  3. Déplacer les additional_properties valeurs directement dans la options dictée

Mises à jour ChatAgent

  1. Rechercher tous les constructeurs et ChatAgent appels run() qui utilisent des arguments de mot clé
  2. Déplacer des arguments de mot clé sur les constructeurs vers default_options={...}
  3. Déplacer les arguments de mot clé vers run()options={...}
  4. Exception : tools et instructions peut rester en tant qu’arguments de mot clé sur ChatAgent.__init__() et create_agent()
  5. Exception : tools peut rester en tant qu’argument de mot clé sur run()

Mises à jour personnalisées du client de chat

  1. Mettre à jour les signatures des méthodes _inner_get_response() et _inner_get_streaming_response() : remplacer le paramètre chat_options: ChatOptions par options: dict[str, Any]
  2. Mettre à jour l’accès aux attributs (par exemple, chat_options.model_id) pour l’accès dictionnaire (par exemple, options.get("model_id"))
  3. (Facultatif) Si vous utilisez des paramètres non standard : Définir un TypedDict personnalisé
  4. Ajouter des paramètres de type générique à votre classe cliente

Pour tous

  1. Exécuter le vérificateur de type : Utiliser mypy ou pyright pour intercepter les erreurs de type
  2. Tester de bout en bout : exécutez votre application pour vérifier la fonctionnalité

Prise en charge de l’IDE

Le nouveau système TypedDict offre une excellente prise en charge de l’IDE :

  • Saisie semi-automatique : obtenir des suggestions pour toutes les options disponibles
  • Vérification de type : intercepter les clés d’option non valides au moment du développement
  • Documentation : Pointez sur les clés pour afficher les descriptions
  • Spécifique au fournisseur : les options de chaque fournisseur affichent uniquement les paramètres pertinents

Étapes suivantes

Pour voir les dictionnaires typés en action dans le cadre de l'utilisation des modèles de raisonnement OpenAI avec l'API de complétion de chat, explorez cet échantillon

Une fois la migration terminée :

  1. Explorer les options spécifiques au fournisseur dans la documentation de l’API
  2. Passer en revue les exemples mis à jour
  3. En savoir plus sur la création de clients de conversation personnalisés

Pour obtenir de l’aide supplémentaire, reportez-vous à la documentation agent Framework ou contactez la communauté.