当前位置: 首页 > news >正文

大模型通义千问3-VL-Plus - 视觉推理(本地图片)

一、概论

官方给出的解释:视觉推理模型能够先输出思考过程,再输出回答内容,适用于处理复杂的视觉分析任务,如解读数学题、分析图表数据或复杂视频理解等任务。

简单来说,视觉推理是人工智能的一个分支,核心是让模型像人一样 “看懂” 图像并进行逻辑分析,而非仅识别表面元素。只要训练好智能体,你甚至可以拍摄一个人的样貌,然后智能体可以根据知识库来判断出一个人的心理活动(当然,这需要大量的训练)

二、视觉推理模型核心技术与典型应用清单

核心是通过 “图像理解 + 逻辑推理” 实现复杂视觉任务处理,以下是关键技术与落地场景梳理:

1、核心技术(支撑模型推理能力)

  • 多模态融合技术:将图像像素信息与文字、数学符号等跨模态数据关联,打破单一模态的信息局限。
  • 视觉元素解析技术:精准提取图像中的关键元素,如图表的坐标轴 / 数据点、数学题的图形条件、视频的场景物体。
  • 逻辑推理引擎:基于提取的信息搭建推理链条,处理因果、逻辑运算、数据关联等复杂关系。
  • 可解释性模块:专门生成推理过程,把 “如何从图像到结论” 的步骤清晰输出,提升结果可信度。

2、典型应用场景(落地价值体现)

  • 教育领域:解读数学几何题、物理示意图,拆解解题条件与推导步骤。
  • 数据处理领域:分析柱状图 / 折线图 / 饼图,不仅提取数字,还计算增长率、占比、趋势变化。
  • 视频分析领域:理解长视频中的事件逻辑,如监控视频中异常行为的因果推导、影视剧情的关键情节梳理。
  • 医疗领域:辅助解读医学影像,结合病灶形态与临床知识,推理可能病症及诊断依据。
  • 工业领域:质检时识别产品缺陷,同时推理缺陷产生的可能环节(如零件装配偏差、材料问题)。

三、代码实现

在前文 大模型通义千问3-VL-Plus - 视觉理解-CSDN博客 中我们已经简单的写了一个需要https图片链接的视觉理解功能,现在我们改造一下,要做到可以上传本地文件。

1、Base64

通义千问VL 提供两种本地文件上传方式:Base64 编码上传和文件路径直接上传。可根据文件大小、SDK类型选择上传方式.

两者的区别:

Base64编码:将文件转换为 Base64 编码字符串,再传入模型。适用于 OpenAI 和 DashScope SDK 及 HTTP 方式

本地文件路径:直接向模型传入本地文件路径,仅 DashScope Python 和 Java SDK 支持,不支持 DashScope HTTP 和OpenAI 兼容方式。

这里为了方便各位后续可以使用 OpenAI 的内容,所以我们直接用 Base64编码,当然我也会给出本地文件路径的核心修改代码,但是就不做演示啦。

注意:通义千问VL API对单张图像编码后的视觉 Token 数量设有限制,默认配置下,高分辨率图像会被压缩,可能丢失细节,影响理解准确性。启用vl_high_resolution_images或调整max_pixels可增加视觉 Token 数量,从而保留更多图像细节,提升理解效果。

1.1 调整请求参数实体MultimodalRequest

新增本地图片路径字段,用于接收本地文件路径(二选一:imageUrl 传网络图片,localImagePath 传本地图片)

import lombok.Data; @Data public class MultimodalRequest { /** 图片URL */ private String imageUrl; /** 提问文本 */ private String question; /** 本地图片路径(如:/usr/local/images/test.png 或 D:/images/test.jpg) */ private String localImagePath; }

1.2 修改核心服务类MultimodalServiceImpl

