fix(deepseek): 按模型能力放开图片输入,flash 家族不再被当成纯文本 - #796
Merged
Conversation
官方《图像理解》指南已明确 deepseek-flash 支持图片(image_url / input_image / Files API file_id,input_image 可出现在 user 消息与 function_call_output 的 output 中),旧模型名 deepseek-v4-flash-vision-exp 下线后由其承接。此前 LiveAgent 把 DeepSeek 一律声明成纯文本,图片被拦在三处: - modelFactory 的 deepseek 分支写死 input: ["text"],用户的 inputModalities 覆盖也被显式排除。改为按模型 id 推断(flash 家族吃图、Pro 与更早模型仍纯 文本),并让覆盖生效,中转端点可改回 ["text"]。 - deepSeekNative 对 user 消息里的图片直接抛错,并强制把所有工具结果图片降级 为说明文字。硬抛会让一张图之后每一轮都失败(#730 之前的老毛病),改为按 model.input 门控:声明了 image 的模型保留图片,纯文本模型继续降级。 - nativeResponsesAttachments 只放行 codex/xai 走 input_image 内联。放行 deepseek,图片附件首次请求即内联;PDF 仍退回 Read(指南只用 file 描述图片)。
StackCairn
marked this pull request as draft
September 11, 2026 16:23
Contributor
|
PR governance checks failed — this PR has been converted to draft.
Fix the items above, then click Ready for review to re-run the checks. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issue
Closes #795
Summary
DeepSeek 官方《图像理解》指南已明确
deepseek-flash吃图片(base64 data URL / 外部 URL / Files APIfile_id三种传法;input_image可出现在 user / developer 消息与function_call_output的 output 中),并注明旧模型名deepseek-v4-flash-vision-exp已下线、其请求由最新 Flash 承接。但 LiveAgent 从 #502 / #554 起把 DeepSeek 一律声明成纯文本,图片被拦在三处,请求侧完全用不上这个能力。本次把"DeepSeek 不吃图"这个过期假设收敛掉,图片能力一律交给
model.input决定:modelFactory.ts(能力声明):deepseek 分支原本写死input: ["text"],并显式把 DeepSeek 排除在用户inputModalities覆盖之外(注释理由是"wire 层硬拒绝图片")。改为按模型 id 推断——flash 家族["text", "image"]、Pro 与更早模型仍["text"]——并让覆盖生效。官方只承诺 flash 家族,所以不跟着一起放开 Pro,避免产生新的虚假能力声明;中转端点不吃图时用覆盖改回["text"]。deepSeekNative.ts(协议层):删掉assertNoUserImageInput的无条件硬抛,工具结果图片从"强制降级"改为按model.input门控。硬抛正是 fix(providers): 纯文本模型的工具结果图片降级为说明文字,不再让会话永久失败 #730 修过的那类故障成因:一张图之后,用户消息/工具结果永久留在历史里,每一轮都在本地被同一断言拦下,会话实质报废。纯文本模型(Pro,或被覆盖成["text"]的中转)仍降级为说明文字,pi-ai 也会给不支持的图片补占位文本,两条路都不会 400。nativeResponsesAttachments.ts(附件内联):原本只放行codex/xai。放行 DeepSeek,图片附件首次请求即以input_image内联(不再先让模型去Read本地路径再等一轮),并给 DeepSeek 用专属的 upload 指令文案("DeepSeek Responses request",此前会误写成 OpenAI)。PDF 仍退回 Read:指南只用file描述图片,没有承诺 PDF 的 document 结构,supportsNativePdfInline有意让deepseek-responses走 default 分支。providerUtils.ts(设置页):providerSupportsModelInputModalitiesOverride加入 deepseek,设置里可对单个 DeepSeek 模型选择"自动 / 纯文本 / 文本+图片"。刻意没动的地方:
toolResultImageFallback.ts的 helper 语义不变(只是调用点改成门控版);deepSeekAttachments.ts的大段粘贴内联不变。Change scope
crates/agent-gui/src/lib/providers/runtime/modelFactory.tscrates/agent-gui/src/lib/providers/deepSeekNative.tscrates/agent-gui/src/lib/providers/nativeResponsesAttachments.tscrates/agent-ui/src/pages/settings/providerUtils.tscrates/agent-gui/test/providers/deepseek-native.test.mjscrates/agent-gui/test/providers/native-responses-attachments.test.mjscrates/agent-gui/test/settings/input-modalities.test.mjsScreenshots / preview
无 UI 像素变化,因此没有 before/after 截图:本次唯一的界面可见效果是设置里 DeepSeek 模型的"输入模态"开关从隐藏变为可见(
ProviderModal复用providerSupportsModelInputModalitiesOverride)。治理检查会因改动命中前端路径而要求配图,处理方式沿用 #730 的先例(该 PR 同为前端路径下的纯行为改动,被 bot 转 draft 后由维护者加governance-exempt)。以下为线格式层面的修复前后对照。
修复前 —— 工具结果图片被强制降级,模型只看到说明文字:
修复前 —— 用户直接上传图片则在 fetch 之前抛错,请求根本不发出:
修复后 —— 同一 context 走
streamDeepSeekResponses(mock fetch 截获请求体),图片作为input_image到达线上:{ "role": "user", "content": [ { "type": "input_text", "text": "describe" }, { "type": "input_image", "detail": "auto", "image_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg…" } ] }修复后 —— 工具结果里的截图保留在
function_call_output的 output 中(指南允许该位置带input_image),不再需要模型换模型;纯文本模型仍降级:Verification
cd crates/agent-gui && pnpm test:frontend→ 3088/3088 通过(与改动前同一套全量前端用例,无回归、无快照更新)。cd crates/agent-gui && pnpm build(tsc && vite build)通过;pnpm lint(biome check src/,333 文件)无问题。cd crates/agent-gui && pnpm test:release→ 9/9 通过。cd crates/agent-gateway/web && pnpm build && pnpm lint && pnpm test→ 718/718 通过(providerUtils.ts属共享 @liveagent/ui,WebUI 侧一并验证;本地首次跑缺 jsdom,pnpm install --filter @liveagent/gateway-webui...后全绿,与本次改动无关)。deepseek-native.test.mjs:把原「DeepSeek rejects image input before sending a request」换成两条——视觉模型下图片以input_image上线;纯文本模型下请求照常发出、线上无图片字节、由 pi-ai 补占位文本。原「工具结果图片降级」用例保持不变并继续通过(模型input: ["text"])。native-responses-attachments.test.mjs:DeepSeek 图片内联、PDF 留在 Read 路径(断言只读了一次附件且是 image)、纯文本模型不读图片字节且 payload 保持同一性;另加一条锁定providerId === "deepseek"才装 hook。input-modalities.test.mjs:原「deepseek keeps the hard text-only constraint despite the override」换成 id 推断 + 覆盖双向生效(flash 默认吃图、Pro 默认纯文本、覆盖可双向改),并把providerSupportsModelInputModalitiesOverride("deepseek")断言改为 true。未验证的部分(需要真实 key):本次没有对
api.deepseek.com发真实请求(本地无可用 key),上游对deepseek-flash之外 id 的视觉支持边界(如deepseek-v4-pro)也没有实测。若线上表现与 id 推断不符,用设置里的输入模态覆盖即可纠正,无需改代码。Pre-submit checklist
desktop-release.yml的既有本地改动未纳入本 PR)catalog.generated.ts)里 DeepSeek 仍标inputModalities: ["text"],设置页模态徽标会继续显示纯文本;该文件由 models.dev 生成(scripts/generate-model-catalog.mjs+ 定时工作流),等上游数据更新即可,不影响请求路径。