Spring Ai 集成 DashScope 多模态模型实现身份证信息识别
背景
用户上传身份证图片,自动提取姓名、性别、民族、出生日期、住址、身份证号等信息。如果上传的不是身份证图片,返回"图片不合法"。
项目技术栈:Spring Boot 3.4.5 + Spring AI 1.1.2 + DashScope(通义千问)。之前只用了纯文本模型 qwen-flash,这次需要引入多模态能力。
踩坑记录
第一次尝试:Spring AI ChatClient + qwen-vl-plus
一开始想沿用项目中已有的 ChatClient 模式,只是在请求时通过 DashScopeChatOptions 把模型切换为 qwen-vl-plus,图片用 ByteArrayResource 传进去:
java
chatClient.prompt()
.system(prompt)
.user(u -> u.text("请识别图片中的身份证信息。")
.media(mimeType, new ByteArrayResource(imageBytes)))
.options(DashScopeChatOptions.builder().withModel("qwen-vl-plus").build())
.call()
.content();
结果报错:HTTP 400 - url error。原因是 Spring AI Alibaba 的 DashscopeChatModel 内部走的依然是 chat/completions 端点,这个端点不支持多模态输入。ByteArrayResource 传到内部后被当成 URL 去解析,自然失败。
第二次尝试:直接调用 multimodal-generation HTTP 端点
用 WebClient 直接调 DashScope 的多模态生成端点:
POST https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation
请求体按 JSON 格式手动拼接,图片以 base64 data URI 形式传进去。这个方式能工作,但代码里手动拼接 JSON、解析响应,比较原始,也没有 SDK 带来的类型安全和异常处理。
最终方案:DashScope Java SDK
引入官方 SDK com.alibaba:dashscope-sdk-java:2.15.1,用 MultiModalConversation.call() 方法:
java
MultiModalMessage systemMsg = MultiModalMessage.builder()
.role("system")
.content(List.of(Map.of("text", systemPrompt)))
.build();
MultiModalMessage userMsg = MultiModalMessage.builder()
.role("user")
.content(List.of(
Map.of("text", userText),
Map.of("image", dataUri)))
.build();
MultiModalConversationParam param = MultiModalConversationParam.builder()
.model("qwen-vl-plus")
.apiKey(apiKey)
.message(systemMsg)
.message(userMsg)
.build();
MultiModalConversation conv = new MultiModalConversation();
MultiModalConversationResult result = conv.call(param);
SDK 自动处理了 API 路由、认证、请求序列化和响应反序列化,代码干净很多。
架构设计
Controller (Web)
↓ ApiResult<T>
Service (IdCardRecognitionService)
↓ MultiModalConversation.call()
DashScope multimodal-generation API (qwen-vl-plus)
- Controller :
POST /api/id-card/recognize,接收MultipartFile,service 返回 null 时返回code=402, msg="图片不合法" - Service: 校验图片格式 → base64 编码 → 构造 MultiModalMessage(system + user, text + image)→ 调用 SDK → 解析 JSON 响应 → 校验字段合法性
- DTO :
IdCardRecognitionResponserecord,6 个字段
Prompt 设计关键
- 明确字段定义:姓名、性别、民族、出生日期、住址、身份证号,每个字段都给了中文说明和格式要求
- 验证规则:必须有姓名 + 身份证号才算合法
- 输出格式约束:两个明确示例(合法/不合法),禁止 markdown 围栏
- 结构化输出 :
{"valid":true,...}/{"valid":false},便于代码解析
响应格式
合法身份证:
json
{"code":200,"msg":"ok","data":{"name":"张三","gender":"男","ethnicity":"汉","birthDate":"1990年01月01日","address":"北京市朝阳区...","idNumber":"11010119900101001X"}}
非身份证图片:
json
{"code":402,"msg":"图片不合法","data":null}
一点体会
Spring AI Alibaba 的 DashscopeChatModel 虽然方便,但只适用于纯文本 chat/completions 端点。多模态场景需要用官方的 MultiModalConversation SDK 或直接调 multimodal-generation 端点。如果两种场景都有,建议各走各的路------纯文本继续用 ChatClient,多模态走 SDK。