关键网址:
如何快速开始通义千问_模型服务灵积(DashScope)-阿里云帮助中心
如何使用通义千问API_模型服务灵积(DashScope)-阿里云帮助中心
在官网文档中提及了通过Messages调用(推荐)和通过prompt调用两种方式,于是我调查了这两种调用方式的区别:
通过 prompt
调用和通过 messages
调用的主要区别在于输入数据的方式和适用场景:
-
通过
prompt
调用:- 使用单个文本作为输入,称为提示文本(prompt),代表用户的一个请求或问题。
- 适用于单次性的、独立的文本生成任务,不需要考虑上下文或历史消息。
- 例如,当用户提出一个问题或请求时,可以直接将该问题或请求作为提示文本传递给模型进行文本生成。
-
通过
messages
调用:- 使用消息管理器(MessageManager)来管理多个消息,包括用户消息和系统消息,形成消息队列。
- 适用于需要考虑上下文、历史消息、多轮对话等情况。
- 可以在多轮对话中保持上下文,模拟与用户的自然对话,根据之前的交互进行文本生成。
- 例如,在一个聊天机器人的场景中,用户提出的问题可能需要结合之前的对话历史来进行回答,此时就需要使用消息管理器来管理上下文信息。
通过上面对比可以看出Messages通用性更高,因为智慧医疗问诊确实需要使用到累计的对话记录。
所以下面就重点研究通过Messages调用的方法。
首先是官方的示例代码,但是官方代码不能直接运行,还需要做相关配置。下面是我调试好的代码,为了保险,我把key值隐藏了,替换掉即可。
package com.A611699;// Copyright (c) Alibaba, Inc. and its affiliates.
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.common.Message;
import com.alibaba.dashscope.common.MessageManager;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
public class Maintest {
public static void callWithMessage()
throws NoApiKeyException, ApiException, InputRequiredException {
Generation gen = new Generation();
com.alibaba.dashscope.utils.Constants.apiKey = "*********";
MessageManager msgManager = new MessageManager(10);
Message systemMsg =
Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();
Message userMsg = Message.builder().role(Role.USER.getValue()).content("如何做西红柿鸡蛋?").build();
msgManager.add(systemMsg);
msgManager.add(userMsg);
QwenParam param =
QwenParam.builder().model(Generation.Models.QWEN_TURBO).messages(msgManager.get())
.resultFormat(QwenParam.ResultFormat.MESSAGE)
.build();
GenerationResult result = gen.call(param);
System.out.println(result);
}
public static void main(String[] args){
try {
callWithMessage();
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
System.out.println(e.getMessage());
}
System.exit(0);
}
}
通义千问模型的调用有两种方式:使用DashScope SDK和HTTP接口
一、使用DashScope SDK调用
1、首先需要 安装DashScope SDK。
2、开通服务并且获得通义千问的API-KEY 开通DashScope并创建API-KEY。
3、推荐将API-KEY配置到环境变量中来降低API-KEY的泄露风险,可参考通过环境变量配置API-KEY,当然也可以在代码中配置API-KEY,但是这样泄露了话就可能就烧钱了。
官方的单轮对话代码:已经调试好了,替换掉API-KEY就行
package com.A611699;// Copyright (c) Alibaba, Inc. and its affiliates.
// 建议dashscope SDK的版本 >= 2.12.0
import java.util.Arrays;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
public class Maintest {
public static GenerationResult callWithMessage() throws ApiException, NoApiKeyException, InputRequiredException {
Generation gen = new Generation();
com.alibaba.dashscope.utils.Constants.apiKey = "**********";
Message systemMsg = Message.builder()
.role(Role.SYSTEM.getValue())
.content("You are a helpful assistant.")
.build();
Message userMsg = Message.builder()
.role(Role.USER.getValue())
.content("如何做西红柿炒鸡蛋?")
.build();
GenerationParam param = GenerationParam.builder()
.model("qwen-turbo")
.messages(Arrays.asList(systemMsg, userMsg))
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.topP(0.8)
.build();
return gen.call(param);
}
public static void main(String[] args) {
try {
GenerationResult result = callWithMessage();
System.out.println(result);
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
// 使用日志框架记录异常信息
// Logger.error("An error occurred while calling the generation service", e);
System.err.println("An error occurred while calling the generation service: " + e.getMessage());
}
System.exit(0);
}
}
相对于单轮对话,多轮对话可以参考历史聊天信息,更符合日常交流的场景。但由于调用时会引入历史聊天信息,使用的token量会增多。下面是多轮对话的代码。但是多轮的提问问题已经在代码中写死了。
package com.A611699;// Copyright (c) Alibaba, Inc. and its affiliates.
import java.util.ArrayList;
import java.util.List;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.JsonUtils;
public class Maintest {
// 设置 API key
static {
com.alibaba.dashscope.utils.Constants.apiKey = "sk****************";
}
public static GenerationParam createGenerationParam(List<Message> messages) {
return GenerationParam.builder()
.model("qwen-turbo")
.messages(messages)
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.topP(0.8)
.build();
}
public static GenerationResult callGenerationWithMessages(GenerationParam param) throws ApiException, NoApiKeyException, InputRequiredException {
Generation gen = new Generation();
return gen.call(param);
}
public static void main(String[] args) {
try {
List<Message> messages = new ArrayList<>();
messages.add(createMessage(Role.SYSTEM, "You are a helpful assistant."));
messages.add(createMessage(Role.USER, "如何做西红柿炖牛腩?"));
GenerationParam param = createGenerationParam(messages);
GenerationResult result = callGenerationWithMessages(param);
printResult(result);
// 添加assistant返回的消息到列表
messages.add(result.getOutput().getChoices().get(0).getMessage());
// 添加新的用户消息
messages.add(createMessage(Role.USER, "不放糖可以吗?"));
result = callGenerationWithMessages(param);
printResult(result);
printResultAsJson(result);
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
e.printStackTrace();
}
System.exit(0);
}
private static Message createMessage(Role role, String content) {
return Message.builder().role(role.getValue()).content(content).build();
}
private static void printResult(GenerationResult result) {
System.out.println(result);
}
private static void printResultAsJson(GenerationResult result) {
System.out.println(JsonUtils.toJson(result));
}
}
下面再做改进,体验实时在线多轮对话功能,但是对话轮数已经写固定了(10轮),可以在代码中修改。
package com.A611699;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import java.util.Scanner;
public class Maintest {
// 设置 API key
static {
com.alibaba.dashscope.utils.Constants.apiKey = "sk-****************";
}
public static GenerationParam createGenerationParam(List<Message> messages) {
return GenerationParam.builder()
.model("qwen-turbo")
.messages(messages)
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.topP(0.8)
.build();
}
public static GenerationResult callGenerationWithMessages(GenerationParam param) throws ApiException, NoApiKeyException, InputRequiredException {
Generation gen = new Generation();
return gen.call(param);
}
public static void main(String[] args) {
try {
List<Message> messages = new ArrayList<>();
messages.add(createMessage(Role.SYSTEM, "You are a helpful assistant."));
for (int i = 0; i < 10;i++) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入:");
String userInput = scanner.nextLine();
if ("exit".equalsIgnoreCase(userInput)) {
break;
}
messages.add(createMessage(Role.USER, userInput));
GenerationParam param = createGenerationParam(messages);
GenerationResult result = callGenerationWithMessages(param);
System.out.println("模型输出:"+result.getOutput().getChoices().get(0).getMessage().getContent());
messages.add(result.getOutput().getChoices().get(0).getMessage());
}
} catch (ApiException | NoApiKeyException | InputRequiredException e) {
e.printStackTrace();
}
System.exit(0);
}
private static Message createMessage(Role role, String content) {
return Message.builder().role(role.getValue()).content(content).build();
}
}
大模型并不是一次性生成最终结果,而是逐步地生成中间结果,最终结果由这些中间结果拼接而成。在非流式输出方式中,等待模型生成结束后,所有中间结果将被拼接成最终结果,然后返回。相比之下,流式输出可以实时地将中间结果返回,您可以在模型继续进行输出的同时进行阅读,从而减少等待模型回复的时间。要使用流式输出,您需要进行一些配置。在 DashScope Python SDK 中,您需要设置 stream 参数为 True;在 DashScope Java SDK 中,您需要使用 streamCall 接口调用。下面是调试好的代码:
package com.A611699;// Copyright (c) Alibaba, Inc. and its affiliates.
import java.util.Arrays;
import java.util.concurrent.Semaphore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.Semaphore;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.aigc.generation.GenerationResult;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.ResultCallback;
import com.alibaba.dashscope.common.Role;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.utils.JsonUtils;
import io.reactivex.Flowable;
public class Maintest {
static {
// 设置 API key
com.alibaba.dashscope.utils.Constants.apiKey = "sk-***********************";
}
private static final Logger logger = LoggerFactory.getLogger(Main.class);
private static void handleGenerationResult(GenerationResult message, StringBuilder fullContent) {
fullContent.append(message.getOutput().getChoices().get(0).getMessage().getContent());
logger.info("Received message: {}", JsonUtils.toJson(message));
}
public static void streamCallWithMessage(Generation gen, Message userMsg)
throws NoApiKeyException, ApiException, InputRequiredException {
GenerationParam param = buildGenerationParam(userMsg);
Flowable<GenerationResult> result = gen.streamCall(param);
StringBuilder fullContent = new StringBuilder();
result.blockingForEach(message -> handleGenerationResult(message, fullContent));
logger.info("Full content: \n{}", fullContent.toString());
}
public static void streamCallWithCallback(Generation gen, Message userMsg)
throws NoApiKeyException, ApiException, InputRequiredException, InterruptedException {
GenerationParam param = buildGenerationParam(userMsg);
Semaphore semaphore = new Semaphore(0);
StringBuilder fullContent = new StringBuilder();
gen.streamCall(param, new ResultCallback<GenerationResult>() {
@Override
public void onEvent(GenerationResult message) {
handleGenerationResult(message, fullContent);
}
@Override
public void onError(Exception err) {
logger.error("Exception occurred: {}", err.getMessage());
semaphore.release();
}
@Override
public void onComplete() {
logger.info("Completed");
semaphore.release();
}
});
semaphore.acquire();
logger.info("Full content: \n{}", fullContent.toString());
}
private static GenerationParam buildGenerationParam(Message userMsg) {
return GenerationParam.builder()
.model("qwen-turbo")
.messages(Arrays.asList(userMsg))
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.topP(0.8)
.incrementalOutput(true)
.build();
}
public static void main(String[] args) {
try {
Generation gen = new Generation();
Message userMsg = Message.builder().role(Role.USER.getValue()).content("如何做西红柿炖牛腩?").build();
streamCallWithMessage(gen, userMsg);
streamCallWithCallback(gen, userMsg);
} catch (ApiException | NoApiKeyException | InputRequiredException | InterruptedException e) {
logger.error("An exception occurred: {}", e.getMessage());
}
}
}