文章目录
一、大模型服务平台百炼
百炼是阿里新出的一个大模型服务平台,聚合了多个千问大模型及其它一些大模型的调用,暴露了一个同一的http请求入口,调用接口需要申请一个apikey,不需apisecret用于计费,有免费额度,较小的模型很便宜,各语言可以直接拼接请求参数发起http调用,主流开发语言python,Java等还提供了SDK使用起来更方便。
二、Java sdk调用与eventStream
package com.example.demo.qianwen;
import java.util.Arrays;
import com.alibaba.dashscope.aigc.generation.Generation;
import com.alibaba.dashscope.aigc.generation.GenerationParam;
import com.alibaba.dashscope.common.Message;
import com.alibaba.dashscope.common.Role;
import lombok.SneakyThrows;
public class Main {
@SneakyThrows
public static void main(String[] args) {
Generation gen = new Generation();
Message systemMsg = Message.builder()
.role(Role.SYSTEM.getValue())
.content("You are a helpful assistant.")
.build();
Message userMsg = Message.builder()
.role(Role.USER.getValue())
.content("Java udp代码案例?")
.build();
GenerationParam param = GenerationParam.builder()
.model("qwen-turbo")
.apiKey("sk-f6a3b3**************") // 替换自己的
.messages(Arrays.asList(systemMsg, userMsg))
.resultFormat(GenerationParam.ResultFormat.MESSAGE)
.temperature(0.8f)
.incrementalOutput(true)
.build();
// String content = gen.call(param).getOutput().getChoices().get(0).getMessage().getContent();
gen.streamCall(param).blockingSubscribe(generationResult -> {
System.out.println(generationResult.getOutput().getText());
});
}
}
这里获取模型推理结果有两种方式:call一次性获取全部结果与sreamCall流式获取数据。后者是比较常用的,因为模型推理往往需要数秒设置更长时间,推理出一点数据就先给用户展示,避免干等。这里持续往前端推送数据比不是websocket,而是利用了HTTP自带的一种更轻量的特性eventStream,用法比较类似websocket。如上代码只需要在streamCall回调函数中改为使用httpserverlet response对象将数据发送到前端即可(注意添加一个响应头Content-Type: text/event-stream;charset=UTF-8
)
`1
springboot web支持了http这种特性,往前端send数据调用SseEmitter 的方法即可,它会帮我们加上必要的响应头,如上代码streamCall回调函数中改为SseEmitter的send方法即可。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
@RestController
public class SseController {
private static final Map<Long, SseEmitter> emitters = new ConcurrentHashMap<>();
private static final AtomicInteger eventId = new AtomicInteger(0);
@GetMapping("/sse/events")
public SseEmitter getEvents() {
SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
Long id = System.currentTimeMillis();
emitters.put(id, emitter);
// 发送初始事件
sendToClient(emitter, "Welcome to the SSE example!");
// 设置超时处理
emitter.onTimeout(() -> emitters.remove(id));
// 设置错误处理
emitter.onCompletion(() -> emitters.remove(id));
return emitter;
}
public void sendToClient(SseEmitter emitter, String message) {
try {
emitter.send(SseEmitter.event()
.id(String.valueOf(eventId.incrementAndGet()))
.name("sse")
.data(message));
} catch (Exception e) {
emitters.values().removeIf(ee -> ee.equals(emitter));
}
}
}
前端处理示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SSE Example</title>
</head>
<body>
<h1>Server-Sent Events Demo</h1>
<ul id="events-list">
</ul>
<script>
// 创建EventSource实例
const source = new EventSource('/sse/events');
// 当接收到新的事件时
source.onmessage = function(event) {
// 解析接收到的数据
const data = JSON.parse(event.data);
// 在页面上显示数据
displayEvent(data);
};
// 当发生错误时
source.onerror = function(event) {
console.error('Error occurred:', event);
// 如果连接丢失,可以尝试重新连接
// source.close(); // 关闭连接
};
// 显示事件数据
function displayEvent(data) {
const list = document.getElementById('events-list');
const item = document.createElement('li');
item.textContent = data.message;
list.appendChild(item);
}
</script>
</body>
</html>
三、百炼平台其它
百炼平台文档非常齐全,这里主要再总结一下
//TODO