[Discuss][API] Multimodal content parts in ChatMessage #1031
Replies: 3 comments
|
Thanks for bringing this up. I’m tied up with other things right now, but I’ll try to check it out this week. |
|
Thanks for proposing this. I agree that supporting multimodal messages is necessary for Flink Agents. At the moment, however, I feel the proposal is still too high-level to evaluate as an API change. It would be helpful to extend it with two concrete parts: 1. The public data model Please provide the proposed Java and Python structures, including their serialized representation. For example, one possible shape could be: The proposal should also define:
Since Flink Agents is currently in Beta and we do not need to preserve this API for compatibility, I would prefer replacing 2. Integration with model providers The proposal should explain how these blocks flow into a model provider, for example: Each provider uses a different representation for multimodal input. Therefore, it would be useful to clarify:
Frameworks such as LlamaIndex and AgentScope demonstrate different valid approaches: LlamaIndex exposes modality-specific block types, while AgentScope uses a more generic |
|
Here are my thoughts on the four open questions. 1. Event Log representationI would prefer recording media metadata rather than a truncated Base64 prefix. A Base64 prefix has little diagnostic value, but it can still expose part of the original content. For example, the Event Log could contain: {
"type": "image",
"mime_type": "image/png",
"source_type": "inline",
"size_bytes": 126432,
"sha256": "...",
"data": "<omitted>"
}For URL-backed content, we could record a sanitized URI or reference identifier, avoiding signed query parameters where appropriate. I also do not think 2. URL-backed content versus a Blob/Reference typeFor 0.4, I think supporting inline data and externally managed URLs is sufficient. I would not introduce a Flink Agents-managed Blob Storage service as part of this change, since that would also require decisions about storage backends, credentials, cleanup, lifetime, and recovery. However, the data model should leave room for adding a managed reference later. For example, an image block could initially allow mutually exclusive The documentation should also make it clear that URL-backed content is externally managed. The user is responsible for its accessibility and lifetime. URLs may expire, may not be accessible to the model provider, and may no longer be valid after recovery from a checkpoint. Therefore, recommending URLs reduces state size, but it does not provide durable media storage. 3. Existing
|
Uh oh!
There was an error while loading. Please reload this page.
Follow-up to the 0.4 planning discussion in #862. I volunteered for the “Support invoking multimodal models” Must item there, and @wenjin272 confirmed no one is working on it yet.
The proposal is to add first-class typed content parts to
ChatMessagein both Java and Python, while keeping plain-string content fully backward compatible.Motivation
Today
ChatMessage.contentis a plain string, even though the chat-model SDKs we already integrate with support multimodal input natively.There are also two concrete problems in the current code:
We already have provider-specific workarounds. For example, Python Anthropic carries native content blocks through
extra_args["anthropic_content_blocks"]. This works, but it is untyped and provider-specific.MCP tool results can already contain images, but
ChatModelActioneventually stringifies the result before sending it back to the model. So an image currently becomes the string representation of a map containing base64 data rather than actual image content.A first-class content-part API would give us one framework-level representation for these cases.
Proposed API
Add a flat
ContentParttype in both languages with three initial variants:textimagedocumentEach part would carry only the fields it needs, e.g.
text,mime_type, and eitherdataorurl.I’d keep it flat rather than introducing a nested provider-style
sourceobject. Besides being simpler across providers, this also works better with the current Event Log depth limits.ChatMessagewould keep its existingcontent: Stringand gaincontentParts/content_parts, defaulting to empty.The compatibility rule would be:
contentbehaves exactly as it does todaycontentremains a plain-text projection of the text parts for existing consumersI considered making
contentitself aString | List<ContentPart>union, but that would be much more disruptive across Java callers, Jackson mapping, and the pemja bridge. An additive field seems safer for 0.4.This also requires one small framework fix: image-only messages must not be dropped by the current “empty text content” filtering in the prompt/message merge logic.
Cross-language / serialization
content_partswould be additive in the serialized Event Log format, with old records continuing to deserialize normally.The pemja bridge needs explicit support because those conversions copy fields directly rather than going through JSON.
I’d leave multimodal YAML prompts out of scope for 0.4. Existing text YAML stays unchanged, and YAML
parts:can be added separately once the API settles.Event Log and state
At STANDARD Event Log level, inline base64 is already bounded by the existing string truncation limit, so this does not make logs unbounded by default.
There is still a state-size concern for long agent/tool loops, since inline media may be carried through sensory memory. For 0.4, my preference would be to recommend URL-backed parts for large media and leave a first-class blob/reference type for follow-up work.
Proposed 0.4 scope
Phase 1 — framework
ContentPart+ChatMessagesupport in Java and PythonPhase 2 — initial providers
Start with OpenAI Chat Completions and Ollama.
OpenAI is a good first target because the shared conversion path also covers Azure OpenAI and vLLM. Ollama already has direct image support in both SDKs.
I’d start with USER-role multimodal input, which covers the primary invocation use case.
Follow-ups
Anthropic, Gemini, Bedrock, Responses API, Tongyi, MCP image tool results, YAML parts, and richer media-reference support can follow incrementally.
Open questions
<image/png, 123 KB>? In particular, should VERBOSE ever record full media bytes?extra_argsescape hatches, my inclination is to gradually subsume provider-specific ones likeanthropic_content_blocks, while leaving genericextra_argsavailable for other provider-specific options.content_partsor simplyparts?If this direction looks reasonable, I’ll open a tracking issue with Phase 1 / Phase 2 subtasks and start with the framework work.
All reactions