Sprint AI OpenAI 对接Deepseek,示范Skills,Function Calling Tools使用
理解SkillsSkills 底层逻辑 是啥 是spring ai 通过跟大模型api调用 将skill中的逻辑匹配到 合并到 提示词中 最后一次性 发给 大模型吗跟RAG一样对接大模型一直是通过Http APi 接口无状态访问的只不过将可使用的tools工具 合并到提示词中 让大模型判断 需要调用哪个 tool工具并生成tool参数客户端通过结构化大模型返回的数据如果有需要调用tool工具的返回报文 则 调用本地对应方法然后将结果再次发送给大模型。 Skill也类似一方面描述 skill适用的场景这是大号的tool工具说明将场景工具脚本发送给大模型也是通过function calling 实现。也是为了 适应大模型一次处理message的信息量有限问题。 将信息分为目录和详细内容 进行分级多次调用来适应这个 问题。 目录就是 skill的 场景思考过程执行脚本。 场景是第一次全部发给大模型大模型觉得用那个场景匹配然后调用思考过程组成新的提示词调用大模型最后是 返回执行脚本的参数本地根据参数进行执行。代码验证代码实现POM!-- Spring AI OpenAI Starter -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId version2.0.0/version /dependency !-- Agent Utils支持Agent Skills -- dependency groupIdorg.springaicommunity/groupId artifactIdspring-ai-agent-utils/artifactId version0.10.0/version /dependencyToolspackage com.haiwei.javaai.tool; import com.haiwei.javaai.utils.JsonUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; Slf4j Component public class OrderTools { Tool(description 根据订单ID查询订单详情返回订单状态、金额、创建时间等信息) public Object getOrderById( ToolParam(description 订单ID) Long orderId ) { MapString, Object map new HashMap(); map.put(orderId, orderId); map.put(price, 2000); map.put(state, 待发货); log.info(getOrderById ,result:{}, JsonUtil.toJson(map)); return map; } Tool(description 查询今日新增订单数量) public int getTodayOrderCount() { log.info(getTodayOrderCount ,result:{}, 11); return 11; } Tool(description 取消指定订单需要订单ID) public boolean cancelOrder( ToolParam(description 要取消的订单ID) Long orderId ) { log.info(cancelOrder ,orderId:{},result:{}, orderId, false); return false; } }LoggingAdvisor用来拦截并打印日志package com.haiwei.javaai.tool; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.client.ChatClientRequest; import org.springframework.ai.chat.client.ChatClientResponse; import org.springframework.ai.chat.client.advisor.api.CallAdvisor; import org.springframework.ai.chat.client.advisor.api.CallAdvisorChain; import org.springframework.ai.chat.client.advisor.api.StreamAdvisor; import org.springframework.ai.chat.client.advisor.api.StreamAdvisorChain; import reactor.core.publisher.Flux; import java.util.concurrent.atomic.AtomicInteger; Slf4j public class LoggingAdvisor implements CallAdvisor, StreamAdvisor { private final AtomicInteger round new AtomicInteger(1); Override public String getName() { return loggingAdvisor; } Override public int getOrder() { return 0; } Override public ChatClientResponse adviseCall(ChatClientRequest request, CallAdvisorChain chain) { log.info( 第 round.getAndAdd(1) 轮 ); log.info(USER: truncate(request.prompt().getContents(), 3000)); ChatClientResponse response chain.nextCall(request); String output response.chatResponse().getResult().getOutput().getText(); log.info(ASSISTANT: truncate(output, 300)); return response; } Override public FluxChatClientResponse adviseStream(ChatClientRequest request, StreamAdvisorChain chain) { return chain.nextStream(request); } private static String truncate(String text, int maxLen) { if (text null) return null; return text.length() maxLen ? text : text.substring(0, maxLen) ...; } }Skill定义目录SKILL.md文件--- name: team-java-standards description: Review code against team Java coding standards. Use for all code review tasks. --- # Team Java Coding Standards Review ## Instructions 审查代码时检查以下团队规范 ### 强制规范违反必须指出 1. 禁止 Autowired 字段注入使用构造器注入 2. Controller 方法必须有 Operation 注解Springdoc OpenAPI 3. 不允许在 Controller 中直接处理异常使用 RestControllerAdvice ### 建议规范违反给出建议 4. Service 方法建议添加 Transactional(readOnlytrue) 5. DTO 和 Entity 之间必须使用 MapStruct 转换 6. 日志使用 Slf4j禁止 System.out.println ## Output Format 输出格式 - 强制规范违反(行号) 说明 问题代码 修正代码 - 建议规范违反(行号) 说明 问题代码 修正代码 - ✅ 通过项简要说明 - 不同问题之间使用 隔离SkillController加载Skills访问并加载tools完整代码package com.haiwei.javaai.controller; import com.haiwei.javaai.tool.LoggingAdvisor; import com.haiwei.javaai.tool.OrderTools; import lombok.extern.slf4j.Slf4j; import org.springaicommunity.agent.tools.SkillsTool; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.tool.ToolCallback; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; Slf4j RestController public class SkillController { private final ChatClient chatClient; private final OrderTools orderTools; public SkillController(ChatClient.Builder chatClientBuilder, ResourceLoader resourceLoader, OrderTools orderTools) { // 加载Skill文件 Resource resource resourceLoader.getResource(classpath:skills); // 将Skill添加为Skill Tool ToolCallback skillsTool SkillsTool.builder() .addSkillsResource(resource) .build(); // 生成Chat Client 添加默认Skill 和 日志 this.chatClient chatClientBuilder .defaultTools(skillsTool) .defaultAdvisors(new LoggingAdvisor()) .build(); this.orderTools orderTools; } GetMapping(/char/get1) public Object get1() { // String message 帮我查一下订单123456的状态; String code Controller public class UserController { Autowired private UserRepository userRepo; GetMapping(/user/{id}) public User getUser(PathVariable String id) { System.out.println(123); return userRepo.findById(id).get(); } } ; String message 请审查以下Java代码\njava\n code \n; log.info(Start call LLM,message:{}); String content chatClient.prompt() .user(message) .tools(orderTools) .call().content(); log.info(content); return content; } }示例1帮我查一下订单123456的状态日志c.h.javaai.controller.SkillController : Start call LLM,message:{}com.haiwei.javaai.tool.LoggingAdvisor : 第 1 轮 com.haiwei.javaai.tool.LoggingAdvisor : USER: 帮我查一下订单123456的状态com.haiwei.javaai.tool.LoggingAdvisor : ASSISTANT:com.haiwei.javaai.tool.OrderTools : getOrderById ,result:{orderId:123456,price:2000,state:待发货}com.haiwei.javaai.tool.LoggingAdvisor : 第 2 轮 com.haiwei.javaai.tool.LoggingAdvisor : USER: 帮我查一下订单123456的状态com.haiwei.javaai.tool.LoggingAdvisor : ASSISTANT: 订单 **123456** 的当前状态如下| 字段 | 内容 ||------|------|| **订单ID** | 123456 || **订单金额** | ¥2,000.00 || **订单状态** | **待发货** |目前该订单处于**待发货**状态商家还未发货。请问还需要其他帮助吗2026-07-07T16:48:34.30508:00 INFO 9500 --- [nio-8080-exec-1] c.h.javaai.controller.SkillController : 订单 **123456** 的当前状态如下| 字段 | 内容 ||------|------|| **订单ID** | 123456 || **订单金额** | ¥2,000.00 || **订单状态** | **待发货** |目前该订单处于**待发货**状态商家还未发货。请问还需要其他帮助吗结果示例2帮忙审查代码审查过程日志2026-07-07T16:24:04.50008:00 INFO 16196 --- [nio-8080-exec-1] o.a.c.c.C.[.[localhost].[/javaai] : Initializing Spring DispatcherServlet dispatcherServlet2026-07-07T16:24:04.50008:00 INFO 16196 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet dispatcherServlet2026-07-07T16:24:04.50308:00 INFO 16196 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms2026-07-07T16:24:04.77408:00 INFO 16196 --- [nio-8080-exec-1] c.h.javaai.controller.SkillController : Start call LLM,message:{}2026-07-07T16:24:04.97008:00 INFO 16196 --- [nio-8080-exec-1] com.haiwei.javaai.tool.LoggingAdvisor : 第 1 轮 2026-07-07T16:24:04.97008:00 INFO 16196 --- [nio-8080-exec-1] com.haiwei.javaai.tool.LoggingAdvisor : USER: 请审查以下Java代码javaControllerpublic class UserController {Autowiredprivate UserRepository userRepo;GetMapping(/user/{id})public User getUser(PathVariable String id) {System.out.println(123);return userRepo.findById(id).get();}}2026-07-07T16:24:09.14108:00 INFO 16196 --- [nio-8080-exec-1] com.haiwei.javaai.tool.LoggingAdvisor : ASSISTANT: Ill invoke the team Java standards skill to review this code.2026-07-07T16:24:09.18708:00 INFO 16196 --- [nio-8080-exec-1] com.haiwei.javaai.tool.LoggingAdvisor : 第 2 轮 2026-07-07T16:24:09.18708:00 INFO 16196 --- [nio-8080-exec-1] com.haiwei.javaai.tool.LoggingAdvisor : USER: 请审查以下Java代码javaControllerpublic class UserController {Autowiredprivate UserRepository userRepo;GetMapping(/user/{id})public User getUser(PathVariable String id) {System.out.println(123);return userRepo.findById(id).get();}}Ill invoke the team Java standards skill to review this code.2026-07-07T16:24:14.10808:00 INFO 16196 --- [nio-8080-exec-1] com.haiwei.javaai.tool.LoggingAdvisor : ASSISTANT: 以下是根据团队 Java 编码规范对该代码的审查结果---## Java 代码审查报告### 强制规范违反**1. 禁止 Autowired 字段注入应使用构造器注入**- **问题代码第3行**javaAutowiredprivate UserRepository userRepo;- **说明** 字段注入不利于测试和不可变性团队规范要求使用构造器注入。- **修正代码**javaprivate final UserRepository userRepo;public UserController(Use...2026-07-07T16:24:14.11108:00 INFO 16196 --- [nio-8080-exec-1] c.h.javaai.controller.SkillController : ** 结果审查结果这个是上面 **结果 的MD展示实际比这个多。可以看出结果是按照Skill中设置的返回的如下是对比结果可观测性application.propertieslogging.level.org.springframework.ai.chat.observabilityDEBUG spring.ai.chat.client.observations.log-prompttrue spring.ai.chat.client.observations.log-completiontrue logging.level.org.springframework.aiTRACE日志记录