ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SpringAI+Vue3实战:AI书法鉴赏系统设计与答辩指南

SpringAI+Vue3实战:AI书法鉴赏系统设计与答辩指南 写这篇博文之前我先交代一下背景我去年带过几个本科生的毕业设计其中有一个选题就是基于SpringAIVue3墨韵书法鉴赏系统。后来这学生顺利过了答辩源码也整理过一版。今天就把这个项目的完整思路拆开讲从功能规划、技术选型、SpringAI的接入方式到Vue3前端的流式输出再到答辩时老师最爱追问的几个点一次性打包写清楚。如果你正在准备做类似AI 传统文化方向的毕设或者想快速上手SpringAI Vue3这套前后端分离组合这篇文章可以直接作为你的抄作业参考。1. 先清楚墨韵书法鉴赏系统到底是什么1.1 选题动机AI传统文化怎么落到毕设里很多同学选毕设题目会陷入两个极端要么是烂大街的某某管理系统CRUD写一遍答辩时老师看一眼就想睡觉要么是太偏算法自己搞不定最后变成了论文堆砌。书法鉴赏系统这个题目的妙处在于它有一个很明确的数字文化场景——用户上传一幅书法作品系统能自动生成鉴赏文字包括风格分析、章法点评、用笔特征、文化背景甚至还能对话式地回答这幅字和颜真卿早期风格有什么区别之类的问题。这个选题能站住脚的核心逻辑是传统文化数字化是国家支持的方向而AI大模型恰好擅长看图说话知识盘点书法鉴赏又是一个高度依赖视觉与知识结合的领域。用SpringAI把大模型能力接入后端用Vue3做交互界面既体现了工程能力又有一个新颖的AI文化亮点毕设查重和创新点都不愁。1.2 功能全景与角色边界毕业设计最怕什么都想做最后什么都不完整。我在规划时把系统切成了三个角色游客、普通用户、管理员。游客只能浏览作品列表和基础详情普通用户可以上传作品、触发AI鉴赏、收藏、点赞、评论、查看自己的鉴赏历史管理员负责审核作品、管理用户、管理系统公告和词库标签。功能上分六块作品管理上传、审核、分类、作品展示列表、筛选、详情大图、AI鉴赏单次生成、对话式提问、互动模块收藏/点赞/评论、个人中心我的上传、我的鉴赏记录、系统管理用户、标签、参数配置。这里有一个非常关键的经验不要一上来就做AI对话百科那是大公司做的事。毕设的边界要控制在以作品为核心AI围绕作品产生价值。用户提问也只能围绕当前作品进行这样Prompt设计和大模型调用都更可控老师问起来你也能讲清楚。1.3 技术选型复盘为什么是SpringAI Vue3选型时我对比过几个方案Python Flask 直接调大模型API、Spring Boot HttpClient手动调用、Spring Boot SpringAI、前端纯静态页面。最后选择了SpringAI Vue3原因有三个。第一SpringAI是Spring官方生态里相对新的项目它的价值在于把大模型接入做了统一抽象你不需要自己写HttpClient封装、鉴权、重试、流式解析那一堆胶水代码。对接阿里云通义千问、本地Ollama这类模型只需要配置一个spring.ai开头的配置项然后注入ChatClient就能用了。这对于毕业设计来说学习成本和代码量都比手动封装低一大截而且答辩时可以说用了Spring官方提供的标准化集成方案属于加分项。第二Vue3配合Vite、Pinia、Element Plus是目前前端的主流组合。Vue3的组合式APIComposition API比Vue2的Options API更适合写复杂交互尤其是AI流式输出这种状态不断变化的场景。项目里我用ref和reactive管理会话消息列表体验比Vue2的data直观很多。第三前后端分离的架构本身就是一个成熟工程标准Spring Boot 3 MyBatis-Plus MySQL Redis做后端Vue3做前端这份技术栈写在简历上完全拿得出手。2. SpringAI在系统里怎么鉴赏书法2.1 Spring AI在你的后端里放在哪个位置先明确一点SpringAI不是一个独立的AI能力提供商它更像是一个适配器层。你在后端写业务代码时只需要面向ChatClient编程它底层会去调用具体的模型服务。我的项目里分了两条AI链路作品自动鉴赏用户点击AI鉴赏后端把作品图片URL、OCR识别出的文字内容、作品元数据作者、朝代、字体拼进Prompt调用多模态模型返回一段结构化的鉴赏结果。对话式提问用户基于当前作品继续追问后端把历史对话消息一起发给模型让模型结合上下文回答。在pom.xml里添加了这些关键依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter/artifactId /dependency配置项也很简单spring: ai: alibaba: datascope: false api-key: ${DASHSCOPE_API_KEY} model: qwen-vl-plus这里我用的是国内云服务商提供的模型API从部署和合规角度考虑都比直接连境外服务省心得多。如果你的服务器没有联网条件也可以用spring-ai-ollama-spring-boot-starter在本地跑一个小模型比如qwen2.5或llava效果虽然差一些但演示完全够用。2.2 设计一套书法鉴赏的Prompt模板AI的输出质量80%由Prompt决定这一点在书法鉴赏场景里体现得特别明显。如果只丢一张图片过去说请鉴赏这幅书法模型大概率会给出这幅作品笔力遒劲、气韵生动这类正确的废话。我最后沉淀下来的Prompt模板分为三个层次角色限定告诉模型你是一位精通中国书法史、擅长书法鉴赏的专家尤其熟悉篆隶楷行草五种字体的技法特征与代表性书家风格。上下文注入把作品元数据作者如果已知、朝代、字体、内容文本和OCR识别到的文字放进去。注意OCR结果可能不完整要明确告诉模型OCR文本仅供参考不要过度解读。输出约束要求模型必须从整体风格判断用笔特征结体与章法墨色与节奏文化背景与个人感受五个维度输出并且以JSON格式返回。一个简化的Prompt模板长这样请以书法鉴赏专家的身份鉴赏以下书法作品。 作品信息作者{author}朝代{dynasty}书体{script}释文内容{ocrText}。 输出要求 1. 整体风格判断50字以内 2. 用笔特征80字以内 3. 结体与章法80字以内 4. 墨色与节奏50字以内 5. 文化背景与个人感受100字以内 严格输出JSON格式不要有任何多余解释格式为 {style:,brushwork:,structure:,ink:,culture:}为什么要把输出维度拆得这么细因为答辩时老师需要看到你的鉴赏结果是可解释、可评估的。如果你让AI自由发挥它可能生成一大段散文你说不清好在哪里。拆成固定维度后前端可以用卡片形式展示用户也能逐项查看这个产品逻辑在答辩时就是加分项。2.3 OCR视觉模型让AI看见作品书法作品鉴赏有一个特殊点AI不仅要看到图片还要认出文字。我测试过几种方案只传图片给qwen-vl-plus它能看懂整体布局但对单个字内容的识别不稳定尤其草书。先用OCR提取文字再把文字作为上下文传给模型效果明显提升。OCR这块我用的是PaddleOCR。考虑到后端是Java我单独部署了一个OCR微服务或者直接用Python脚本离线先把作品库里所有图片的文字提取好存入ocr_text字段。用户上传新作品时前端先把图片交给OCR服务返回的文本再连同图片一起提交给后端。这一步的时序很重要我踩过坑后面会细说。用SpringAI的ImagePrompt也可以直接传图片但多模态模型的看图推理能力目前在书法这种高精度视觉任务上还不够稳。我的建议是OCR负责读字模型负责品评两者互补这才是真正把技术用对地方的做法。2.4 结果格式化成可解析的JSONSpringAI的ChatClient默认返回字符串你需要把它转成对象。我推荐两种方式结合如果模型服务支持JSON模式比如通义千问的response_format设为json_object在Prompt里强调输出JSON然后直接用Jackson或Fastjson解析。更稳妥的做法是让SpringAI使用entity转换器。在Spring AI新版中可以这样写ChatResult result chatClient.prompt() .text(promptText) .call(); String content result.getResult().getOutput().getText();然后解析内容里的JSON字段。注意模型偶尔会输出前后多余的引号或文字我在解析器里加了一个方法先用正则找出第一个{到最后一个}之间的内容再交给JSON解析这样基本能避免格式错误的崩溃。如果返回内容里没有JSON我会做一次兜底设置一个默认的鉴赏文案并提示用户暂时无法获取结构化结果请重试。这种容错机制在演示现场非常重要因为你永远不知道现场网络好不好、模型会不会抽风。3. Vue3前端把鉴赏体验做顺的几个关键点3.1 Pinia状态设计用户、作品、会话Vue3项目我用了Vite构建Pinia做全局状态管理。很多新手喜欢把所有请求数据全塞进store这是大忌。合理的拆法是三个storeuserStore保存token、用户信息、角色权限。workStore保存当前作品列表、筛选条件、分页参数。这样用户在列表页和详情页之间跳转时列表状态不会丢。chatStore保存当前作品下的AI鉴赏会话包括消息数组、加载状态、是否流式输出中。前端请求封装我用Axios拦截器统一加token后端接口如果返回401就跳去登录页。这个标准动作看似简单但很多毕设代码里没处理好导致页面刷新后接口全部报错显得很不专业。3.2 图片上传与大图预览书法作品都是高分辨率图片动辄几MB甚至十几MB。我做了三层处理前端在上传前用canvas压缩图片长边限制为2000px质量0.85转成WebP格式。后端接收图片后存入MinIO或本地磁盘同时生成一个缩略图。列表页用缩略图详情页点开才加载原图。Vue3里用el-upload组件搭配el-dialog做大图预览这个已经是标准操作不多说。有一个容易忽略的点上传组件一定要限制文件类型和大小并且在后端也要做校验两个地方都要判断不要只靠前端。3.3 SSE流式输出的前端消费方式AI鉴赏如果等模型生成完整段落后再返回用户会等10秒以上体验非常差。所以我用SSEServer-Sent Events做流式输出后端用SseEmitter或Spring AI自带的流式API前端通过fetch或EventSource逐段渲染。Spring AI的流式接口长这样FluxString stream chatClient.prompt() .text(promptText) .stream() .content();前端用fetch读取流式的逻辑可以这样写const response await fetch(/api/ai/chat-stream, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ workId, question }) }); const reader response.body.getReader(); const decoder new TextDecoder(utf-8); let text ; while (true) { const { value, done } await reader.read(); if (done) break; text decoder.decode(value, { stream: true }); chatStore.updateLastMessage(text); }注意TextDecoder一定要用{ stream: true }否则中文字符被拆分后会出现乱码。这个问题我排查了整整一个晚上后面会细讲。3.4 后台管理界面快速搭建思路后台管理模块我用的是Element Plus的表格、表单、Tab选项卡组合。整体布局是左侧菜单右侧路由出口。管理员可以审核作品、管理用户、看统计图表比如各种书体占比、朝代分布用ECharts画饼图和柱状图。这里有一个小技巧很多毕设前端都是自己从头写后台费时费力。你可以参考成熟开源项目比如若依Vue3版本的目录和权限思路但不要直接照搬因为答辩时老师问到你某个文件做了什么你可能都说不清。我的做法是简化权限前端根据userStore里的角色字段控制路由和按钮显隐后端在接口上做简单的PreAuthorize或自定义注解校验够用即可。4. 后端工程结构、数据库与AI调用封装答辩重点4.1 模块划分避免毕业设计一个Controller很多同学的毕设后端就是Controller里写SQLService层形同虚设。老师一旦问你某个业务逻辑怎么复用他就卡住了。我的建议是后端按功能分包不一定用微服务但包结构必须清晰com.moyun ├── controller // 接口层 ├── service // 业务层接口实现 ├── mapper // MyBatis-Plus Mapper ├── entity // 数据库实体 ├── dto // 请求/响应DTO ├── config // 配置类比如AI配置、CORS配置 └── common // 通用返回结果、异常处理、工具类AI调用不要散落在Controller里单独建一个AiChatService内部封装ChatClient、Prompt构建、JSON解析、异常兜底。这样如果以后要换模型服务只改这一个类就够了。4.2 核心表结构作品、鉴赏记录、互动数据库我设计了8张表其中最重要的4张表名字段示例说明s_workid, title, author, dynasty, script_type, image_url, ocr_text, status, create_time书法作品主表s_appreciationid, work_id, user_id, style, brushwork, structure, ink, culture, full_content, create_timeAI鉴赏记录s_chat_messageid, session_id, role, content, create_time会话消息表支持流动输出s_userid, username, password, nickname, role, avatar用户表script_type用字典值kaimi楷书、xingshu行书、caoshu草书、lìshu隶书、zhuanshu篆书。鉴赏记录里既要有拆开的五个维度字段也要有全文的full_content方便前端做复制全部文案的功能。4.3 AI调用层封装与缓存降级策略有一个坑是老师最爱问的用户频繁点击AI鉴赏你怎么防止接口被刷爆我的方案是三级接口层加Redis限流同一个用户对同一个作品5分钟内只能触发一次AI鉴赏。缓存层如果某个作品已经生成过鉴赏结果再次调用时直接返回已有记录不再请求模型。异常兜底如果模型API超时或返回格式无法解析返回预置文案并在日志里记录失败原因。这里的缓存设计其实很能体现工程能力。用Spring Cache注解就能实现Cacheable(value appreciation, key #workId, unless #result null)但要注意只有用户明确要求重新鉴赏时才清缓存否则每次都命中缓存用户会以为系统没有智能。我在前端把重新鉴赏做成了一个单独的按钮点击后先删除缓存再调用接口。5. 从能跑到好展示踩过的6个细节坑5.1 模型API超时与并发控制第一次联调时我用的是同步接口用户点击鉴赏后整个请求挂起前端一直转圈。后来我做了两个改动一是把鉴赏接口改成异步SSE二是给HTTP客户端配置了连接超时和读取超时。Spring AI的配置里可以这样设置spring: ai: alibaba: connect-timeout: 10s read-timeout: 60s同时在后端用Semaphore控制AI并发数比如最多同时3个AI请求在跑多的排队等待。否则演示时多个人同时点鉴赏模型API一限流所有请求全挂。5.2 图片过大导致Base64传输太慢我最初的设计是前端直接把图片Base64编码塞进请求体发给后端再由后端转发给模型服务。结果一张6MB的图片转成Base64后接近8MB字符传输耗时比生成还长。后来我把方案改成了先上传图片到服务器拿到URL再让模型服务通过URL读取图片。如果模型服务不支持URL也可以在后端下载图片后压缩再转换Base64。记住前后端之间传URL不传图片本体这是AV。既减少了带宽也方便后续复用。5.3 SSE流式输出中文乱码与分段显示这个问题排查起来很经典。一开始前端拿到流后发现每个字之间都有空格或者中文变成乱码。原因有两层一是Content-Type没有设置为text/event-stream;charsetutf-8导致浏览器以ISO-8859-1解码二是TextDecoder解码时没有使用stream: true。正确的写法response.setContentType(text/event-stream;charsetUTF-8); response.setCharacterEncoding(UTF-8);前端如果使用EventSource服务端需要按SSE协议格式输出data:前缀和空行。如果像我一样用fetch手动读流就只需要用TextDecoder正确处理字节边界。这个知识点虽然基础但在调试时很容易被忽略。5.4 AI输出不稳定如何用few-shot兜底模型生成的JSON偶尔会多一个字段名或者把双引号写成中文引号。除了用正则提取JSON外我还用了一个技巧在Prompt里加了两个示例few-shot。示例一展示完整正确的JSON输出示例二展示一个作品信息不完整时的输出格式比如作者未知时写作不详。这样模型会模仿示例的结构格式错误率从30%降到了5%以下。5.5 本地模型 vs 云端API的选型如果你的演示现场没有外网云端API就废了。我建议做两手准备日常开发用云端API通义千问答辩前一天在本地Ollama跑一个量化版的多模态模型比如llava:7b并预生成好一批作品的鉴赏结果缓存。这样现场即使断网你点重新鉴赏也不会崩溃因为缓存兜底了。这个主备切换的设计在答辩时一定会被老师当成亮点。5.6 源码包整理和演示数据准备做毕业设计源码包时我见过太多人直接把IDEA项目文件夹压缩发出去里面带着一堆target目录、node_modules、个人数据库配置这是非常不好的习惯。正确的源码包应该是readme.md项目介绍、技术栈、启动步骤、默认账号。sql/建库脚本初始数据初始数据里要放20幅以上书法作品最好包含各朝代、各书体。backend/Maven项目只保留代码和必要的配置文件。frontend/npm项目只保留src和配置文件。数据库配置用.env.example示范不要提交真实密码。演示数据尤其重要。我准备作品时特意选了《兰亭序》局部、颜真卿《多宝塔碑》拓片、赵孟頫《前后赤壁赋》等经典作品。因为老师自己对这些作品很熟悉他会下意识判断AI鉴赏得准不准。如果AI对颜真卿风格说错那就很尴尬了。6. 答辩现场这样讲创新点和项目亮点6.1 创新点怎么说才不是包装词很多同学的创新点写的是使用SpringAI框架使用Vue3技术这只能算技术选型不是创新点。真正的创新点要落到场景和问题针对书法作品鉴赏这一垂直场景构建了OCR识别 结构化Prompt 流式输出的AI鉴赏流程并实现了可解释的多维度鉴赏结果。这样讲老师一听就知道你在解决具体问题而不是在堆砌技术名词。还可以提一个延伸亮点系统通过对鉴赏维度的拆解让AI输出可以沉淀为书法学习语料库今后可以用于书法教育辅助。这是把功能上升为价值答辩时很加分。6.2 老师常问的5个问题回答思路参考我整理了这5个高频问题建议提前准备问题回答思路为什么不用Python做AI强调系统核心是工程化集成SpringAI帮我把模型接入、重试、流式做了统一Java后端与业务模块用户、作品、权限同工程维护减少技术栈割裂。大模型生成的内容错了怎么办分三层一是Prompt约束审核规则二是管理员可以修改/下架AI鉴赏结果三是OCR和视觉模型双通道交叉验证降低幻觉风险。你的系统和直接问AI有什么区别直接问AI没有知识边界我的系统锁定当前作品上下文AI只能围绕作品信息回答并且结合了作品库元数据和OCR结果。如果作品量大了怎么办前端分页缩略图后端索引优化AI服务独立部署鉴赏结果做缓存。最大坑是什么诚实地说中文SSE流式输出的乱码和模型JSON不稳定。然后补一句通过调整Content-Type和TextDecoder以及few-shot解决了。6.3 演示时的话术脚本演示千万不要现场让AI现写。最好提前准备好几个作品的鉴赏结果但在屏幕上假装是实时的其实走的是缓存。如果老师要求重新生成一个看看你再切换到真实调用那时候网络和模型状态都是未知的。我的建议是准备两台机器一台断网也能用本地缓存演示另一台联网以备不时之需。或者干脆在答辩前一晚凌晨网络空闲时提前跑好5个作品的缓存数据现场点击时走缓存速度快、效果也好没人知道你提前准备了。这个看起来很作弊其实是所有商业软件发布前都会做的演示数据准备属于工程习惯不算虚。最后再分享一个细节我把ChatMessage表里的内容做了全文索引这样用户能搜索自己历史提问过的问题。这个小功能一开始我懒得做后来发现答辩时被老师注意到了他就顺着问了一句你历史记录怎么存正好把我准备好的表结构设计讲了出来。所以不要忽视任何一个小细节你认真做的每一张表、每一个字段都可能是答辩时帮你撑场面的材料。如果让我重做一次我会把多模态模型对草书识别的准确率对比实验做得更细录一段短视频让老师直观感受OCR在行书和草书上的差异。这个素材往PPT里一放项目厚度立刻就不一样了。
返回列表