Skip to content

Python: Fix media placeholder placement in ONNX Phi-3-vision and Phi-4-multimodal templates - #14737

Open
Qiming Bao (14H034160212) wants to merge 1 commit into
microsoft:mainfrom
14H034160212:fix-onnx-phi-multimodal-templates
Open

Qiming Bao (14H034160212) wants to merge 1 commit into
microsoft:mainfrom
14H034160212:fix-onnx-phi-multimodal-templates

Conversation

@14H034160212

Copy link
Copy Markdown

Motivation and Context

Fixes #14735

ONNXTemplate.PHI3V and ONNXTemplate.PHI4MM built prompts that the Phi-3-vision, Phi-3.5-vision and Phi-4-multimodal models were not trained on:

  • <|image_N|> / <|audio_N|> were written outside the <|user|> ... <|end|> turn. With [text, image] the tag came after <|end|>, and with [image, text] it came before <|user|>.
  • Each TextContent item opened its own <|user|> turn.
before: '<|user|>\nDescribe this image.<|end|>\n<|image_1|>\n<|assistant|>\n'
after:  '<|user|>\n<|image_1|>\nDescribe this image.<|end|>\n<|assistant|>\n'

The new format is the one given in the Phi-3-vision, Phi-3.5-vision and Phi-4-multimodal model cards, and it is how the onnxruntime-genai multimodal example builds the user content (get_user_content): image tags, then audio tags, then the text.

Description

  • Added a private helper, _multimodal_user_content, in connectors/ai/onnx/utils.py. For one user message it returns the image placeholders, then the audio placeholders (Phi-4-mm only), each on its own line, then the text items joined with \n, along with the updated image and audio counters. Placeholders are still numbered across the whole chat history, starting at 1. That numbering matches the image and audio lists that _get_images_from_history / _get_audios_from_history pass to the processor, and Phi-3-vision's requirement that image ids be consecutive from 1.
  • phi3v_template and phi4mm_template now emit a single <|user|>\n{content}<|end|>\n per user message. System and assistant turns, and the \n style, are unchanged.
  • Removed the outdated "Currently only one image is supported in Onnx" comment. The onnxruntime-genai Phi-4-mm example passes several images.
  • Tests (tests/unit/connectors/ai/onnx/services/test_onnx_utils.py): the two existing multimodal tests asserted the broken format, so I updated them. I also added cases for [image, text], multiple images, image numbering across turns, several text items in one message, text + audio, audio only, and audio listed before images.

No public API changes. Only the prompt string produced for multimodal user messages changes.

Verification (from python/):

uv run --no-sync pytest tests/unit/connectors/ai/onnx            # 43 passed (11 of the new/updated tests fail on main)
uv run --no-sync ruff check <changed files> && uv run --no-sync ruff format --check <changed files>
uv run --no-sync mypy -p semantic_kernel.connectors.ai.onnx --config-file mypy.ini   # Success: no issues found
uv run --no-sync pre-commit run -c python/.pre-commit-config.yaml --files <changed files>  # all hooks passed

Contribution Checklist

…-vision and Phi-4-multimodal templates

phi3v_template and phi4mm_template emitted <|image_N|> / <|audio_N|> outside
the <|user|> ... <|end|> turn and opened a separate user turn for every
TextContent item. Build one user turn per message instead, with the image
placeholders first, then the audio placeholders, then the text, which is
the format in the Phi-3-vision, Phi-3.5-vision and Phi-4-multimodal model
cards and in the onnxruntime-genai multimodal example.
@14H034160212
Qiming Bao (14H034160212) requested a review from a team as a code owner November 7, 2026 04:32
Copilot AI balanced review requested due to automatic review settings November 7, 2026 04:32
@semantic-kernel-automation semantic-kernel-automation Bot added the python Pull requests for the Python Semantic Kernel label Nov 7, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues are reported for the multimodal prompt-formatting changes.

No open issues 🎉

What changed in this PR

This PR fixes multimodal prompt formatting in the Python ONNX connector for Phi-3-vision and Phi-4-multimodal, addressing the media-placement portion of #14735.

Changes:

  • Places image and supported audio placeholders inside a single user turn, before text.
  • Shares content formatting between templates while preserving media numbering across chat history.
  • Updates and expands regression tests for content ordering, multiple images, multiple text items, and audio-only messages.
File Description
python/​tests/​unit/​connectors/​ai/​onnx/​services/​test_onnx_utils.py Corrects expected prompts and adds multimodal formatting regression cases.
python/​semantic_kernel/​connectors/​ai/​onnx/​utils.py Adds a shared helper and updates both templates to emit one correctly formatted user turn per message.

Review effort: Balanced

This branch was previously deployed

1 inactive deployment
github-app-auth — 30b40fda Deployed Nov 7, 2026 by 14H034160212 via add_label #29617
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: ONNX connector puts Phi-3-vision / Phi-4-multimodal media tags outside the user turn, and rejects repetition_penalty > 1

2 participants