SpringAI对接Deepseek避坑指南

心得体会

得看官网,搜了几篇博客 发现都不能用。其实不能不能用,而是写博客的作者没有写一些前提条件,比如:Spring AI spring-ai-starter-model-deepseek 必须要求springboot 版本是 > 4。

即使你再初始化https://start.spring.io/选择了3.5.15也可以生产,但没法下载包。也可能是其他问题导致没法下载。

Spring AI Deepseek 官网文档

DeepSeek Chat :: Spring AI Reference 慢慢看,比博客👍

交互图

初始化工程

Spring | Quickstart

选择对接Deepseek:

POM

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.1.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.haiwei</groupId>
    <artifactId>javaai</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-deepseek</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.5</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>2.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <release>17</release>
                    <parameters>true</parameters>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

ChatController

java 复制代码
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.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import java.util.Map;

@RestController
public class ChatController {

    private final DeepSeekChatModel chatModel;

    @Autowired
    public ChatController(DeepSeekChatModel chatModel) {
        this.chatModel = chatModel;
    }

    @GetMapping("/ai/generate")
    public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        return Map.of("generation", chatModel.call(message));
    }

    @GetMapping("/ai/generateStream")
    public Flux<ChatResponse> generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        var prompt = new Prompt(new UserMessage(message));
        return chatModel.stream(prompt);
    }
}

property文件

