[Bugfix][Multimodal] Preserve DeepSeek V4 image block spacing (#56882)
Signed-off-by: Xucheng Zhou <aden1350@outlook.com> Signed-off-by: Isotr0py <Isotr0py@outlook.com> Co-authored-by: OpenAI Codex <noreply@openai.com> Co-authored-by: Isotr0py <Isotr0py@outlook.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
OpenAI Codex
Isotr0py
mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
parent
04a3a00eb7
commit
cc09352e5c
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"thinking_mode": "thinking",
|
||||
"reasoning_effort": "max",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a helpful vision assistant."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "请按“第一张、第二张”的顺序回答:第一张图"
|
||||
},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": "examples/images/carrots.jpeg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"text": "和第二张图"
|
||||
},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": "examples/images/corn.jpeg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"text": "中分别是什么食材?它们通常食用的部位分别是什么?"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<|begin▁of▁sentence|>You are a helpful vision assistant.<|User|>请按“第一张、第二张”的顺序回答:第一张图
|
||||
|
||||
<|deepseek_image|>
|
||||
|
||||
和第二张图
|
||||
|
||||
<|deepseek_image|>
|
||||
|
||||
中分别是什么食材?它们通常食用的部位分别是什么?<|Assistant|></think>
|
||||
@@ -54,13 +54,9 @@ def _load_reference_case(case_id: int):
|
||||
|
||||
def _render_reference_case(case_id: int, **kwargs):
|
||||
messages, tools = _load_reference_case(case_id)
|
||||
conversation, _, _ = parse_chat_messages(
|
||||
messages,
|
||||
_model_config(),
|
||||
content_format="string",
|
||||
)
|
||||
# Preserve content blocks for encoding without fetching fixture media.
|
||||
return _tokenizer().apply_chat_template(
|
||||
conversation=conversation,
|
||||
conversation=messages,
|
||||
messages=messages,
|
||||
tools=tools,
|
||||
tokenize=False,
|
||||
@@ -397,6 +393,7 @@ def test_deepseek_v4_maps_xhigh_to_high_reasoning_effort():
|
||||
(2, {"thinking": True, "reasoning_effort": "low"}),
|
||||
(3, {"thinking": True, "reasoning_effort": "low"}),
|
||||
(4, {"thinking": False}),
|
||||
(5, {"thinking": False}),
|
||||
],
|
||||
)
|
||||
def test_deepseek_v4_matches_reference_golden_fixtures(case_id, kwargs):
|
||||
@@ -447,7 +444,10 @@ def test_deepseek_v4_image_blocks_become_placeholders():
|
||||
thinking=False,
|
||||
)
|
||||
|
||||
assert "<|User|>first:<|deepseek_image|>second:<|deepseek_image|>" in prompt
|
||||
assert (
|
||||
"<|User|>first:\n\n<|deepseek_image|>\n\n"
|
||||
"second:\n\n<|deepseek_image|>" in prompt
|
||||
)
|
||||
|
||||
|
||||
def test_deepseek_v4_image_sentinel_ids_match_tokenizer():
|
||||
|
||||
@@ -40,7 +40,7 @@ class DeepseekV4Renderer(BaseRenderer[DeepseekV4Tokenizer]):
|
||||
conversation, mm_data, mm_uuids = parse_chat_messages(
|
||||
messages,
|
||||
self.model_config,
|
||||
content_format="string",
|
||||
content_format="openai",
|
||||
media_io_kwargs=params.media_io_kwargs,
|
||||
mm_processor_kwargs=params.mm_processor_kwargs,
|
||||
)
|
||||
@@ -67,7 +67,7 @@ class DeepseekV4Renderer(BaseRenderer[DeepseekV4Tokenizer]):
|
||||
conversation, mm_data, mm_uuids = await parse_chat_messages_async(
|
||||
messages,
|
||||
self.model_config,
|
||||
content_format="string",
|
||||
content_format="openai",
|
||||
media_io_kwargs=params.media_io_kwargs,
|
||||
mm_processor_kwargs=params.mm_processor_kwargs,
|
||||
)
|
||||
|
||||
@@ -224,7 +224,7 @@ def flatten_content_blocks(content: Any) -> Any:
|
||||
raise ValueError(
|
||||
f"Unsupported content block type: {block.get('type')!r}"
|
||||
)
|
||||
return "".join(parts)
|
||||
return "\n\n".join(parts)
|
||||
|
||||
|
||||
def render_message(
|
||||
@@ -267,7 +267,7 @@ def render_message(
|
||||
)
|
||||
|
||||
role = msg.get("role")
|
||||
content = msg.get("content")
|
||||
content = flatten_content_blocks(msg.get("content"))
|
||||
tools = msg.get("tools")
|
||||
response_format = msg.get("response_format")
|
||||
tool_calls = msg.get("tool_calls")
|
||||
@@ -337,7 +337,7 @@ def render_message(
|
||||
parts.append(f"[Unsupported {block_type}]")
|
||||
prompt += "\n\n".join(parts)
|
||||
else:
|
||||
prompt += flatten_content_blocks(content) or ""
|
||||
prompt += content or ""
|
||||
|
||||
elif role == "latest_reminder":
|
||||
prompt += LATEST_REMINDER_SP_TOKEN + latest_reminder_msg_template.format(content=content)
|
||||
|
||||
Reference in New Issue
Block a user