Skip to content

Infinite tool calling loop with tool_choice: function #4464

@TLoud

Description

@TLoud

Setting an OpenAi's tool_choice option to "function" triggers an infinite loop of llm trying to call this function.

Looks like when spring-ai calls llm with a tool execution result it copies chatOptions with tool_choice set to function, which forces model to call the same tool again.

I've found this: https://community.openai.com/t/infinite-loop-with-tool-choice-required-or-type-function/755129

Ive tried to reset the tool_choice option in debugger before options are copied for sending a tool call result (at the bottom of org.springframework.ai.openai.OpenAiChatModel#createRequest) - looks like it helped llm to exit loop. But i didnt find an intended way to get around this problem. So maybe im doing something wrong.

Maybe disbling internal toolExecution will help - so i would be able to create OpenAiChatOptions with tool_choice - auto while construncting a message with tool execution result. But it would be nice to continue using internalToolExecution.

I've also encontered similar behaviour with DeepSeek's toolChoice. Didn't try to reset the tool_choice though.

im using spring-ai version 1.0.2

public class ToolChoiceTest {

public void test() {
	try {
		String openaiApiKey = System.getenv("OPENAI_API_KEY");
		var openAiApi = OpenAiApi.builder().apiKey(openaiApiKey).build();
		Object toolChoice = OpenAiApi.ChatCompletionRequest.ToolChoiceBuilder.FUNCTION("getMarineYetiDescription");
		var openAiChatOptions = OpenAiChatOptions.builder().model("gpt-5").toolChoice(toolChoice).build();
		var chatModel = OpenAiChatModel.builder().openAiApi(openAiApi).defaultOptions(openAiChatOptions).build();
		var chatClient = ChatClient.builder(chatModel).defaultTools(this).build();
		var prompt = new Prompt("What is the color of a marine yeti?");
		String response = chatClient.prompt(prompt).call().content();
		System.out.println(response);
	} catch (Exception exception) {
		System.err.println(exception);
	}
}

@Tool(description = "Get description of marine yeti")
public String getMarineYetiDescription() {
	return "Marine yeti is orange";
}

public static void main(String[] args) {
	new ToolChoiceTest().test();
}

}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions