Skip to content

fix: Fix BedrockChatGenerator to be able to handle multiple tool calls from one response #1711

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

Merged
merged 20 commits into from
May 9, 2025

Conversation

sjrl
Copy link
Contributor

@sjrl sjrl commented May 7, 2025

Related Issues

Proposed Changes:

Fixing Multi Tool Calling
Repairs the expected formatting of the bedrock messages.

Basically if a ChatMessage has multiple Tool Calls in it then the corresponding Tool Result ChatMessage must also contain both tool results. This is currently not possible because the ToolInvoker in Haystack returns a separate ChatMessage per Tool Call no matter if the original Tool Calls came one from one or multiple ChatMessages.

As a workaround, we retroactively repair the bedrock formatted messages to regroup the Tool Results based on how the Tool Calls are grouped.

This could also be "fixed" in the ToolInvoker, but I'm not sure if that would have adverse effects on our other integrations. Update: Nothing to fix in the ToolInvoker, most providers expect separate messages per tool result. So it's better to modify the behavior only in this integration.

Fixing Tool Call Streaming
Changed the internal logic of the integration to take Events from Bedrock, convert them into Haystack StreamingChunks that follow the same format as OpenAIChatGenerator and then pass the streaming chunk to the streaming callback. Now we will be able to reuse the print_streaming_chunk in Haystack main after a slight change is made. Here is an example of the output with the updated print_streaming_chunk coming in a separate PR.
Screenshot 2025-05-09 at 09 54 38

Fixing Consistency Between Streaming and Non-Streaming
I updated the streaming processing to produce one ChatMessage like the non-streaming processing. This makes the most sense since this singular ChatMessage is converted into a single Bedrock formatted message.

How did you test it?

  • Added unit tests
  • Updated integration tests

Notes for the reviewer

Checklist

@sjrl sjrl requested a review from a team as a code owner May 7, 2025 09:23
@sjrl sjrl requested review from anakin87 and removed request for a team May 7, 2025 09:23
@sjrl sjrl requested review from vblagoje and removed request for anakin87 May 7, 2025 09:31
@sjrl
Copy link
Contributor Author

sjrl commented May 7, 2025

@anakin87 I've assigned @vblagoje as the reviewer since he has more context.

However, @anakin87 I think you'd find the root of the problem to be potentially interesting which is described in the PR description. Basically this could have been also overcome by updating how the ToolInvoker works and by adding support for multiple tool results being stored in a ChatMessage dataclass.

@anakin87
Copy link
Member

anakin87 commented May 7, 2025

I'm not sure if I understand this correctly.

I think the choices we made in the past stem from the fact that most model providers (OpenAI, Google, Ollama) only accept messages from tool containing a single tool call result.
In this perspective, I think that handling this aspect specifically in the affected integrations is a viable option.

Please add more details if you think I have missed the point.

@sjrl
Copy link
Contributor Author

sjrl commented May 7, 2025

I'm not sure if I understand this correctly.

I think the choices we made in the past stem from the fact that most model providers (OpenAI, Google, Ollama) only accept messages from tool containing a single tool call result. In this perspective, I think that handling this aspect specifically in the affected integrations is a viable option.

Please add more details if you think I have missed the point.

No I don't think you have. I ultimately agree that fixing it here makes the most sense. I just wasn't sure about this point

I think the choices we made in the past stem from the fact that most model providers (OpenAI, Google, Ollama) only accept messages from tool containing a single tool call result.

so thanks for the clarification!

In that case I agree leaving ToolInvoker as is makes the most sense.

@Amnah199
Copy link
Contributor

Amnah199 commented May 7, 2025

@sjrl As discussed in the other PR, if this PR also addresses #1680 and #1681, please link them in the PR description for clarity.

@github-actions github-actions bot added the type:documentation Improvements or additions to documentation label May 9, 2025
Copy link
Member

@vblagoje vblagoje left a comment

Choose a reason for hiding this comment

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

I've checked with agent and it works in both streaming and non-streaming method - including multiple tool calls. ✅
The repair method is crucial and it deserves a bit more pydoc.
Suggested a small improvement for repair and other helper methods
I'll still take a look into streaming in detail, and verify tests.

Copy link
Member

@vblagoje vblagoje left a comment

Choose a reason for hiding this comment

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

I've completed the review. Finally we get this one 🔥
I'd use this opportunity to add some comments throughout the code so we can maintain it easier in the future. Great work 👍

@sjrl sjrl merged commit 6cf9414 into main May 9, 2025
10 checks passed
@sjrl sjrl deleted the fix-bedrock-multi-tool branch May 9, 2025 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
integration:amazon-bedrock type:documentation Improvements or additions to documentation
Projects
None yet
4 participants