ARTICLE DETAIL

资讯详情

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

LangChain4J 配 TaoToken:SpringBoot RAG 应用 settings.json 骨架与 MCP 接入验证

LangChain4J 配 TaoToken:SpringBoot RAG 应用 settings.json 骨架与 MCP 接入验证 1. 为什么 Java 开发者需要一套统一的模型接入骨架LangChain4J 是 Java 生态里做 RAG 应用最顺手的框架之一它把模型调用、向量检索、会话记忆、工具调用这些能力都封装成了可复用的组件。但真正落到 SpringBoot 项目里很多人卡住的地方不是框架本身而是模型接入这一层Key 散落在 yml、环境变量、代码里换一个模型就要改一堆配置团队协作时更是各写各的。我这次要解决的就是这个问题用 TaoToken 作为统一的 Key 与 API 通道把 LangChain4J 的模型配置收敛到一份可复制的 settings.json 骨架里再补上 MCP 工具注册和一次完整的问答链路验证。目标很明确——本地跑通检索增强生成流程配置能直接抄验证动作能直接执行。适合谁看已经在用 SpringBoot 写业务、想给项目加 RAG 能力的 Java 开发者或者刚接触 LangChain4J被 base-url、api-key、model-name 这几个参数绕晕的人。整篇按“先讲问题、再给配置、最后验证排障”的顺序走代码块都能直接复制。TaoToken 在这里的角色是统一入口官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。你只需要维护一份 KeyLangChain4J 侧只改 base-url 和 model-name不用为每个模型单独记一套凭证。2. TaoToken 前置准备Key、模型名与 settings.json 骨架2.1 拿到 Key 与确认模型名先去控制台创建 API Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。创建完复制出来形如sk-开头的一串字符。注意两点一是 Key 只在创建时完整显示一次二是不要把它提交到 Git。模型名在模型列表里能看到比如对话模型、向量模型是分开的。LangChain4J 里 chat-model 和 embedding-model 要分别填别混用。如果你不确定用哪个先在模型对话页试一下 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。2.2 settings.json 骨架设计思路LangChain4J 本身读的是 SpringBoot 的 yml但团队协作时我更推荐把模型接入参数抽成一份 settings.json由配置类加载后注入。这样做的好处是Key 和模型名集中管理yml 里只留引用换环境时只改 json不动业务代码。骨架分三块provider放 base-url 和 api-keychat放对话模型参数embedding放向量模型参数。下面这份可以直接复制把apiKey换成你自己的即可。{ provider: { baseUrl: https://taotoken.net/api, apiKey: sk-你的Key, logRequests: true, logResponses: true }, chat: { modelName: 你的对话模型名, temperature: 0.7, maxTokens: 2048 }, embedding: { modelName: 你的向量模型名, maxSegmentsPerBatch: 10 } }注意baseUrl结尾不要带/v1LangChain4J 的 OpenAI 兼容实现会自己拼路径。带了反而会 404。2.3 依赖引入SpringBoot 项目里引入 LangChain4J 的 starter注意用整合版依赖否则会出现 Bean 注入不到的问题。dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-open-ai-spring-boot-starter/artifactId version1.7.1-beta14/version /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-spring-boot-starter/artifactId version1.7.1-beta14/version /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-easy-rag/artifactId version1.7.1-beta14/version /dependency3. 可复制配置把 settings.json 接进 SpringBoot3.1 配置类加载 settings.json写一个ModelConfigLoader在启动时把 json 读进来构建OpenAiChatModel和OpenAiEmbeddingModel两个 Bean。这样业务层只依赖接口不关心底层是哪家模型。Configuration public class ModelConfigLoader { Bean public OpenAiChatModel openAiChatModel() throws IOException { ObjectMapper mapper new ObjectMapper(); JsonNode root mapper.readTree( new ClassPathResource(settings.json).getInputStream()); JsonNode provider root.get(provider); JsonNode chat root.get(chat); return OpenAiChatModel.builder() .baseUrl(provider.get(baseUrl).asText()) .apiKey(provider.get(apiKey).asText()) .modelName(chat.get(modelName).asText()) .temperature(chat.get(temperature).asDouble()) .maxTokens(chat.get(maxTokens).asInt()) .logRequests(provider.get(logRequests).asBoolean()) .logResponses(provider.get(logResponses).asBoolean()) .build(); } Bean public OpenAiEmbeddingModel openAiEmbeddingModel() throws IOException { ObjectMapper mapper new ObjectMapper(); JsonNode root mapper.readTree( new ClassPathResource(settings.json).getInputStream()); JsonNode provider root.get(provider); JsonNode embedding root.get(embedding); return OpenAiEmbeddingModel.builder() .baseUrl(provider.get(baseUrl).asText()) .apiKey(provider.get(apiKey).asText()) .modelName(embedding.get(modelName).asText()) .maxSegmentsPerBatch(embedding.get(maxSegmentsPerBatch).asInt()) .build(); } }3.2 向量库与检索器配置RAG 的核心是“先检索、再生成”。这里用内存向量库做演示生产环境换成 Redis 或 pgvector 即可接口不变。Configuration public class RagConfig { Resource private OpenAiEmbeddingModel embeddingModel; Bean public EmbeddingStoreTextSegment embeddingStore() { ListDocument docs ClassPathDocumentLoader.loadDocuments(content); InMemoryEmbeddingStoreTextSegment store new InMemoryEmbeddingStore(); DocumentSplitter splitter DocumentSplitters.recursive(500, 100); EmbeddingStoreIngestor.builder() .embeddingStore(store) .documentSplitter(splitter) .embeddingModel(embeddingModel) .build() .ingest(docs); return store; } Bean public ContentRetriever contentRetriever(EmbeddingStoreTextSegment store) { return EmbeddingStoreContentRetriever.builder() .embeddingStore(store) .embeddingModel(embeddingModel) .maxResults(3) .minScore(0.6) .build(); } }3.3 AiService 接口声明用AiService把检索器、记忆、工具都挂上业务层只调接口。AiService( wiringMode AiServiceWiringMode.EXPLICIT, chatModel openAiChatModel, contentRetriever contentRetriever, chatMemoryProvider chatMemoryProvider, tools reservationTool ) public interface ConsultantService { SystemMessage(fromResource system.txt) String chat(MemoryId String memoryId, UserMessage String message); }4. MCP 工具注册与问答链路验证4.1 MCP 工具注册步骤MCP 可以理解为 AI 世界的 USB 协议把外部工具标准化地暴露给模型。LangChain4J 侧注册 MCP 工具分三步。第一步写工具类用Tool描述方法作用P描述参数。工具类要注册成 Spring 组件。Component public class ReservationTool { Tool(根据考生手机号查询预约单) public String findReservation(P(考生手机号) String phone) { return 预约单号: R2024001, 状态: 已确认; } }第二步在AiService的tools属性里引用这个 Bean 名。上文的tools reservationTool就是这一步。第三步验证工具是否被模型识别。启动后看日志里有没有Tool相关的注册信息或者直接问一个会触发工具的问题比如“帮我查一下手机号 138xxxx 的预约单”。4.2 一次完整问答链路验证写一个 Controller暴露/chat接口传入 memoryId 和 message。RestController public class ChatController { Resource private ConsultantService consultantService; RequestMapping(value /chat, produces text/html;charsetUTF-8) public String chat(String memoryId, String message) { return consultantService.chat(memoryId, message); } }启动项目后用 curl 发一次请求curl http://localhost:8080/chat?memoryIduser001message预约服务的流程是什么预期结果返回内容里应该包含你content目录下文档里的信息而不是模型自己编的。如果日志里能看到Retrieved或ContentInjector字样说明检索环节生效了。再发一次带工具触发词的请求看返回是否走了工具方法。5. 本篇常见错排查5.1 401 或 403Key 没生效最常见的原因是settings.json没被加载到或者 Key 前后有空格。先确认ClassPathResource能读到文件再打印一下apiKey的长度。另外注意baseUrl不要写成https://taotoken.net/api/v1多一层路径会 404。5.2 向量检索返回空minScore设太高是主因。0.6 是个经验值如果你的文档和问题表述差异大降到 0.4 试试。另外确认content目录在resources下且文档格式被解析器支持。PDF 要额外引langchain4j-document-parser-apache-pdfbox。5.3 工具不触发检查Tool的描述是否够具体。模型是根据描述判断要不要调用的写“查询预约”比写“处理数据”更容易命中。还要确认工具 Bean 名和AiService里tools的值一致大小写敏感。5.4 流式输出乱码如果用FluxString返回RequestMapping要加produces text/html;charsetUTF-8否则浏览器会按默认编码解析中文变问号。6. 下一步把配置固化下来跑通之后建议做两件事。一是把settings.json里的 Key 换成环境变量引用配置类里用System.getenv读取避免明文入库。二是把内存向量库换成 Redis 或 pgvectorLangChain4J 对这些都有 starter接口不变只换 Bean 实现。如果你还没创建 Key从这里进 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各语言的最小示例。长期做编码或 Agent 的话可以看 Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。想先验证模型效果直接去模型对话页试 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。
返回列表