复制代码
spring.ai.deepseek.api-key=${DEEPSEEK_API_KEY:}
spring.ai.deepseek.base-url=${DEEPSEEK_API_BASE_URL:https://api.deepseek.com}

其他配置

属性 描述 默认值
spring.ai.retry.max-attempts 最大重试次数 10
spring.ai.retry.backoff.initial-interval 指数退避策略的初始休眠时长 2秒
spring.ai.retry.backoff.multiplier 退避间隔的乘数因子 5
spring.ai.retry.backoff.max-interval 最大退避时长 3分钟
spring.ai.retry.on-client-errors 如果为 false,则抛出 NonTransientAiException,并且不会对 4xx 客户端错误码进行重试 false
spring.ai.retry.exclude-on-http-codes 不应触发重试的 HTTP 状态码列表(例如抛出 NonTransientAiException
spring.ai.retry.on-http-codes 应触发重试的 HTTP 状态码列表(例如抛出 TransientAiException

下面配置只有对接Deepseek有效

属性 描述 默认值
spring.ai.deepseek.chat.enabled(已移除,不再有效) 启用 DeepSeek 聊天模型。 true
spring.ai.model.chat 启用 DeepSeek 聊天模型。 deepseek
spring.ai.deepseek.chat.base-url 可选地覆盖 spring.ai.deepseek.base-url,以提供聊天专用的 URL。 https://api.deepseek.com/
spring.ai.deepseek.chat.api-key 可选地覆盖 spring.ai.deepseek.api-key,以提供聊天专用的 API 密钥。 -
spring.ai.deepseek.chat.completions-path 聊天补全接口的路径。 /chat/completions
spring.ai.deepseek.chat.beta-prefix-path Beta 功能接口的前缀路径。 /beta
spring.ai.deepseek.chat.model 要使用的模型 ID。可选值:deepseek-v4-flashdeepseek-v4-prodeepseek-chatdeepseek-reasoner deepseek-v4-flash
spring.ai.deepseek.chat.frequency-penalty 取值范围为 -2.0 到 2.0 之间的数值。正值会根据新令牌在现有文本中已有的出现频率对其进行惩罚,从而降低模型逐字重复同一句话的可能性。 0.0f
spring.ai.deepseek.chat.max-tokens 聊天补全中生成的最大令牌数。输入令牌与生成令牌的总长度受限于模型的上下文长度。 -
spring.ai.deepseek.chat.presence-penalty 取值范围为 -2.0 到 2.0 之间的数值。正值会根据新令牌是否已在现有文本中出现过对其进行惩罚,从而提高模型谈论新话题的可能性。 0.0f
spring.ai.deepseek.chat.stop 最多 4 个终止序列,当 API 遇到这些序列时将停止继续生成令牌。 -
spring.ai.deepseek.chat.temperature 使用的采样温度,取值范围为 0 到 2。较高的值(如 0.8)会使输出更加随机,而较低的值(如 0.2)则使其更加聚焦和确定。通常建议只调整此参数或 top_p,但不要同时调整两者。 1.0F
spring.ai.deepseek.chat.top-p 一种替代温度采样的方法,称为核采样(nucleus sampling),模型会考虑累积概率质量达到 top_p 的令牌结果。例如,0.1 表示仅考虑占前 10% 概率质量的令牌。通常建议只调整此参数或 temperature,但不要同时调整两者。 1.0F
spring.ai.deepseek.chat.logprobs 是否返回输出令牌的对数概率。如果为 true,则返回消息内容中每个输出令牌的对数概率。 -
spring.ai.deepseek.chat.top-logprobs 取值范围为 0 到 20 的整数,指定在每个令牌位置返回的最可能令牌数量,每个令牌都附带对应的对数概率。如果使用此参数,必须将 logprobs 设置为 true。 -
spring.ai.deepseek.chat.tool-callbacks 要注册到 ChatModel 的工具回调。 -

DEEPSEEK_API_KEY新建

点击进入DeepSeek开发平台:DeepSeek,点击创建即可:

使用需要充值的。

调用验证

访问:http://localhost:8080/javaai/ai/generate?message=回复123

查看Token用量:

设置模型和温度参数

java 复制代码
    @GetMapping("/ai/generateWithOptions")
    public Map generateWithOptions(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        DeepSeekChatOptions options = DeepSeekChatOptions.builder()
                .model(DeepSeekApi.ChatModel.DEEPSEEK_V4_PRO.getValue())
                .temperature(0.8)
                .build();
        Prompt prompt = new Prompt(message, options);
        ChatResponse response = chatModel.call(prompt);
        response.getMetadata().get
        return Map.of("generation", response.toString());
    }

输出报文样例

报文解析

ChatResponse

├── metadata

│ ├── id: "0f6a808b-11d6-4ae6-981a-4d267dd782c8"

│ │

│ ├── usage: DefaultUsage

│ │ ├── promptTokens: 6 (输入提示词的令牌数)

│ │ ├── completionTokens: 146 (生成回复的令牌数)

│ │ └── totalTokens: 152 (总令牌数)

│ │

│ └── rateLimit: EmptyRateLimit (速率限制信息,此处为空)

└── generations: [ (生成结果列表,此处只有1个)

└── Generation index: 0

├── assistantMessage: DeepSeekAssistantMessage

│ ├── messageType: ASSISTANT

│ ├── toolCalls: \[\] (无工具调用)

│ ├── textContent: "收到你的"123"啦!👋\n\n看起来你像是在测试我是否在线,或者是不是发错了消息?\n\n不管怎样,我都在这里,有什么问题或想聊的随时告诉我~ ✨"

│ ├── reasoningContent: "嗯,用户只发了"回复123"三个字,信息非常简短。\n\n我需要拆解一下这个指令。用户可能是想测试我的反应,或者单纯输入错误,也可能是在进行某种交互测试。\n\n深层需求可能是想看我如何处理这种模糊的、无上下文的输入。问题本身很简单,不需要复杂分析。\n\n我可以用一种友好、轻松的方式回应,先表明收到了消息,然后询问用户的具体意图,并提供几个可能的猜测(比如测试、希望计数),引导用户给出更明确的指令。"

│ ├── prefix: null

│ └── metadata:

│ ├── finishReason: STOP (生成结束原因:正常停止)

│ ├── index: 0 (该生成在列表中的索引)

│ ├── role: ASSISTANT (角色:助手)

│ ├── id: "0f6a808b-11d6-4ae6-981a-4d267dd782c8"

│ └── messageType: ASSISTANT

└── chatGenerationMetadata: DefaultChatGenerationMetadata

├── finishReason: "STOP" (生成结束原因)

├── filters: 0 (过滤计数)

└── metadata: {} (额外的元数据,此处为空)

关键字段说明

字段 说明
id 本次请求的唯一标识符
usage 令牌使用统计:输入6个令牌,输出146个,总计152个
textContent 模型生成的最终回复文本(用户看到的回答)
reasoningContent DeepSeek 的推理过程 (思考链),展示模型如何一步步推理出最终回答。这是 DeepSeek 模型(如 deepseek-reasoner)的特色功能,会先输出思考过程,再输出最终答案
finishReason: STOP 生成结束原因,STOP 表示正常完成(遇到停止序列或自然结束)
toolCalls: [] 工具调用列表,此处为空,表示本次没有调用任何外部工具/函数

全局参数设置

application.properties

spring.ai.deepseek.api-key=YOUR_API_KEY

spring.ai.deepseek.chat.model=deepseek-v4-pro

spring.ai.deepseek.chat.temperature=0.8

Tool Calling

WeatherService

java 复制代码
import com.haiwei.javaai.entities.WeatherRequest;
import com.haiwei.javaai.entities.WeatherResponse;
import lombok.extern.slf4j.Slf4j;

import java.util.function.Function;

@Slf4j
public class WeatherService implements Function<WeatherRequest, WeatherResponse> {
    public WeatherResponse apply(WeatherRequest request) {
        log.info("WeatherService apply .....");
        return new WeatherResponse(30.0);
    }
}


=============================================
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class WeatherResponse {
    private double v;
}

=============================================


import lombok.Data;

@Data
public class WeatherRequest {
}

调用过程

java 复制代码
    @GetMapping("/ai/generateWithTool")
    public Map generateWithTool(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) {
        ToolCallback weatherCallback = FunctionToolCallback.builder("getCurrentWeather", new WeatherService())
                .description("Get the weather in location")
                .inputType(WeatherRequest.class)
                .build();

        // Synchronous
        String response = ChatClient.create(chatModel)
                .prompt()
                .user("What's the weather in Paris, Tokyo, and New York?")
                .tools(weatherCallback)
                .call()
                .content();

        return Map.of("generation", response);
    }

结果输出

调用了三次

结果:

{

"generation": "Here's the current weather for all three cities:\n\n| City | Temperature |\n|------|-------------|\n| 🌆 **Paris** | 30°C |\n| 🗼 **Tokyo** | 30°C |\n| 🗽 **New York** | 30°C |\n\nAll three cities are experiencing a warm **30°C** (86°F) at the moment! Looks like a nice, consistent temperature across the globe today. ☀️"

}

如果Request中有位置

java 复制代码
import lombok.Data;

@Data
public class WeatherRequest {
    private String local;
}

调用代码不变(我也不清楚local怎么传进去的),local就会被打印

获取local信息:

结果:

{

"generation": "Here's the current weather for each city:\n\n| City | Temperature |\n|-----------|-------------|\n| **Paris** 🌍 | 30°C |\n| **Tokyo** 🌍 | 30°C |\n| **New York** 🌍 | 30°C |\n\nLooks like all three cities are enjoying a nice, warm day at **30°C**! ☀️"

}

手动处理Tool Calling

处理类:WeatherService1

java 复制代码
import com.haiwei.javaai.entities.WeatherRequest;
import com.haiwei.javaai.entities.WeatherResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;

import java.util.function.Function;

@Slf4j
public class WeatherService1 {

    @Tool(description = "Get the weather in location")
    WeatherResponse getWeather(@ToolParam(required = false) WeatherRequest request) {
        log.info("getWeather apply ..... {}" , request.getLocal());
        return new WeatherResponse(30.0);
    }
}


==================

import lombok.Data;

@Data
public class WeatherRequest {
    private String local;
}

==================

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class WeatherResponse {
    private double v;
}

调用代码

java 复制代码
    @GetMapping("/ai/generateWithToolBySelf")
    public Map generateWithToolBySelf() {
        ToolCallingManager toolCallingManager = ToolCallingManager.builder().build();

        DeepSeekChatOptions options = DeepSeekChatOptions.builder()
                .toolCallbacks(ToolCallbacks.from(new WeatherService1()))
                .build();

        Prompt prompt = new Prompt("What's the weather in Paris, Tokyo, and New York?", options);
        ChatResponse response = chatModel.call(prompt);
        log.info("response:{}",JsonUtil.toJson(response));

        while (response.hasToolCalls()) {
            ToolExecutionResult result = toolCallingManager.executeToolCalls(prompt, response);
            log.info("result:{}",JsonUtil.toJson(result));
            prompt = new Prompt(result.conversationHistory(), options);
            response = chatModel.call(prompt);
            log.info("response:{}",JsonUtil.toJson(response));
        }

        return Map.of("generation", response);
    }

打印日志

日志详细:可自行转换json:

2026-06-17T15:09:37.240+08:00 INFO 3264 --- nio-8080-exec-1 c.h.javaai.controller.ChatController : response:{"chatResponseMetadata":{"id":"788a1c68-9321-4ab3-885c-5f166250c9a3","model":"deepseek-v4-flash","rateLimit":{},"usage":{"promptTokens":332,"completionTokens":168,"totalTokens":500,"nativeUsage":{"completionTokens":168,"promptTokens":332,"totalTokens":500,"promptTokensDetails":{"cachedTokens":0}}},"promptMetadata":{"arg$1":\[\]},"map":{"system-fingerprint":"fp_8b330d02d0_prod0820_fp8_kvcache_20260402","created":1781680175}},"generations":{"assistantMessage":{"reasoningContent":"I need to get the weather for three cities: Paris, Tokyo, and New York. Let me call the getWeather function for all three simultaneously since they\\u0027re independent.","toolCalls":\[{"id":"call_00_2ZlgVAJisUilpYCh8njK7645","type":"function","name":"getWeather","arguments":"{\\"request\\": {\\"local\\": \\"Paris\\"}}"},{"id":"call_01_9HBLaUpbixlrD12kqrDh7711","type":"function","name":"getWeather","arguments":"{\\"request\\": {\\"local\\": \\"Tokyo\\"}}"},{"id":"call_02_sDrxA5ZCKwAWflI4zrl37922","type":"function","name":"getWeather","arguments":"{\\"request\\": {\\"local\\": \\"New York\\"}}"},"media":\[\],"messageType":"ASSISTANT","textContent":"Of course! Let me check the weather for all three cities at once.","metadata":{"finishReason":"TOOL_CALLS","index":0,"id":"788a1c68-9321-4ab3-885c-5f166250c9a3","role":"ASSISTANT","messageType":"ASSISTANT"}},"chatGenerationMetadata":{"metadata":{},"finishReason":"TOOL_CALLS","contentFilters":\[\]}}]}

2026-06-17T15:09:37.252+08:00 INFO 3264 --- nio-8080-exec-1 c.h.javaai.service.impl.WeatherService1 : getWeather apply ..... Paris

2026-06-17T15:09:37.257+08:00 INFO 3264 --- nio-8080-exec-1 c.h.javaai.service.impl.WeatherService1 : getWeather apply ..... Tokyo

2026-06-17T15:09:37.258+08:00 INFO 3264 --- nio-8080-exec-1 c.h.javaai.service.impl.WeatherService1 : getWeather apply ..... New York

2026-06-17T15:09:37.263+08:00 INFO 3264 --- nio-8080-exec-1 c.h.javaai.controller.ChatController : result:{"conversationHistory":{"media":\[,"messageType":"USER","textContent":"What\u0027s the weather in Paris, Tokyo, and New York?","metadata":{"messageType":"USER"}},{"reasoningContent":"I need to get the weather for three cities: Paris, Tokyo, and New York. Let me call the getWeather function for all three simultaneously since they\u0027re independent.","toolCalls":{"id":"call_00_2ZlgVAJisUilpYCh8njK7645","type":"function","name":"getWeather","arguments":"{\\"request\\": {\\"local\\": \\"Paris\\"}}"},{"id":"call_01_9HBLaUpbixlrD12kqrDh7711","type":"function","name":"getWeather","arguments":"{\\"request\\": {\\"local\\": \\"Tokyo\\"}}"},{"id":"call_02_sDrxA5ZCKwAWflI4zrl37922","type":"function","name":"getWeather","arguments":"{\\"request\\": {\\"local\\": \\"New York\\"}}"},"media":\[\],"messageType":"ASSISTANT","textContent":"Of course! Let me check the weather for all three cities at once.","metadata":{"finishReason":"TOOL_CALLS","index":0,"id":"788a1c68-9321-4ab3-885c-5f166250c9a3","role":"ASSISTANT","messageType":"ASSISTANT"}},{"responses":{"id":"call_00_2ZlgVAJisUilpYCh8njK7645","name":"getWeather","responseData":"{\\"v\\":30.0}"},{"id":"call_01_9HBLaUpbixlrD12kqrDh7711","name":"getWeather","responseData":"{\\"v\\":30.0}"},{"id":"call_02_sDrxA5ZCKwAWflI4zrl37922","name":"getWeather","responseData":"{\\"v\\":30.0}"},"messageType":"TOOL","textContent":"","metadata":{"messageType":"TOOL"}}],"returnDirect":false}

2026-06-17T15:09:38.877+08:00 INFO 3264 --- nio-8080-exec-1 c.h.javaai.controller.ChatController : response:{"chatResponseMetadata":{"id":"70664122-5935-49d8-86ca-a1ce8ad10ac5","model":"deepseek-v4-flash","rateLimit":{},"usage":{"promptTokens":543,"completionTokens":115,"totalTokens":658,"nativeUsage":{"completionTokens":115,"promptTokens":543,"totalTokens":658,"promptTokensDetails":{"cachedTokens":384}}},"promptMetadata":{"arg$1":\[\]},"map":{"system-fingerprint":"fp_8b330d02d0_prod0820_fp8_kvcache_20260402","created":1781680178}},"generations":{"assistantMessage":{"reasoningContent":"All three cities returned a temperature of 30.0. Let me present this information clearly to the user.","toolCalls":\[,"media":\[\],"messageType":"ASSISTANT","textContent":"Here\u0027s the current weather in all three cities:\n\n| City | Temperature 🌡️ |\n|----------|:--------------:|\n| **Paris** | 30°C |\n| **Tokyo** | 30°C |\n| **New York** | 30°C |\n\nAll three cities are experiencing the same temperature of **30°C (86°F)**! Quite a warm day across the globe. ☀️","metadata":{"finishReason":"STOP","index":0,"id":"70664122-5935-49d8-86ca-a1ce8ad10ac5","role":"ASSISTANT","messageType":"ASSISTANT"}},"chatGenerationMetadata":{"metadata":{},"finishReason":"STOP","contentFilters":\[\]}}]}

这里只要这个不为空就需要调用ToolCalling。

result结果解析

java 复制代码
{
  "conversationHistory": [
    // ============ 第1条消息:用户提问 ============
    {
      "media": [],
      "messageType": "USER",
      "textContent": "What's the weather in Paris, Tokyo, and New York?",
      "metadata": {
        "messageType": "USER"
      }
    },

    // ============ 第2条消息:AI 响应(含推理 + 工具调用) ============
    {
      "reasoningContent": "I need to get the weather for three cities: Paris, Tokyo, and New York. Let me call the getWeather function for all three simultaneously since they're independent.",
      "toolCalls": [
        {
          "id": "call_00_2ZlgVAJisUilpYCh8njK7645",
          "type": "function",
          "name": "getWeather",
          "arguments": "{\"request\": {\"local\": \"Paris\"}}"
        },
        {
          "id": "call_01_9HBLaUpbixlrD12kqrDh7711",
          "type": "function",
          "name": "getWeather",
          "arguments": "{\"request\": {\"local\": \"Tokyo\"}}"
        },
        {
          "id": "call_02_sDrxA5ZCKwAWflI4zrl37922",
          "type": "function",
          "name": "getWeather",
          "arguments": "{\"request\": {\"local\": \"New York\"}}"
        }
      ],
      "media": [],
      "messageType": "ASSISTANT",
      "textContent": "Of course! Let me check the weather for all three cities at once.",
      "metadata": {
        "finishReason": "TOOL_CALLS",
        "index": 0,
        "id": "788a1c68-9321-4ab3-885c-5f166250c9a3",
        "role": "ASSISTANT",
        "messageType": "ASSISTANT"
      }
    },

    // ============ 第3条消息:工具执行结果返回 ============
    {
      "responses": [
        {
          "id": "call_00_2ZlgVAJisUilpYCh8njK7645",
          "name": "getWeather",
          "responseData": "{\"v\":30.0}"
        },
        {
          "id": "call_01_9HBLaUpbixlrD12kqrDh7711",
          "name": "getWeather",
          "responseData": "{\"v\":30.0}"
        },
        {
          "id": "call_02_sDrxA5ZCKwAWflI4zrl37922",
          "name": "getWeather",
          "responseData": "{\"v\":30.0}"
        }
      ],
      "messageType": "TOOL",
      "textContent": "",
      "metadata": {
        "messageType": "TOOL"
      }
    }
  ],
  "returnDirect": false
}

结果:

java 复制代码
{
    "generation": {
        "metadata": {
            "empty": false,
            "id": "70664122-5935-49d8-86ca-a1ce8ad10ac5",
            "model": "deepseek-v4-flash",
            "promptMetadata": [],
            "rateLimit": {
                "requestsLimit": 0,
                "requestsRemaining": 0,
                "requestsReset": "PT0S",
                "tokensLimit": 0,
                "tokensRemaining": 0,
                "tokensReset": "PT0S"
            },
            "usage": {
                "promptTokens": 543,
                "completionTokens": 115,
                "totalTokens": 658,
                "nativeUsage": {
                    "completion_tokens": 115,
                    "prompt_tokens": 543,
                    "total_tokens": 658,
                    "prompt_tokens_details": {
                        "cached_tokens": 384
                    }
                }
            }
        },
        "result": {
            "metadata": {
                "contentFilters": [],
                "empty": true,
                "finishReason": "STOP"
            },
            "output": {
                "media": [],
                "messageType": "ASSISTANT",
                "metadata": {
                    "finishReason": "STOP",
                    "index": 0,
                    "id": "70664122-5935-49d8-86ca-a1ce8ad10ac5",
                    "role": "ASSISTANT",
                    "messageType": "ASSISTANT"
                },
                "prefix": null,
                "reasoningContent": "All three cities returned a temperature of 30.0. Let me present this information clearly to the user.",
                "text": "Here's the current weather in all three cities:\n\n| City     | Temperature 🌡️ |\n|----------|:--------------:|\n| **Paris**    | 30°C           |\n| **Tokyo**    | 30°C           |\n| **New York** | 30°C           |\n\nAll three cities are experiencing the same temperature of **30°C (86°F)**! Quite a warm day across the globe. ☀️",
                "toolCalls": []
            }
        },
        "results": [
            {
                "metadata": {
                    "contentFilters": [],
                    "empty": true,
                    "finishReason": "STOP"
                },
                "output": {
                    "media": [],
                    "messageType": "ASSISTANT",
                    "metadata": {
                        "finishReason": "STOP",
                        "index": 0,
                        "id": "70664122-5935-49d8-86ca-a1ce8ad10ac5",
                        "role": "ASSISTANT",
                        "messageType": "ASSISTANT"
                    },
                    "prefix": null,
                    "reasoningContent": "All three cities returned a temperature of 30.0. Let me present this information clearly to the user.",
                    "text": "Here's the current weather in all three cities:\n\n| City     | Temperature 🌡️ |\n|----------|:--------------:|\n| **Paris**    | 30°C           |\n| **Tokyo**    | 30°C           |\n| **New York** | 30°C           |\n\nAll three cities are experiencing the same temperature of **30°C (86°F)**! Quite a warm day across the globe. ☀️",
                    "toolCalls": []
                }
            }
        ]
    }
}

自动补全

调用代码

java 复制代码
    @GetMapping("/ai/generatePythonCode")
    public String generatePythonCode(@RequestParam(value = "message", defaultValue = "Please write quick sort code") String message) {
        UserMessage userMessage = new UserMessage(message);
        Message assistantMessage = DeepSeekAssistantMessage
                .builder()
                .content("```python\\n")
                .prefix(true)
                .build();
        Prompt prompt = new Prompt(List.of(userMessage, assistantMessage)
                , DeepSeekChatOptions.builder().stopSequences(List.of("```")).build()
        );
        ChatResponse response = chatModel.call(prompt);
        return response.getResult().getOutput().getText();
    }

结果

print(123)\n

获取思考过程

代码

java 复制代码
    @GetMapping("/ai/deepSeekReasoningExample")
    public Map<String, String> deepSeekReasoningExample() {
        DeepSeekChatOptions promptOptions = DeepSeekChatOptions.builder()
                .build();
        Prompt prompt = new Prompt("9.11 and 9.8, which is greater?", promptOptions);
        ChatResponse response = chatModel.call(prompt);

        // Get the CoT content generated by the model
        DeepSeekAssistantMessage deepSeekAssistantMessage = (DeepSeekAssistantMessage) response.getResult().getOutput();
        String reasoningContent = deepSeekAssistantMessage.getReasoningContent();
        String text = deepSeekAssistantMessage.getText();
        return Map.of(reasoningContent, text);
    }

输出

{

"We need to compare 9.11 and 9.8. This is a simple decimal comparison. 9.11 is 9 and 11/100, while 9.8 is 9 and 8/10 or 80/100. So 9.8 = 9.80, which is greater than 9.11 because 80/100 > 11/100. So 9.8 is greater. However, sometimes people might mistakenly think 9.11 is larger because 11 > 8, but that's ignoring the decimal place. So answer: 9.8 is greater.": "9.8 is greater than 9.11 because 9.8 is equivalent to 9.80, and 80/100 is larger than 11/100."

}