ARTICLE DETAIL

资讯详情

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

知析智能AI助手系统开发全流程解析:Vue 3 + Spring Boot + Spring AI 的 RAG 落地实践与 TaoToken 统一接入

知析智能AI助手系统开发全流程解析:Vue 3 + Spring Boot + Spring AI 的 RAG 落地实践与 TaoToken 统一接入 1. 知析智能AI助手系统从需求到可运行骨架知析智能AI助手系统是一套面向文档处理、知识检索、内容生成和任务执行场景的全栈 AI 应用前端用 Vue 3 Element Plus后端用 Spring Boot Spring AI核心能力是 RAG 检索增强问答。它适合想复刻同类 AI 助手的全栈开发者尤其是已经会写 CRUD、但没完整跑通过「上传文档 → 切片 → 向量化 → 检索 → 大模型回答」这条链路的人。我先把整体链路说清楚避免你写到一半发现方向错了。系统分四层前端层负责页面展示、SSE 流式接收、任务状态渲染接口层提供 REST API 和 SSE 流式接口业务层包含对话服务、知识库服务、文档服务、网页服务、内容生成服务、工具服务、MCP 服务、智能体调度服务AI 能力层用 Spring AI 承载 RAG 检索增强、Prompt 模板、ChatMemory、Advisor、Tool Calling、ReAct Agent。数据层用 MySQL 存业务数据Redis 做缓存PGvector 存向量本地文件存储或 MinIO 存原始文档。数据库表设计上用户、会话、消息、知识库、知识库文档、文档切片、网页资源、AI 任务、智能体计划、工具调用日志、MCP 调用日志、导出记录这些表要提前建好。接口统一返回格式是{ code: 200, message: success, data: {} }这个格式看着简单但后面所有 Controller 都靠它统一前端 Axios 拦截器也靠它判断成功失败所以一开始就定死别中途改。前端页面清单是 8 个核心页面登录页、首页/工作台、智能对话页、知识库管理页、文档处理页、网页分析页、智能体任务页、系统管理页。其中智能对话页是三栏布局左侧会话列表中间聊天区域右侧参数配置面板。右侧面板包含模型选择DeepSeek、通义千问、本地 Ollama、是否启用知识库开关、是否启用工具调用开关、是否启用智能体模式开关、输出风格下拉框、最大输出长度、保存配置按钮。这些参数不是摆设后面接后端时它们会直接映射到请求体字段。用户使用流程有三条主线。文档摘要流程上传文档 → 系统解析文本 → 用户选择「摘要生成」→ 大模型生成摘要 → 用户预览并导出。知识库问答流程新建知识库 → 上传多个文档 → 系统切片与向量化 → 进入问答页面 → 系统检索相关片段 → 大模型生成答案。智能体执行流程输入任务目标 → 系统生成计划 → 调用搜索/抓取/下载/PDF 工具 → 汇总结果 → 展示最终报告。这三条流程里知识库问答是 RAG 的核心也是本文重点。文档摘要和智能体执行可以后面再补但 RAG 链路必须先跑通否则整个系统没有灵魂。技术栈版本上JDK 建议 21Maven 也用 21 对应版本。前端用npm create vitelatest zhixi-ai-frontend选 vue JavaScript。后端 Spring Boot 项目建好后先跑一次package和run确认能启动再往下写。依赖包引入 hutool、knife4jknife4j 的配置后面在 IDEA 里改。配置文件在resources下默认是 properties我们改成 ymlspring: application: name: zhixi-ai server: port: 8123 servlet: context-path: /api springdoc: swagger-ui: path: /swagger-ui.html tags-sorter: alpha operations-sorter: alpha api-docs: path: /v3/api-docs group-configs: - group: default paths-to-match: /** packages-to-scan: org.zhuhe.zhixiai.controller knife4j: enable: true setting: language: zh_cn注意packages-to-scan这一行它指定扫描哪些包的接口写错了 doc.html 就打不开。冒号之后要连着空格YAML 对缩进和空格敏感。写完写一个测试接口访问api/doc.html确认能打开。到这里项目骨架和配置就齐了。下一步是接入大模型这是整个系统能不能跑起来的关键。2. TaoToken 统一接入一个 Key 打通多模型调用大模型接入这块很多人卡在「每个平台一个 Key、一套 SDK、一套计费」的碎片化问题上。知析系统要支持 DeepSeek、通义千问、本地 Ollama 多种模型切换如果每个都单独接代码里会散落一堆 if-else。我的做法是用 TaoToken 做统一接入层一个 Key、一个 Base URL通过改 Model ID 切换模型。TaoToken 的官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。它提供 OpenAI 兼容的接口格式所以 Spring AI 的 OpenAI starter、LangChain4j 的 OpenAI 模块都能直接对接不需要为每个模型写适配器。先说清楚它解决什么问题。知析系统的对话服务需要调用大模型RAG 问答需要调用大模型内容生成需要调用大模型智能体的 think 步骤也需要调用大模型。如果每个场景都硬编码某个厂商的 SDK后面换模型就要改多处代码。用 TaoToken 之后所有调用都走同一个 Base URL模型差异只体现在 Model ID 上切换成本从「改代码」降到「改配置」。接入前需要准备三样东西Base URL、API Key、Model ID。Base URL 填https://taotoken.net/apiAPI Key 在控制台创建Model ID 根据你要用的模型填比如gpt-4o-mini、claude-3-5-sonnet这类。这三件套在后面的 Spring AI 配置、Cline MCP 配置、Codex auth.json 里都会反复出现格式要记牢。Spring AI 里配置 OpenAI 兼容端点application-local.yml这样写spring: ai: openai: base-url: https://taotoken.net/api api-key: sk-你的TaoToken密钥 chat: options: model: gpt-4o-mini temperature: 0.7这里base-url不要带/v1后缀Spring AI 的 OpenAI starter 会自己拼路径。api-key建议放在application-local.yml里并且把application-local.yml加入.gitignore避免密钥上传到仓库。application.yml里通过spring.profiles.active: local激活本地配置。如果你用 LangChain4j配置方式类似OpenAiChatModel model OpenAiChatModel.builder() .baseUrl(https://taotoken.net/api) .apiKey(sk-你的TaoToken密钥) .modelName(gpt-4o-mini) .build(); String answer model.chat(你好); System.out.println(answer);注意 LangChain4j 的baseUrl有时需要带/v1具体看版本。如果报 404先检查路径拼接。我实测下来Spring AI 的 starter 对路径处理更省心建议后端统一用 Spring AI。如果你用 Cline 或 Claude Code 这类编码工具配置也是同一套三件套。Cline 的 MCP 配置里填 Base URL、API Key、Model IDClaude Code 的 settings 里同样填这三项。Codex 的auth.json里也是这三个字段。格式统一的好处是你在一个地方配通了换个工具只是复制粘贴。TaoToken 的 Coding Plan 适合长期编码和 Agent 场景模型对话入口适合验证模型是否通API Keys 页面用来创建和管理密钥接入文档里有各语言的示例代码。这几个入口后面 CTA 会分别给出。配置写完后先别急着写业务代码用最小请求验证一下通道是否通。这是下一步。3. 可复制配置Spring AI RAG 向量库落地这一节给出可直接复制的配置片段包括 Spring AI 的 OpenAI 兼容配置、RAG 向量库配置、ChatMemory 配置。路径和原文一致你照着填就能跑。先看完整的application-local.ymlspring: ai: openai: base-url: https://taotoken.net/api api-key: sk-你的TaoToken密钥 chat: options: model: gpt-4o-mini temperature: 0.7 embedding: options: model: text-embedding-3-small datasource: url: jdbc:mysql://localhost:3306/zhixi_ai?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: 你的数据库密码 driver-class-name: com.mysql.cj.jdbc.Driver data: redis: host: localhost port: 6379application.yml里激活 local profilespring: application: name: zhixi-ai profiles: active: local server: port: 8123 servlet: context-path: /apiRAG 向量库配置类用 Spring AI 内置的 SimpleVectorStore 做内存向量库适合开发和演示package org.zhuhe.zhixiai.ai.Rag; import jakarta.annotation.Resource; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.vectorstore.SimpleVectorStore; import org.springframework.ai.vectorstore.VectorStore; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; Configuration public class OfficeVectorStoreConfig { Resource private OfficeDocumentLoader officeDocumentLoader; Bean VectorStore officeVectorStore(EmbeddingModel embeddingModel) { SimpleVectorStore simpleVectorStore SimpleVectorStore.builder(embeddingModel).build(); ListDocument documentList officeDocumentLoader.loadMarkdowns(); simpleVectorStore.add(documentList); return simpleVectorStore; } }Markdown 文档加载器负责批量读取、分割、存储 markdown 文件并写入 meta 信息package org.zhuhe.zhixiai.ai.Rag; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.document.Document; import org.springframework.ai.reader.markdown.MarkdownDocumentReader; import org.springframework.ai.reader.markdown.config.MarkdownDocumentReaderConfig; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.stereotype.Component; import java.io.IOException; import java.util.ArrayList; import java.util.List; Component Slf4j public class OfficeDocumentLoader { private final ResourcePatternResolver resourcePatternResolver; public OfficeDocumentLoader(ResourcePatternResolver resourcePatternResolver) { this.resourcePatternResolver resourcePatternResolver; } public ListDocument loadMarkdowns() { ListDocument allDocuments new ArrayList(); try { Resource[] resources resourcePatternResolver.getResources(classpath:document/*.md); for (Resource resource : resources) { String filename resource.getFilename(); String status filename.substring(filename.length() - 8, filename.length() - 4); MarkdownDocumentReaderConfig config MarkdownDocumentReaderConfig.builder() .withHorizontalRuleCreateDocument(true) .withIncludeCodeBlock(false) .withIncludeBlockquote(false) .withAdditionalMetadata(filename, filename) .withAdditionalMetadata(status, status) .build(); MarkdownDocumentReader reader new MarkdownDocumentReader(resource, config); allDocuments.addAll(reader.get()); } } catch (IOException e) { log.error(Markdown 文档加载失败, e); } return allDocuments; } }ChatMemory 用 JDBC 实现先引入依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-autoconfigure-model-chat-memory-repository-jdbc/artifactId version2.0.0-M4/version /dependency然后注入OfficeChatClient再写一个ChatMemory配置就完成了。ChatMemory 的作用是让多轮对话记住上下文RAG 问答时把检索到的片段和对话历史一起拼进 prompt。RAG 问答的核心方法public String chatWithRag(String message, String chatId) { ChatResponse chatResponse chatClient.prompt() .user(message) .advisors(advisor - advisor.param(ChatMemory.CONVERSATION_ID, chatId)) .advisors(QuestionAnswerAdvisor.builder(officeVectorStore).build()) .call() .chatResponse(); return chatResponse.getResult().getOutput().getText(); }这里引入了两个 AdvisorQuestionAnswerAdvisor负责检索增强VectorStoreChatMemoryAdvisor负责对话记忆。多个 Advisor 是责任链模式按顺序执行。如果你要用 PGvector 替代 SimpleVectorStore先在阿里云开通 PGSQL创建管理员账号和数据库安装向量存储插件然后在项目里配置数据库连接。Spring AI 的文档里写得很清楚照着配就行。配置写完后下一步是验证请求是否真的通了。4. 验证请求从 curl 到流式对话的成功结果配置写完不代表通了必须用最小请求验证。我习惯分三步先 curl 验证 TaoToken 通道再验证 Spring AI 调用最后验证 RAG 问答。第一步curl 验证 TaoToken 通道curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的TaoToken密钥 \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [ {role: system, content: You are a helpful assistant.}, {role: user, content: 你是谁} ], stream: false }如果返回 200 并且 body 里有choices字段说明通道通了。如果返回 401检查 Key 是否正确如果返回 404检查路径是否多了或少了/v1。第二步Spring AI 调用验证。写一个CommandLineRunner项目启动后自动执行Component public class SpringAIApi implements CommandLineRunner { Resource private ChatModel chatModel; Override public void run(String... args) throws Exception { AssistantMessage output chatModel.call(new Prompt(你好我是知析助手)) .getResult() .getOutput(); System.out.println(output.getText()); } }启动项目控制台打印出模型回复说明 Spring AI 配置正确。如果报NoApiKeyException检查application-local.yml里的api-key是否被正确加载如果报连接超时检查base-url是否写成了https://taotoken.net/api而不是带/v1的地址。第三步RAG 问答验证。在classpath:document/下放几个 markdown 文件格式要统一否则预处理不好处理。启动项目后调用chatWithRag方法传入问题和 chatId观察返回内容是否引用了文档里的信息。如果返回的是通用回答而不是文档内容说明检索没生效检查QuestionAnswerAdvisor是否被正确注入以及向量库是否成功 add 了文档。流式对话验证用 SSE。前端用 EventSource 接收后端用SseEmitter推送。验证时先发一个简单问题观察前端是否逐字显示。如果一次性显示全部内容说明流式没生效检查后端是否用了stream()而不是call()。成功的结果是这样的curl 返回 200 和 choicesSpring AI 控制台打印模型回复RAG 问答返回文档相关内容SSE 流式逐字显示。四个都通过说明链路完整。验证过程中常见的报错和排查方法下一节集中说。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节对照真实报错给出排查路径。这些错误我在接入过程中都踩过按顺序排查基本能解决。401 Unauthorized。最常见的原因是 API Key 错误或过期。先检查application-local.yml里的api-key是否和 TaoToken 控制台里的一致注意不要有多余空格。如果 Key 正确检查base-url是否写对https://taotoken.net/api不要写成https://taotoken.net/api/v1Spring AI 的 OpenAI starter 会自己拼/v1/chat/completions。如果还报 401去 TaoToken 控制台确认 Key 是否被禁用或额度是否用完。local proxy failed。这个报错通常出现在网络层不是代码问题。检查本机是否能正常访问https://taotoken.net/api用 curl 直接测。如果 curl 也失败检查 DNS 和网络连接。注意不要配置任何非官方的网络工具直接用系统默认网络即可。如果公司网络有限制换一个网络环境再试。reading choices 报错。这个错误通常出现在解析响应时原因是返回的 JSON 结构不符合预期。先看完整响应体确认是否有choices字段。如果没有可能是模型名写错了比如把gpt-4o-mini写成了gpt-4o-min。也可能是请求体格式不对检查messages是否是数组role和content是否都有。还有一种情况是流式和非流式混用stream: true时返回的是 SSE 格式不能用普通 JSON 解析。OAuth 相关报错。如果你用 Claude Code 或 Codex 这类工具可能会遇到 OAuth 报错。这类工具通常需要配置auth.json或 settings 文件里面填 Base URL、API Key、Model ID 三件套。检查auth.json里的字段名是否正确比如base_url和baseUrl在不同工具里写法不同。如果工具提示 OAuth 失败先确认是否误用了需要 OAuth 的官方端点改用 TaoToken 的 API 端点即可。Cline MCP 配置报错。Cline 的 MCP 配置里需要填三件套Base URL 填https://taotoken.net/apiAPI Key 填 TaoToken 密钥Model ID 填你要用的模型。如果 MCP 服务启动失败检查 JSON 格式是否合法逗号和引号是否配对。如果提示模型不存在检查 Model ID 是否拼写正确。Codex auth.json 报错。Codex 的auth.json里同样填三件套。如果报invalid api key检查 Key 是否有多余字符。如果报model not found检查 Model ID。如果报网络错误检查 Base URL 是否可达。向量库相关报错。如果 RAG 问答返回空结果检查classpath:document/下是否有 markdown 文件文件名格式是否统一。如果报EmbeddingModel注入失败检查spring.ai.openai.embedding.options.model是否配置。如果报向量维度不匹配检查 embedding 模型和向量库是否匹配。SSE 流式报错。如果前端收不到流式内容检查后端是否用了SseEmitter并且设置了正确的Content-Type: text/event-stream。如果连接很快断开检查超时时间设置。如果内容一次性返回检查是否误用了call()而不是stream()。排查的核心思路是先确认通道通不通curl再确认配置对不对yml最后确认代码逻辑对不对Advisor、VectorStore、ChatMemory。三步走下来大部分问题都能定位。6. 继续深入Coding Plan 与接入文档RAG 链路跑通后知析系统还有几块可以继续深入。文档处理页要支持 PDF、DOCX、TXT 上传和解析网页分析页要支持 URL 抓取和正文提取智能体任务页要实现 ReAct Agent 的 think-act 循环工具调用要支持 WebSearchTool、WebCrawlerTool、PdfExportTool、FileTool。这些能力都建立在大模型调用之上而大模型调用统一走 TaoToken 通道。如果你要长期做编码和 Agent 场景TaoToken 的 Coding Plan 值得看一下入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它适合需要稳定调用、多模型切换、按量计费的开发场景。如果你在接入过程中遇到 Key 或通道问题去 API Keys 页面管理密钥https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。各语言的接入示例在接入文档里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。想先验证模型是否通用模型对话入口https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 。控制台在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。最后说一个我踩过的坑RAG 的检索效果不好很多时候不是模型问题而是文档切片和 meta 信息没做好。切片太大检索不精准切片太小上下文不完整。meta 信息要标注来源、状态、时间检索时可以用 metadata 过滤。文档格式要统一否则 MarkdownDocumentReader 解析出来的结构不一致后续处理很麻烦。这些细节比换模型更能提升效果。
返回列表