fix: 修复上传图片后 AI 无法识别图片的问题

根因:图片从 ChatInput → agent-store → IPC → adapter 的链路中有两处断裂:

1. DeepSeekAdapter.toNativeRequest 完全忽略 message.images 字段
   - 用户消息中的图片 base64 数据未转换为 OpenAI 多模态 content
     数组格式,导致 LLM 收不到图片数据,只能尝试用工具查磁盘文件

2. AgnesAdapter.toNativeRequest 图片处理存在数组索引错位
   - base.messages[0] 固定为 system 消息(父类插入)
   - request.messages.filter(m => m.role !== 'system') 去掉了 system
   - 同一索引 i 访问两个不同长度的数组,导致图片消息匹配到错误位置

3. agent-store sendMessage 中 images 参数被局部变量遮蔽
   - ChatInput 传入的 images 被  覆盖
   - 改为直接使用参数,避免重复从 attachments 提取

修复:
- DeepSeekAdapter: 在 toNativeRequest 中添加图片→OpenAI content 数组转换
- AgnesAdapter: 移除冗余图片处理(基类已处理),仅保留 Thinking/max_tokens
- agent-store: 移除 images 变量遮蔽,直接使用参数

影响范围: DeepSeek / Agnes AI / Ollama 三个 Provider 的图片传递均已验证
This commit is contained in:
thzxx
2026-06-27 21:39:24 +08:00
parent 1d185db6b3
commit a879b4f38a
3 changed files with 44 additions and 46 deletions
+23 -22
View File
@@ -220,33 +220,34 @@ export const useAgentStore = create<AgentState>((set, get) => ({
}
if (sessionId && window.metona?.agent?.sendMessage) {
// 构建发给 LLM 的 content:纯用户文本 + 文件 JSON(无文字描述)
// 构建发给 LLM 的消息
// images 参数由 ChatInput 传入(已从附件中提取 base64 data URL
let llmContent = content;
const images: Array<{ url: string; detail?: 'low' | 'high' | 'auto' }> = [];
const llmImages: Array<{ url: string; detail?: 'low' | 'high' | 'auto' }> = [
...(images ?? []),
];
if (attachments && attachments.length > 0) {
const parts: string[] = [];
for (const att of attachments) {
if (att.type === 'image' && att.preview) {
// 图片:直接加入 images 数组
images.push({ url: att.preview, detail: 'auto' });
} else {
// 所有文件:JSON 格式,Base64 编码内容
const ext = att.name.split('.').pop() ?? 'unknown';
let base64Content = '';
if (att.textContent) {
base64Content = btoa(unescape(encodeURIComponent(att.textContent)));
} else if (att.preview) {
// 二进制文件从 data URL 提取 base64
base64Content = att.preview.split(',')[1] ?? '';
}
parts.push(JSON.stringify({
file_name: att.name,
file_type: ext,
context_encode: 'Base64',
context: base64Content,
}));
if (att.type === 'image') {
// 图片已在 images 参数中处理,跳过
continue;
}
// 非图片文件:JSON 格式,Base64 编码内容
const ext = att.name.split('.').pop() ?? 'unknown';
let base64Content = '';
if (att.textContent) {
base64Content = btoa(unescape(encodeURIComponent(att.textContent)));
} else if (att.preview) {
base64Content = att.preview.split(',')[1] ?? '';
}
parts.push(JSON.stringify({
file_name: att.name,
file_type: ext,
context_encode: 'Base64',
context: base64Content,
}));
}
llmContent = parts.join('\n') + (content ? '\n\n' + content : '');
}
@@ -254,7 +255,7 @@ export const useAgentStore = create<AgentState>((set, get) => ({
const messageWithImages = {
...userMessage,
content: llmContent,
images: images.length > 0 ? images : undefined,
images: llmImages.length > 0 ? llmImages : undefined,
};
window.metona.agent.sendMessage(messageWithImages, sessionId).catch(() => {});
}