用程序读历史,以数据讲故事。
大模型的调用费虽然是给免了,可毕竟咱们还没进入共产主义,对免费的东西没法过于苛求。像是百度千帆的ERNIE-Speed-128K模型,只支持同步接口调用,一次调用大概要10多秒才能返回:
百度千帆 ▼
再看一下腾讯混元、只支持5个并发的请求:
腾讯混元 ▼
免费模型第一个不省心的地方:给的资源少,体现到使用上就是响应慢、并且是越多人用越慢。
当然,为提高并发数可以把免费大模型们给团一团,不同模型轮着用,这就带来了另一个问题,每家有每家的接口风格,比如百度家是直接HTTP接口、腾讯家给封装了个SDK、都是同步调用,讯飞这边则是来了个WebSocket异步返回:
讯飞星火 ▼
所以既然选择了免费、总归是省心不了的,要达到可用状态还是需要做一点点的二次封装。
第一步,统一接口:
百度、腾讯是同步接口、讯飞是异步接口,从技术上来说既可以选择把他们都封装为同步的、也可以都是异步的。考虑到这些免费模型可用计算资源有限、响应都比较慢,统一封装为异步接口会是一个比较合理的选择,这样可以避免在多人并发请求的情况下挂住大量服务器资源。
至于说怎么把同步接口封装为异步接口,可以参考一下WebSocket的调用代码:
WebSocketClient webSocketClient = new WebSocketClient(uri) {
public void onOpen(ServerHandshake serverHandshake) {
...
}
public void onMessage(String s) {
...
}
public void onClose(int i, String s, boolean b) {
...
}
public void onError(Exception e) {
...
}
};
webSocketClient.connect();
像上面这些onXXX的方法就是对应WebSocket连接建立、有数据、
或是断开等情况下程序的处理逻辑。简单来说,异步就像是去吃饭拿号(webSocketClient.connect()),拿完号后可以该干嘛、干嘛去,等着叫号(onMessage)就行了。
所以这里就要统一这个拿号、叫号的过程,比如定义下面这样的一个回调接口:
public interface AiCallback {
public void onAnswered(String answer);
}
原本大模型的调用还是该咋写咋写,只是在有结果了后通过该接口来通知回调用者:
异步回调 ▼
第二步,整合大模型
接口统一后,这样甭管使用哪个大模型,或者后续再添加新的大模型就都简单了,每次只需要随机选择一个来提问就好了:
随机选择大模型 ▼
第三步,完成整合
前面的第一步其实只是实现了叫号逻辑,并没有取号的部分,这里可以通过Redis的List结构实现一个轻量级的异步队列:
完整流程 ▼
先看向右侧、当用户发出提问的时候把提问的问题从右侧塞入List中(rpush),然后马上返回一个号码给到用户,说你可以用这个号来问,是不是轮到你了
再看List的左侧,有一个进程(ExecutorService)一直等着接单(blpop),接到后就传给处理的进程(ExecutorService)进行大模型提问
提问的处理进程对大模型来个抽卡,抽中了谁就向谁提问,拿到结果后存储到Redis里等待用户来查询
最后用户在某一次询问后终于得到了提问的结果
来看一下最终的集成效果(先忽略这粗糙的界面):
也算是AI原生应用吧 ▼