I posted this ages ago:
Sorry, but cannot agree. It is the behaviour that is wrong.
I posted this ages ago:
Sorry, but cannot agree. It is the behaviour that is wrong.
I am also facing the same problem. My application was in production and everything was working fine but since a week, I am having this inconsistent finish_reason. Sometime, after a tool call, finish_reason=‘stop’ which is wrong as it should be ‘tool_calls’ and sometime it gives me correct finish_reason=‘tool_calls’. I read the docs but I am not sure if I am missing something in the documentation.
NOTE: This code makes 500 chat completion requests with random temperature param
import asyncio
import random
from openai import AsyncOpenAI
client = AsyncOpenAI()
tool_spec = [
{
"type": "function",
"function": {
"name": "generate_simple_list",
"parameters": {
"type": "object",
"properties": {"items": {"type": "array", "items": {"type": "string"}}},
"required": ["items"],
"additionalProperties": False,
},
},
}
]
conve = [
{
"role": "user",
"content": [
{"type": "text", "text": "Give me 3 fruits in a list."}
],
}
]
async def make_request():
temperature = random.uniform(0, 1) # Generate a random temperature between 0 and 1
response = await client.chat.completions.create(
model="gpt-4o", messages=conve, tools=tool_spec, temperature=temperature, tool_choice="required"
)
return response
async def main():
tasks = [make_request() for _ in range(500)]
responses = await asyncio.gather(*tasks)
for response in responses:
if response.choices[0].finish_reason == "stop":
print(response)
asyncio.run(main())
openai Version: 1.53.0
tool_choice="required" : All 500 finish_reason: 'tool_calls'. No finish_reason: 'stop' observed.
tool_choice="auto" : All 500 finish_reason: 'tool_calls'. No finish_reason: 'stop' observed.
tool_choice={"type": "function", "function": {"name": "generate_simple_list"}} : All 500 responses had finish_reason: 'stop'
So what’s your conclusion?
It’s changed but still not consistent? ![]()
Thankfully my code still appears to work with the existing workaround.
Are you guys using only the ChatCompletions API, or are you also leveraging the Responses API?
This Topic predates the launch of responses API.
I’ve not migrated this Chatbot yet but there are projects where some features of the responses API might be compelling enough to make the shift.
I’m hitting a similar issue (GPT 4.1) but as we were able to migrate to the ResponsesAPI, just wondering if we should handle a workaround on our end or if OpenAI already fixed it in the new API.
You should never be making a decision on whether to present text or to run a function based on the finish reason.
The AI can write both text to be displayed to a user and emit a tool call in the same response, where you both stream the text as it is being produced and then fulfill the tool calls and call the API again, until there are no more tool_call outputs and only text.
Got it —but that’s not my point.
My question wasn’t about why the model might return finish_reason: 'stop' instead of 'tool_calls'. That behavior is already well-documented in the thread and in the OpenAI docs.
What I asked was: does this also happen with the Responses API?
That’s the piece I’m trying to clarify — whether this inconsistency persists in the newer API or not.