google / google/adk-python

LLM responses associated with collapsed function_responses should also be removed

Đang mở
#3,642 4 bình luận 0 reaction 2 người được giao Được giao cho @Jacksunwei Xem trên GitHub
core needs review
Ngôn ngữ chính
Python
Star
21.5k
Fork
4k
Merge trung bình
1 ngày 14 giờ
Pull request đã merge (30 ngày)
37

Mô tả

# Bug Report: LLM responses associated with collapsed function_responses should also be removed

** Please make sure you read the contribution guide and file the issues in the right place. **

[Contribution guide.](https://google.github.io/adk-docs/contributing-guide/)

## Describe the bug

When ADK collapses/removes old `function_response` messages from the conversation history (as part of its message history management), it does not remove the associated LLM-generated text responses that were created in response to those function responses. This results in duplicate or confusing messages being sent to the LLM, where both:
1. An intermediate text response (generated before the function_response was collapsed)
2. A final text response (generated after the function_response was processed)

are both present in the conversation history sent to the LLM. This causes the LLM to receive conflicting information and respond in strange or inconsistent ways.

## To Reproduce

Please share a minimal code and data to reproduce your problem.

Steps to reproduce the behavior:

1. Create an agent that makes function calls and receives function responses asynchronously. In this case, the sequence of events end up being:
- Content 1: User message
- Content 2: function_call
- Content 3: function_response -- intermediate while the task is running background
- Content 4: LLM Responds to the intermediate function_response.
- Content 5: function_response -- final response posted.
- Content 6: LLM responds to final function response.

2. After the function call completes and final function_response is received, observe the conversation history in the last LLM call:
- You'll see a pattern like:
```
Content 5: role=user, function_response (for tool X)
Content 4: role=model, text="Calling X now..." (intermediate response)
Content 6: role=model, text="Done! I called X and got result Y" (final response)
```

3. When ADK collapses the function_response (Content 3), it should also remove Content 4 (the intermediate response), but currently it only removes Content 3, leaving both Content 4 and Content 6 in the history.

4. This results in the LLM receiving:
```
Content 4: role=model, text="Calling X now..."
Content 6: role=model, text="Done! I called X and got result Y"
```
Which is confusing because Content 4 is now outdated/incorrect. The LLM gets confused and responds for both messages -- something like "Call X now. I coudln't get through person Y"

## Expected behavior

When ADK collapses/removes old `function_response` messages from the conversation history, it should also remove any associated LLM-generated text responses that were created in response to those function responses.

Specifically:
- If a `function_response` message is removed, any immediately following `model` role messages with text content should also be removed, as they were generated based on the now-removed function_response context.

This ensures the conversation history sent to the LLM only contains the most recent, accurate responses.

## Actual behavior

ADK removes the `function_response` message but leaves the associated LLM text responses, resulting in:
- Duplicate or conflicting messages in the conversation history
- Outdated intermediate responses being sent to the LLM
- Confusion for the LLM, leading to strange or inconsistent responses

## Workaround

A workaround is to use `before_model_callback` to detect and remove consecutive model/assistant messages with text blocks:

```python
def remove_duplicate_text_blocks(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmRequest]:
"""Remove consecutive model/assistant text blocks (sign of collapsed function_responses)."""
if not llm_request.contents or len(llm_request.contents) < 2:
return None

def has_text_part(content):
if not content.parts:
return False
for part in content.parts:
if hasattr(part, 'text') and part.text is not None:
return True
return False

modified_contents = []
i = 0

while i < len(llm_request.contents):
content = llm_request.contents[i]

# Check if this is a model/assistant message with text
if content.role in ("assistant", "model") and has_text_part(content):
# Check if next content is also a model/assistant message with text
if (i + 1 < len(llm_request.contents) and
llm_request.contents[i + 1].role in ("assistant", "model") and
has_text_part(llm_request.contents[i + 1])):
# Skip this content (first of the two consecutive text blocks)
i += 1
continue

modified_contents.append(content)
i += 1

# Modify the request in place
llm_request.contents = modified_contents
return None
```

However, this is a workaround that detects the symptom (consecutive text blocks) rather than fixing the root cause (removing associated responses when function_responses are collapsed).

## Desktop (please complete the following information):

- ADK version: 1.17

## Model Information:

- Are you using LiteLLM: Yes
- Which model is being used: `anthropic/claude-sonnet-4-5`

## Additional context

This bug is particularly problematic because:
1. It creates confusion for the LLM, which receives conflicting information about the state of function calls
2. It leads to inconsistent or incorrect responses from the LLM
3. It requires workarounds that add complexity and may not catch all edge cases
4. The fix should be in ADK's message history management logic, not in user code

The recommended fix is to update ADK's function_response collapse logic to:
1. Identify which LLM text responses are associated with a function_response being collapsed
2. Remove those associated text responses along with the function_response
3. This ensures the conversation history only contains the most recent, accurate state

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.