Lucaju 的技术笔记 - Spring AI
type: channel
link: https://www.lucaju.cn/index.php/tag/Spring-AI/
items: Agent Skill 踩坑记录 | SpringBoot 打包后 Skill 加载失败问题排查与解决
items: Spring AI Alibaba + MCP：调用MCP市场公开服务实操
items: 一文吃透 Spring AI Alibaba + MCP：服务端搭建 + 客户端调用全流程
items: Agent Skills | Spring Ai Alibaba从零构建可扩展 AI 智能体
items: Spring AI Alibaba 人工介入实战｜Human-in-the-Loop 让 AI 更可靠
items: 使用Spring AI Alibaba构建智能体Agent
items: Spring AI Tool 工具方法调用源码深度解析：从流式交互到工具执行全流程
items: Spring AI 实战：调用本地 Tool 工具方法实现大模型能力扩展
items: Spring AI 无法获取大模型深度思考内容？解决方案来了
items: 接入 DeepSeek | Java 调用大模型实战保姆级教程：新手快速上手

Agent Skill 踩坑记录 | SpringBoot 打包后 Skill 加载失败问题排查与解决
type: item
date: 2026-03-24T13:23:00+08:00
description: 在之前的开发中，我使用 ClasspathSkillRegistry 作为 Agent Skill 的查找策略，本地开发环境下调试、运行都一切正常，没有出现任何异常。感兴趣的小伙伴可以回顾上一篇相关内容：https://www.lucaju.cn/index.php/archives/168/一、问题出现：上线后频繁报「Skill not found」本以为本地测试无误后，上线就能顺利运行，结果程序部署到服务器后，日志中频繁出现 Skill not found: 错误，导致相关功能完全无法使用。二、问题排查：排除常见误区遇到问题后，首先排查了最容易出现问题的两个点，均排除异常：确认 Skill 已成功打包：检查部署的 jar 包，解压后确认 skill 相关文件已正常包含在内，不存在打包遗漏的情况；确认 Skill Name 无误：核对代码中调用 Skill 的名称与配置文件中的名称，完全一致，排除拼写错误、大小写错误等问题。三、问题根源：找到官方 Issue排除上述常见问题后，推测可能是框架本身的兼容性问题，于是去 GitHub 上搜索相关问题，果然发现已有其他开发者遇到过相同情况，并且提交了 Issue：https://github.com/alibaba/spring-ai-alibaba/issues/4426从 Issue 中得知，问题根源在于 SpringBoot 项目打包成 jar 包后，路径机制发生变化，导致 ClasspathSkillRegistry 无法正常加载 resources 下的 Skill 目录，这是目前 spring-ai-alibaba 框架的一个已知 bug。四、临时解决方案：改用 FileSystemSkillRegistry由于官方尚未修复该 bug，为了不影响线上功能正常使用，我采用了临时解决方案：将 Skill 目录存放在服务器的文件系统中，通过指定真实路径获取 Skill，对应的查找策略改用 FileSystemSkillRegistry。修改后的核心代码如下：/** * 获取技能智能体钩子。 */ private static SkillsAgentHook getSkillsAgentHook() { // 注释掉原有的ClasspathSkillRegistry方式（本地可用，打包后失效） // SkillRegistry registry = ClasspathSkillRegistry.builder() // .classpathPath("skills") // .build(); /* 临时解决方案说明： spring ai alibaba 目前使用 ClasspathSkillRegistry 打包后，无法获取 Resource 下的目录 因此修改为使用 FileSystemSkillRegistry，从文件系统真实路径获取 Skill 相关 Issue：https://github.com/alibaba/spring-ai-alibaba/issues/4426 */ String skillPath = SpringUtils.getProperty("doc.skills-path"); log.info("skillPath: {}",skillPath); FileSystemSkillRegistry registry = FileSystemSkillRegistry.builder() .projectSkillsDirectory(skillPath) .build(); return SkillsAgentHook.builder() .skillRegistry(registry) .build(); }五、后续需要说明的是，这只是一个临时解决方案——使用该方案后，需要手动将 Skill 配置文件同步到服务器的指定路径（即配置项 doc.skills-path 对应的路径），增加了少量部署成本。后续会持续关注官方 Issue 的修复进度，待 bug 修复后，再切换回 ClasspathSkillRegistry 方式，减少部署环节的手动操作。也希望遇到相同问题的小伙伴，能通过这篇踩坑记录少走弯路～

