Udostępnij przez


Przewodnik aktualizacji: Opcje czatu jako TypedDict z typami ogólnymi

Ten przewodnik pomaga uaktualnić kod języka Python do nowego systemu opartego na TypedDict wprowadzonego w wersji Options programu Microsoft Agent Framework. Jest to zmiana powodująca niezgodność , która zapewnia ulepszone bezpieczeństwo typów, autouzupełnianie środowiska IDE i rozszerzalność środowiska uruchomieniowego.

Omówienie zmian

W tej wersji wprowadzono główną refaktoryzację sposobu przekazywania opcji do klientów czatów i agentów czatów.

Jak to działało wcześniej

Wcześniej opcje zostały przekazane jako bezpośrednie argumenty słów kluczowych dla metod, takich jak get_response(), get_streaming_response(), run()i konstruktory agentów:

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

Jak to działa teraz

Większość opcji jest teraz przekazywana jako typizowany słownik za pomocą pojedynczego parametru options.

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

Uwaga: W przypadku agentów parametry instructions i tools pozostają dostępne jako bezpośrednie argumenty słów kluczowych na ChatAgent.__init__() i client.as_agent(). W przypadku agent.run() elementu tylko tools jest dostępny jako argument słowa kluczowego.

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

Kluczowe zmiany

  1. Parametr opcji skonsolidowanych: większość argumentów słów kluczowych (model_id, temperatureitp.) jest teraz przekazywana za pośrednictwem pojedynczego options dyktowania
  2. Wyjątek dotyczący tworzenia agenta: instructions i tools pozostają dostępne jako argumenty słów kluczowych bezpośrednich w systemach ChatAgent.__init__() i create_agent()
  3. Wyjątek dla uruchomienia agenta: tools pozostaje dostępny jako bezpośredni argument słowa kluczowego na agent.run()
  4. Opcje oparte na TypedDict: Opcje są definiowane jako klasy dla bezpieczeństwa typów
  5. Obsługa typów ogólnych: klienci czatu i agenci obsługują typy ogólne dla opcji specyficznych dla dostawcy, aby umożliwić przeciążenia środowiska uruchomieniowego
  6. Opcje specyficzne dla dostawcy: każdy dostawca ma własny domyślny typdDict (np. OpenAIChatOptions, ) OllamaChatOptions
  7. Koniec z additional_properties: Parametry specyficzne dla dostawcy są teraz polami o określonym typie pierwszego rzędu.

Korzyści

  • Bezpieczeństwo typu: autouzupełnianie IDE i sprawdzanie typu dla wszystkich opcji
  • Elastyczność dostawcy: obsługa parametrów specyficznych dla dostawcy pierwszego dnia
  • Czysty kod: spójne przekazywanie parametrów opartych na słownikach
  • Łatwiejsze rozszerzenie: tworzenie opcji niestandardowych dla wyspecjalizowanych przypadków użycia (np. modeli rozumowania lub innych zapleczy interfejsu API)

Przewodnik migracji

1. Konwertowanie argumentów słów kluczowych na opcje Dyktowanie

Najczęstszą zmianą jest konwertowanie pojedynczych argumentów słów kluczowych na options słownik.

Przed (argumenty kluczowe):

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

Po (opcje dict):

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

Jeśli przekażesz opcje, które nie są odpowiednie dla tego klienta, wystąpi błąd typu w środowisku IDE.

2. Korzystanie z opcji specyficznych dla dostawcy (brak dodatkowych właściwości)

Wcześniej, aby przekazać parametry specyficzne dla dostawcy, które nie były częścią podstawowego zestawu argumentów słów kluczowych, trzeba było użyć parametru additional_properties :

Przed (przy użyciu 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
    },
)

Po użyciu opcji bezpośrednich z 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
    },
)

Po (niestandardowym podklasowaniu dla nowych parametrów):

Lub jeśli jest to parametr, który nie jest jeszcze częścią struktury agenta (ponieważ jest nowy lub jest niestandardowy dla zaplecza zgodnego z interfejsem OpenAI), możesz teraz podklasować opcje i korzystać z ogólnej obsługi:

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

Kluczową korzyścią jest to, że większość parametrów specyficznych dla dostawcy jest teraz częścią słownika typów opcji, co daje:

  • Autouzupełnianie środowiska IDE dla wszystkich dostępnych opcji
  • Sprawdzanie typów w celu przechwycenia nieprawidłowych kluczy lub wartości
  • Nie ma potrzeby używania additional_properties dla znanych parametrów dostawcy
  • Łatwe rozszerzenie dla niestandardowych lub nowych parametrów

3. Zaktualizuj konfigurację czatagenta

Inicjowanie czatAgent i metody uruchamiania są zgodne z tym samym wzorcem:

Przed (argumenty słów kluczowych w konstruktorze i uruchomieniu):

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. Opcje Provider-Specific

Każdy dostawca ma teraz własny TypedDict przeznaczony dla opcji, który jest domyślnie włączony. Dzięki temu można używać parametrów specyficznych dla dostawcy z bezpieczeństwem pełnego typu:

Przykład interfejsu 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",
    },
)

Można jednak również jawnie określić:

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. Tworzenie opcji niestandardowych dla wyspecjalizowanych modeli

