QWQ 32B
在本章节中,我们将学习如何使用 Spring AI Alibaba 接入阿里云 QWQ 32B 系列模型。在开始学习之前,请确保您已经了解相关概念。
- Chat Client;
- Chat Model;
- 本章节的代码您可以在 Spring AI Alibaba Example 中找到。
本示例主要演示如何以 ChatClient 形式接入。关于如何使用 ChatModel,请参阅其他模型的 ChatModel 代码示例。
QWQ 32B
基于 Qwen2.5 模型训练的 QwQ 推理模型,通过强化学习大幅度提升了模型推理能力。模型数学代码等核心指标(AIME 24/25、LiveCodeBench)以及部分通用指标(IFEval、LiveBench等)达到DeepSeek-R1 满血版水平。相较于开源版,商业版具有最新的能力和改进。
Spring AI Alibaba 接入
-
引入
spring-ai-alibaba-starter:<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M6.1</version>
</dependency> -
配置 application.yml:
server:
port: 10002
spring:
application:
name: spring-ai-alibaba-qwq-chat-client-example
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY}
chat:
options:
model: qwq-plus -
注入 ChatClient (假设类名为 QWQChatClientController)
public QWQChatClientController(ChatModel chatModel) {
this.chatModel = chatModel;
// 构造时,可以设置 ChatClient 的参数
// {@link org.springframework.ai.chat.client.ChatClient};
this.chatClient = ChatClient.builder(chatModel)
// 实现 Chat Memory 的 Advisor
// 在使用 Chat Memory 时,需要指定对话 ID,以便 Spring AI 处理上下文。
.defaultAdvisors(
new MessageChatMemoryAdvisor(new InMemoryChatMemory()),
)
// 实现 Logger 的 Advisor
.defaultAdvisors(
new SimpleLoggerAdvisor()
)
// 设置 ChatClient 中 ChatModel 的 Options 参数
.defaultOptions(
DashScopeChatOptions.builder()
.withTopP(0.7)
.build()
)
.build();
} -
编写 Controller 接口:
@GetMapping("/stream/chat")
public Flux<String> streamChat(HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return chatClient.prompt(DEFAULT_PROMPT)
.stream()
.content();
}
至此,已经完成了 QWQ 32B 模型的基本接入。现在您已经可以和 QWQ 32B 模型对话了。
获取 QWQ 32B 模型的思考输出
Spring AI Alibaba 1.0.0-M6.1 版本支持获取 DeepSeek-r1 和 QWQ 32B 模型的思维链。
编写 ReasoningContentAdvisor
public class ReasoningContentAdvisor implements BaseAdvisor {
private static final Logger logger = LoggerFactory.getLogger(ReasoningContentAdvisor.class);
private final int order;
public ReasoningContentAdvisor(Integer order) {
this.order = order != null ? order : 0;
}
@NotNull
@Override
public AdvisedRequest before(@NotNull AdvisedRequest request) {
return request;
}
@NotNull
@Override
public AdvisedResponse after(AdvisedResponse advisedResponse) {
ChatResponse resp = advisedResponse.response();
if (Objects.isNull(resp)) {
return advisedResponse;
}
logger.debug(String.valueOf(resp.getResults().get(0).getOutput().getMetadata()));
String reasoningContent = String.valueOf(resp.getResults().get(0).getOutput().getMetadata().get("reasoningContent"));
if (StringUtils.hasText(reasoningContent)) {
List<Generation> thinkGenerations = resp.getResults().stream()
.map(generation -> {
AssistantMessage output = generation.getOutput();
AssistantMessage thinkAssistantMessage = new AssistantMessage(
String.format("<think>%s</think>", reasoningContent) + output.getText(),
output.getMetadata(),
output.getToolCalls(),
output.getMedia()
);
return new Generation(thinkAssistantMessage, generation.getMetadata());
}).toList();
ChatResponse thinkChatResp = ChatResponse.builder().from(resp).generations(thinkGenerations).build();
return AdvisedResponse.from(advisedResponse).response(thinkChatResp).build();
}
return advisedResponse;
}
@Override
public int getOrder() {
return this.order;
}
}
注入 ReasoningContentAdvisor
public QWQChatClientController(ChatModel chatModel) {
this.chatModel = chatModel;
// ...
.defaultAdvisors(
new MessageChatMemoryAdvisor(new InMemoryChatMemory()),
// 整合 QWQ 的思考过程到输出中
new ReasoningContentAdvisor(0)
)
// ...
}
请求接口查看输出
$ curl http://localhost:10002/qwq/chat-client/stream/chat
<think>好的,用户让我</think>
<think>介绍自己,我之前</think>
<think>已经回答过一次了</think>
<think>,现在又问</think>
<think>同样的问题。用户</think>
<think>可能是想再确认一下</think>
<think>我的功能,或者需要</think>
<think>更详细的介绍?</think>
<think>也有可能他们想</think>
<think>测试我的一致性hink>
<think>又全面,同时保持简洁</think>
<think>。首先,回顾之前的回答</think>
<think>,已经涵盖了基本</think>
<think>功能、支持的语言、应用场景</think>
<think>。这次可能需要添加</think>
<think>一些信息,比如</think>
<think>最近的更新或者</think>
<think>更多例子,让用户</think>
<think>觉得有新内容</think>
<think>。不过根据指示</think>
<think>,不能编造新</think>
<think>功能,所以只能</think>
<think>在原有基础上调整</think>
<think>结构或补充细节。</think>
<think>用户可能希望了解我的应用场景</think>
<think>,或者想确认</think>
<think>我的能力是否符合他们的</think>
<think>需求。需要强调</think>
<think>我的多语能力和</think>
<think>具体应用实例,比如编程</think>
<think>、逻辑推理等。</think>
<think>另外,可以加入</think>
<think>一些鼓励用户提问的</think> >
<think>语句,促进进一步互动</think>
<think>。检查是否有需要</think>
<think>避免的内容,比如不</think>
<think>提及未实现的功能。</think>
<think>确保语气友好,使用</think>
<think>表情符号增加亲切</think>
<think>。最后,保持回答自然</think>
<think>流畅,避免重复之前的</think>
<think>结构,但信息</think>
<think>要准确一致。</think>
你好!我是是义千问(Qwen),阿里巴巴集团旗下的超大规模语言模型。我能够帮助你完成各种任务,比如:
- **回答问题**:无论是常识、专业知识,还是复杂问题,我都会尽力为你解答。
- **创作文字**:写故事、公文、邮件、剧本、诗歌等,我都可以尝试。
- **逻辑与编程**:解决数学问题、编写代码、进行逻辑推理。
- **多语言支持**:除了中文,我还支持英文、德语、法语、西班牙语等多种语言。
- **表达观点与互动**:聊日常话题、玩游戏,甚至讨论观点。
我的目标是成为一位全能的AI助手,无论你需要学习、工作还是娱乐上的帮助,我都会用友好且实用的方式回应你。有什么需要我帮忙的吗?😊
注意事项
QWQ 32B 目前仍有许多限制,在开发时需要注意:
- 模型调用方式
QWQ 模型目前只支持 Stream 调用。如果使用非 Stream 调用时会出现如下错误:
400 - {"code":"InvalidParameter","message":"This model only support stream mode, please enable the stream parameter to access the model."}
- QWQ 模型的其他限制
2.1 不支持功能
- 工具调用(Function Call)
- 结构化输出(JSON Mode)
- 前缀续写(Partial Mode)
- 上下文缓存(Context Cache)
2.2 不支持的参数
- temperature
- top_p
- presence_penalty
- frequency_penalty
- logprobs
- top_logprobs
设置这些参数都不会生效,即使没有输出错误提示。
- System Message
为了达到模型的最佳推理效果,不建议设置 System Message。