Spring AI Alibaba + MCP：调用MCP市场公开服务实操
type: item
date: 2026-03-21T21:08:00+08:00
description: 上一篇博客，我们介绍了如何将本地工具封装为 MCP 服务，并成功创建客户端实现连接，感兴趣的朋友可以回顾：https://www.lucaju.cn/index.php/archives/169/今天，我们聚焦实操——如何调用 MCP 市场上的公开服务，以「高德地图 MCP 服务」为例，步骤清晰可复现，新手也能快速上手。一、先了解：MCP 公开服务市场首先给大家推荐一个优质的 MCP 公开服务平台：https://mcp.so/zh这个平台类似 MCP 服务的「GitHub」，目前已收录超过一万八千个公开 MCP 服务，涵盖地图、工具、接口等各类场景，我们今天要用的高德地图 MCP 服务也收录其中。高德地图 MCP 服务直达链接：https://mcp.so/zh/server/amap-maps/amap进入链接后，注意保存页面中的「服务器配置 JSON」（如下所示），后续配置项目时会直接用到，重点留意 env 中的 AMAP_MAPS_API_KEY 字段。二、前置准备：申请高德 API-Key调用高德地图 MCP 服务，需先获取个人 API-Key，步骤如下（3步搞定）：1. 登录高德开放平台访问高德开放平台：https://lbs.amap.com/ ，注册一个用户，完成认证后登录到后台2. 创建一个应用3. 生成 API-Key注意：服务平台选择Web服务，填写完成后提交，即可生成 API-Key，保存好该 Key，后续替换配置使用。三、编写客户端代码连接高德服务前置准备完成后，开始配置项目、编写代码，全程分为3个步骤，也很简单操作。1. 拷贝高德MCP服务中的json文件到项目中注意: 替换api_key，使用我们刚刚创建好的api_key{ "mcpServers": { "amap-maps": { "command": "npx", "args": [ "-y", "@amap/amap-maps-mcp-server" ], "env": { "AMAP_MAPS_API_KEY": "api_key" } } } }把这个json放到项目resource目录下，命名为 mcp-servers-config.json （可自定义，但需与后续配置对应）2. 修改application.yml配置文件添加 MCP 客户端配置，核心是指定上述 JSON 文件的路径spring: application: name: spring-ai-alibaba-agent ai: dashscope: api-key: ${AliQwen_API} mcp: client: type: async request-timeout: 10s toolcallback: enabled: true stdio: servers-configuration: classpath:/mcp-servers-config.json3. 编写测试代码测试代码其实和上一篇的客户端代码基本没有什么改动，我就简单放上来一些啦～@GetMapping("mcpTest") private void mcpTest() throws GraphRunnerException { ChatModel chatModel = getChatModel(); ToolCallback[] toolCallbacks = toolCallbackProvider.getToolCallbacks(); System.out.printf(""" =====Find the tools from spring ToolCallbackProvider===== %s """, JSON.toJSONString(toolCallbacks)); // 构建智能体并绑定mcp服务 ReactAgent agent = ReactAgent.builder() .name("ip_search") .model(chatModel) .description("你是一个天气查询助手") .saver(new MemorySaver()) .toolCallbackProviders(toolCallbackProvider) .build(); // 运行时配置 RunnableConfig config = RunnableConfig.builder() .threadId("session") .build(); // 流式调用agent Flux<NodeOutput> stream = agent.stream("上海未来天气怎么样", config); StringBuffer answerString = new StringBuffer();…

