☰
3. LangChain 视觉理解
2026/10/13 14:58:46 网站建设 项目流程

LangChain4j 视觉理解入门指南 - AI 也能看懂图片了!

前言

你有没有想过:AI 能不能像人类一样看图说话?“这张 K 线图走势怎么样?”"这个报错信息是什么意思?"LangChain4j 的多模态能力让 Java 应用也能实现这些功能。本文基于实战项目,详细解析如何让大模型"看懂"图片。


一、什么是视觉理解(Vision)?

传统大模型只能处理文字输入和输出
视觉大模型可以理解图片内容,实现图文对话

比如你给一张上证指数截图,它可以告诉你:

从图片来看,上证指数近期呈现震荡上行态势...成交量明显放大,显示资金活跃度高...MACD 指标金叉向上,趋势偏乐观...

这就是所谓的“多模态”—— 图像 + 文本的混合输入输出。


二、项目结构概览

2.1 pom.xml —— 依赖与基础版相同

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"><modelVersion>4.0.0</modelVersion><parent><groupId>com.study.ai</groupId><artifactId>study-ai</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>langchain4j-04-chatapi-image</artifactId><dependencies><!-- Spring Boot 基础 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- LangChain4j 核心与 OpenAI 适配器 --><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId></dependency><dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-open-ai</artifactId></dependency><!-- Lombok --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>compile</scope></dependency></dependencies></project>

说明:视觉理解和纯文本对话的依赖完全一致,因为底层模型本身就支持多模态。


三、核心原理:图片怎么传给大模型?

3.1 为什么需要 Base64 编码?

网络传输数据都是二进制流,但 JSON 协议只认文本格式。所以必须把图片转换成字符串才能打包发送:

原始图片 (PNG) → 字节数组 → Base64 编码 → 字符串

Base64 是什么?

  • 一种编码方式,能把任何二进制数据转成A-Za-z0-9+/组成的 ASCII 字符
  • 类似 URL 编码(把空格变成%20),但专门用于图片等二进制数据
  • 解码后能恢复成原始文件(不会丢失数据)

类比:就像快递要把易碎品打包到纸箱里——图片本身是玻璃杯,Base64 就是把玻璃杯放进泡沫箱再贴上标签的过程。


四、关键代码逐行详解

4.1 ChatConfig.java —— 超长等待时间设置

