本指南幫助你將 Python 程式碼升級到 Microsoft Agent Framework 版本 Options 中引入的基於 TypedDict 的新系統。 這是一個 突破性的變更 ,提供了更好的型別安全性、IDE 自動補全以及執行時的可擴充性。
變更概觀
此版本引入了對選項傳遞給聊天客戶端與聊天代理的方式進行重大重構。
過去的運作方式
過去,期權是以 直接關鍵字參數 的形式傳遞於像 get_response()、 get_streaming_response()、 run()和 代理構造子等方法上:
# 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"},
)
現今運作方式
大多數選項現在會透過單一 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
},
)
註: 對於 代理人,
instructions和tools參數仍可作為直接關鍵字參數在ChatAgent.__init__()和client.as_agent()上。 對於agent.run(),只有tools作為關鍵字參數可用:# 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 )
關鍵變更
-
合併選項參數:大多數關鍵字參數(
model_id、temperature、等)現在都透過單一options指令傳遞 - 代理創建例外:以及
instructions作為直接關鍵字參數在tools和ChatAgent.__init__()上可用 - 代理執行例外:仍可在
tools上作為直接關鍵字參數使用 - 基於 TypedDict 的選項:選項被定義為以確保型別安全的類別
- 通用型態支援:聊天客戶端與代理支援提供者專用選項的通用型態,以允許執行時過載
- 提供者專屬選項:每個提供者都有其預設的 TypedDict(例如,
OpenAIChatOptions,OllamaChatOptions) - 不再有任何額外屬性:提供者的專用參數現在為主要型別欄位
優點
- 型別安全:IDE 自動補全與所有選項的型別檢查
- 提供者彈性:第一天就支援提供者專屬參數
- 更乾淨的程式碼:一致的基於字典的參數傳遞
- 更簡單的擴充:為特定使用情境(例如推理模型或其他 API 後端)建立自訂選項
移轉指南
1. 將關鍵字參數轉換為選項指令
最常見的變更是將個別關鍵字參數轉換到 options 字典中。
之前(關鍵字論證):
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="")
在(選項字典)之後:
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="")
如果你傳遞了不適合該客戶端的選項,IDE 會出現類型錯誤。
2. 使用特定提供者的選項(不再使用additional_properties)
過去,要傳遞非關鍵字參數集合中的提供者專用參數,必須使用 additional_properties 以下參數:
之前(使用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
},
)
之後(使用 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
},
)
之後(自訂子類別以適應新參數):
或者如果這個參數還沒加入 Agent Framework(因為它是新出現的,或是為 OpenAI 相容後端自訂),你現在可以將選項子類化,並使用通用支援:
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!
},
)
主要優點是大多數提供者專用的參數現在已成為類型化選項字典的一部分,為您提供:
- IDE 自動補全 功能涵蓋所有可用選項
- 類型檢查以捕捉無效的鍵或值
- 對於已知的提供者參數,不需要additional_properties
- 自訂或新增參數的簡單擴充
3. 更新 ChatAgent 設定
ChatAgent 初始化與執行方法遵循相同的模式:
之前(建構子與執行的關鍵字參數):
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. 供應商特定選項
每個提供者現在都有自己的 TypedDict 選項,這些選項預設已啟用。 這讓你能使用提供者專屬參數,並具備完整的型別安全:
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",
},
)
但你也可以明確說明:
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. 為專用模型建立自訂選項
新系統的一大強大功能是能為專門模型建立自訂的 TypedDict 選項。 這對於具有獨特參數的模型特別有用,例如使用 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. 提供選項的聊天代理
通用設定也擴展至聊天代理:
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",
},
)
而且你可以在客戶端和代理上指定泛型,因此這也成立:
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. 更新自訂聊天客戶端實作
如果你已經透過擴充 BaseChatClient實作自訂聊天客戶端,請更新內部方法:
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")
# ...
常見的移轉模式
模式一:簡單參數更新
# Before - keyword arguments
await client.get_response("Hello", temperature=0.7)
# After - options dict
await client.get_response("Hello", options={"temperature": 0.7})
模式二:多重參數
# 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,
},
)
模式三:帶有工具的聊天客戶端
對於聊天客戶端,tools 現在進入選項字典:
# 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",
},
)
模式四:帶工具與指令的代理人
對於建立代理而言, tools 和 instructions 可以保留為關鍵字參數。 對於 run(),只有 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",
},
)
模式五:提供者特定參數
# 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}
重大變更摘要
| 層面 | 之前 | 之後 |
|---|---|---|
| 聊天客戶端選項 | 個別關鍵字參數(temperature=0.7) |
單一 options 字詞 (options={"temperature": 0.7}) |
| 聊天客戶端工具 |
tools=[...] 關鍵字論證 |
options={"tools": [...]} |
代理創建 tools 與 instructions |
關鍵字論證 | 關鍵字參數(不變) |
代理人 run()tools |
關鍵詞論證 | 仍是關鍵字論證 (未改變) |
代理人 run()instructions |
關鍵詞論證 | 搬遷至 options={"instructions": ...} |
| 提供者專屬選項 | additional_properties={...} |
直接包含在 options dict中 |
| 代理預設選項 | 建構子上的關鍵詞參數 | default_options={...} |
| 代理程式執行選項 | 關鍵字參數 run() |
options={...} 參數 |
| 客戶正在輸入 | OpenAIChatClient() |
OpenAIChatClient[CustomOptions]() (選用) |
| 客服人員正在輸入 | ChatAgent(...) |
ChatAgent[CustomOptions](...) (選用) |
測試您的移轉
ChatClient 的更新
- 找出所有對
get_response()和get_streaming_response()的呼叫,它們使用的關鍵字參數如model_id=、temperature=、tools=等。 - 將所有關鍵字參數移入
options={...}字典 - 直接將任何
additional_properties數值移入字典options
ChatAgent 更新
- 找出所有使用關鍵字參數的
ChatAgent建構子和run()呼叫 - 將建構子上的關鍵字參數移至
default_options={...} - 將關鍵字參數從
run()移至options={...} -
例外:
tools和instructions可以作為關鍵字參數保留在ChatAgent.__init__()和create_agent()上 -
例外:
tools可以作為run()上的關鍵字參數保留
自訂聊天客戶端更新
- 更新
_inner_get_response()和_inner_get_streaming_response()方法簽名:將參數改chat_options: ChatOptions為options: dict[str, Any] - 將屬性存取(例如
chat_options.model_id)更新為 dict 存取(例如,options.get("model_id")) - (可選) 若使用非標準參數:定義自訂 TypedDict
- 在你的客戶端類別中加入通用型別參數
為所有人
-
執行類型檢查器:使用
mypy或pyright捕捉類型錯誤 - 端對端測試:執行應用程式以驗證功能
IDE 支援
新的基於 TypedDict 的系統提供優秀的 IDE 支援:
- 自動完成:獲得所有可用選項的建議
- 型別檢查:在開發時檢測無效選項鍵
- 文件說明:將滑鼠移到鍵上可查看說明
- 提供者專屬:每個提供者的選項僅顯示相關參數
後續步驟
想看看使用 OpenAI 推理模型搭配聊天完成 API 時,輸入的指令如何運作,請參考 此範例
完成移轉之後:
如需更多協助,請參閱 代理框架文件 或聯繫社群。