Skip to content

Commit 0690748

Browse files
authored
Don't send sampling settings like temperature and top_p to OpenAI reasoning models (#1956)
1 parent a1259fe commit 0690748

File tree

6 files changed

+223
-11
lines changed

6 files changed

+223
-11
lines changed

pydantic_ai_slim/pydantic_ai/models/openai.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,12 @@ async def _completions_create(
281281

282282
openai_messages = await self._map_messages(messages)
283283

284+
sampling_settings = (
285+
model_settings
286+
if OpenAIModelProfile.from_profile(self.profile).openai_supports_sampling_settings
287+
else OpenAIModelSettings()
288+
)
289+
284290
try:
285291
extra_headers = model_settings.get('extra_headers', {})
286292
extra_headers.setdefault('User-Agent', get_user_agent())
@@ -294,18 +300,18 @@ async def _completions_create(
294300
stream_options={'include_usage': True} if stream else NOT_GIVEN,
295301
stop=model_settings.get('stop_sequences', NOT_GIVEN),
296302
max_completion_tokens=model_settings.get('max_tokens', NOT_GIVEN),
297-
temperature=model_settings.get('temperature', NOT_GIVEN),
298-
top_p=model_settings.get('top_p', NOT_GIVEN),
299303
timeout=model_settings.get('timeout', NOT_GIVEN),
300304
seed=model_settings.get('seed', NOT_GIVEN),
301-
presence_penalty=model_settings.get('presence_penalty', NOT_GIVEN),
302-
frequency_penalty=model_settings.get('frequency_penalty', NOT_GIVEN),
303-
logit_bias=model_settings.get('logit_bias', NOT_GIVEN),
304305
reasoning_effort=model_settings.get('openai_reasoning_effort', NOT_GIVEN),
305-
logprobs=model_settings.get('openai_logprobs', NOT_GIVEN),
306-
top_logprobs=model_settings.get('openai_top_logprobs', NOT_GIVEN),
307306
user=model_settings.get('openai_user', NOT_GIVEN),
308307
service_tier=model_settings.get('openai_service_tier', NOT_GIVEN),
308+
temperature=sampling_settings.get('temperature', NOT_GIVEN),
309+
top_p=sampling_settings.get('top_p', NOT_GIVEN),
310+
presence_penalty=sampling_settings.get('presence_penalty', NOT_GIVEN),
311+
frequency_penalty=sampling_settings.get('frequency_penalty', NOT_GIVEN),
312+
logit_bias=sampling_settings.get('logit_bias', NOT_GIVEN),
313+
logprobs=sampling_settings.get('openai_logprobs', NOT_GIVEN),
314+
top_logprobs=sampling_settings.get('openai_top_logprobs', NOT_GIVEN),
309315
extra_headers=extra_headers,
310316
extra_body=model_settings.get('extra_body'),
311317
)
@@ -664,6 +670,12 @@ async def _responses_create(
664670
instructions, openai_messages = await self._map_messages(messages)
665671
reasoning = self._get_reasoning(model_settings)
666672

673+
sampling_settings = (
674+
model_settings
675+
if OpenAIModelProfile.from_profile(self.profile).openai_supports_sampling_settings
676+
else OpenAIResponsesModelSettings()
677+
)
678+
667679
try:
668680
extra_headers = model_settings.get('extra_headers', {})
669681
extra_headers.setdefault('User-Agent', get_user_agent())
@@ -676,8 +688,8 @@ async def _responses_create(
676688
tool_choice=tool_choice or NOT_GIVEN,
677689
max_output_tokens=model_settings.get('max_tokens', NOT_GIVEN),
678690
stream=stream,
679-
temperature=model_settings.get('temperature', NOT_GIVEN),
680-
top_p=model_settings.get('top_p', NOT_GIVEN),
691+
temperature=sampling_settings.get('temperature', NOT_GIVEN),
692+
top_p=sampling_settings.get('top_p', NOT_GIVEN),
681693
truncation=model_settings.get('openai_truncation', NOT_GIVEN),
682694
timeout=model_settings.get('timeout', NOT_GIVEN),
683695
reasoning=reasoning,

pydantic_ai_slim/pydantic_ai/profiles/openai.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,20 @@ class OpenAIModelProfile(ModelProfile):
1515
ALL FIELDS MUST BE `openai_` PREFIXED SO YOU CAN MERGE THEM WITH OTHER MODELS.
1616
"""
1717

18-
# This can be set by a provider or user if the OpenAI-"compatible" API doesn't support strict tool definitions
1918
openai_supports_strict_tool_definition: bool = True
19+
"""This can be set by a provider or user if the OpenAI-"compatible" API doesn't support strict tool definitions."""
20+
21+
openai_supports_sampling_settings: bool = True
22+
"""Turn off to don't send sampling settings like `temperature` and `top_p` to models that don't support them, like OpenAI's o-series reasoning models."""
2023

2124

2225
def openai_model_profile(model_name: str) -> ModelProfile:
2326
"""Get the model profile for an OpenAI model."""
24-
return OpenAIModelProfile(json_schema_transformer=OpenAIJsonSchemaTransformer)
27+
is_reasoning_model = model_name.startswith('o')
28+
return OpenAIModelProfile(
29+
json_schema_transformer=OpenAIJsonSchemaTransformer,
30+
openai_supports_sampling_settings=not is_reasoning_model,
31+
)
2532

2633

2734
_STRICT_INCOMPATIBLE_KEYS = [
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
interactions:
2+
- request:
3+
headers:
4+
accept:
5+
- application/json
6+
accept-encoding:
7+
- gzip, deflate
8+
connection:
9+
- keep-alive
10+
content-length:
11+
- '106'
12+
content-type:
13+
- application/json
14+
host:
15+
- api.openai.com
16+
method: POST
17+
parsed_body:
18+
messages:
19+
- content: What is the capital of Mexico?
20+
role: user
21+
model: o3-mini
22+
stream: false
23+
uri: https://api.openai.com/v1/chat/completions
24+
response:
25+
headers:
26+
access-control-expose-headers:
27+
- X-Request-ID
28+
alt-svc:
29+
- h3=":443"; ma=86400
30+
connection:
31+
- keep-alive
32+
content-length:
33+
- '944'
34+
content-type:
35+
- application/json
36+
openai-organization:
37+
- pydantic-28gund
38+
openai-processing-ms:
39+
- '5417'
40+
openai-version:
41+
- '2020-10-01'
42+
strict-transport-security:
43+
- max-age=31536000; includeSubDomains; preload
44+
transfer-encoding:
45+
- chunked
46+
parsed_body:
47+
choices:
48+
- finish_reason: stop
49+
index: 0
50+
message:
51+
annotations: []
52+
content: The capital of Mexico is Mexico City. It is not only the seat of the federal government but also a major
53+
cultural, political, and economic center in the country.
54+
refusal: null
55+
role: assistant
56+
created: 1749586227
57+
id: chatcmpl-BgzadlOEkRTXYim8s2TzQfnSpaZ4u
58+
model: o3-mini-2025-01-31
59+
object: chat.completion
60+
service_tier: default
61+
system_fingerprint: fp_e20469f047
62+
usage:
63+
completion_tokens: 238
64+
completion_tokens_details:
65+
accepted_prediction_tokens: 0
66+
audio_tokens: 0
67+
reasoning_tokens: 192
68+
rejected_prediction_tokens: 0
69+
prompt_tokens: 13
70+
prompt_tokens_details:
71+
audio_tokens: 0
72+
cached_tokens: 0
73+
total_tokens: 251
74+
status:
75+
code: 200
76+
message: OK
77+
version: 1
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
interactions:
2+
- request:
3+
headers:
4+
accept:
5+
- application/json
6+
accept-encoding:
7+
- gzip, deflate
8+
connection:
9+
- keep-alive
10+
content-length:
11+
- '103'
12+
content-type:
13+
- application/json
14+
host:
15+
- api.openai.com
16+
method: POST
17+
parsed_body:
18+
input:
19+
- content: What is the capital of Mexico?
20+
role: user
21+
model: o3-mini
22+
stream: false
23+
uri: https://api.openai.com/v1/responses
24+
response:
25+
headers:
26+
alt-svc:
27+
- h3=":443"; ma=86400
28+
connection:
29+
- keep-alive
30+
content-length:
31+
- '1502'
32+
content-type:
33+
- application/json
34+
openai-organization:
35+
- pydantic-28gund
36+
openai-processing-ms:
37+
- '5769'
38+
openai-version:
39+
- '2020-10-01'
40+
strict-transport-security:
41+
- max-age=31536000; includeSubDomains; preload
42+
transfer-encoding:
43+
- chunked
44+
parsed_body:
45+
background: false
46+
created_at: 1749586308
47+
error: null
48+
id: resp_684891844d0481a28f2d4ed6ea21aa8a0a1b41b457712f86
49+
incomplete_details: null
50+
instructions: null
51+
max_output_tokens: null
52+
metadata: {}
53+
model: o3-mini-2025-01-31
54+
object: response
55+
output:
56+
- id: rs_68489188081c81a29dea5b85122ad5ed0a1b41b457712f86
57+
summary: []
58+
type: reasoning
59+
- content:
60+
- annotations: []
61+
text: The capital of Mexico is Mexico City. It serves as the political, cultural, and economic heart of the country
62+
and is one of the largest metropolitan areas in the world.
63+
type: output_text
64+
id: msg_684891892e2481a2a1a8ae81c0541d800a1b41b457712f86
65+
role: assistant
66+
status: completed
67+
type: message
68+
parallel_tool_calls: true
69+
previous_response_id: null
70+
reasoning:
71+
effort: medium
72+
summary: null
73+
service_tier: default
74+
status: completed
75+
store: true
76+
temperature: 1.0
77+
text:
78+
format:
79+
type: text
80+
tool_choice: auto
81+
tools: []
82+
top_p: 1.0
83+
truncation: disabled
84+
usage:
85+
input_tokens: 13
86+
input_tokens_details:
87+
cached_tokens: 0
88+
output_tokens: 227
89+
output_tokens_details:
90+
reasoning_tokens: 192
91+
total_tokens: 240
92+
user: null
93+
status:
94+
code: 200
95+
message: OK
96+
version: 1

tests/models/test_openai.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,6 +1617,16 @@ async def test_openai_instructions_with_logprobs(allow_model_requests: None):
16171617
]
16181618

16191619

1620+
@pytest.mark.vcr()
1621+
async def test_reasoning_model_with_temperature(allow_model_requests: None, openai_api_key: str):
1622+
m = OpenAIModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key))
1623+
agent = Agent(m, model_settings=OpenAIModelSettings(temperature=0.5))
1624+
result = await agent.run('What is the capital of Mexico?')
1625+
assert result.output == snapshot(
1626+
'The capital of Mexico is Mexico City. It is not only the seat of the federal government but also a major cultural, political, and economic center in the country.'
1627+
)
1628+
1629+
16201630
def test_openai_model_profile():
16211631
m = OpenAIModel('gpt-4o', provider=OpenAIProvider(api_key='foobar'))
16221632
assert isinstance(m.profile, OpenAIModelProfile)

tests/models/test_openai_responses.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,3 +505,13 @@ def test_model_profile_strict_not_supported():
505505
'strict': False,
506506
}
507507
)
508+
509+
510+
@pytest.mark.vcr()
511+
async def test_reasoning_model_with_temperature(allow_model_requests: None, openai_api_key: str):
512+
m = OpenAIResponsesModel('o3-mini', provider=OpenAIProvider(api_key=openai_api_key))
513+
agent = Agent(m, model_settings=OpenAIResponsesModelSettings(temperature=0.5))
514+
result = await agent.run('What is the capital of Mexico?')
515+
assert result.output == snapshot(
516+
'The capital of Mexico is Mexico City. It serves as the political, cultural, and economic heart of the country and is one of the largest metropolitan areas in the world.'
517+
)

0 commit comments

Comments
 (0)