Skip to content

Support image media in DeepSeek chat requests - #6980

Open
Lubaoshuai wants to merge 4 commits into
spring-projects:mainfrom
Lubaoshuai:fix/deepseek-vision-media
Open

Lubaoshuai wants to merge 4 commits into
spring-projects:mainfrom
Lubaoshuai:fix/deepseek-vision-media

Conversation

@Lubaoshuai

Copy link
Copy Markdown
Contributor

Fixes #6978

Problem

DeepSeekChatModel.createRequest only read message.getText() for USER messages, so any Media attached to a UserMessage was silently dropped: a vision-capable model such as deepseek-flash received a text-only request, with no error telling the caller the image was discarded.

Solution

Map user message media to the OpenAI-compatible multimodal content array that the DeepSeek vision documentation describes (text and image_url blocks), mirroring the approach the Mistral AI adapter already uses:

  • DeepSeekApi.ChatCompletionMessage.content is now a polymorphic String-or-ContentChunk-list with a custom serializer/deserializer, so text-only messages serialize exactly as before while multimodal user messages serialize as [{"type":"text",...},{"type":"image_url",...}].
  • Added ContentChunk, TextChunk and ImageUrlChunk (whose ImageUrl supports base64 data URIs for byte[] media; String media data is passed through as a URL).
  • DeepSeekChatModel maps user message media on both the synchronous and streaming paths (both go through createRequest).
  • Response handling is unchanged: assistant content still always deserializes as a String.

Tests

New tests in DeepSeekChatCompletionRequestTests:

  • URL media produces a content array with a text chunk and an image_url chunk
  • byte[] media is inlined as a data:image/png;base64,... URI
  • text-only user messages keep plain string content (backward compatibility)
  • wire-format test asserting the serialized request message JSON

Full spring-ai-deepseek module run: 48 tests, all passing.

DeepSeekChatModel.createRequest only read message.getText() for USER
messages, so Media attached to a UserMessage was silently dropped and
vision-capable models such as deepseek-flash received a text-only
request.

Map user message media to the OpenAI-compatible content array that the
DeepSeek vision API documents (text and image_url chunks), mirroring
the Mistral AI adapter: ChatCompletionMessage.content is now a
polymorphic String-or-ContentChunk-list with custom JSON serialization,
text-only messages are unchanged, and byte[] media is inlined as a
base64 data URI.

Fixes spring-projects#6978

Signed-off-by: Lubaoshuai <128781758+Lubaoshuai@users.noreply.github.com>
@lilingshan

Copy link
Copy Markdown

In addition, the default model should be changed to DEEPSEEK_FLASH, as DEEPSEEK_V4_FLASH has now been officially replaced by the official release.

Signed-off-by: Lubaoshuai <128781758+Lubaoshuai@users.noreply.github.com>
Signed-off-by: Lubaoshuai <128781758+Lubaoshuai@users.noreply.github.com>
…onIT.java)

Signed-off-by: Lubaoshuai <128781758+Lubaoshuai@users.noreply.github.com>
@Lubaoshuai
Lubaoshuai force-pushed the fix/deepseek-vision-media branch from e0441d7 to 47c05a3 Compare September 15, 2026 13:36
@Lubaoshuai

Copy link
Copy Markdown
Contributor Author

Thanks @lilingshan — done. DeepSeekApi.DEFAULT_CHAT_MODEL now resolves to ChatModel.DEEPSEEK_FLASH (deepseek-flash), and the two integration tests that referenced the previous default were updated accordingly. DEEPSEEK_V4_FLASH remains available as an explicit option for users who still need it.

Also noticed the DCO check was stuck pending because the three review-follow-up commits were missing Signed-off-by — the branch has been rewritten with the sign-off added (force-pushed, no other changes), and the checks are re-running.

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.

DeepSeekChatModel silently drops UserMessage image media for vision-capable deepseek-flash

3 participants