Spring Boot中接入DeepSeek的流式输出

第一步,添加依赖:

 <!-- WebFlux 响应式支持 -->
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

第二步,配置WebClient。这里需要设置WebClient实例,用于向DeepSeek的API发送请求。需要配置baseUrl,可能还需要添加认证头,比如Authorization Bearer token

@Configuration
public class DeepSeekConfig {
    @Value("${deepseek.api.key}")
    private String apiKey;

    @Value("${deepseek.api.url}")
    private String apiUrl;


    @Bean
    public WebClient deepseekWebClient() {
        return WebClient.builder()
                .baseUrl(apiUrl)
                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .codecs(configurer ->
                        configurer.defaultCodecs().maxInMemorySize(16 * 1024 * 1024)) //处理大响应
                .build();
    }
}

第三步,创建服务类,使用WebClient发送请求并处理流式响应。这里可能需要将响应转换为Flux,然后处理每个数据块。比如,读取每个chunk的数据,提取需要的内容,可能还要处理不同的数据格式,比如JSON对象或者特定格式的文本。

@Service
@RequiredArgsConstructor
public class DeepSeekService {

    private final WebClient deepSeekClient;

    public Flux<String> streamCompletion(String prompt) {
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("model", "deepseek-reasoner");
        requestBody.put("messages", List.of(Map.of("role", "user", "content", prompt)));
        // 启用流式
        requestBody.put("stream", true);
        requestBody.put("temperature", 0.7);

        return deepSeekClient.post()
                .contentType(MediaType.APPLICATION_JSON)
                .bodyValue(requestBody)
                .retrieve()
                .bodyToFlux(String.class)
                .filter(data -> !"[DONE]".equals(data)) // 过滤结束标记
                .map(this::extractContent)
                .onErrorResume(e -> {
                    // 错误处理
                    return Flux.error(new RuntimeException("API调用失败: " + e.getMessage()));
                });
    }
    // 解析响应数据
    private String extractContent(String data) {
        try {
            JsonNode node = new ObjectMapper().readTree(data);
            return (Strings.isBlank(node.at("/choices/0/delta/reasoning_content").asText()) || "null".equalsIgnoreCase(node.at("/choices/0/delta/reasoning_content").asText())) ? node.at("/choices/0/delta/content").asText() : node.at("/choices/0/delta/reasoning_content").asText();
        } catch (Exception e) {
            return "";
        }
    }


}

第四步,创建控制器

@RestController
@RequiredArgsConstructor
@Slf4j
public class StreamController {
    // 添加速率限制
    private final RateLimiter rateLimiter = RateLimiter.create(10); // 10次/秒

    private final DeepSeekService deepSeekService;

    @GetMapping(value = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestParam String message) {
        if (!rateLimiter.tryAcquire()) {
            return Flux.error(new RuntimeException("请求过于频繁"));
        }
        return deepSeekService.streamCompletion(message)
                .map(content -> "data: " + content + "\n\n") // SSE格式
                .doOnComplete(() -> log.info("流式传输完成"))
                .doOnError(e -> log.error("流式错误: {}", e.getMessage()))
                .log("deepseek-stream", Level.FINE) // 详细日志
                .metrics();// 集成Micrometer监控
    }
}

配置

spring.application.name=deepseek_demo
server.port=8080

deepseek.api.key=sk-?????????????
deepseek.api.url=https://api.deepseek.com/v1/chat/completions

测试:

@SpringBootTest
class DeepseekDemoApplicationTests {
    @Autowired
    private DeepSeekService deepSeekService;
    @Test
    void contextLoads() {
        Flux<String> flux = deepSeekService.streamCompletion("springboot如何接入deepseek的流式输出,给出详细的步骤及代码实现");
        StepVerifier.create(flux)
                .thenConsumeWhile(content -> {
                    System.out.print(content);
                    return true;
                })
                .verifyComplete();
    }
}

### Java DeepSeek 流式接入教程 为了实现在Java环境中与DeepSeek流式数据交互,可以采用基于HTTP协议的WebSocket技术来建立持久连接。这允许客户端和服务端之间进行全双工通信,在Spring Boot框架下实现这一功能相对较为简便。 #### 准备工作 确保已经创建了有效的`API key`用于认证访问[^2]。此密钥将在后续配置中作为请求头的一部分发送给服务器验证身份合法性。 #### 添加依赖项 在项目的`pom.xml`文件内加入必要的库支持: ```xml <dependency> <groupId>org.java-websocket</groupId> <artifactId>Java-WebSocket</artifactId> <version>1.5.3</version> </dependency> <!-- 如果使用spring boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` #### 编写WebSocket客户端类 下面是一个简单的WebSocket客户端实现例子,它能够向指定URL发起连接并处理来自服务端的消息推送: ```java import org.java_websocket.client.WebSocketClient; import org.java_websocket.handshake.ServerHandshake; import java.net.URI; import java.nio.ByteBuffer; public class DeepSeekStreamClient extends WebSocketClient { public DeepSeekStreamClient(URI serverUri) { super(serverUri); } @Override public void onOpen(ServerHandshake handshakedata) { System.out.println("Connected to server"); send("{\"api_key\":\"your_api_key_here\"}"); // 发送apikey完成鉴权 } @Override public void onMessage(String message) { System.out.println("Received text message from server: " + message); } @Override public void onClose(int code, String reason, boolean remote) { System.out.println("Connection closed by " + (remote ? "server" : "us") + ": " + reason); } @Override public void onError(Exception ex) { ex.printStackTrace(); } } ``` 请注意替换上述代码中的`your_api_key_here`为实际获取到的有效API Key字符串。 通过这种方式就可以轻松地构建起一个基本版的支持流式传输特性的应用程序接口,从而充分利用DeepSeek所提供的强大自然语言处理能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值