项目接入通义千问 api 接口实现步骤详解
随着科技的飞速发展,ai 越来越火,比如平常有问题时,可以询问 ai 给我们解答。越来越多的项目也接入了 ai,智能会话、智能问诊等。那么,我们应该如何在项目中接入 ai 呢?编写一个简单的页面进行对话呢?今天,我们以接入千义通问 api 为例,总结一下实现的基本步骤。
一:引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dashscope-sdk-java</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
二:编写接口
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@RestController
@RequestMapping("/demo/ai")
public class ChatController {
/**
* 问答内容
*/
@PostMapping("/queryAnswer")
public SseEmitter test(@RequestBody QueryVO vo) throws Exception {
return AiUtils.qwenQuickStart(vo.getQuestion());
}
}
三:获取 api key
登录阿里云控制台,选择大模型进入,根据自己需求选择合适的模型,开通服务。
1:开通百炼大模型服务
2:创建 api-key
3:查看 api-key 列表
四:调用 api 接口
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.aigc.generation.models.QwenParam;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.Constants;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* ai 接口调用工具类
*/
public class AiChatUtils {
private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
private static String message="您的问题暂时无法回答。";
/**
* 调用通义千
*/
public static SseEmitter queryAnsWer(String chatContent) {
SseEmitter emitter = new SseEmitter();
executorService.submit(() -> {
try {
// 注意替换 ai key
Constants.apiKey="your ai key";
Generation gen = new Generation();
QwenParam param = QwenParam.builder().model(Generation.Models.QWEN_TURBO).prompt(chatContent)
.topP(0.8).build();
GenerationResult result = gen.call(param);
message=result.getOutput().getText().toString();
// 流式发送消息
for (int i = 0; i < message.length(); i++) {
String chunk = String.valueOf(message.charAt(i));
emitter.send(SseEmitter.event().data(chunk));
Thread.sleep(100); // 模拟处理延迟
}
emitter.complete();
} catch (IOException | InterruptedException e) {
emitter.completeWithError(e);
} catch (NoApiKeyException e) {
throw new RuntimeException(e);
} catch (InputRequiredException e) {
throw new RuntimeException(e);
}
});
return emitter;
}
}
五:编写 HTML 页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>测试 AI</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f4f4f9;
}
.chat-container {
width: 600px;
height: 600px;
border: 1px solid #ccc;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.chat-header {
background-color: #5b8cff;
color: white;
text-align: center;
padding: 10px;
font-size: 20px;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
background-color: #fff;
display: flex;
flex-direction: column;
}
.message {
margin-bottom: 20px;
padding: 8px 12px;
border-radius: 8px;
max-width: 70%;
}
.user-message {
background-color: #e0f7fa;
align-self: flex-end;
}
.ai-message {
background-color: #f1f8e9;
align-self: flex-start;
}
.input-container {
display: flex;
padding: 10px;
background-color: #eee;
}
#question-input {
flex: 1;
padding: 15px;
border: 1px solid #ccc;
border-radius: 10px;
margin-right: 15px;
}
#send-button {
padding: 8px 20px;
background-color: #2196f3;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">测试 AI</div>
<div class="chat-messages" id="chat-messages"></div>
<div class="input-container">
<input type="text" id="question-input" placeholder="输入你的问题">
<button id="send-button">发送</button>
</div>
</div>
<script>
document.getElementById('send-button').addEventListener('click', async () => {
const question = document.getElementById('question-input').value;
if (question.trim() === '') return;
// 显示用户消息
const chatMessages = document.getElementById('chat-messages');
const userMessage = document.createElement('div');
userMessage.classList.add('message', 'user-message');
userMessage.textContent = question;
chatMessages.appendChild(userMessage);
// 清空输入框
document.getElementById('question-input').value = '';
// 创建流式响应的请求
const response = await fetch('http://localhost:8088/demo/ai/queryAnswer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'text/event-stream'
},
body: JSON.stringify({ question })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let aiMessage = document.createElement('div');
aiMessage.classList.add('message', 'ai-message');
chatMessages.appendChild(aiMessage);
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
// 去除 data: 前缀
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data:')) {
const data = line.replace('data:', '').trim();
if (data) {
aiMessage.textContent += data;
}
}
}
}
});
</script>
</body>
</html>
六:进行测试
七:总结
以上为接入ai的基本步骤,主要是开通大模型服务和api接口接入,以上实现了一个简单的调用。过程中遇到的主要问题是,先开始返回数据直接将所有的数据全部返回了,这样看起来不太友好。所以采用 SseEmitter 实现服务器发送事件流失响应的,这样看起来更加的友好。