适用场景:快速在 Java 本地/服务端调用通义千问系列模型进行对话生成。
适合人群:熟悉 Spring Boot/RestTemplate 的 Java 开发者或技术爱好者。
建议先看:实践三(RESTful API 设计原则)。
你将收获:最小可运行的文本对话/流式对话/图片生成调用,含代理与安全要点。
1. 准备工作
- JDK: 8+(推荐 17+)
- 构建工具: Maven
- API Key: 在阿里云百炼/灵积控制台创建 API-KEY
- 百炼控制台:通义千问-文生图模型(Qwen-Image)
创建RestTemplate(安全与代理)
@Bean("aliAiHttpClient")
public RestTemplate aliRestTemplate(RestTemplateBuilder builder) {
ClientHttpRequestInterceptor authInterceptor = (request, body, execution) -> {
request.getHeaders().setBearerAuth(System.getenv("ALI_API_KEY"));
return execution.execute(request, body);
};
RestTemplate restTemplate = builder
.connectTimeout(Duration.ofSeconds(10))
.readTimeout(Duration.ofSeconds(60))
.additionalInterceptors(authInterceptor)
.build();
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// 设置代理(以 http://127.0.0.1:7890 为例)
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890));
factory.setProxy(proxy);
restTemplate.setRequestFactory(factory);
return restTemplate;
}获取模型
public List getModel() {
List<Map<String, String>> modelList = new ArrayList<>();
Map<String, String> model = new HashMap<>();
model.put("id", "qwen-plus");
modelList.add(model);
model = new HashMap<>();
model.put("id", "qwen-image");
modelList.add(model);
return modelList;
}文字聊天
public Map chat(String model, String message) throws JsonProcessingException {
HttpHeaders headers = new HttpHeaders();
Map param = new HashMap();
param.put("model", model);
Map messageMap = new HashMap();
messageMap.put("role", "user");
messageMap.put("content", message);
param.put("messages", List.of(messageMap));
HttpEntity<Map> entity = new HttpEntity<>(param, headers);
ResponseEntity<String> exchange = restTemplate.exchange("https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions",
HttpMethod.POST,
entity,
String.class);
return objectMapper.readValue(exchange.getBody(), Map.class);
}文字聊天 SSE
public void chatStream(String model, String message, Consumer<String> onDelta) throws JsonProcessingException {
String url = "https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions";
Map<String, Object> body = new HashMap<>();
body.put("model", model);
body.put("stream", true);
Map messageMap = new HashMap();
messageMap.put("role", "user");
messageMap.put("content", message);
body.put("messages", List.of(messageMap));
RequestCallback requestCallback = request -> {
request.getHeaders().setContentType(MediaType.APPLICATION_JSON);
byte[] json = objectMapper.writeValueAsBytes(body);
StreamUtils.copy(json, request.getBody());
};
ResponseExtractor<Void> responseExtractor = response -> {
try (InputStream in = response.getBody();
BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
log.info("chatStream,{}", line);
if (!line.startsWith("data:")) {
continue; // 忽略注释或空行
}
try {
String data = line.substring("data:".length()).trim();
if ("[DONE]".equals(data)) {
break;
}
Map map = objectMapper.readValue(data, Map.class);
List choices = (List) map.get("choices");
if (choices != null && !choices.isEmpty()) {
for (Object choice : choices) {
Map choiceMap = (Map) choice;
Map delta = (Map) choiceMap.get("delta");
String content = delta.get("content").toString();
if (content != null && !content.isEmpty()) {
onDelta.accept(content);
}
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
return null;
};
restTemplate.execute(url, HttpMethod.POST, requestCallback, responseExtractor);
}控制器
@PostMapping(value ="/chat/stream",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chatStream(@RequestBody Map<String, String> param, HttpServletResponse response) throws JsonProcessingException {
String model;
if (param.get("model") != null) {
model = param.get("model");
} else {
model = "";
}
String message;
if (param.get("message") != null) {
message = param.get("message");
} else {
message = "";
}
SseEmitter emitter = new SseEmitter(0L); // 0 表示不超时;可按需设置毫秒
CompletableFuture.runAsync(() -> {
try {
aliAiService.chatStream(model, message, delta -> {
try {
emitter.send(SseEmitter.event().name("delta").data(delta));
} catch (IOException e) {
emitter.completeWithError(e);
}
});
// 上游完成
emitter.send(SseEmitter.event().name("done").data("[DONE]"));
emitter.complete();
} catch (Exception ex) {
emitter.completeWithError(ex);
}
});
return emitter;
}生成图片
public Map generateImageUrl(String model, String prompt, String size) throws JsonProcessingException {
HttpHeaders headers = new HttpHeaders();
Map body = new HashMap();
body.put("model", model);
Map input = new HashMap();
Map message = new HashMap();
message.put("role", "user");
message.put("content", List.of(Map.of("text", prompt)));
input.put("messages", List.of(message));
body.put("input", input);
body.put("parameters", Map.of("negative_prompt", "", "prompt_extend", true, "watermark", true, "size", size));
HttpEntity<Map> entity = new HttpEntity<>(body, headers);
ResponseEntity<String> exchange = restTemplate.exchange("https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation",
HttpMethod.POST,
entity,
String.class);
return objectMapper.readValue(exchange.getBody(), Map.class);
}控制器
@PostMapping("/image/url")
public Map imageUrl(@RequestBody Map<String, String> param) throws JsonProcessingException {
String model = param.getOrDefault("model", "qwen-image");
String prompt = param.getOrDefault("prompt", "");
String size = param.getOrDefault("size", "1328*1328");
return aliAiService.generateImageUrl(model, prompt, size);
}
