Skip to content

ToolCallingChatOptions support internalToolExecutionMaxAttempts, to limit the maximum number of tool calls and prevent infinite recursive calls to LLM in special cases #3380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

lambochen
Copy link
Contributor

@lambochen lambochen commented May 29, 2025

This PR primarily addresses the issue of infinite recursive calls to LLM under certain special conditions, with internalToolExecutionEnabled=true in place, ref issue: #3333.

By introducing support for internalToolExecutionMaxAttempts in ToolCallingChatOptions and performing call count checks in each ChatModel, interrupt the process when the maximum call count is reached.

[ x ] Sign the contributor license agreement
[ x ] Rebase your changes on the latest main branch and squash your commits
[ x ] Add/Update unit tests as needed
[ x ] Run a build and make sure all tests pass prior to submission

@lambochen lambochen marked this pull request as draft May 29, 2025 16:37
@markpollack
Copy link
Member

thanks, one comment is that we need to preserve api compatability and

public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatResponse, int attempts) {

would need to be an overload vs adding a new method parameter.

@lambochen
Copy link
Contributor Author

thanks, one comment is that we need to preserve api compatability and

public ChatResponse internalCall(Prompt prompt, ChatResponse previousChatResponse, int attempts) {

would need to be an overload vs adding a new method parameter.

Your suggestion is great, I'll optimize it, thanks

@lambochen lambochen marked this pull request as ready for review May 31, 2025 13:37
@lambochen
Copy link
Contributor Author

Hi, @markpollack @tzolov , the PR is ready, please review it, thank you.

If there are any issues or if additional content is needed, please to comment, and I will promptly correct or supplement it. thank you

@@ -46,6 +47,9 @@ public class DefaultToolCallingChatOptions implements ToolCallingChatOptions {
@Nullable
private Boolean internalToolExecutionEnabled;

@Nullable
private Integer internalToolExecutionMaxAttempts = ToolCallingChatOptions.DEFAULT_TOOL_EXECUTION_MAX_ATTEMPTS;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming this to something like toolExecutionMaxIterations.

I'm suggesting dropping the internal prefix since this option can also be used as part of the user-controller tool execution, which is executed externally from the ChatModel.

Also, I'm suggesting replacing attempts with iterations since attempts would make seem related to the concept of retrying tool calls, whereas here we want to limit the number of iterations in the loop supporting the tool call requests from the model.

Copy link
Contributor Author

@lambochen lambochen Jun 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, ThomasVitale, thank you for your attention and comments.

Regarding removing the internal prefix: I agree. In the past,considering consistency with internalToolExecutionEnabled, I think we should reconsider this.

Regarding replacing attempts with iterations: Yes, I accept your suggestion, actually, I initially considered iterations as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, I also agree with the naming of the previous developer. The internal can express that it is executed internally by the Spring AI framework, which is a preset behavior.

Regarding the internal prefix, I support not using the prefix, as I believe this is a capability of the framework, a feature. The internal prefix makes users think this is a field only for internal use of the framework, and using it may come with some "concerns."

Discussion:If the internal prefix is removed, should the original internalToolExecutionEnabled field also be deprecated and a new toolExecutionEnabled created to replace it?

/**
* No limit for tool execution attempts.
*/
int TOOL_EXECUTION_NO_LIMIT = Integer.MAX_VALUE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say it's a mistake that no limit was set in the original implementation. I would consider having a lower value as the default limit. We should think of a good default value here that avoids infinite loops.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree with your point. To ensure downward compatibility, I have used Integer.MAX_VALUE (a very large number) to indicate no limit.

I tend to prefer setting a smaller value to limit the number of executions and the scope of impact on the program, but I don't have specific comparative data. If you have suggestions, please feel free to share them. Thank you

@@ -109,6 +131,21 @@ static boolean isInternalToolExecutionEnabled(ChatOptions chatOptions) {
return internalToolExecutionEnabled;
}

static boolean isInternalToolExecutionEnabled(ChatOptions chatOptions, int attempts) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I would suggest replacing attempts with iterations. In this case, I would make it more specific and name the argument toolExecutionIterations or toolExecutionCompletedIterations or something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your suggestion, I will rename attempts to use iterations.

@lambochen lambochen requested a review from ThomasVitale June 1, 2025 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants