一套用于学习 Spring AI 的前后端完整项目,通过 10 个可交互的功能页面,逐个实践 Spring AI 的核心知识点(含在线上传文件建库、智能生成表格、多模型转发网关、智能报价助手综合实战)。
SpringAi/
├── backend/ # 后端:Spring Boot 3.4 + Spring AI 1.0.0
│ ├── pom.xml
│ └── src/main/
│ ├── java/com/example/springai/
│ │ ├── SpringAiApplication.java # 启动类
│ │ ├── config/
│ │ │ ├── AiConfig.java # ChatClient/ChatMemory/VectorStore 核心 Bean
│ │ │ └── CorsConfig.java # 跨域配置
│ │ ├── controller/
│ │ │ ├── ChatController.java # ① 基础对话 ② 流式对话
│ │ │ ├── MemoryChatController.java # ③ 多轮记忆对话
│ │ │ ├── PromptController.java # ④ 提示词模板·角色扮演
│ │ │ ├── StructuredController.java # ⑤ 结构化输出
│ │ │ ├── ToolController.java # ⑥ 工具调用
│ │ │ ├── RagController.java # ⑦ RAG 知识库问答(含文件上传)
│ │ │ ├── TableController.java # ⑧ 智能表格生成
│ │ │ ├── GatewayController.java # ⑨ 多模型转发网关(含OpenAI兼容端点)
│ │ │ └── QuoteController.java # ⑩ 智能报价助手(综合实战)
│ │ ├── service/RagService.java # RAG 入库+检索+文件解析逻辑
│ │ ├── gateway/ # 网关:多模型路由 + 用量统计 + 配置绑定
│ │ ├── tools/ # @Tool 工具(时间/天气/报价精算)
│ │ └── dto/ # 请求/响应数据类
│ └── resources/
│ ├── application.yml # 模型服务配置(重点看注释)
│ └── rag/knowledge.txt # RAG 示例知识(虚构公司资料)
└── frontend/ # 前端:Vue 3 + Vite
├── package.json
├── vite.config.js # 含 /api 代理配置
└── src/
├── App.vue # 主框架:左侧菜单 + 右侧功能页
├── api.js # fetch/SSE 请求封装
├── components/ChatPanel.vue # 可复用聊天面板
└── views/ # 8 个功能页面,与后端知识点一一对应
项目通过 OpenAI 兼容协议 接入大模型,改配置即可切换服务商:
| 服务商 | 推荐度 | 说明 |
|---|---|---|
| 阿里云百炼(通义千问) | ⭐⭐⭐ 默认配置 | 聊天+向量模型都有,RAG 功能可完整体验,新用户有免费额度。控制台:https://bailian.console.aliyun.com/ |
| DeepSeek | ⭐⭐ | 便宜好用,但没有向量模型,RAG 页面不可用 |
| OpenAI | ⭐⭐ | 功能全,需要海外支付方式 |
各服务商对应的配置(见 backend/src/main/resources/application.yml 顶部注释):
# 百炼(默认,无需改配置)
AI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode
AI_CHAT_MODEL=qwen-plus AI_EMBEDDING_MODEL=text-embedding-v3
# DeepSeek
AI_BASE_URL=https://api.deepseek.com
AI_CHAT_MODEL=deepseek-chat
# OpenAI
AI_BASE_URL=https://api.openai.com
AI_CHAT_MODEL=gpt-4o-mini AI_EMBEDDING_MODEL=text-embedding-3-small
cd backend
export AI_API_KEY=sk-你的APIKey # Windows PowerShell: $env:AI_API_KEY="sk-xxx"
mvn spring-boot:run看到 Tomcat started on port 8080 即启动成功。
cd frontend
npm install
npm run dev浏览器打开 http://localhost:5173 开始体验。
| 顺序 | 功能页面 | Spring AI 知识点 | 核心代码 |
|---|---|---|---|
| ① | 💬 基础对话 | ChatClient 与 call() 同步调用 |
ChatController |
| ② | ⚡ 流式对话 | stream() 流式调用 + SSE 推送 |
ChatController |
| ③ | 🧠 多轮记忆对话 | ChatMemory + MessageChatMemoryAdvisor,理解 Advisor 机制 |
MemoryChatController / AiConfig |
| ④ | 🎭 角色扮演 | System Prompt 系统提示词 + {变量} 模板填充 |
PromptController |
| ⑤ | 📋 结构化输出 | .entity(Class) 把模型输出映射为 Java 对象 |
StructuredController / TravelPlan |
| ⑥ | 🔧 工具调用 | @Tool / @ToolParam 注解,Agent 的基石 |
ToolController / tools/ |
| ⑦ | 📚 RAG 问答 | EmbeddingModel + VectorStore + QuestionAnswerAdvisor,支持在线上传文件建库 |
RagService |
| ⑧ | 📊 智能表格生成 | 结构化输出 + RAG 组合:自然语言 → 二维表格对象 → 渲染+导出 Excel | TableController |
| ⑨ | 🔀 多模型转发网关 | 手动构建多个 OpenAiChatModel + 按 model 路由 + Token 用量统计 + OpenAI 兼容端点 |
GatewayController / ModelRouter |
| ⑩ | 💰 智能报价助手 | 综合实战:工具调用(精算) + 结构化输出(报价单) + 多轮记忆(议价) 三合一 | QuoteController / QuoteTools |
每个页面顶部都标注了对应的后端类名和验证方法;后端代码里的中文注释详细解释了原理。
底层用 Apache Tika(spring-ai-tika-document-reader)解析文件,支持 PDF / Word(doc/docx) / PPT / TXT / Markdown / HTML / CSV 等格式:
- 进入"RAG 知识库问答"页面 → 点"📎 上传文件",选一个你自己的文档;
- 后端流程:
Tika 提取文本 → TokenTextSplitter 按 Token 切块 → 向量化写入向量库,页面会显示"提取 N 字,切分为 M 块"; - 上传成功后,直接在下方针对文件内容提问即可。可上传多个文件叠加,"清空知识库"一键重置。
这是最贴近真实业务的场景 —— 把杂乱信息一键整理成规整表格:
- 进入"智能表格生成"页面,用大白话描述需求(如"把上传合同里的关键条款整理成表格");
- 勾选 结合知识库(RAG) 时:先检索你上传/录入的资料,再据实生成表格(数据准确、可溯源);不勾选时:靠模型自身知识生成(适合通用常识类表格);
- 结果会渲染成 HTML 表格,可 一键导出 CSV(Excel 可直接打开,已处理中文乱码);页面还会展示模型返回的原始
TableData结构,帮助理解"结构化输出"的本质。
技术要点:
TableController把QuestionAnswerAdvisor(RAG 检索)和.entity(TableData.class)(结构化输出)组合使用 —— 检索到的资料被注入提示词,模型再按二维表结构输出 JSON,前端直接渲染。
把 Spring AI "反过来用":不再是自己调模型,而是对外提供统一 API、内部按需路由:
application.yml的gateway.models声明多个上游模型(默认 3 个 qwen 共用一套 Key,开箱即用);ModelRouter启动时为每个模型各建一个OpenAiChatModel(因为百炼/DeepSeek/OpenAI 都是 OpenAI 协议);- 页面上切换模型发送消息,会显示本次的 输入/输出 Token 和耗时,下方"用量看板"实时累计每个模型的调用量 —— 这正是网关做计费/限流/容量规划的数据基础;
- 网关还暴露了标准
/v1/chat/completionsOpenAI 兼容端点,可被 curl、openai-python、LangChain 直接调用(页面有 curl 示例)—— 把别的程序的 baseURL 指向本网关,就能"偷梁换柱"接入国产模型。
想跨服务商路由:设置环境变量
DEEPSEEK_API_KEY后,下拉里的 DeepSeek 即可用。
最能体现工程价值的毕业设计 —— 一次请求同时用到工具调用、结构化输出、多轮记忆:
- 用大白话描述需求("50人团队用专业版签3年能优惠吗"),助手调用
QuoteTools获取产品目录、用 BigDecimal 精确计算每一项金额,输出结构化报价单并渲染成专业表格,可导出 CSV; - 可多轮议价:接着说"太贵了再打个折""加10个坐席""补上私有化报价",助手(靠
ChatMemory)记得前面的上下文,增量更新报价; - 核心设计思想:AI 负责理解需求,Java 负责精算金额。即便模型已通过工具算过,
QuoteController仍在 Java 侧用recalculate()重新核算小计与总价(双保险)—— 金额这种不能容错的数据,绝不交给大模型心算。
技术要点:
chatClient.prompt().tools(new QuoteTools()).advisors(memoryAdvisor).call().entity(Quotation.class)一行串起三大能力。这是 Spring AI 在真实业务里的典型落地形态。
- 看提示词日志:
application.yml已开启 Advisor 的 DEBUG 日志,控制台可以看到实际发给大模型的完整提示词 —— 观察"记忆"和"RAG 检索片段"是如何被拼进请求的,是理解原理的最快方式。 - 对比实验:
- 在"基础对话"问 "星云科技的年假有几天?"(模型瞎猜)→ 再到 RAG 页面初始化知识库后问同一个问题(答案准确且附检索依据)。
- 在"多轮记忆"页面清空记忆前后各问一次 "我叫什么?"。
- 动手改造:改
knowledge.txt换成自己的资料;给WeatherTools接一个真实天气 API;把SimpleVectorStore换成 Redis/PGVector。
- 接口报 401:API Key 没配置或不正确,检查环境变量
AI_API_KEY。 - RAG 初始化报错:当前服务商不支持向量模型(如 DeepSeek),换用百炼或 OpenAI。
- 流式页面没反应:确认后端已启动(前端通过 Vite 代理转发到 8080 端口)。
- 记忆重启后丢失:正常现象,
MessageWindowChatMemory默认存内存;持久化可自行扩展 JDBC/Redis 实现。