Dela via


Uppgraderingsguide: Chattalternativ som TypedDict med generika

Den här guiden hjälper dig att uppgradera Din Python-kod till det nya TypedDict-baserade Options systemet som introducerades i version 1.0.0b260114 av Microsoft Agent Framework. Det här är en icke-bakåtkompatibel ändring som ger bättre IDE:s automatiska komplettering, typsäkerhet och körningstidens utökningsbarhet.

Översikt över ändringar

Den här versionen introducerar en stor refaktorisering av hur alternativ skickas till chattklienter och chattagenter.

Hur det fungerade innan

Tidigare skickades alternativ som direkta nyckelordsargument på metoder som get_response(), get_streaming_response(), run()och agentkonstruktorer:

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

Så här fungerar det nu

De flesta alternativ skickas nu via en enskild options parameter som en skriven ordlista:

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

Observera: För Agenter förblir parametrarna instructions och tools tillgängliga som direkta nyckelordsargument på ChatAgent.__init__() och client.as_agent(). För agent.run()är endast tools tillgängligt som ett nyckelordsargument:

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

Viktiga ändringar

  1. Parameter för konsoliderade alternativ: De flesta nyckelordsargument (model_id, temperatureosv.) skickas nu via en enda options diktamen
  2. Undantag för skapande av agent: instructions och tools förblir tillgängligt som direkta nyckelordsargument på ChatAgent.__init__() och create_agent()
  3. Undantag för Agent Run: tools är fortfarande tillgängligt som ett direkt keyword-argument på agent.run()
  4. TypedDict-baserade alternativ: Alternativ definieras som TypedDict klasser för typsäkerhet
  5. Stöd för generisk typ: Chattklienter och -agenter stöder generiska tjänster för leverantörsspecifika alternativ, för att möjliggöra overloads vid körning
  6. Providerspecifika alternativ: Varje provider har sin egen standardtypeddict (t.ex. OpenAIChatOptions, OllamaChatOptions)
  7. Inga fler additional_properties: Providerspecifika parametrar är nu förstklassiga typfält

Fördelar

  • Typsäkerhet: IDE-automatisk komplettering och typkontroll för alla alternativ
  • Providerflexitet: Stöd för providerspecifika parametrar dag ett
  • Renare kod: Konsekvent dikteringsbaserad parameteröverföring
  • Enklare tillägg: Skapa anpassade alternativ för specialiserade användningsfall (t.ex. resonemangsmodeller eller andra API-serverdelar)

Migreringsguide

1. Konvertera nyckelordsargument till Alternativ Diktering

Den vanligaste ändringen är att konvertera enskilda nyckelordsargument till options ordlistan.

Före (argument med nyckelord):

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

Efter (alternativordlista):

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

Om du skickar alternativ som inte är lämpliga för den klienten får du ett typfel i din IDE.

2. Använda leverantörsspecifika alternativen (inga fler additional_properties)

Tidigare behövde du använda additional_properties-parametern för att skicka providerspecifika parametrar som inte ingick i basuppsättningen av nyckelordsargument.

Före (användning av 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
    },
)

Efter (direkta alternativ med 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
    },
)

Efter (anpassad underklassificering för nya parametrar):

Eller om det är en parameter som ännu inte är en del av Agent Framework (eftersom den är ny eller för att den är anpassad för en OpenAI-kompatibel serverdel) kan du nu underklassa alternativen och använda det allmänna stödet:

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

Den viktigaste fördelen är att de flesta providerspecifika parametrar nu är en del av ordlistan med inskrivna alternativ, vilket ger dig följande:

  • IDE-automatisk komplettering för alla tillgängliga alternativ
  • Typkontroll för att fånga ogiltiga nycklar eller värden
  • Inget behov av additional_properties för kända providerparametrar
  • Enkelt tillägg för anpassade eller nya parametrar

3. Uppdatera ChatAgent-konfiguration

ChatAgent-initiering och körningsmetoder följer samma mönster:

Före (nyckelordsargument för konstruktor och run-metod):

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. Leverantörsspecifika alternativ

Varje provider har nu sin egen TypedDict för alternativ, dessa är aktiverade som standard. På så sätt kan du använda providerspecifika parametrar med fullständig typsäkerhet:

OpenAI-exempel:

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

Men du kan också göra det explicit:

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. Skapa anpassade alternativ för specialiserade modeller