Jedną z zaawansowanych funkcji nowego systemu jest możliwość tworzenia niestandardowych opcji TypedDict dla wyspecjalizowanych modeli. Jest to szczególnie przydatne w przypadku modeli, które mają unikatowe parametry, takie jak modele rozumowania za pomocą interfejsu 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. Agenci czatu z opcjami

Konfiguracja ogólna została również rozszerzona na agentów czatu:

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

i można określić ogólny zarówno na kliencie, jak i na agencie, więc jest to również prawidłowe:

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. Aktualizowanie niestandardowych implementacji klienta czatu

Jeśli zaimplementowałeś niestandardowego klienta czatu poprzez rozszerzenie BaseChatClient, zaktualizuj metody wewnętrzne:

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

Typowe wzorce migracji

Wzorzec 1. Aktualizacja prostego parametru

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

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

Wzorzec 2: wiele parametrów

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

Wzorzec 3: Klient czatu z narzędziami

W przypadku klientów czatu tools teraz znajduje się w słowniku opcji.

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

Wzorzec 4: Agent z narzędziami i instrukcjami

W przypadku tworzenia agenta, tools i instructions mogą pozostać jako argumenty słowa kluczowego. Dla run() dostępny jest tylko tools.

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

Wzorzec 5: parametry specyficzne dla dostawcy

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

Podsumowanie zmian przełomowych

Aspekt Przed Po
Opcje klienta czatu Pojedyncze argumenty słów kluczowych (temperature=0.7) Pojedynczy options dykt (options={"temperature": 0.7})
Narzędzia klienta czatu tools=[...] argument słowa kluczowego options={"tools": [...]}
Tworzenie tools agenta i instructions Argumenty słów kluczowych Nadal argumenty słów kluczowych (bez zmian)
Agenta run()tools Argument słowa kluczowego Nadal argument słowa kluczowego (bez zmian)
Agenta run()instructions Argument słowa kluczowego Przeniesiono do options={"instructions": ...}
Opcje specyficzne dla dostawcy additional_properties={...} Zawarty bezpośrednio w options słowniku
Opcje domyślne agenta Argumenty słów kluczowych w konstruktorze default_options={...}
Opcje uruchamiania agenta Argumenty słów kluczowych na run() parametr options={...}
Wpisywanie klienta OpenAIChatClient() OpenAIChatClient[CustomOptions]() (opcjonalny)
Wpisywanie przez agenta ChatAgent(...) ChatAgent[CustomOptions](...) (opcjonalny)

Testowanie migracji

Aktualizacje ChatClient

  1. Znajdź wszystkie wywołania metody get_response() i get_streaming_response() używających argumentów słów kluczowych, takich jak model_id=, temperature=, tools=, itp.
  2. Przenoszenie wszystkich argumentów słów kluczowych do słownika options={...}
  3. Przenoszenie dowolnych additional_properties wartości bezpośrednio do dyktowania options

Aktualizacje usługi ChatAgent

  1. Znajdowanie wszystkich ChatAgent konstruktorów i run() wywołań używających argumentów słów kluczowych
  2. Przenoszenie argumentów słów kluczowych w konstruktorach do default_options={...}
  3. Przenieś argumenty słów kluczowych na run() do options={...}
  4. Wyjątek: tools i instructions mogą pozostać jako argumenty słowa kluczowego w ChatAgent.__init__() i create_agent()
  5. Wyjątek: tools może pozostać jako argument słowa kluczowego w run()

Niestandardowe aktualizacje klienta czatu

  1. Zaktualizuj podpisy metod _inner_get_response() i _inner_get_streaming_response(): zmień parametr chat_options: ChatOptions na options: dict[str, Any]
  2. Zaktualizuj dostęp do atrybutów (np. chat_options.model_id) na dostęp do słownika (np. options.get("model_id"))
  3. (Opcjonalnie) W przypadku używania niestandardowych parametrów: Definiowanie niestandardowego elementu TypedDict
  4. Dodawanie parametrów typu ogólnego do klasy klienta

Dla wszystkich

  1. Uruchom moduł sprawdzania typów: użyj polecenia mypy lub pyright , aby przechwycić błędy typu
  2. Testowanie kompleksowe: uruchamianie aplikacji w celu zweryfikowania funkcjonalności

Obsługa środowiska IDE

Nowy system oparty na typedDict zapewnia doskonałą obsługę środowiska IDE:

  • Autouzupełnianie: uzyskiwanie sugestii dotyczących wszystkich dostępnych opcji
  • Sprawdzanie typów: przechwytywanie nieprawidłowych kluczy opcji w czasie programowania
  • Dokumentacja: Umieść kursor nad kluczami, aby wyświetlić opisy
  • Specyficzne dla dostawcy: opcje każdego dostawcy pokazują tylko odpowiednie parametry

Dalsze kroki

Aby wyświetlić wpisane dykty w działaniu w przypadku używania modeli rozumowania openAI z interfejsem API uzupełniania czatu, zapoznaj się z tym przykładem

Po zakończeniu migracji:

  1. Eksplorowanie opcji specyficznych dla dostawcy w dokumentacji interfejsu API
  2. Przejrzyj zaktualizowane przykłady
  3. Dowiedz się więcej o tworzeniu niestandardowych klientów czatów

Aby uzyskać dodatkową pomoc, zapoznaj się z dokumentacją platformy Agent Framework lub skontaktuj się ze społecznością.