mirror of
https://github.com/hwchase17/langchain.git
synced 2025-08-12 14:23:58 +00:00
fix(core): revert "fix: tool call streaming bug with inconsistent indices from Qwen3" (#32307)
Reverts langchain-ai/langchain#32160 Original issue stems from using `ChatOpenAI` to interact with a `qwen` model. Recommended to use [langchain-qwq](https://python.langchain.com/docs/integrations/chat/qwq/) which is built for Qwen
This commit is contained in:
parent
fc2f66ca80
commit
fbd5a238d8
@ -108,39 +108,6 @@ def merge_lists(left: Optional[list], *others: Optional[list]) -> Optional[list]
|
|||||||
else e
|
else e
|
||||||
)
|
)
|
||||||
merged[to_merge[0]] = merge_dicts(merged[to_merge[0]], new_e)
|
merged[to_merge[0]] = merge_dicts(merged[to_merge[0]], new_e)
|
||||||
# Special handling for tool call chunks: if this chunk appears to be
|
|
||||||
# a continuation of a prior chunk (has None name/id) and no matching
|
|
||||||
# index was found, try to merge with the most recent tool call chunk
|
|
||||||
# that has a name/id.
|
|
||||||
# Fixes issues with models that send inconsistent indices.
|
|
||||||
# See #31511 for more.
|
|
||||||
elif (
|
|
||||||
e.get("type") == "tool_call_chunk"
|
|
||||||
and e.get("name") is None
|
|
||||||
and e.get("id") is None
|
|
||||||
and merged
|
|
||||||
):
|
|
||||||
# Find the most recent tool call chunk with a valid name or id
|
|
||||||
for i in reversed(range(len(merged))):
|
|
||||||
if (
|
|
||||||
isinstance(merged[i], dict)
|
|
||||||
and merged[i].get("type") == "tool_call_chunk"
|
|
||||||
and (
|
|
||||||
merged[i].get("name") is not None
|
|
||||||
or merged[i].get("id") is not None
|
|
||||||
)
|
|
||||||
):
|
|
||||||
# Merge with this chunk
|
|
||||||
new_e = (
|
|
||||||
{k: v for k, v in e.items() if k != "type"}
|
|
||||||
if "type" in e
|
|
||||||
else e
|
|
||||||
)
|
|
||||||
merged[i] = merge_dicts(merged[i], new_e)
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# No suitable chunk found, append as new
|
|
||||||
merged.append(e)
|
|
||||||
else:
|
else:
|
||||||
merged.append(e)
|
merged.append(e)
|
||||||
else:
|
else:
|
||||||
|
@ -1197,65 +1197,3 @@ def test_convert_to_openai_image_block() -> None:
|
|||||||
}
|
}
|
||||||
result = convert_to_openai_image_block(input_block)
|
result = convert_to_openai_image_block(input_block)
|
||||||
assert result == expected
|
assert result == expected
|
||||||
|
|
||||||
|
|
||||||
def test_tool_call_streaming_different_indices() -> None:
|
|
||||||
"""Test that tool call chunks with different indices but logically part of the same
|
|
||||||
tool call are merged correctly. This addresses issues with models like Qwen3 that
|
|
||||||
send inconsistent indices during streaming.
|
|
||||||
|
|
||||||
See #31511.
|
|
||||||
|
|
||||||
""" # noqa: D205
|
|
||||||
# Create chunks that simulate Qwen3 behavior:
|
|
||||||
# First chunk has index=1, subsequent chunks have index=0 with name=None, id=None
|
|
||||||
chunk1 = AIMessageChunk(
|
|
||||||
content="",
|
|
||||||
tool_call_chunks=[
|
|
||||||
create_tool_call_chunk(
|
|
||||||
name="search_function",
|
|
||||||
args='{"query": "langchain',
|
|
||||||
id="call_123",
|
|
||||||
index=1, # Initial index
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
chunk2 = AIMessageChunk(
|
|
||||||
content="",
|
|
||||||
tool_call_chunks=[
|
|
||||||
create_tool_call_chunk(
|
|
||||||
name=None, # Continuation chunk
|
|
||||||
args=' tutorial"}',
|
|
||||||
id=None, # Continuation chunk
|
|
||||||
index=0, # Different index
|
|
||||||
)
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
# Merge chunks as happens during streaming
|
|
||||||
merged_chunk: AIMessageChunk = chunk1 + chunk2 # type: ignore[assignment]
|
|
||||||
|
|
||||||
# Should result in a single merged tool call chunk
|
|
||||||
assert len(merged_chunk.tool_call_chunks) == 1
|
|
||||||
assert merged_chunk.tool_call_chunks[0]["name"] == "search_function"
|
|
||||||
assert merged_chunk.tool_call_chunks[0]["args"] == '{"query": "langchain tutorial"}'
|
|
||||||
assert merged_chunk.tool_call_chunks[0]["id"] == "call_123"
|
|
||||||
|
|
||||||
# Should result in a single valid tool call
|
|
||||||
assert len(merged_chunk.tool_calls) == 1
|
|
||||||
assert len(merged_chunk.invalid_tool_calls) == 0
|
|
||||||
|
|
||||||
# Verify the final tool call is correct
|
|
||||||
tool_call = merged_chunk.tool_calls[0]
|
|
||||||
assert tool_call["name"] == "search_function"
|
|
||||||
assert tool_call["args"] == {"query": "langchain tutorial"}
|
|
||||||
assert tool_call["id"] == "call_123"
|
|
||||||
|
|
||||||
# Test with message_chunk_to_message
|
|
||||||
message: AIMessage = message_chunk_to_message(merged_chunk) # type: ignore[assignment]
|
|
||||||
|
|
||||||
assert len(message.tool_calls) == 1
|
|
||||||
assert len(message.invalid_tool_calls) == 0
|
|
||||||
assert message.tool_calls[0]["name"] == "search_function"
|
|
||||||
assert message.tool_calls[0]["args"] == {"query": "langchain tutorial"}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user