通义千问集成
大约 5 分钟
第三章:集成千问(Qwen)
3.1 千问模型介绍
千问(Qwen)是阿里巴巴达摩院开发的大语言模型系列,具有强大的自然语言处理能力。Spring AI提供了对千问模型的完整支持。
3.1.1 千问模型特点
- 多语言支持:优秀的中文和英文处理能力
- 知识丰富:涵盖广泛的知识领域
- 性能优越:高效的推理能力
- API友好:易于集成和使用
3.1.2 可用的千问模型
千问提供了多个模型版本:
- qwen-turbo:高速版本,适合实时对话
- qwen-plus:增强版本,知识更丰富
- qwen-max:高性能版本,适合复杂任务
- qwen-vl:视觉语言模型,支持图像处理
3.2 配置千问客户端
3.2.1 添加依赖
在pom.xml中添加千问依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qwen-spring-boot-starter</artifactId>
</dependency>3.2.2 配置API密钥
在application.properties中配置千问API密钥:
# 千问配置
spring.ai.qwen.api-key=your-qwen-api-key
spring.ai.qwen.chat.options.model=qwen-turbo
spring.ai.qwen.chat.options.temperature=0.7
spring.ai.qwen.chat.options.max-tokens=10003.2.3 编程配置
@Configuration
public class QwenConfig {
@Bean
public ChatClient qwenChatClient(ChatClient.Builder builder) {
return builder
.defaultSystem("You are a helpful assistant")
.defaultOptions(QwenChatOptions.builder()
.withModel("qwen-plus")
.withTemperature(0.8f)
.withMaxTokens(1500)
.build())
.build();
}
}3.3 基础对话示例
3.3.1 简单对话
@RestController
public class QwenController {
private final ChatClient qwenChatClient;
public QwenController(ChatClient qwenChatClient) {
this.qwenChatClient = qwenChatClient;
}
@GetMapping("/qwen/chat")
public String chat(@RequestParam String message) {
return qwenChatClient.prompt()
.user(message)
.call()
.content();
}
}3.3.2 系统提示对话
@GetMapping("/qwen/system-chat")
public String systemChat(@RequestParam String message) {
return qwenChatClient.prompt()
.system("You are a professional Spring developer")
.user(message)
.call()
.content();
}3.3.3 多轮对话
@GetMapping("/qwen/multi-turn")
public String multiTurnChat(
@RequestParam String initialMessage,
@RequestParam String followUpMessage) {
ChatResponse firstResponse = qwenChatClient.prompt()
.user(initialMessage)
.call();
String assistantResponse = firstResponse.getResult().getOutput().getContent();
ChatResponse secondResponse = qwenChatClient.prompt()
.user(followUpMessage)
.call();
return secondResponse.getContent();
}3.4 高级功能
3.4.1 流式响应
千问支持流式响应,适合实时交互场景:
@GetMapping("/qwen/stream")
public Flux<ServerSentEvent<String>> streamChat(@RequestParam String message) {
return qwenChatClient.prompt()
.user(message)
.stream()
.flatMapIterable(ChatResponse::getResults)
.map(result -> result.getOutput().getContent())
.map(content -> ServerSentEvent.builder(content).build());
}前端使用示例:
<!DOCTYPE html>
<html>
<head>
<title>千问流式对话</title>
</head>
<body>
<div id="response"></div>
<script>
const eventSource = new EventSource('/qwen/stream?message=Tell me about Spring AI');
eventSource.onmessage = function(event) {
document.getElementById('response').innerHTML += event.data + ' ';
};
</script>
</body>
</html>3.4.2 函数调用
千问支持函数调用,可以集成外部工具:
@RestController
public class QwenFunctionController {
private final ChatClient qwenChatClient;
public QwenFunctionController(ChatClient qwenChatClient) {
this.qwenChatClient = qwenChatClient;
}
@GetMapping("/qwen/function")
public String functionCall(@RequestParam String question) {
FunctionCallback functionCallback = new FunctionCallback(
"getWeather",
"Get current weather for a location",
new Schema(SchemaType.OBJECT)
.addProperty("location", SchemaProperty.of(SchemaType.STRING, "City name"))
.addRequired("location"),
this::getWeather
);
return qwenChatClient.prompt()
.user(question)
.functions(functionCallback)
.call()
.content();
}
private String getWeather(Map<String, Object> arguments) {
String location = (String) arguments.get("location");
// 实际天气API调用
return "The current weather in " + location + " is sunny with 25°C";
}
}3.4.3 图像生成
千问视觉模型支持图像生成:
@RestController
public class QwenImageController {
private final ImageClient imageClient;
public QwenImageController(ImageClient imageClient) {
this.imageClient = imageClient;
}
@GetMapping("/qwen/image")
public String generateImage(@RequestParam String prompt) {
ImagePrompt imagePrompt = new ImagePrompt(prompt);
ImageResponse response = imageClient.generate(imagePrompt);
return response.getResult().getOutput().getUrl();
}
}3.5 实际应用示例
3.5.1 智能客服系统
@Service
public class QwenCustomerService {
private final ChatClient qwenChatClient;
public QwenCustomerService(ChatClient qwenChatClient) {
this.qwenChatClient = qwenChatClient;
}
public String handleCustomerQuery(String customerMessage) {
return qwenChatClient.prompt()
.system("You are a customer service representative for an e-commerce platform")
.user(customerMessage)
.call()
.content();
}
}3.5.2 内容生成器
@RestController
public class ContentGenerator {
private final ChatClient qwenChatClient;
public ContentGenerator(ChatClient qwenChatClient) {
this.qwenChatClient = qwenChatClient;
}
@GetMapping("/qwen/content")
public String generateContent(
@RequestParam String topic,
@RequestParam String format,
@RequestParam int length) {
PromptTemplate template = new PromptTemplate(
"Generate {format} content about {topic} with approximately {length} words"
);
Prompt prompt = template.create(
Map.of("topic", topic, "format", format, "length", length)
);
return qwenChatClient.prompt(prompt).call().content();
}
}3.6 性能优化
3.6.1 缓存策略
@Configuration
@EnableCaching
public class QwenCacheConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(
new ConcurrentMapCache("qwen-responses")
));
return cacheManager;
}
}3.6.2 异步调用
@RestController
public class AsyncQwenController {
private final ChatClient qwenChatClient;
public AsyncQwenController(ChatClient qwenChatClient) {
this.qwenChatClient = qwenChatClient;
}
@GetMapping("/qwen/async")
public CompletableFuture<String> asyncChat(@RequestParam String message) {
return qwenChatClient.prompt()
.user(message)
.callAsync()
.thenApply(ChatResponse::getContent);
}
}3.7 错误处理
3.7.1 异常处理
@RestControllerAdvice
public class QwenExceptionHandler {
@ExceptionHandler(QwenApiException.class)
public ResponseEntity<ErrorResponse> handleQwenError(QwenApiException ex) {
ErrorResponse error = new ErrorResponse(
"QWEN_API_ERROR",
"千问API调用失败: " + ex.getMessage()
);
return new ResponseEntity<>(error, HttpStatus.SERVICE_UNAVAILABLE);
}
}3.7.2 重试机制
@Configuration
public class QwenRetryConfig {
@Bean
public ChatClient retryChatClient(ChatClient chatClient) {
return new ChatClient() {
@Override
public ChatResponse call(Prompt prompt) {
int maxAttempts = 3;
for (int attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return chatClient.call(prompt);
} catch (Exception ex) {
if (attempt == maxAttempts) {
throw ex;
}
try {
Thread.sleep(1000 * attempt);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
throw new RuntimeException("Max retry attempts reached");
}
// 实现其他方法...
};
}
}3.8 监控与日志
3.8.1 日志记录
@Configuration
public class QwenLogging {
@Bean
public ChatClient loggingChatClient(ChatClient chatClient) {
return new ChatClient() {
@Override
public ChatResponse call(Prompt prompt) {
long startTime = System.currentTimeMillis();
try {
ChatResponse response = chatClient.call(prompt);
long duration = System.currentTimeMillis() - startTime;
log.info("千问调用耗时: {}ms, Prompt: {}", duration, prompt);
return response;
} catch (Exception ex) {
log.error("千问调用失败", ex);
throw ex;
}
}
// 实现其他方法...
};
}
}3.8.2 指标监控
@RestController
public class QwenMetricsController {
private final MeterRegistry meterRegistry;
public QwenMetricsController(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@GetMapping("/qwen/metrics")
public Map<String, Object> getMetrics() {
return Map.of(
"totalCalls", meterRegistry.counter("qwen.total.calls").count(),
"averageDuration", meterRegistry.timer("qwen.duration").mean(),
"errorRate", meterRegistry.counter("qwen.errors").count() /
(meterRegistry.counter("qwen.total.calls").count() + 1.0)
);
}
}3.9 小结
本章详细介绍了千问模型的集成和使用:
- 模型特点:了解千问的核心优势
- 客户端配置:掌握千问客户端的配置方法
- 基础对话:学习基本的对话交互
- 高级功能:掌握流式响应、函数调用等高级特性
- 实际应用:了解千问在实际项目中的应用场景
- 性能优化:学习缓存、异步等优化技术
- 错误处理:掌握异常处理和重试机制
- 监控日志:了解监控和日志记录
在下一章中,我们将学习如何集成DeepSeek模型。 点击这里👇🏻获取:100万QPS短链系统、复杂的商城微服务系统、智能翻译助手AI Agent、SaaS点餐系统、刷题吧小程序、商城系统、秒杀系统、AI项目、代码生成神器、苏三demo项目、智能天气播报AI Agent、智能代码审查AI Agent等 10 个项目的:项目源代码、开发教程和技术答疑
