> ## Documentation Index
> Fetch the complete documentation index at: https://blog.pig4cloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 为什么 Spring AI 不能用？DeepSeek R1 的正确打开方式

> 本文详细介绍 DeepSeek R1 模型的特性，分析为什么需要直接调用API而不是使用现有框架，并提供完整的 Java 实现方案

DeepSeek 最近推出的 R1 模型因其强大的思维链(Chain-of-Thought)能力而备受关注。然而，在实际开发中，许多开发者发现主流的 AI 框架（如 Spring AI 和 LangChain4j）并不能完全支持这个模型的特性。本文将深入分析这个问题，并提供一个优雅的解决方案。

<img src="https://minio.pigx.vip/oss/202502/1738686817.png" alt="DeepSeek R1 架构图" />

## 为什么不能使用现有框架？

### 官方 R1 模型的特殊性

虽然目前网上有许多教程介绍如何通过 Spring AI 或 LangChain4j 的 OpenAI 适配器来接入 DeepSeek，但这种方式存在以下关键问题：

1. **思维链内容丢失**：R1 模型最核心的特性是提供详细的推理过程，这些内容包含在特殊的 `reasoning_content` 字段中，**现有框架会完全忽略这个关键信息**

2. **响应模式的改变**：R1 模型强依赖流式输出，其推理过程与通用文本大模型不同 - 会先输出详细的思考过程，再给出最终推理结果。这种"思考在前、结论在后"的模式导致整个响应时间较长，因此必须采用流式输出和专门的思维链展示交互，否则用户体验会大打折扣

3. **参数限制**：R1 模型对以下参数有特殊要求：
   * temperature、top\_p、presence\_penalty、frequency\_penalty：虽然可以设置但不会生效
   * logprobs、top\_logprobs：设置会导致API调用失败

<img src="https://minio.pigx.vip/oss/202502/1738685785.png" alt="R1 API 响应示例" />

**框架适配现状**

目前主流的 AI 框架都未对 DeepSeek R1 进行官方适配：

* LangChain4j：暂无计划支持 DeepSeek 特有的思维链功能
* Spring AI：当前版本仅支持标准的 OpenAI 协议，无法处理 R1 的特殊响应格式

这种情况预计在短期内不会改变，主要原因是 R1 模型的非标准响应格式以及特殊的参数要求。因此，对于想要充分利用 R1 模型能力的开发者来说，直接调用 API 是目前最佳的选择。

### Ollama 部署的特殊处理

当使用 Ollama 私有化部署 R1 时，情况略有不同：

```bash theme={null}
ollama run deepseek-r1:14b
```

Ollama 为了保持与 OpenAI 协议的兼容性，采用了一个变通方案：将思维链内容用 `<think>` 标签包装后通过 content 字段输出。这种方式虽然保证了兼容性，但在多轮对话中会产生额外的 token 开销。

<img src="https://minio.pigx.vip/oss/202502/1738686232.png" alt="Ollama 输出示例" />

建议在前端实现以下处理逻辑来提取思维链内容：

```typescript theme={null}
export function withMessageThought(message: ChatMessage, startTime?: number) {
	const content = message.content;

	const thinkPattern = /<think>(.*?)<\/think>/s;
	const matches = content.match(thinkPattern);

	if (matches) {
		const reasoning_content = matches[1].trim();
		return reasoning_content;
	}

	return message;
}
```

## 基于 Spring WebFlux 的实现方案

虽然 Spring AI 和 LangChain4j 提供了便捷的 AI 集成方案，但对于 DeepSeek R1 这样的特殊模型，直接调用 API 是更好的选择。使用 Spring WebFlux 不仅可以完整获取思维链内容，还能通过其异步非阻塞特性提供更好的性能表现。

## 基于 Spring WebFlux 的优雅实现

为了充分利用 R1 模型的特性，我们可以使用 Spring WebFlux 实现一个直接调用 API 的解决方案。这不仅能完整保留思维链内容，还能通过响应式编程提供更好的性能。

在处理 AI 模型 API 调用时，WebFlux 相比传统的阻塞式 HTTP 客户端有以下优势：

1. **非阻塞 I/O**
   * 使用 Netty 作为底层实现，支持异步非阻塞的网络操作
   * 不会因为长时间的 API 调用而阻塞线程池
   * 能更高效地处理大量并发请求

2. **响应式流**
   * 通过 SpringBoot WebClient 的声明式 API 简化调用流程
   * 简化 Server-Sent Events (SSE) 开发，实现实时数据推送
   * 方便实现流式输出的 UI 交互

### API 实现

```java theme={null}
@PostMapping(value = "/deepseek", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Map<String, String>> chatStream(String inputPrompt) {
    Map<String, Object> message = new HashMap<>();
    message.put("role", "user");
    message.put("content", inputPrompt);

    Map<String, Object> requestBody = new HashMap<>();
    requestBody.put("messages", List.of(message));
    requestBody.put("stream", true);
    requestBody.put("model", "deepseek-reason");

    WebClient webClient = WebClient.builder()
            .baseUrl("https://api.deepseek.com/v1")
            .defaultHeader("Authorization", "Bearer ${DEEPSEEK_API_KEY}")
            .build();

    return webClient.post()
            .uri("/chat/completions")
            .bodyValue(requestBody)
            .retrieve()
            .bodyToFlux(JsonNode.class)
            .map(this::parseDeepseekResponse)
            .takeUntil(response -> response.containsKey("finish_reason"))
            .onErrorResume(error -> Flux.just(Map.of("content", "API 调用异常：" + error.getMessage())));
}
```

### 响应解析

```java theme={null}
private Map<String, String> parseDeepseekResponse(JsonNode response) {
    JsonNode choices = response.get("choices");
    Map<String, String> result = new HashMap<>();
    
    if (choices != null && choices.isArray() && !choices.isEmpty()) {
        JsonNode choice = choices.get(0);
        JsonNode delta = choice.get("delta");

        if (delta != null) {
            result.put("content", 
                Optional.ofNullable(delta.get("content"))
                    .map(JsonNode::asText)
                    .orElse(""));
                    
            result.put("reasoning_content", 
                Optional.ofNullable(delta.get("reasoning_content"))
                    .map(JsonNode::asText)
                    .orElse(""));
        }

        Optional.ofNullable(choice.get("finish_reason"))
            .filter(node -> !node.isNull())
            .ifPresent(node -> result.put("finish_reason", node.asText()));
    }
    return result;
}
```

## 总结

通过本文提供的实现方案，我们可以：

1. 完整保留 R1 模型的思维链能力
2. 利用 WebFlux 实现高性能的流式处理

虽然目前 DeepSeek 官方 API 基本不可用，可以考虑使用硅基流动(SiliconFlow)部署的 671B 满血 R1 模型作为替代方案：[https://cloud.siliconflow.cn/i/YKcJJTYP](https://cloud.siliconflow.cn/i/YKcJJTYP)

本文的实现方案不仅解决了当前的集成问题，也为未来框架的改进提供了参考。随着大语言模型领域的快速发展，掌握直接调用 API 的技巧将变得越发重要，特别是在处理具有特殊功能的新型模型时。