一文吃透 Spring AI Alibaba + MCP：服务端搭建 + 客户端调用全流程
type: item
date: 2026-03-19T16:22:00+08:00
description: 一、MCP概念介绍MCP（Model Context Protocol，模型上下文协议）是 Anthropic 于 2024 年推出的AI 领域统一连接协议，被称为 “AI 的 USB-C 接口”，核心是让大模型（LLM）通过标准化方式安全、灵活地调用外部工具、数据库、API 与文件系统，打破数据孤岛。从架构来看，MCP基于C/S（客户端-服务端）模式实现，因此要完成MCP调用，需分别搭建MCP服务端（暴露工具方法）和MCP客户端（调用服务端方法）。本文将基于Spring Ai Alibaba生态，完整实现“本地方法封装为MCP服务 + 客户端调用MCP服务”的全流程，步骤清晰、可直接落地。二、Spring AI MCP的介绍Spring AI MCP 为模型上下文协议提供 Java 和 Spring 框架集成。它使 Spring AI 应用程序能够通过标准化的接口与不同的数据源和工具进行交互，支持同步和异步通信模式。整体架构如下：三、搭建本地MCP服务端1. 添加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server-webflux</artifactId> <version>1.1.2</version> </dependency>注意：此处未使用常规的spring-boot-starter-web（内置Tomcat），因为spring-ai-starter-mcp-server-webflux与Tomcat存在冲突。使用spring-boot-starter会默认通过Netty启动服务，适配MCP服务端要求。2. 配置服务端application.ymlserver: port: 8088 # 服务端口，可自定义 servlet: encoding: enabled: true force: true charset: UTF-8 # 避免中文乱码 spring: application: name: local-mcp-server # 服务端应用名称 ai: mcp: server: type: async # 异步模式，提升调用性能 name: local-mcp-server # MCP服务名称 version: 1.0.0 # 服务版本3. 添加工具方法创建工具类，将需要对外暴露的方法用@Tool注解标记，并将该类交给Spring容器管理：@Service public class WeatherService { /** * 根据城市名称获取天气信息 * @param city 城市名称 * @return 天气描述 */ @Tool(description = "根据城市名称获取天气信息") public String getWeatherByCity(String city) { return city + " 今天天气很好！"; } }4. 添加MCP服务配置（McpServerConfig）创建配置类，通过ToolCallbackProvider将工具类（WeatherService）封装为MCP服务：@Configuration public class McpServerConfig { @Bean public ToolCallbackProvider weatherTools(WeatherService weatherService) { return MethodToolCallbackProvider.builder() .toolObjects(weatherService) .build(); } }5. 启动mcp-server 服务启动Spring Boot应用，查看控制台输出，确认服务启动成功（重点关注Netty启动信息）：2026-03-19T14:33:17.730+08:00 INFO 35517 --- [local-mcp-server] [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8088 (http) 2026-03-19T14:33:17.734+08:00 INFO 35517 --- [local-mcp-server] [ main] com.jcq.server.McpServerAppli…

