Skip to content

Commit d7db35d

Browse files
authored
Python: Fix Azure AI Inference connector model_extras duplication (#13066)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> Addresses #13005 ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> 1. Remove the `extra_parameters` key from `AzureAIInferenceChatPromptExecutionSettings` before calling the chat completion API to avoid unknown parameter error. 2. Allow setting the API version on the `AzureAIInferenceXXX` connectors. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄
1 parent 06d6494 commit d7db35d

File tree

8 files changed

+130
-3
lines changed

8 files changed

+130
-3
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Copyright (c) Microsoft. All rights reserved.
2+
3+
import asyncio
4+
5+
from semantic_kernel.connectors.ai.azure_ai_inference import (
6+
AzureAIInferenceChatCompletion,
7+
AzureAIInferenceChatPromptExecutionSettings,
8+
)
9+
from semantic_kernel.contents import ChatHistory
10+
11+
"""
12+
This sample demonstrates an example of how to use reasoning models using the Azure AI Inference service.
13+
"""
14+
15+
chat_service = AzureAIInferenceChatCompletion(
16+
ai_model_id="gpt-5-mini",
17+
# You must specify the endpoint and api_key or configure them via environment variables:
18+
# AZURE_AI_INFERENCE_ENDPOINT
19+
# AZURE_AI_INFERENCE_API_KEY
20+
endpoint="...",
21+
api_key="...",
22+
)
23+
request_settings = AzureAIInferenceChatPromptExecutionSettings(
24+
extra_parameters={
25+
"reasoning_effort": "medium",
26+
"verbosity": "medium",
27+
},
28+
)
29+
30+
# Create a ChatHistory object
31+
chat_history = ChatHistory()
32+
33+
# This is the system message that gives the chatbot its personality.
34+
developer_message = """
35+
As an assistant supporting the user,
36+
you recognize all user input
37+
as questions or consultations and answer them.
38+
"""
39+
# The developer message was newly introduced for reasoning models such as OpenAI’s o1 and o1-mini.
40+
# `system message` cannot be used with reasoning models.
41+
chat_history.add_developer_message(developer_message)
42+
43+
44+
async def chat() -> bool:
45+
try:
46+
user_input = input("User:> ")
47+
except KeyboardInterrupt:
48+
print("\n\nExiting chat...")
49+
return False
50+
except EOFError:
51+
print("\n\nExiting chat...")
52+
return False
53+
54+
if user_input == "exit":
55+
print("\n\nExiting chat...")
56+
return False
57+
58+
chat_history.add_user_message(user_input)
59+
60+
# Get the chat message content from the chat completion service.
61+
response = await chat_service.get_chat_message_content(
62+
chat_history=chat_history,
63+
settings=request_settings,
64+
)
65+
if response:
66+
print(f"Reasoning model:> {response}")
67+
68+
# Add the chat message to the chat history to keep track of the conversation.
69+
chat_history.add_message(response)
70+
71+
return True
72+
73+
74+
async def main() -> None:
75+
# Start the chat loop. The chat loop will continue until the user types "exit".
76+
chatting = True
77+
while chatting:
78+
chatting = await chat()
79+
80+
# Sample output:
81+
# User:> Why is the sky blue in one sentence?
82+
# Mosscap:> The sky appears blue because air molecules in the atmosphere scatter shorter-wavelength (blue)
83+
# light more efficiently than longer-wavelength (red) light.
84+
85+
86+
if __name__ == "__main__":
87+
asyncio.run(main())

python/semantic_kernel/connectors/ai/azure_ai_inference/azure_ai_inference_settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from pydantic import SecretStr
66

7+
from semantic_kernel.connectors.ai.open_ai.const import DEFAULT_AZURE_API_VERSION
78
from semantic_kernel.kernel_pydantic import HttpsUrl, KernelBaseSettings
89
from semantic_kernel.utils.feature_stage_decorator import experimental
910

@@ -29,9 +30,12 @@ class AzureAIInferenceSettings(KernelBaseSettings):
2930
This value can be found in the Keys & Endpoint section when examining
3031
your resource from the Azure portal. You can use either KEY1 or KEY2.
3132
(Env var AZURE_AI_INFERENCE_API_KEY)
33+
- api_version: str | None - The API version to use. The default value is "2024-10-21".
34+
(Env var AZURE_AI_INFERENCE_API_VERSION)
3235
"""
3336

3437
env_prefix: ClassVar[str] = "AZURE_AI_INFERENCE_"
3538

3639
endpoint: HttpsUrl
3740
api_key: SecretStr | None = None
41+
api_version: str = DEFAULT_AZURE_API_VERSION

python/semantic_kernel/connectors/ai/azure_ai_inference/services/azure_ai_inference_base.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def __init__(
4747
client_type: AzureAIInferenceClientType,
4848
api_key: str | None = None,
4949
endpoint: str | None = None,
50+
api_version: str | None = None,
5051
env_file_path: str | None = None,
5152
env_file_encoding: str | None = None,
5253
client: ChatCompletionsClient | EmbeddingsClient | None = None,
@@ -60,11 +61,13 @@ def __init__(
6061
The following environment variables are used:
6162
- AZURE_AI_INFERENCE_API_KEY
6263
- AZURE_AI_INFERENCE_ENDPOINT
64+
- AZURE_AI_INFERENCE_API_VERSION
6365
6466
Args:
6567
client_type (AzureAIInferenceClientType): The client type to use.
6668
api_key (str | None): The API key for the Azure AI Inference service deployment. (Optional)
6769
endpoint (str | None): The endpoint of the Azure AI Inference service deployment. (Optional)
70+
api_version (str | None): The API version to use. (Optional)
6871
env_file_path (str | None): The path to the environment file. (Optional)
6972
env_file_encoding (str | None): The encoding of the environment file. (Optional)
7073
client (ChatCompletionsClient | None): The Azure AI Inference client to use. (Optional)
@@ -81,6 +84,7 @@ def __init__(
8184
azure_ai_inference_settings = AzureAIInferenceSettings(
8285
api_key=api_key,
8386
endpoint=endpoint,
87+
api_version=api_version,
8488
env_file_path=env_file_path,
8589
env_file_encoding=env_file_encoding,
8690
)
@@ -93,6 +97,7 @@ def __init__(
9397
endpoint=endpoint,
9498
credential=AzureKeyCredential(azure_ai_inference_settings.api_key.get_secret_value()),
9599
user_agent=SEMANTIC_KERNEL_USER_AGENT,
100+
api_version=azure_ai_inference_settings.api_version,
96101
)
97102
else:
98103
if credential is None:
@@ -102,6 +107,7 @@ def __init__(
102107
endpoint=endpoint,
103108
credential=credential,
104109
user_agent=SEMANTIC_KERNEL_USER_AGENT,
110+
api_version=azure_ai_inference_settings.api_version,
105111
)
106112

107113
args: dict[str, Any] = {

python/semantic_kernel/connectors/ai/azure_ai_inference/services/azure_ai_inference_chat_completion.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def __init__(
6666
ai_model_id: str,
6767
api_key: str | None = None,
6868
endpoint: str | None = None,
69+
api_version: str | None = None,
6970
service_id: str | None = None,
7071
env_file_path: str | None = None,
7172
env_file_encoding: str | None = None,
@@ -78,11 +79,13 @@ def __init__(
7879
The following environment variables are used:
7980
- AZURE_AI_INFERENCE_API_KEY
8081
- AZURE_AI_INFERENCE_ENDPOINT
82+
- AZURE_AI_INFERENCE_API_VERSION
8183
8284
Args:
8385
ai_model_id: (str): A string that is used to identify the model such as the model name. (Required)
8486
api_key (str | None): The API key for the Azure AI Inference service deployment. (Optional)
8587
endpoint (str | None): The endpoint of the Azure AI Inference service deployment. (Optional)
88+
api_version (str | None): The API version to use. (Optional)
8689
service_id (str | None): Service ID for the chat completion service. (Optional)
8790
env_file_path (str | None): The path to the environment file. (Optional)
8891
env_file_encoding (str | None): The encoding of the environment file. (Optional)
@@ -99,6 +102,7 @@ def __init__(
99102
"client_type": AzureAIInferenceClientType.ChatCompletions,
100103
"client": client,
101104
"endpoint": endpoint,
105+
"api_version": api_version,
102106
"env_file_path": env_file_path,
103107
"env_file_encoding": env_file_encoding,
104108
}
@@ -139,6 +143,9 @@ async def _inner_get_chat_message_contents(
139143
assert isinstance(self.client, ChatCompletionsClient) # nosec
140144
with AzureAIInferenceTracing():
141145
settings_dict = settings.prepare_settings_dict()
146+
# Remove the extra parameters since it will be passed in via the `model_extras` param
147+
settings_dict.pop("extra_parameters", None)
148+
142149
self._handle_structured_output(settings, settings_dict)
143150
response: ChatCompletions = await self.client.complete(
144151
messages=self._prepare_chat_history_for_request(chat_history),
@@ -165,6 +172,9 @@ async def _inner_get_streaming_chat_message_contents(
165172
assert isinstance(self.client, ChatCompletionsClient) # nosec
166173
with AzureAIInferenceTracing():
167174
settings_dict = settings.prepare_settings_dict()
175+
# Remove the extra parameters since it will be passed in via the `model_extras` param
176+
settings_dict.pop("extra_parameters", None)
177+
168178
self._handle_structured_output(settings, settings_dict)
169179
response: AsyncStreamingChatCompletions = await self.client.complete(
170180
stream=True,

python/semantic_kernel/connectors/ai/azure_ai_inference/services/azure_ai_inference_text_embedding.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def __init__(
3535
ai_model_id: str,
3636
api_key: str | None = None,
3737
endpoint: str | None = None,
38+
api_version: str | None = None,
3839
service_id: str | None = None,
3940
env_file_path: str | None = None,
4041
env_file_encoding: str | None = None,
@@ -46,11 +47,13 @@ def __init__(
4647
The following environment variables are used:
4748
- AZURE_AI_INFERENCE_API_KEY
4849
- AZURE_AI_INFERENCE_ENDPOINT
50+
- AZURE_AI_INFERENCE_API_VERSION
4951
5052
Args:
5153
ai_model_id: (str): A string that is used to identify the model such as the model name. (Required)
5254
api_key (str | None): The API key for the Azure AI Inference service deployment. (Optional)
5355
endpoint (str | None): The endpoint of the Azure AI Inference service deployment. (Optional)
56+
api_version (str | None): The API version to use. (Optional)
5457
service_id (str | None): Service ID for the chat completion service. (Optional)
5558
env_file_path (str | None): The path to the environment file. (Optional)
5659
env_file_encoding (str | None): The encoding of the environment file. (Optional)
@@ -65,6 +68,7 @@ def __init__(
6568
client_type=AzureAIInferenceClientType.Embeddings,
6669
api_key=api_key,
6770
endpoint=endpoint,
71+
api_version=api_version,
6872
env_file_path=env_file_path,
6973
env_file_encoding=env_file_encoding,
7074
client=client,

python/semantic_kernel/connectors/ai/open_ai/settings/azure_open_ai_settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class AzureOpenAISettings(KernelBaseSettings):
8484
your resource from the Azure portal, the endpoint should end in openai.azure.com.
8585
If both base_url and endpoint are supplied, base_url will be used.
8686
(Env var AZURE_OPENAI_ENDPOINT)
87-
- api_version: str | None - The API version to use. The default value is "2024-02-01".
87+
- api_version: str | None - The API version to use. The default value is "2024-10-21".
8888
(Env var AZURE_OPENAI_API_VERSION)
8989
- token_endpoint: str - The token endpoint to use to retrieve the authentication token.
9090
The default value is "https://cognitiveservices.azure.com/.default".

python/tests/unit/connectors/ai/azure_ai_inference/services/test_azure_ai_inference_chat_completion.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,15 @@ def test_azure_ai_inference_chat_completion_init_with_service_id(
6666
assert isinstance(azure_ai_inference.client, ChatCompletionsClient)
6767

6868

69+
def test_azure_ai_inference_chat_completion_init_with_api_version(azure_ai_inference_unit_test_env, model_id) -> None:
70+
"""Test initialization of AzureAIInferenceChatCompletion with api_version"""
71+
azure_ai_inference = AzureAIInferenceChatCompletion(model_id, api_version="2024-02-15-test")
72+
73+
assert azure_ai_inference.ai_model_id == model_id
74+
assert isinstance(azure_ai_inference.client, ChatCompletionsClient)
75+
assert azure_ai_inference.client._config.api_version == "2024-02-15-test"
76+
77+
6978
@pytest.mark.parametrize(
7079
"azure_ai_inference_client",
7180
[AzureAIInferenceChatCompletion.__name__],
@@ -210,7 +219,6 @@ async def test_azure_ai_inference_chat_completion_with_extra_parameters(
210219
messages=[UserMessage(content=user_message_content)],
211220
model=model_id,
212221
model_extras=settings.extra_parameters,
213-
**settings.prepare_settings_dict(),
214222
)
215223
assert len(responses) == 1
216224
assert responses[0].role == "assistant"
@@ -506,7 +514,6 @@ async def test_azure_ai_inference_streaming_chat_completion_with_extra_parameter
506514
messages=[UserMessage(content=user_message_content)],
507515
model=model_id,
508516
model_extras=settings.extra_parameters,
509-
**settings.prepare_settings_dict(),
510517
)
511518

512519

python/tests/unit/connectors/ai/azure_ai_inference/services/test_azure_ai_inference_text_embedding.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ def test_azure_ai_inference_text_embedding_init_with_service_id(
5252
assert isinstance(azure_ai_inference.client, EmbeddingsClient)
5353

5454

55+
def test_azure_ai_inference_text_embedding_init_with_api_version(azure_ai_inference_unit_test_env, model_id) -> None:
56+
"""Test initialization of AzureAIInferenceTextEmbedding with api_version"""
57+
azure_ai_inference = AzureAIInferenceTextEmbedding(model_id, api_version="2024-02-15-test")
58+
59+
assert azure_ai_inference.ai_model_id == model_id
60+
assert isinstance(azure_ai_inference.client, EmbeddingsClient)
61+
assert azure_ai_inference.client._config.api_version == "2024-02-15-test"
62+
63+
5564
@pytest.mark.parametrize(
5665
"azure_ai_inference_client",
5766
[AzureAIInferenceTextEmbedding.__name__],

0 commit comments

Comments
 (0)