通义千问聊天
大约 3 分钟
第三章:接入Qwen对话(DashScope)
3.1 本章目标
本章做两件事:
- 写一个更像“产品”的对话接口:支持 system 规则、支持自定义温度、支持简单的多轮上下文
- 把配置做成可切换:本地/测试/线上环境使用不同模型与参数
3.2 依赖与配置回顾
pom.xml 里至少需要:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-dashscope</artifactId>
</dependency>application.yml(建议从环境变量注入 Key):
spring:
ai:
dashscope:
api-key: ${AI_DASHSCOPE_API_KEY:}
chat:
options:
model: ${DASHSCOPE_CHAT_MODEL:qwen-plus}
temperature: ${DASHSCOPE_TEMPERATURE:0.2}
max-tokens: ${DASHSCOPE_MAX_TOKENS:1024}3.3 设计一个“可扩展”的对话 API
推荐用一个请求对象承载可选参数,而不是把所有东西塞到 query string:
package com.example.saa.api.dto;
import java.util.List;
public record ChatRequest(
String message,
String system,
Double temperature,
List<String> history
) {
}返回对象也尽量结构化,为后面扩展 token、模型信息预留空间:
package com.example.saa.api.dto;
public record ChatResponse(
String answer
) {
}3.4 Controller:同步对话 + 简单多轮上下文
为了让示例“复制就能跑”,我们用最朴素的方式组织历史:把最近几轮对话拼进 prompt 的“上下文层”。真实生产中,你可以把 history 做成 Message 列表,或者接入持久化 Memory。
package com.example.saa.api;
import com.example.saa.api.dto.ChatRequest;
import com.example.saa.api.dto.ChatResponse;
import java.util.List;
import java.util.StringJoiner;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class QwenChatController {
private static final int MAX_HISTORY_ITEMS = 10;
private final ChatClient chatClient;
public QwenChatController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@PostMapping(value = "/chat", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ChatResponse chat(@RequestBody ChatRequest request) {
String system = StringUtils.hasText(request.system())
? request.system()
: "你是一个严谨的Java助手,回答要先给结论再解释。";
String userPrompt = buildUserPrompt(request.message(), request.history());
String answer = chatClient.prompt()
.system(system)
.user(userPrompt)
.call()
.content();
return new ChatResponse(answer);
}
private String buildUserPrompt(String message, List<String> history) {
StringJoiner joiner = new StringJoiner("\n");
if (history != null && !history.isEmpty()) {
joiner.add("历史对话(按时间从旧到新,可能不完整):");
int from = Math.max(0, history.size() - MAX_HISTORY_ITEMS);
for (int i = from; i < history.size(); i++) {
joiner.add("- " + history.get(i));
}
joiner.add("当前问题:");
}
joiner.add(message == null ? "" : message);
return joiner.toString();
}
}3.5 验证
启动服务后,用 curl 测一下:
curl -X POST http://localhost:8080/chat \
-H 'Content-Type: application/json' \
-d '{
"system": "你是一个只回答中文的后端工程师助手。",
"history": ["用户:我在做订单系统", "助手:好的,我们从领域模型开始"],
"message": "请给出一个最小可行的订单状态机设计"
}'3.6 多环境配置:把“模型/参数”交给 profile
你可以拆分 application-dev.yml、application-prod.yml:
spring:
ai:
dashscope:
chat:
options:
model: qwen-turbo
temperature: 0.4spring:
ai:
dashscope:
chat:
options:
model: qwen-plus
temperature: 0.2启动时切换:
mvn spring-boot:run -Dspring-boot.run.profiles=dev3.7 本章小结
你现在已经具备一条“可扩展”的对话链路:
- 请求对象承载可选参数与 history
- Prompt 分层组织:system 规则 + history 上下文 + 当前问题
- 通过 profile 管理模型与参数,为后续“按任务选模型”打基础
下一章我们会把体验从“等结果”升级到“边生成边展示”:实现流式输出(SSE),并处理断线、取消与背压。 点击这里👇🏻获取:100万QPS短链系统、复杂的商城微服务系统、智能翻译助手AI Agent、SaaS点餐系统、刷题吧小程序、商城系统、秒杀系统、AI项目、代码生成神器、苏三demo项目、智能天气播报AI Agent、智能代码审查AI Agent等 10 个项目的:项目源代码、开发教程和技术答疑
