-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
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();
}
}