Agent Skills | Spring Ai Alibaba从零构建可扩展 AI 智能体
type: item
date: 2026-03-18T13:32:04+08:00
description: 在当今AI应用开发领域，让AI智能体具备灵活的工具调用能力和可扩展的技能体系，是落地复杂业务场景的核心挑战。Spring AI Alibaba 原生提供了完善的 Skill 技能支持，能让智能体实现「技能发现→按需加载→工具执行」的全流程自动化。本文将从核心概念、组件解析、实战场景、最佳实践四个维度，手把手教你掌握 Spring AI Alibaba Skill 的使用方法。一、核心概念1.1 渐进式披露（核心设计思想）Spring AI Alibaba Skill 采用渐进式披露机制，最大化提升模型效率：系统初始仅注入技能元数据（名称、描述、路径）；模型判断需要使用某技能时，调用 read_skill(skill_name) 加载完整的 SKILL.md 文档；最后按需访问技能资源、执行绑定工具。1.2 Skill 标准目录结构每个技能独立为一个子目录，SKILL.md 为强制必需文件，目录结构如下：skills/ # 技能根目录 └── pdf-extractor/ # 单个技能目录（自定义命名） ├── SKILL.md # ✅ 必需：技能核心定义文档 ├── references/ # 可选：技能参考资料 ├── examples/ # 可选：使用示例 └── scripts/ # 可选：执行脚本1.3 SKILL.md 格式规范SKILL.md 采用元数据+正文结构，元数据通过 --- 包裹，是模型识别技能的关键：--- name: pdf-extractor # 必需：小写字母、数字、连字符，最长64字符 description: 用于从PDF文档中提取文本、表格和表单数据 # 必需：简洁描述，超长会被截断 --- # PDF 提取技能 ## 功能说明 You are a PDF extraction specialist. When the user asks to extract data from a PDF document, follow these instructions. ## 使用方法 1. **Validate Input** - Confirm the PDF file path is provided. - The default path for the pdf file is the current working directory. - Use the `shell` or `read_file` tool to check if the file exists - Verify it's a valid PDF format 2. **Extract Content** - Execute the extraction script using the `shell` tool: ```bash python scripts/extract_pdf.py <pdf_file_path> ``` - The script will output JSON format with extracted data 3. **Process Results** - Parse the JSON output from the script - Structure the data in a readable format - Handle any encoding issues (UTF-8, special characters) 4. **Present Output** - Summarize what was extracted - Present data in the requested format (JSON, Markdown, plain text) - Highlight any issues or limitations ## Script Location The extraction script is located at: `scripts/extract_pdf.py` ## Output Format The script returns JSON: ```json { "success": true, "filename": "report.pdf", "text": "Full text content...", "page_count": 10, "tables": [ { "page": 1, "data": [["Header1", "Header2"], ["Value1", "Value2"]] } ], "metadata": { "title": "Document Title", "author": "Author Name", "cr…

Spring AI Alibaba 人工介入实战｜Human-in-the-Loop 让 AI 更可靠
type: item
date: 2026-03-16T14:29:00+08:00
description: 引言在构建AI智能体应用时，我们经常面临一个关键挑战：如何让AI在执行某些敏感操作前获得人工确认？Spring AI Alibaba框架提供了强大的人工介入（Human-in-the-Loop）机制，让开发者能够精确控制AI工具的执行流程，在关键节点引入人工审批环节。本文将通过一个完整的实战示例，详细介绍如何在Spring AI Alibaba应用中实现人工介入功能。什么是人工介入？人工介入是一种机制，它允许AI智能体在执行特定工具前暂停执行，等待人工审批后再继续。这种机制特别适用于：敏感操作：如数据删除、资金转账等内容生成：如文章发布、诗歌创作等需要质量把控的场景权限控制：某些需要特定权限才能执行的操作审计要求：需要记录人工决策过程的场景实战示例：诗歌创作的人工审批让我们通过一个具体的例子来理解人工介入Hook的使用。这个示例展示了如何让AI在创作诗歌前获得人工确认。1. 项目依赖配置首先，确保你的项目中包含了Spring AI Alibaba相关依赖：<dependencies> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-agent-framework</artifactId> <version>1.1.2.0</version> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> <version>1.1.2.0</version> </dependency> </dependencies>2. 代码实现解析步骤1：构建AI模型// 构建DashScope API对象 DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); // 创建聊天模型 ChatModel chatModel = DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .build();步骤2：配置工具public class PoetTool implements BiFunction<String, ToolContext, String> { public int count = 0; public PoetTool() { } @Override public String apply( @ToolParam(description = "The original user query that triggered this tool call") String originalUserQuery, ToolContext toolContext) { count++; System.out.println("Poet tool called : " + originalUserQuery); return "在城市的缝隙里， \n" + "一束光悄悄发芽， \n" + "穿过钢筋水泥的沉默， \n" + "在风中轻轻说话。 \n" + "\n" + "夜色如墨，却不再黑， \n" + "星星点亮了每一个角落， \n" + "我站在时间的边缘， \n" + "等一朵云，轻轻落下"; } public static ToolCallback createPoetToolCallback() { return FunctionToolCallback.builder("poem", new PoetTool()) .description("用来写诗的工具") .inputType(String.class) .build(); } public static ToolCallback createPoetToolCallback(String name, PoetTool poetTool) { return FunctionToolCallback.builder(name, poetTool) .description("用来写诗的工具") .inputType(String.class) .build(); } }步骤3：构建带有Hook的智能体// 这里我们配置了poem工具需要人工审批，并提供了审批时的描述信息。 Map<String, ToolConfig> approvalOn = Map.of( "poem"…

