
1. 为什么简历上写 Spring AI RAG 总被追问细节很多同学在简历里写「基于 Spring AI 搭建 RAG 知识库问答系统」面试官一句「你的向量库怎么初始化的、Embedding 模型在哪一步被调用」就卡住了。问题不在你不会用而在于你只记住了 API 名字没把「文档加载 → 切片 → 向量化 → 存储 → 检索 → 拼 Prompt」这条链路讲成工程细节。Spring AI 的价值恰恰是把这条链路封装成了几个 Bean 和 Advisor你只要把配置骨架和调用顺序说清楚亮点自然就立住了。这篇聚焦三件事Spring AI 框架怎么用、LLaMA 3 与 OpenAI 这类模型怎么统一接入、Milvus 向量库怎么做检索增强。为了让「统一 Key」这件事不成为你项目里的脏活我会用 TaoToken 作为统一 API 通道来演示配置这样你在简历里可以写「通过统一网关管理多模型 Key降低接入成本」而不是写一堆散落的 api-key。先说清楚 RAG 是什么检索增强生成让大模型先查资料再回答。你的私有文档产品手册、公司制度先被切成片段、转成向量存进向量库用户提问时问题也转成向量去库里找最相似的几段再连同问题一起塞进 Prompt 给模型。这样模型回答有依据不会瞎编。适合谁做 Java 后端、想往 AI 应用方向转、需要拿一个能讲透的项目写进简历的人。Milvus 在这里的角色是「专门存向量的数据库」相比内存版 SimpleVectorStore它支持持久化、亿级向量、多种索引是简历里更拿得出手的选型。下面从依赖到配置到验证一步步来。2. TaoToken 统一 Key 接入 LLaMA 3 与 OpenAI 的前置准备在写配置之前先把「统一 Key」这件事讲明白。你项目里如果同时要调 OpenAI 的模型和 LLaMA 3传统做法是维护两套 api-key、两套 base-url、两套 SDK 配置换模型就要改代码。TaoToken 提供的是 OpenAI 兼容的统一 API 通道你只需要一个 Key、一个 Base URL通过改 model 名就能在 OpenAI、LLaMA 3 之间切换。这对简历项目的意义是你可以写「设计统一模型接入层支持多模型热切换」而不是「调用了两个 API」。前置准备分三步。第一步去 TaoToken 官网注册并拿到 API Key地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 登录后在控制台的 API Keys 页面创建deep link 是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。创建后复制那串 sk- 开头的字符串只显示一次先存到密码管理器。第二步确认你要用的模型 ID。TaoToken 的模型列表里OpenAI 系和 LLaMA 3 系都有对应的 model 名你在模型对话页面可以先试跑一下地址 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 选一个模型发一句话确认通道正常。这一步别跳过很多人配置写完跑不通其实是 Key 或模型名的问题先在网页端验证能省半小时。第三步理解 Base URL 的写法。OpenAI 兼容接口的 base-url 是 https://taotoken.net/api 注意结尾不带 /v1Spring AI 的 OpenAI starter 会自动拼 /v1/chat/completions。如果你用的是原生 OpenAI SDK那 base_url 要写成 https://taotoken.net/api/v1 。这个细节是踩坑高发区配置里写错一个斜杠就是 404。关于 EmbeddingRAG 里向量化也要调模型。TaoToken 同样提供 embedding 接口你在 application.yml 里把 embedding 的 base-url 和 api-key 指向同一套即可。这样 chat 和 embedding 共用一个 Key简历上「统一 Key 管理」才站得住。注意不要把 Key 硬编码进代码提交到 Git。用环境变量或配置中心application.yml 里写${TAOTOKEN_API_KEY}本地用 IDE 的 EnvFile 或启动参数注入。到这里前置就齐了一个 Key、一个 Base URL、两个模型名一个 chat、一个 embedding。接下来进配置。3. 可复制的 application.yml 与 config.toml 配置骨架这一节是全文最该抄走的部分。先给 Maven 依赖坐标Spring AI 的版本要和 Spring Boot 对齐Spring Boot 3.2.x 配 Spring AI 0.8.1 及以上比较稳。核心依赖是 spring-ai-openai-spring-boot-starter走 OpenAI 兼容协议接 TaoToken和 spring-ai-milvus-spring-boot-starter。dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-openai-spring-boot-starter/artifactId version0.8.1/version /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-milvus-spring-boot-starter/artifactId version0.8.1/version /dependency然后是 application.yml。这里把 chat、embedding、vectorstore 三段都写全注意 base-url 和 api-key 都指向 TaoTokenmodel 名按你实际选的填。spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: gpt-4o-mini temperature: 0.7 max-tokens: 2048 embedding: options: model: text-embedding-3-small vectorstore: milvus: client: host: 127.0.0.1 port: 19530 database-name: default collection-name: rag_docs embedding-dimension: 1536 index-type: IVF_FLAT metric-type: COSINE如果你更习惯用 TOML 管理配置比如 GraalVM 或某些云平台等价写法如下字段路径和 yml 一一对应[spring.ai.openai] base-url https://taotoken.net/api api-key ${TAOTOKEN_API_KEY} [spring.ai.openai.chat.options] model gpt-4o-mini temperature 0.7 max-tokens 2048 [spring.ai.openai.embedding.options] model text-embedding-3-small [spring.ai.vectorstore.milvus] database-name default collection-name rag_docs embedding-dimension 1536 index-type IVF_FLAT metric-type COSINE [spring.ai.vectorstore.milvus.client] host 127.0.0.1 port 19530几个参数解释一下面试也会问。embedding-dimension 必须和你选的 embedding 模型输出维度一致text-embedding-3-small 是 1536写错 Milvus 建集合时会报维度不匹配。metric-type 用 COSINE 是文本相似度常用选择IVF_FLAT 是入门索引数据量大再换 HNSW。collection-name 是你自己定的集合名Milvus 里相当于一张表。Milvus 本地起一个最快的方式是 Docker一条命令docker run -d --name milvus-standalone -p 19530:19530 -p 9091:9091 milvusdb/milvus:v2.4.0 milvus run standalone起来后用docker logs milvus-standalone看到 Milvus Standalone started 就 OK。这一步别用生产库本地容器足够验证。配置骨架到这里就完整了。简历上你可以写「基于 Spring AI 抽象层完成 OpenAI 兼容通道与 Milvus 向量库的配置化接入模型与向量库均可通过配置切换」这句话背后就是上面这些 yml。4. 一次检索增强问答的验证请求与成功结果配置写完必须跑一次端到端否则简历上写「实现 RAG」是虚的。验证分两步先把文档灌进 Milvus再发一次带检索的问答。第一步写一个启动时加载文档的 Bean。把 Markdown 文档放src/main/resources/documents/下用 Spring AI 的 MarkdownDocumentReader 读再用 TokenTextSplitter 切片最后 add 进 VectorStore。切片这步不能省不切片整篇文档一个向量检索精度极差。Configuration public class RagConfig { Bean VectorStore vectorStore(EmbeddingModel embeddingModel, MilvusVectorStoreConfig config) { return MilvusVectorStore.builder(config) .embeddingModel(embeddingModel) .build(); } Bean ApplicationRunner loadDocs(VectorStore vectorStore, ResourcePatternResolver resolver) { return args - { Resource[] resources resolver.getResources(classpath:documents/*.md); ListDocument docs new ArrayList(); for (Resource r : resources) { MarkdownDocumentReader reader new MarkdownDocumentReader(r, MarkdownDocumentReaderConfig.builder() .withAdditionalMetadata(filename, r.getFilename()) .build()); docs.addAll(reader.get()); } TokenTextSplitter splitter new TokenTextSplitter(); vectorStore.add(splitter.apply(docs)); System.out.println(已写入向量数: docs.size()); }; } }启动应用控制台打印「已写入向量数: N」说明 embedding 调用成功、Milvus 写入成功。如果这里报 401往下看第 5 节。第二步写一个检索增强的问答接口。核心是 QuestionAnswerAdvisor它会在每次提问时自动去 VectorStore 检索相似片段并拼进 Prompt。RestController public class RagController { private final ChatClient chatClient; public RagController(ChatClient.Builder builder, VectorStore vectorStore) { this.chatClient builder .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore)) .build(); } GetMapping(/rag/ask) public String ask(RequestParam String q) { return chatClient.prompt().user(q).call().content(); } }启动后请求curl http://localhost:8080/rag/ask?q你们的退货政策是什么成功的结果是模型回答里包含你文档中的具体条款而不是泛泛而谈。你可以在 QuestionAnswerAdvisor 外面再套一个日志 Advisor把检索到的上下文打出来确认真的命中了文档片段。这一步的日志就是你面试时的证据「我通过日志确认检索命中了 3 条相关片段相似度都在 0.8 以上」。提示第一次跑如果回答和文档无关先确认文档确实写进了 Milvus用docker exec进容器或 Milvus 的 Attu 可视化工具查 collection 里的实体数。到这里一次完整的检索增强问答就验证完了。简历上可以写「完成文档加载、切片、向量化、检索、Prompt 增强的端到端链路并通过日志验证检索命中率」比「使用 RAG」具体得多。5. 本篇常见报错排查401、local proxy failed 与 reading choices配置和验证过程中最容易撞的几个错逐个拆。401 Unauthorized。最常见的原因是 api-key 没注入成功。检查${TAOTOKEN_API_KEY}这个环境变量在启动时是否真的存在IDEA 里要在 Run Configuration 的 Environment variables 里加命令行用export TAOTOKEN_API_KEYsk-xxx。另一个原因是 Key 复制时带了空格或换行重新从 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 复制一次。还有一种情况是 base-url 写成了https://taotoken.net/api/v1Spring AI 的 OpenAI starter 会再拼一次 /v1变成 /v1/v1/chat/completions也会 401 或 404。记住Spring AI 配置里 base-url 写https://taotoken.net/api不带 /v1。local proxy failed / Connection refused。这个报错通常和 Milvus 有关不是模型通道的问题。检查 Milvus 容器是否在跑docker ps看 milvus-standalone 状态检查 yml 里 host 和 port 是否和容器映射一致本地默认 127.0.0.1:19530。如果你在 WSL 或远程服务器上跑 Milvushost 不能写 localhost要写实际 IP。另外 embedding-dimension 和模型不匹配时Milvus 建集合会失败日志里会有 dimension mismatch回去核对 1536 这个值。Error reading choices / 返回体解析失败。这个错说明请求发出去了但返回的 JSON 结构不是 OpenAI 标准格式。原因通常是 model 名写错TaoToken 返回了一个错误对象Spring AI 按 choices 字段解析就失败了。去模型对话页面确认你填的 model 名在列表里地址 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。还有一种可能是你误用了非 OpenAI 兼容的端点确认 base-url 是 https://taotoken.net/api 。OAuth / token 过期类报错。如果你用的是某些需要 OAuth 的客户端比如 Claude Code 或 Codex 的 auth.json 配置报 OAuth 相关错误时检查 auth.json 里的 base_url 和 api_key 是否都指向 TaoToken。这类客户端的三件套是Base URL 填https://taotoken.net/apiKey 填你的 sk-Model ID 填具体模型名。三件套缺一个都会报鉴权失败。如果你用 Cline 或 CC Switch 这类工具MCP 配置里同样要写全这三项别只填 Key。排查顺序建议先看报错关键词401 查 Key 和 base-urlconnection 查 Milvusreading choices 查 model 名。把这几类错都踩一遍你对整条链路的理解就到位了面试时被问「你遇到过什么问题」也有真实素材。6. 把项目经验写成可讲清的工程细节回到简历这个目标。你现在的素材已经足够写三条有区分度的描述。第一条关于框架「基于 Spring AI 的 ChatClient 与 Advisor 机制实现检索增强问答通过 QuestionAnswerAdvisor 将向量检索结果自动注入 Prompt」。第二条关于统一接入「通过 TaoToken 统一 API 通道管理 OpenAI 与 LLaMA 3 的 Key 与 Base URL模型切换仅需修改配置降低多模型接入成本」。第三条关于向量库「使用 Milvus 作为向量存储配置 IVF_FLAT 索引与 COSINE 相似度完成文档切片、向量化与检索的端到端链路」。面试被追问时你要能讲出三个细节切片为什么必要不切片检索精度差、文档过长会超 token、embedding 在哪一步被调用vectorStore.add 时由 EmbeddingModel 完成、检索结果怎么进 PromptAdvisor 在 call 前拦截并增强。这三点讲清楚比背十个 API 名字管用。如果你还想把项目往深了做下一步可以接 Coding Plan 做长期迭代地址 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 或者去接入文档看更多模型和参数地址 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。把配置骨架跑通、把报错踩一遍、把日志留好这个项目就能从「简历上的一行字」变成「能聊二十分钟的工程经验」。