通义千问接入TG机器人
前提:你已经知道如何使用Java搭建一个机器人并实现自动回复功能,若还未掌握,请移步
TG机器人从0到1搭建(Node.js/Java)Telegram机器人从0到1搭建Telegram机器人从0到1搭建T - 掘金 (juejin.cn)
获取ApiKey
要将千问接入TG机器人,需要获取ApiKey,相当于一个凭证
获取方式:如何获取通义千问API的KEY_模型服务灵积(DashScope)-阿里云帮助中心 (aliyun.com)
开通DashScope服务后可以创建ApiKey
在模型广场中选择要调用的模型,可以查看收费情况
在示例(这里以文本输入为例)中查看请求的地址、模型
导入依赖
该依赖用来发送请求
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.0</version>
</dependency>
编写代码
package com.example.telegram_bot;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import okhttp3.*;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.bots.DefaultBotOptions;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* 长轮询方式部署机器人
*/
@Component
public class ExecBot extends TelegramLongPollingBot {
// 填你自己的token和username
private String botToken = "YOUR_TOKEN";
private String botName = "YOUR_BOT_NAME";// newbot时你的第二个名字
// 通义千问API Key
private static final String QIANWEN_API_KEY = "YOUR_API_KEY";
// 请求地址
private static final String QIANWEN_API_URL = "YOUR_URL";
// 设置 OkHttpClient 的超时时间
private static final OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS) // 连接超时时间
.readTimeout(60, TimeUnit.SECONDS) // 读取超时时间
.writeTimeout(60, TimeUnit.SECONDS) // 写入超时时间
.build();
public ExecBot() {
this(new DefaultBotOptions());
}
// 通过 DefaultBotOptions 允许你指定代理服务器等配置。super(options) 将这个配置传给父类 TelegramLongPollingBot 进行处理
public ExecBot(DefaultBotOptions options) {
super(options);
}
@Override
public String getBotToken() {
return botToken;
}
@Override
public String getBotUsername() {
return botName;
}
@Override
public void onUpdateReceived(Update update) {
// 检查消息更新
if (update.hasMessage()) {
// 取出消息及聊天Id
Message message = update.getMessage();
Long chatId = message.getChatId();
// 获取用户输入的消息文本
String text = message.getText().trim();
// 检查是否是特定的命令,比如"/ask"
if (text.startsWith("/ask")) {
// 移除命令前缀并获取实际的问题
String question = text.substring(5).trim();
// 调用通义千问API
String answer = getAnswerFromQianwen(question);
// 发送回答给用户
sendMsg(answer, chatId);
} else {
// 如果不是/ask命令,则按原逻辑处理
sendMsg("你好,请输入”/ask 问题“进行提问", chatId);
}
}
}
// 调用通义千问API的方法
private String getAnswerFromQianwen(String question) {
// OkHttpClient 实例,用于发送 HTTP 请求
OkHttpClient client = new OkHttpClient();
/** 设置请求体
* MediaType:指定请求的内容类型为 JSON
* requestBody:创建一个 JsonObject 来存储请求体
* 添加 "model" 属性,值为 "qwen-plus",表示调用的模型
* 添加 "messages" 属性,值为通过 createMessages(question) 方法生成的消息数组
*/
MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
JsonObject requestBody = new JsonObject();
requestBody.addProperty("model", "qwen-plus");
requestBody.add("messages", createMessages(question));
/** 构建 HTTP 请求
* 设置请求的 URL,指向通义千问 API 的 /chat/completions 端点
* 使用 POST 方法发送请求,并设置请求体为 requestBody
* 添加 Authorization 头,值为 Bearer <API Key>,用于身份验证
* 构建最终的 Request 对象
*/
Request request = new Request.Builder()
.url(QIANWEN_API_URL + "/chat/completions")
.post(RequestBody.create(mediaType, requestBody.toString()))
.addHeader("Authorization", "Bearer " + QIANWEN_API_KEY)
.build();
int maxRetries = 3; // 最大重试次数
for (int attempt = 0; attempt < maxRetries; attempt++) {
// client.newCall(request).execute():执行 HTTP 请求并获取响应
try (Response response = client.newCall(request).execute()) {
// response.isSuccessful():检查响应是否成功(HTTP 状态码在 200-299 之间)
if (response.isSuccessful() && response.body() != null) {
// response.body().string():读取响应体内容
String responseBody = response.body().string();
// JsonParser 和 Gson 解析 JSON 响应
JsonParser parser = new JsonParser();
JsonObject json = parser.parse(responseBody).getAsJsonObject();
// 提取 choices 数组中的第一个元素,并从中获取 message 的 content 字段,作为最终答案返回
JsonObject choice = json.getAsJsonArray("choices").get(0).getAsJsonObject();
return choice.getAsJsonObject("message").get("content").getAsString();
} else {
return "抱歉,出现了一个错误。" + response.code();
}
} catch (IOException e) {
if (attempt == maxRetries - 1) { // 如果是最后一次重试,抛出异常
e.printStackTrace();
return "抱歉,出现了一个错误。" + e.getMessage();
}
// 否则等待一段时间后重试
try {
Thread.sleep(1000 * (attempt + 1)); // 等待时间逐渐增加
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException(ie);
}
}
}
return "抱歉,出现了一个错误。";
}
// 创建消息数组
private JsonArray createMessages(String question) {
Gson gson = new Gson();
// systemMessage:创建一个 JsonObject 实例
JsonObject systemMessage = new JsonObject();
// 添加一个键为 "role"、值为 "system" 的属性,表示这是一个系统消息
systemMessage.addProperty("role", "system");
// 添加一个键为 "content"、值为 "You are a helpful assistant." 的属性,这是系统消息的内容
systemMessage.addProperty("content", "You are a helpful assistant.");
JsonObject userMessage = new JsonObject();
// 添加一个键为 "role"、值为 "user" 的属性,表示这是一个用户消息
userMessage.addProperty("role", "user");
// 添加一个键为 "content"、值为 question 的属性,这是用户消息的内容(即用户提出的问题)
userMessage.addProperty("content", question);
JsonArray messages = new JsonArray();
// 将系统消息对象、用户消息对象添加到 JSON 数组中
messages.add(systemMessage);
messages.add(userMessage);
return messages;
}
// 回复消息
public void sendMsg(String text, Long chatId) {
// 使用 SendMessage 对象构建回复消息
SendMessage response = new SendMessage();
// 设置要发送消息的聊天对象、发送内容、消息内容支持 HTML 格式的解析
response.setChatId(String.valueOf(chatId));
response.setText(text);
response.setParseMode("html");
try {
// 执行发送消息
execute(response);
} catch (TelegramApiException e) {
e.getMessage();
}
}
}
注意点:
1、超时时间的设置,设置得太短,可能因为响应太慢而报错
2、最终生成的消息数组格式如下:
系统消息:告诉 API 系统角色是一个乐于助人的助手。
用户消息:包含用户提出的问题
[ { "role": "system", "content": "You are a helpful assistant." }, { "role": "user", "content": "用户提出的问题" }]