From 7f975de20e399ae6b297d314fbad8e7266da6f2d Mon Sep 17 00:00:00 2001 From: thzxx Date: Sat, 27 Jun 2026 21:43:53 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BB=8E=E5=85=B1=E4=BA=AB=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E4=B8=AD=E7=A7=BB=E9=99=A4=E5=9B=BE=E7=89=87=E5=A4=84?= =?UTF-8?q?=E7=90=86=EF=BC=8CDeepSeek=20=E4=B8=8D=E5=BA=94=E6=8E=A5?= =?UTF-8?q?=E6=94=B6=E5=9B=BE=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题:shared/openai-format.ts 对所有 OpenAI 兼容 Adapter 统一处理 多模态图片 → content 数组。但 DeepSeek 不支持多模态,不应发送图片。 修复: - shared/openai-format.ts: 移除图片处理逻辑(由各 Provider 自行决定) - AgnesAdapter.toNativeRequest: 添加多模态图片转换(OpenAI content 数组) - DeepSeekAdapter: 不处理图片(DeepSeek 不支持多模态) - OllamaAdapter: 已有独立的图片处理(images: [base64] 数组) 各 Provider 多模态支持: DeepSeek ❌ 不支持 → 不发送 images 字段 Agnes AI ✅ 支持 → OpenAI content 数组 [{type:image_url}] Ollama ✅ 支持 → images: [base64] --- electron/harness/adapters/agnes-ai.adapter.ts | 23 ++++++++++++++++++ .../harness/adapters/shared/openai-format.ts | 24 ++++--------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/electron/harness/adapters/agnes-ai.adapter.ts b/electron/harness/adapters/agnes-ai.adapter.ts index 057463a..6502b53 100644 --- a/electron/harness/adapters/agnes-ai.adapter.ts +++ b/electron/harness/adapters/agnes-ai.adapter.ts @@ -98,6 +98,7 @@ export class AgnesAdapter extends BaseAdapter { * 构建 Agnes AI 原生请求体 * * Agnes AI 特有参数: + * - 多模态图片:user 消息的 images[] → OpenAI content 数组 [{type:"text"}, {type:"image_url"}] * - chat_template_kwargs: { enable_thinking: true } — 启用思考模式(非 thinking 字段) * - 默认 max_tokens: 65536(512K 上下文) */ @@ -105,6 +106,28 @@ export class AgnesAdapter extends BaseAdapter { const messages = buildOpenAICompatibleMessages(request); const tools = buildOpenAICompatibleTools(request.tools); + // === Agnes 多模态:将 images 转为 OpenAI content 数组 === + // buildOpenAICompatibleMessages 不处理图片(各 Provider 自行处理) + const nonSystemMsgs = request.messages.filter((m) => m.role !== 'system'); + for (let i = 0; i < messages.length; i++) { + // messages[0] 是 system,非 system 消息从 messages[1] 开始 + if (i === 0) continue; + const origMsg = nonSystemMsgs[i - 1]; + if (!origMsg?.images?.length) continue; + + const contentParts: Array> = []; + if (origMsg.content) { + contentParts.push({ type: 'text', text: origMsg.content }); + } + for (const img of origMsg.images) { + contentParts.push({ + type: 'image_url', + image_url: { url: img.url, detail: img.detail ?? 'auto' }, + }); + } + messages[i].content = contentParts; + } + const body: Record = { model: this.config.defaultModel, messages, diff --git a/electron/harness/adapters/shared/openai-format.ts b/electron/harness/adapters/shared/openai-format.ts index bcaf498..4af2e10 100644 --- a/electron/harness/adapters/shared/openai-format.ts +++ b/electron/harness/adapters/shared/openai-format.ts @@ -16,9 +16,12 @@ import type { MetonaRequest, MetonaToolDef } from '../../types'; * * 处理: * - System Prompt 拼接(静态区 + 动态区 + 安全准则) - * - 图片 → 多模态 content 数组 [{type:"text"}, {type:"image_url"}] * - 工具调用历史保留(reasoning_content + tool_calls) * - 工具结果注入(tool_call_id + content) + * + * 注意:图片(多模态)处理不属于此共享函数。 + * 各 Provider 对多模态的支持不同(DeepSeek 不支持,Agnes/Ollama 支持但格式各异), + * 应在各自 Adapter 的 toNativeRequest 中处理。 */ export function buildOpenAICompatibleMessages( request: MetonaRequest, @@ -35,24 +38,7 @@ export function buildOpenAICompatibleMessages( const nonSystemMessages = request.messages .filter((m) => m.role !== 'system') .map((m) => { - const msg: Record = { role: m.role }; - - // === 多模态图片处理 === - if (m.images && m.images.length > 0) { - const contentParts: Array> = []; - if (m.content) { - contentParts.push({ type: 'text', text: m.content }); - } - for (const img of m.images) { - contentParts.push({ - type: 'image_url', - image_url: { url: img.url, detail: img.detail ?? 'auto' }, - }); - } - msg.content = contentParts; - } else { - msg.content = m.content; - } + const msg: Record = { role: m.role, content: m.content }; // === Assistant 工具调用历史 === if (m.role === 'assistant' && m.toolCalls?.length) {