使用Spring AI Alibaba构建智能体Agent
type: item
date: 2026-03-13T15:58:00+08:00
description: 前言随着大语言模型(LLM)技术的快速发展，构建智能Agent应用变得越来越简单。本文将通过两个实际的代码示例，展示如何使用Spring AI Alibaba框架构建功能丰富的天气查询Agent，从基础的测试实现到生产级的完整应用。技术栈概述Spring AI Alibaba: 阿里巴巴开源的AI应用开发框架DashScope: 阿里云的AI模型服务平台React Agent: 基于ReAct(Reasoning and Acting)范式的智能代理示例一：SimpleTest - 快速入门添加核心依赖<dependencies> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-agent-framework</artifactId> <version>1.1.2.0</version> </dependency> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> <version>1.1.2.0</version> </dependency> </dependencies>代码结构分析@Test void agentTest() throws GraphRunnerException { // 1. 初始化 DashScope API DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); // 2. 创建 ChatModel ChatModel chatModel = DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .build(); // 3. 定义天气工具 ToolCallback weatherTool = FunctionToolCallback.builder("get_weather", new WeatherTool()) .description("获取某个城市的天气") .inputType(String.class) .build(); // 4. 构建React Agent ReactAgent agent = ReactAgent.builder() .name("weather_agent") .model(chatModel) .tools(weatherTool) .systemPrompt("你是一个非常有帮助的助手") .saver(new MemorySaver()) .build(); // 5. 调用Agent AssistantMessage response = agent.call("上海今天天气怎么样？"); System.out.println(response.getText()); }核心特性简洁的配置: 通过Builder模式快速构建Agent工具集成: 使用FunctionToolCallback将自定义函数包装为Agent可调用的工具内存存储: 使用MemorySaver保存对话历史中文支持: 完整的中文提示词和工具描述自定义工具实现class WeatherTool implements BiFunction<String, ToolContext, String> { @Override public String apply(String city, ToolContext toolContext) { return city + "今天天气非常好！"; } }这个简单的工具类展示了如何将业务逻辑封装为Agent可调用的函数。示例二：RealAgent - 真实的智能体高级特性概览相比SimpleTest，RealAgent展示了更多生产级特性：精细的模型配置多工具协同结构化输出对话上下文管理核心代码解析1. 系统提示词设计String SYSTEM_PROMPT = """ 你是一位擅长说**天气冷笑话/谐音梗**的专业天气预报员。 你可以使用两个工具： - **get_weather_for_location**：用于获取指定地点的天气 - **get_user_location**：用于获取用户当前所在位置 如果用户询问天气，**必须先确认地点**。 如果从问题中能判断出他们指的是**自己所在的地方**， 就使用 **get_user_location** …

Spring AI Tool 工具方法调用源码深度解析：从流式交互到工具执行全流程
type: item
date: 2025-08-23T14:06:58+08:00
description: Spring AI Tool 工具方法调用源码深度解析：从流式交互到工具执行全流程前言：为什么需要读源码？如何高效读源码？在上一篇博客中，我们介绍了如何通过 Spring AI 快速调用本地 Tool 方法实现大模型的工具能力扩展。但对于开发者来说，仅仅会用还不够 —— 理解框架的底层逻辑，才能在遇到问题时快速定位、在定制需求时游刃有余。博客链接：https://www.lucaju.cn/index.php/archives/131/很多小伙伴对读源码望而却步，其实掌握方法就能事半功倍：详略得当：聚焦核心业务逻辑，忽略日志、校验等辅助代码从命名和注释入手：规范框架的源码命名和注释会清晰指引核心流程由浅入深：先抓整体流程，再钻关键细节，避免一开始陷入代码迷宫本文将从 Spring AI 调用大模型的业务代码出发，逐步深入源码，解析 Tool 工具方法调用的完整流程，重点剖析工具执行的核心逻辑。1. 业务代码回顾：流式调用大模型的入口先看一段典型的 Spring AI 流式调用大模型并启用工具的业务代码，这是我们源码解析的起点：public Flux<String> stream(String content) { // 创建chatModel对象，配置模型参数和工具回调管理器 OpenAiChatModel chatModel = OpenAiChatModel.builder() .openAiApi(OpenAiApi.builder() .baseUrl("https://api.siliconflow.cn") .apiKey(System.getenv("SiliconFlow_API")) .build()) .defaultOptions(OpenAiChatOptions.builder() .model("Qwen/Qwen3-8B") .build()) // 关键：配置工具调用管理器 .toolCallingManager(SpringUtil.getBean(ToolCallingManager.class)) .build(); // 创建prompt对象 Prompt prompt = new Prompt(content); // 调用流式输出接口 Flux<ChatResponse> stream = chatModel.stream(prompt); return stream.map(chunk -> { String text = chunk.getResult() != null ? chunk.getResult().getOutput() != null ? chunk.getResult().getOutput().getText() : "" : ""; text = StrUtil.nullToDefault(text, ""); return text; }); }核心逻辑很清晰：创建配置好的OpenAiChatModel，构造Prompt，调用stream方法获取流式响应。其中toolCallingManager的配置是启用工具调用的关键。2. 入口：ChatModel 的 stream 方法从业务代码的chatModel.stream(prompt)进入源码，这是整个流程的入口：@Override public Flux<ChatResponse> stream(Prompt prompt) { // 合并运行时和默认选项，创建最终请求prompt Prompt requestPrompt = buildRequestPrompt(prompt); // 实际发起请求 return internalStream(requestPrompt, null); }2.1 配置合并：buildRequestPrompt 方法buildRequestPrompt的核心作用是合并运行时配置和默认配置，确保模型使用正确的参数（如工具列表、回调、上下文等）：Prompt buildRequestPrompt(Prompt prompt) { // 处理运行时prompt options OpenAiChatOptions runtimeOptions = null; if (prompt.getOptions() != null) { // 转换运行时选项为OpenAiChatOptions类型 if (prompt.getOptions() instanceof ToolCallingChatOptions toolCallingChatOptions) { runtimeOptions = ModelOptionsUtils.copyToTarget(toolCallingChatO…

Spring AI 实战：调用本地 Tool 工具方法实现大模型能力扩展
type: item
date: 2025-08-20T16:47:35+08:00
description: 前言大模型虽强，但在实时信息获取（如当前日期、天气）、复杂计算等场景下存在局限。而 Tool 工具方法 正是解决这一问题的关键 —— 它让大模型能调用本地代码获取结果，弥补自身能力短板。本文将通过具体代码案例，手把手教你在 Spring AI 中集成本地 Tool，实现大模型与本地逻辑的联动。一、基础准备：Spring AI 调用大模型环境搭建在集成 Tool 前，先搭建 Spring AI 调用大模型的基础环境，确保能正常与大模型交互。1. 添加核心依赖在 pom.xml 中引入 Spring AI OpenAI 适配器依赖（兼容主流大模型平台）： <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>1.0.0</version> </dependency>2. 基础调用代码实现（1）Controller：定义接口入口创建一个简单的 HTTP 接口，接收用户提问并调用服务层处理：import com.yeeiee.ailogic.module.ai.service.chat.SpringAiTestService; import jakarta.annotation.Resource; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Flux; @RestController @RequestMapping("ai-test") public class SpringAiTestController { @Resource private SpringAiTestService springAiTestService; // 流式输出接口（支持实时返回大模型响应） @GetMapping(value = "stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux<String> stream(@RequestParam("content") String content) { return springAiTestService.stream(content); } }（2）Service：实现大模型调用逻辑定义服务接口及实现类，配置大模型连接信息并发起调用：// 服务接口 public interface SpringAiTestService { // 大模型流式输出方法 Flux<String> stream(String content); } // 服务实现类 import cn.hutool.core.util.StrUtil; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiChatOptions; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; @Service public class SpringAiTestServiceImpl implements SpringAiTestService { @Override public Flux<String> stream(String content) { // 配置大模型平台（以硅基流动为例，兼容 OpenAI 接口格式） OpenAiChatMode…

Spring AI 无法获取大模型深度思考内容？解决方案来了
type: item
date: 2025-08-13T17:54:00+08:00
description: 大模型的 “深度思考” 能力（即生成回答前的推理过程）正在成为提升交互体验的关键比如下面图中所看到的，Qwen 等模型会将推理过程放在reasoning_content字段中，让用户看到 “思考过程” 而非直接得到结果。但在 Java 开发中，使用 Spring AI 或 LangChain4J 等框架时，你可能会发现：这些框架会忽略reasoning_content字段，只返回最终回答。 这篇文章就来拆解这个问题的原因，并提供一套通过自定义接口调用实现 “获取完整思考过程” 的解决方案。问题：为什么框架无法获取深度思考内容？目前主流 Java 框架（Spring AI、LangChain4J）在设计时，默认只处理大模型的 “最终回答”（通常在content字段），而忽略了部分模型新增的 “思考过程” 字段（如reasoning_content）。具体表现为：字段被过滤：框架的响应解析逻辑中，没有处理reasoning_content的代码，导致这部分数据被直接丢弃。交互体验割裂：大模型的生成逻辑是 “先思考、后输出”，但框架会等待完整结果生成后才返回，用户需要长时间等待，且看不到中间思考过程。举个例子：当你调用 Qwen 模型时，原始接口返回会包含两部分内容：reasoning_content：“用户问我是谁，我需要先介绍自己的名字，再说明我的能力，还要保持友好的语气……”（思考过程）content：“我是通义千问，由通义实验室研发的超大规模语言模型。我能够帮助用户回答问题、创作文字，以及进行对话交流。如果你有任何问题或需要帮助，随时告诉我！”（最终回答）但通过 Spring AI 调用时，你只能拿到content部分，错失了展示 “思考过程” 的机会。解决方案：自定义接口调用，掌控原始数据既然框架的封装会丢失信息，那最直接的方案就是：绕过框架的限制，直接调用大模型的原生 API，获取完整响应数据。这种方式的优势在于：可获取所有字段（包括reasoning_content、usage等元数据）；灵活控制流式输出逻辑，实现 “思考过程” 和 “最终回答” 的实时展示；便于业务扩展（如自定义缓存、日志、过滤规则等）。下面以 “调用硅基流动接口获取 Qwen 模型的思考过程” 为例，演示具体实现。实战：用 Spring WebFlux 调用硅基流动 API硅基流动是一个大模型聚合平台，支持 Qwen、GPT 等模型的调用，其 API 会返回完整的reasoning_content字段。我们用 Spring WebFlux（响应式 HTTP 客户端）实现调用，既能处理流式输出，又能获取原始响应。步骤 1：了解接口参数参考硅基流动官方 API 文档，核心请求参数如下：messages：对话历史（包含role和content）；model：模型名称（如moonshotai/Kimi-Dev-72B）；stream：是否开启流式输出（设为true，实时获取思考和回答）；temperature：控制输出随机性（0-1 之间）。步骤 2：编码实现（获取完整响应）import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Flux; public class SiliconFlowTest { // 硅基流动API地址 private static final String API_URL = "https://api.siliconflow.cn/v1/chat/completions"; // 你的API Key（从硅基流动控制台获取） private static final String API_KEY = "your api-key"; private static final String NULL_MESSAGE = "null"; @Test public void testGetReasoningContent() { // 1. 构建请求体（包含对话和参数） String requestBody = """ { "messages": [ { "content": "你是一个聊天大师，请回答用户的问题。", "role": "system" }, { "content": "什么是Java响应式编程？", "role": "user" } ], "model": "Qwen/Qwen3-8B", "stream": true, "tempe…

接入 DeepSeek | Java 调用大模型实战保姆级教程：新手快速上手
type: item
date: 2025-08-11T17:33:00+08:00
description: 接入 DeepSeek | Java 调用大模型实战保姆级教程：新手快速上手最近各大平台接入 DeepSeek 大模型的案例越来越多，作为程序员，你是不是也想亲手实现一次？别担心，这篇教程会用3 种实战方式，带你从零开始用 Java 接入 DeepSeek 大模型，从 SDK 调用到原生 HTTP 请求全覆盖，新手也能轻松上手～前置知识：为什么需要响应式编程？大模型对话为了提升用户体验，通常会采用流式输出（像 ChatGPT 那样逐字显示回复）。而 Java 中实现流式输出需要用到响应式编程（Reactive Programming），核心是通过Flux（Reactor 框架）处理异步数据流。如果你对响应式编程不太熟悉，可以先简单理解：Flux能帮你 “实时接收” 大模型的每一段输出，而不是等全部结果返回后才处理。👉 快速入门参考：Spring 响应式编程官方文档👉 也可参考我的博客：响应式编程学习笔记准备工作：先获取 DeepSeek API Key在开始编码前，需要先申请 DeepSeek 的 API Key：访问 DeepSeek 开放平台：https://platform.deepseek.com/api_keys注册 / 登录账号后，在 “API Keys” 页面点击 “创建 API Key”，保存生成的密钥（后续代码中会用到）。方式一：通过 DeepSeek 官方 SDK 调用（最直接）DeepSeek 官方提供了适配 Spring AI 的 SDK，开箱即用，适合快速集成。1. 添加依赖在pom.xml中引入 Spring AI 对 DeepSeek 的支持（建议使用1.0.0+版本，兼容性更好）： <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-deepseek</artifactId> <version>1.0.0</version> </dependency>2. 编码实现：阻塞式与流式输出import org.junit.jupiter.api.Test; import org.springframework.ai.chat.messages.Message; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.deepseek.DeepSeekChatModel; import org.springframework.ai.deepseek.DeepSeekChatOptions; import org.springframework.ai.deepseek.api.DeepSeekApi; import reactor.core.publisher.Flux; import java.util.ArrayList; import java.util.List; public class DeepSeekSdkTest { // 初始化DeepSeek模型（核心对象） private final DeepSeekChatModel chatModel = DeepSeekChatModel.builder() .deepSeekApi(DeepSeekApi.builder() .apiKey("你的API Key") // 替换为你的DeepSeek API Key .build()) .defaultOptions(DeepSeekChatOptions.builder() .model("deepseek-chat") // 指定模型（支持deepseek-chat、deepseek-coder等） .temperature(0.7) // 控制输出随机性（0-1，值越高越随机） .build()) .build(); // 测试1：阻塞式输出（适合简单场景，等待完整结果返回） @Test public void testBlockingCall() { // 构建对话消息（SystemMessage设定角色，UserMessage是用户提问） List<Message> messages = new ArrayList<>…