核心修改说明

  1. 新增工具方法

    • encodeLocalImageToBase64:读取本地图片文件并转换为带data:image/xxx;base64,前缀的 Base64 字符串(兼容 png/jpg/jpeg 格式)
    • buildImageContent:统一处理图片来源(优先本地文件,其次网络 URL),避免重复逻辑
    • handleEmitterError:统一处理 SSE 发射器的异常推送,简化代码
  2. 兼容两种图片来源

    • 通过判断localImagePath/imageUrl是否为空,自动选择图片处理方式
    • 本地图片:转 Base64 后传入 API;网络图片:直接传入 URL
  3. 完善异常处理

    • 新增IOException捕获(本地文件读取失败)
    • 新增参数校验(必须传入图片来源)
    • 流式调用中统一异常处理,确保前端能收到错误信息
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam; import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationResult; import com.alibaba.dashscope.common.MultiModalMessage; import com.alibaba.dashscope.common.Role; import com.alibaba.dashscope.exception.ApiException; import com.alibaba.dashscope.exception.NoApiKeyException; import com.alibaba.dashscope.exception.UploadFileException; import gzj.spring.ai.Request.MultimodalRequest; import gzj.spring.ai.Service.MultimodalService; import io.reactivex.Flowable; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.*; import java.util.Base64; /** * 多模态服务封装(支持网络图片URL + 本地图片文件) * @author DELL */ @Slf4j @Service public class MultimodalServiceImpl implements MultimodalService { @Value("${dashscope.api-key}") private String apiKey; /** * 工具方法:将本地图片编码为Base64字符串(带data:image前缀) * @param localPath 本地图片绝对路径 * @return 带前缀的Base64字符串 * @throws IOException 文件读取异常 */ private String encodeLocalImageToBase64(String localPath) throws IOException { Path imagePath = Paths.get(localPath); // 校验文件是否存在 if (!Files.exists(imagePath)) { throw new IOException("本地图片文件不存在:" + localPath); } // 读取文件并编码 byte[] imageBytes = Files.readAllBytes(imagePath); String base64Str = Base64.getEncoder().encodeToString(imageBytes); // 自动识别图片格式(支持png/jpg/jpeg) String suffix = localPath.substring(localPath.lastIndexOf(".") + 1).toLowerCase(); if (!Arrays.asList("png", "jpg", "jpeg").contains(suffix)) { suffix = "png"; // 默认png格式 } return String.format("data:image/%s;base64,%s", suffix, base64Str); } /** * 工具方法:构建图片内容(兼容URL/本地文件) * @param request 请求参数 * @return 图片内容字符串(URL或Base64) * @throws IOException 本地文件读取异常 */ private String buildImageContent(MultimodalRequest request) throws IOException { // 优先级:本地文件 > 网络URL(可根据业务调整) if (request.getLocalImagePath() != null && !request.getLocalImagePath().isEmpty()) { log.info("使用本地图片:{}", request.getLocalImagePath()); return encodeLocalImageToBase64(request.getLocalImagePath()); } else if (request.getImageUrl() != null && !request.getImageUrl().isEmpty()) { log.info("使用网络图片URL:{}", request.getImageUrl()); return request.getImageUrl(); } else { throw new IllegalArgumentException("必须传入imageUrl(网络图片)或localImagePath(本地图片)"); } } /** * 普通调用(非流式)- 支持网络/本地图片 */ @Override public String simpleCall(MultimodalRequest request) throws ApiException, NoApiKeyException, UploadFileException, IOException { MultiModalConversation conv = new MultiModalConversation(); // 构建图片内容(兼容URL/本地文件) String imageContent = buildImageContent(request); // 构建用户消息(图片+文本) MultiModalMessage userMessage = MultiModalMessage.builder() .role(Role.USER.getValue()) .content(Arrays.asList( Collections.singletonMap("image", imageContent), Collections.singletonMap("text", request.getQuestion()) )).build(); // 构建请求参数 MultiModalConversationParam param = MultiModalConversationParam.builder() .apiKey(apiKey) .model("qwen3-vl-plus") .messages(Arrays.asList(userMessage)) .build(); // 同步调用 MultiModalConversationResult result = conv.call(param); // 解析返回结果 List<Map<String, Object>> content = result.getOutput().getChoices().get(0).getMessage().getContent(); if (content != null && !content.isEmpty()) { return content.get(0).get("text").toString(); } return "未获取到有效结果"; } /** * 流式调用(SSE推送)- 支持网络/本地图片 */ @Override public SseEmitter streamCall(MultimodalRequest request) { // 设置超时时间30秒 SseEmitter emitter = new SseEmitter(30000L); new Thread(() -> { MultiModalConversation conv = new MultiModalConversation(); try { // 构建图片内容(兼容URL/本地文件) String imageContent = buildImageContent(request); // 构建用户消息 MultiModalMessage userMessage = MultiModalMessage.builder() .role(Role.USER.getValue()) .content(Arrays.asList( Collections.singletonMap("image", imageContent), Collections.singletonMap("text", request.getQuestion()) )).build(); // 构建请求参数 MultiModalConversationParam param = MultiModalConversationParam.builder() .apiKey(apiKey) .model("qwen3-vl-plus") .messages(Arrays.asList(userMessage)) .incrementalOutput(true) // 增量输出(流式) .build(); // 流式调用 Flowable<MultiModalConversationResult> resultFlow = conv.streamCall(param); resultFlow.blockingForEach(item -> { try { List<Map<String, Object>> content = item.getOutput().getChoices().get(0).getMessage().getContent(); if (content != null && !content.isEmpty()) { String text = content.get(0).get("text").toString(); // 推送流式数据到前端 emitter.send(SseEmitter.event().data(text)); } } catch (Exception e) { log.error("流式推送单条数据失败", e); try { emitter.send(SseEmitter.event().name("error").data("数据推送失败:" + e.getMessage())); } catch (Exception ex) { log.error("推送错误信息失败", ex); } } }); // 流式结束标记 emitter.send(SseEmitter.event().name("complete").data("流结束")); emitter.complete(); } catch (IOException e) { log.error("读取本地图片失败", e); handleEmitterError(emitter, "读取本地图片失败:" + e.getMessage()); } catch (ApiException | NoApiKeyException | UploadFileException e) { log.error("多模态API调用失败", e); handleEmitterError(emitter, "API调用失败:" + e.getMessage()); } catch (IllegalArgumentException e) { log.error("请求参数异常", e); handleEmitterError(emitter, "参数错误:" + e.getMessage()); } catch (Exception e) { log.error("流式调用未知异常", e); handleEmitterError(emitter, "系统异常:" + e.getMessage()); } }).start(); return emitter; } /** * 工具方法:统一处理SSE发射器异常 */ private void handleEmitterError(SseEmitter emitter, String errorMsg) { try { emitter.send(SseEmitter.event().name("error").data(errorMsg)); emitter.completeWithError(new RuntimeException(errorMsg)); } catch (Exception e) { log.error("处理发射器异常失败", e); } } }

2、 本地路径

如果只做传本地路径,只需要修改以下内容

四、效果示例

五、总结

本次代码修改围绕让多模态服务同时兼容 HTTPS 网络图片和本地图片文件展开,核心总结如下:

一、核心目标

在保留原有 “普通调用(非流式)” 和 “流式调用(SSE 推送)” 能力的基础上,新增本地图片处理能力,实现「网络图片 URL」和「本地图片文件」两种输入方式的无缝兼容。

二、关键改动

  1. 请求参数扩展MultimodalRequest新增localImagePath字段,与原有imageUrl字段配合,分别接收本地图片绝对路径、HTTPS 图片 URL(二选一传入)。

  2. 新增核心工具方法

    • encodeLocalImageToBase64:读取本地图片文件,校验文件存在性,自动识别 png/jpg/jpeg 格式并转换为带data:image/xxx;base64,前缀的 Base64 字符串(符合通义千问 VL 模型要求);
    • buildImageContent:统一处理图片来源(优先本地文件,其次网络 URL,可灵活调整优先级),参数校验确保必传图片来源;
    • handleEmitterError:流式调用中统一处理异常,向前端推送标准化错误信息,简化异常处理逻辑。
  3. 核心业务方法改造

    • simpleCall/streamCall均接入buildImageContent方法,无需改动原有模型调用、参数构建、结果解析逻辑,仅扩展图片内容构建环节;
    • 新增IOException(文件读取)、IllegalArgumentException(参数缺失)等异常捕获,覆盖本地图片处理的异常场景。

三、核心能力

  1. 双源兼容:调用时只需传入imageUrl(网络图)或localImagePath(本地图),无需修改调用逻辑;
  2. 格式自适应:自动识别本地图片格式,默认兜底 png,避免格式不兼容问题;
  3. 异常友好:文件不存在、参数缺失、API 调用失败等场景均有明确错误提示,流式调用错误可实时推送到前端。

四、使用与注意事项

  1. 使用方式
    • 网络图片:传imageUrl字段,保持原有调用逻辑;
    • 本地图片:传localImagePath字段(需绝对路径),自动转 Base64 后调用 API。
  2. 关键注意
    • 本地图片需保证应用进程有文件读取权限;
    • 图片大小需符合通义千问 VL 模型要求(单张≤10MB);
    • Linux/Windows 路径分隔符需适配(Linux 用/,Windows 用\\/);
    • 图片源优先级可通过修改buildImageContent的判断逻辑调整。

希望这个兼容网络图 + 本地图的多模态服务小改造,能帮到正在折腾 AI 开发的你呀~✨ 代码跑通的瞬间是不是超有成就感!

如果觉得这份修改实用、总结清晰,别忘了动动小手点个赞👍,再关注一下呀~ 后续还会分享更多 AI 接口封装、代码优化的干货技巧,一起解锁更多好用的功能,少踩坑多提效!🥰 你的支持就是我更新的最大动力,咱们下次分享再见呀~🌟

http://www.jsqmd.com/news/83545/

相关文章:

  • Profinet转Modbus TCP工业数据采集网关:实现1200PLC 与打标卡数据实时传输
  • Git能上传多大的文件
  • Burp Suite安装保姆级教程,Burp Suite的基本介绍及使用,收藏这一篇就够了
  • [STM8]学习日志-STM8介绍
  • 【渗透测试零基础入门】搭建 DVWA 靶场保姆级教程(超详细),收藏这一篇就够了!_dvwa靶场搭建
  • 一文详解JUC中乐观锁的实现原理(CAS)、实现方式、优缺点及应用场景总结
  • 3.7 Elasticsearch-查询性能剖析:profile API、DFS query_then_fetch
  • 国内纸纱线FSC春夏14至16针,实力公司推荐排行榜揭秘
  • 参数估计(三)-- 隐参数模型
  • 打CTF,逆向分析攻略!
  • LightModel
  • 数据结构入门:从“是什么”到“为什么要学”
  • 当下的网络安全行业前景到底怎么样?还能入行分蛋糕吗?
  • 国内专业纸纱线FSC春夏14-16针工厂,这份推荐榜单别错过
  • 不同扩散模型下煤层瓦斯运移的Comsol数值模拟:双孔扩散及时变扩散模型文献复现
  • 黑神话 地图APP 程序
  • 【笔记篇】【硬件基础篇】电力电子元器件应用手册 阅读笔记(1)电阻器及其应用
  • 双向buck/boost电路仿真(VDCM控制/电压电流双闭环控制) 利用了传统电机的阻尼和旋...
  • OKR与绩效考核结合:优势、挑战与实践路径
  • AD学习笔记-31 DRC检查
  • Linux系统编程——进程进阶:父子关系、终止与资源回收
  • 微信美业医疗美容院小程序预约会员管理养生馆诊所肌护肤理疗系统
  • behavior interview II
  • 2025年GEO优化机会与争议以及规范发展的必要性
  • 2025最新!大模型学习路线图:超全超详细,从语言模型基础到LLM安全框架! - 详解
  • 聊聊饮料生产罐装生产线的S7 - 1200 PLC开发
  • COMSOL泰勒锥模型:水平集耦合空间电荷密度
  • Spring 开发小白学习过程中常用通用配置文件,即拿即用!(持续更新中)
  • 压缩空气储能和释能阶段模型,附相关文档文献。 建立了压缩空气储能系统中的压缩机、换热器、储气罐...
  • 16. Qt深入 容器