En kraftfull funktion i det nya systemet är möjligheten att skapa anpassade TypedDict-alternativ för specialiserade modeller. Detta är särskilt användbart för modeller som har unika parametrar, till exempel resonemangsmodeller med 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. Chattagenter med alternativ

Den allmänna konfigurationen har också utökats till chattagenter:

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

och du kan ange det allmänna på både klienten och agenten, så detta är också giltigt:

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. Uppdatera implementeringar av anpassad chattklient

Om du har implementerat en anpassad chattklient genom att utöka BaseChatClient, uppdatera de interna metoderna.

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

Vanliga migreringsmönster

Mönster 1: Enkel parameteruppdatering

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

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

Mönster 2: Flera parametrar

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

Mönster 3: Chattklient med verktyg

För chattklienter, tools placeras nu i alternativordlistan:

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

Mönster 4: Agent med verktyg och instruktioner

För att skapa agenter kan tools och instructions vara kvar som nyckelordsargument. För run()är endast tools tillgängligt:

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

Mönster 5: Leverantörsspecifika parametrar

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

Sammanfattning av förändringar som bryter kompatibiliteten

Aspekt Före Efter
Alternativ för chattklient Enskilda nyckelordsargument (temperature=0.7) Enkel options ordlista (options={"temperature": 0.7})
Chattklientverktyg tools=[...] nyckelordsargument options={"tools": [...]}
Skapa agent tools och instructions Nyckelordsargument Fortfarande nyckelordsargument (oförändrade)
Agent run()tools Nyckelordsargument Fortfarande nyckelordsargument (oförändrat)
Agent run()instructions Nyckelordsargument Har flyttats till options={"instructions": ...}
Leverantörsspecifika alternativ additional_properties={...} Ingår direkt i options diktamen
Standardalternativ för agent Nyckelordsargument för konstruktor default_options={...}
Alternativ för agentkörning Nyckelordsargument på run() options={...}-parametern
Klient skriver OpenAIChatClient() OpenAIChatClient[CustomOptions]() (valfritt)
Agent skriver ChatAgent(...) ChatAgent[CustomOptions](...) (valfritt)

Testa migreringen

ChatClient-uppdateringar

  1. Hitta alla anrop till get_response() och get_streaming_response() som använder nyckelordsargument som model_id=, temperature=, tools=, osv.
  2. Flytta alla nyckelordsargument till en options={...} ordlista
  3. Flytta alla additional_properties värden direkt till diktamen options

ChatAgent-uppdateringar

  1. Hitta alla ChatAgent konstruktorer och run() anrop som använder nyckelordsargument
  2. Flytta nyckelordsargument på konstruktorer till default_options={...}
  3. Flytta nyckelordsargument run() till options={...}
  4. Undantag: tools och instructions kan vara kvar som nyckelordsargument på ChatAgent.__init__() och create_agent()
  5. Undantag: tools kan finnas kvar som ett nyckelordsargument på run()

Uppdateringar av anpassad chattklient

  1. _inner_get_response() Uppdatera - och _inner_get_streaming_response() -metodsignaturerna: ändra chat_options: ChatOptions parametern tilloptions: dict[str, Any]
  2. Uppdatera attributåtkomst (t.ex. chat_options.model_id) till dikteringsåtkomst (t.ex. options.get("model_id"))
  3. (Valfritt) Om du använder icke-standardparametrar: Definiera en anpassad TypedDict
  4. Lägga till generiska typparametrar i klientklassen

För alla

  1. Kör typkontroll: Använd mypy eller pyright för att fånga upp typfel
  2. Testa från slutpunkt till slutpunkt: Kör programmet för att verifiera funktioner

IDE-support

Det nya TypedDict-baserade systemet ger utmärkt IDE-stöd:

  • Komplettera automatiskt: Få förslag på alla tillgängliga alternativ
  • Typkontroll: Fånga ogiltiga alternativnycklar under utvecklingsfasen
  • Dokumentation: Hovra över nycklar för att se beskrivningar
  • Providerspecifik: Varje providers alternativ visar endast relevanta parametrar

Nästa steg

Om du vill se de inskrivna dikteringarna i praktiken för att använda OpenAI-resonemangsmodeller med API:et för chattslutsättning kan du utforska det här exemplet

När migreringen har slutförts:

  1. Utforska providerspecifika alternativ i API-dokumentationen
  2. Granska uppdaterade exempel
  3. Lär dig mer om att skapa anpassade chattklienter

Mer hjälp finns i Agent Framework-dokumentationen eller kontakta communityn.