packagecom.study.ai.config;importcom.study.ai.service.ChatAssistant;importdev.langchain4j.model.chat.ChatModel;importdev.langchain4j.model.openai.OpenAiChatModel;importdev.langchain4j.service.AiServices;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.time.Duration;@ConfigurationpublicclassChatConfig{@Value("${langchain4j.open-ai.chat-model.api-key}")privateStringapiKey;@Value("${langchain4j.open-ai.chat-model.model-name}")privateStringmodelName;@Value("${langchain4j.open-ai.chat-model.base-url}")privateStringbaseUrl;@BeanpublicChatModelchatModel(){returnOpenAiChatModel.builder().apiKey(apiKey).modelName(modelName).baseUrl(baseUrl)// 🔑 视觉场景的关键配置:关闭重试.maxRetries(0)// ❗ 关闭自动重试:视觉请求耗时长,重试会成倍增加总等待时间// 🔑 超时时间大幅延长至 5 分钟.timeout(Duration.ofMinutes(5))// 图像处理需要上传 + 推理,默认 60 秒远远不够.build();}@BeanpublicChatAssistantchatAssistant(ChatModelchatModel){returnAiServices.create(ChatAssistant.class,chatModel);}}
为什么要特殊处理超时和重试?
参数默认值视觉场景调整原因
maxRetries2改成 0图片分析通常要几十秒,第一次失败就立刻重试会让总等待时间翻倍,不如慢工出细活直接单次完成
timeout60 秒改成 5 分钟上传图片后需要额外时间:①网络传输耗时 ②模型解析像素 ③生成分析结果,总共可能超过 2 分钟

⚠️重要经验:很多初学者做多模态时报 TimeoutException,就是因为用了默认 60 秒超时!


4.2 ApplicationTests.java —— 测试代码全解析

这是本次学习的核心,我们逐行拆解:

packagecom.study.ai;importdev.langchain4j.data.message.ImageContent;importdev.langchain4j.data.message.TextContent;importdev.langchain4j.data.message.UserMessage;importdev.langchain4j.model.chat.ChatModel;importdev.langchain4j.model.chat.response.ChatResponse;importlombok.SneakyThrows;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.core.io.Resource;importjava.util.Base64;@SpringBootTestclassApplicationTests{@AutowiredprivateChatModelchatModel;@Value("image/上证指数.png")// 📌 重点:从 resources 目录读取图片资源privateResourceimage;

字段说明:

  • @Autowired chatModel:注入已配置的 ChatModel Bean
  • @Value("image/上证指数.png"):Spring 的资源注入,从src/main/resources/image/文件夹加载图片

为什么用 Resource 而不是 File?

方式优点缺点
Resource跨平台兼容,IDE 和 JAR 包都能运行需要先 read 成 byte[]
File简单直观Windows/Linux 路径不同容易出错

✅最佳实践:Spring Boot 项目推荐用Resource读取静态资源。


Step 1:把图片转成 Base64 字符串
@SneakyThrows// ❗ Lombok 注解:自动抛出异常,不用写 try-catch@TestvoidtestImg(){// base64DataStringbase64Data=Base64.getEncoder().encodeToString(image.getContentAsByteArray());// mimeTypeStringmimeType="image/png";

每步解释:

①@SneakyThrows是啥?
  • Lombok 提供的语法糖,自动把方法声明的throws IOException隐藏起来
  • 否则你得写:
@TestvoidtestImg()throwsException{// 👈 烦不烦?...}
②image.getContentAsByteArray()
  • 调用 Spring 的Resource接口,把图片转成字节数组(二进制)
  • 相当于:file.jpg → byte[]
③Base64.getEncoder().encodeToString(...)
  • Java 自带的 Base64 工具类
  • 把字节数组转成 ASCII 字符串,便于 JSON 传输
④String mimeType = "image/png"
  • MIME 类型:告诉接收方这是什么格式的文件
  • 常见值:
    • image/png
    • image/jpeg/image/jpg
    • image/gif
    • image/webp

类比:就像寄快递时填写包裹类型——“这是衣服"还是"这是电子产品”,防止运输中损坏。


Step 2:构建混合消息(文字 + 图片)
UserMessageuserMessage=UserMessage.from(TextContent.from("这是上证指数的截图,我需要你从该图片中观察量价信息,判断后续走势"),ImageContent.from(base64Data,mimeType));

核心类解析:

TextContent.from(...)
  • 创建纯文本内容对象
  • 你的问题:“从图片中观察量价信息…”
ImageContent.from(...)
  • 创建一个图片对象,包含:
    • base64Data:图片的 Base64 编码
    • mimeType:图片格式(如image/png)
UserMessage.from(...)
  • 关键点:可以一次性塞入多个内容(文字、图片、甚至未来还有音频/视频)
  • 顺序很重要:先文字后图片(更符合阅读逻辑)

内部结构示意:

UserMessage{contents:[TextContent(text="这是上证指数的截图..."),ImageContent(data="iVBORw0KGgoAAAANSUhh...",type="image/png")]}

Step 3:发送并获取回答
ChatResponsechat=chatModel.chat(userMessage);System.out.println("结果:"+chat.aiMessage().text());}

返回对象解析:

  • chatModel.chat(...)→ 同步等待 AI 分析完成
  • ChatResponse:包含 AI 的所有回复内容
  • chat.aiMessage().text():提取纯文本部分

预期输出示例:

结果:从这张上证指数截图中,我观察到以下关键技术特征: 1. **价格走势**:近期呈现震荡上行态势,从约 3050 点逐步攀升至当前 3120 点左右... 2. **成交量变化**:今日成交额显著放大,约为 XXXX 亿元,高于前几日均值... 3. **均线系统**:日线级别的 MA5/MA10/MA20 呈多头排列... 4. **MACD 指标**:快线(DIF)上穿慢线(DEA),形成金叉形态... 综合判断:短期走势偏乐观,但需注意上方套牢盘压力,建议关注量能持续性...

五、常见问题解答(FAQ)

Q1:为什么不能直接用 File.path 读图片?

A:在 IDEA 开发环境运行时,资源文件可能在target/classes目录下,但在打包后的 JAR 文件中会变成压缩状态,无法直接用new File()访问。Resource接口会自动适配这两种情况。

Q2:如果图片太大怎么办?

A:

  • 压缩:使用javax.imageio缩放图片
  • 裁剪:只截取关键区域(如 K 线图主体)
  • 阿里云百炼限制:单张图片最大 2MB,超过会被拒绝

Q3:支持 JPG 吗?

A:支持,只需要改两件事:

  1. 准备.jpg图片放到image/目录
  2. mimeType改为"image/jpeg"

Q4:可以同时传多张图吗?

A:可以!只要重复添加ImageContent:

UserMessageuserMessage=UserMessage.from(TextContent.from("对比这两张图表..."),ImageContent.from(base64Data1,"image/png"),ImageContent.from(base64Data2,"image/jpeg"));

Q5:为什么我的程序卡住不动了?

A:最常见的原因是超时时间不够!确保设置:

.timeout(Duration.ofMinutes(5))// 至少 2 分钟以上

六、进阶思考:如何优化体验?

6.1 异步流式输出

目前我们是阻塞式等待——用户得盯着控制台看半天。可以考虑改成流式打字机效果(类似之前的 StreamingChatLanguageModel)。

6.2 前端集成

将本模块封装为 RESTful API:

@PostMapping("/analyze")publicStringanalyzeImage(@RequestParamMultipartFilefile){// 读取图片 -> Base64 -> 调用 chatModel}

前端用户上传图片,后端实时返回分析结果。

6.3 结构化解析

如果你只需要特定数据(如股票价格),可以让 AI 返回 JSON 格式,方便进一步处理。


七、总结与下一步

通过这篇博客,你已经掌握了:

✅ 视觉理解的基本原理(为什么需要 Base64)
✅ Spring Resource 读取静态资源
✅ 构建UserMessage混合图文内容
✅ 超长短重试配置的重要性

接下来你可以尝试:

  1. OCR 识别:让 AI 提取图片中的文字(表格、代码、公式)
  2. 目标检测:识别图片中的物体(人脸、商品、动物)
  3. 图像描述:自动生成一段话总结图片内容
  4. 多轮对话:基于图片继续追问细节

八、参考资料

  • LangChain4j 官方文档
  • 学习来源:JavaAI pig4cloud 中文文档(感谢大佬的学习资料,大家一起进步)
  • 我的项目源码

本文档基于实际项目实战编写,所有代码均已测试通过。作者:8 年 Java 开发者自学转型 AI Agent,专注 Java/Spring AI + LangChain4j 技术栈。如有问题欢迎讨论交流!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询