山东大学创新实训 与模型对接、流式传输

我们的模型终于训好了,现在可以与模型对接了。

由于模型是在云服务器上跑的,因此模型的地址与后端的地址不同,需要特殊处理。

模型访问方式

对于模型的地址与后端的地址不同的问题,有两种解决方案:

  • 中转:前端调用后端,后端再将请求转发至模型,后端收到模型的回复后传回给前端
  • 直连:后端提供查询接口,返回模型的地址,前端直接调用这个地址

中转

后端使用requests重新发送请求给模型,再转发回前端:

@app.route('/chat',methods=['POST'])
def chat():
    response=requests.request(method='POST',url='http://127.0.0.1:8800/v1/chat/completions',json=request.get_json())
    return Response(response.content, content_type=response.headers['Content-Type'], status=response.status_code)

这个方法优势是前端不用区分后端与模型,直接调用后端方法即可,并且后端还可以对数据进行处理。

但是如果使用流式传输,这种方法会将模型的输出合并后再返回,造成了不必要的延迟,并且打破了数据的边界,打乱了返回数据的格式。

直连

后端提供一个方法查询模型地址:

@app.route('/chaturl',methods=['GET'])
def chaturl():
    return jsonify({"url":"http://127.0.0.1:8800/v1/chat/completions","max_token":1024})

这种方法其实优势不大,并且如果前端是Web端,可能会出现跨域问题;但是它能直接获取到模型输出的数据,不经后端中转,性能上好一些。

最终使用了直连方式。

模型调用接口

我们使用了ChatGLM模型,调用对话接口时使用POST方法,传入如下json

{
    "model": "chatglm3-6b",
    "messages": [
    {
    "role": "system",
    "content": "You are ChatGLM3, a large language model trained by Zhipu.AI. Follow the user’s instructions carefully. Respond using markdown."
    },
    {
    "role": "user",
    "content": "山东有什么地方推荐"
    }
    ],
    "stream": true,
    "max_tokens": 1024,
    "temperature": 0.8,
    "top_p": 0.8
}

其中最重要的是messages参数,这是一个列表,里面依次列出了历史对话,因为模型不保存历史对话,所以需要在传参时作为上下文传入。每一条对话有role和content两个属性,role表示这句话是谁说的,content是说的内容。messages的最后一项一定是用户说的,表示用户提问。当收到模型的回答后,需要将其附加到末尾。

stream参数控制是否使用流式传输。

流式传输

启用流式传输后,模型会一词一句地返回,为了流式接收,在flutter中需要在发送请求时添加header,options: Options(responseType: ResponseType.stream);启用流式传输后,可以通过response.data.stream流式获取内容,具体代码如下:

流式调用:

@override
  Future<Stream<Uint8List>> stream(String msg) async{
    message.add(_Message("user", msg));
    log(jsonEncode(message));
    var response=await dio.post(
        "",
        data:{
          "messages":message,
          "model": "chatglm3-6b",
          "stream": true,
          "max_tokens": max_token,
          "temperature": 0.8,
          "top_p": 0.8
        },
        options: Options(responseType: ResponseType.stream)
    );
    Stream<Uint8List> stream=response.data.stream;
    return response.data.stream;
  }

字节流使用:

                            await for(final msg in stream){
                              final res=utf8.decode(msg.toList());
                              // print("${res.substring(6)} ${res.substring(6).length}");
                              if(!res.substring(6).startsWith("[")){
                                String mstr=jsonDecode(res.substring(6))["choices"][0]["delta"]["content"];
                                if(str==""&&mstr.startsWith("\n "))mstr=mstr.substring(2);
                                str="$str$mstr";
                                if(LLMAPIBack.tag.contains(mstr)&&!c.api.visitTag.contains(mstr)){
                                  chater.taged(mstr);
                                  c.api.visitTag.add(mstr);
                                }else chater.gen(mstr);
                              }
                            }

最终结果

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值