2
头图
大模型场景实战培训,提示词效果调优,大模型应用定制开发,点击咨询

前言

大模型推理是一个消耗大量计算资源,耗时较长的一个过程,在实际业务中让大模型写一篇小作文,经常要十几秒。为了降低终端用户体感等待的时长,大家都会开启流式,让大模型生成一部分内容后,就展示出来,从而提升客户的体验。

想必大家也体验过各种各样的大模型对话应用,界面中大模型生成的内容都是一个字一个字往外蹦,效果就像"打字机"一样。这篇文章就是教会大家,如何快速实现这样一个"打字机"效果,不光可以体验实际效果,还附送前后端示例代码。

体验效果流程

第一步:点击流式示例入口,等待自动加载应用鉴权信息

第二步:默认填充了提示词(可自行选择是否编辑),点击大模型输出效果展示

Image 1: a screen shot of a chinese website

架构解析

Image 2: a screen shot of a chinese website

出于安全考虑,百度智能云的鉴权接口不支持跨域,所以必须通过后端获取鉴权用的access\_token。

前端把prompt传给服务端后,服务端获取鉴权,再请求大模型接口(携带开启流式参数)。服务端收到大模型一段一段返回的结果后,经过简单格式化处理后再一段一段的返回给前端,最终前端将结果放入队列,按指定的速度往外吐,实现"打字机"的效果。

前端:

html+javascript,前端基于服务端返回的流式数据,模拟打字机效果。
示例代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Sample</title>
</head>
<body>
  <label for="textInput">Prompt:</label>
  <input type="textarea" id="textInput" placeholder="您有什么问题">
  <button onclick="run_prompt()">执行prompt</button>
  <p><textarea id="answer" rows="10" cols="50" readonly></textarea></p>
<script>
  current_text = document.getElementById('answer');
  text = "";
  char_index = 0
  function run_prompt() {
    var inputValue = document.getElementById('textInput').value;
    document.getElementById('answer').value = "";
    // 调用服务端的流式接口, 修改为自己的服务器地址和端口号
    fetch('http://<server address>:8000/eb_stream', {
      method: 'post',
      headers: {'Content-Type': 'text/plain'},
      body: JSON.stringify({'prompt': inputValue})
    })
    .then(response => {
      return response.body;
    })
    .then(body => {
      const reader = body.getReader();
      const decoder = new TextDecoder();
      function read() {
        return reader.read().then(({ done, value }) => {
          if (done) { // 读取完成
            return;
          }
          data = decoder.decode(value, { stream: true });
          text += JSON.parse(data).result;
          type();  // 打字机效果输出
          return read();
        });
      }
      return read();
    })
    .catch(error => {
      console.error('发生错误:', error);
    });
  }

  function type() {
    let enableCursor = true;  // 启用光标效果
    if (char_index < text.length) {
      let txt = document.getElementById('answer').value;
      let cursor = enableCursor ? "|" : "";
      if (enableCursor && txt.endsWith("|")) {
        txt = txt.slice(0, -1);
      }
      document.getElementById('answer').value = txt + text.charAt(char_index) + cursor;
      char_index++;
      setTimeout(type, 1000/5);  // 打字机速度控制, 每秒5个字
    }
  }
</script>
</body>
</html>

服务端:

支持多种语言(python,java,go,C#,php,nodejs)
查看各语言示例代码
Python示例代码:

# pip安装 fastapi 和 uvicorn
# 执行 "uvicorn main:app --host=0.0.0.0 --port=8000 --reload" 启动服务端

import json
import requests
import time

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import StreamingResponse


app = FastAPI()

# 允许前端跨域调用
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

def get_access_token(ak, sk):
    auth_url = "https://aip.baidubce.com/oauth/2.0/token"
    resp = requests.get(auth_url, params={"grant_type": "client_credentials", "client_id": ak, 'client_secret': sk})
    return resp.json().get("access_token")

def get_stream_response(prompt):
    ak = "z0GH4u7PR3V26xdogoLLc4Oa"
    sk = "CbbEStBiotI5crX956yXO4kUGRUeWHIT"
    source = "&sourceVer=0.0.1&source=app_center&appName=streamDemo"
    # 大模型接口URL
    base_url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant"
    url = base_url + "?access_token=" + get_access_token(ak, sk) + source
    data = {
        "messages": [{"role": "user", "content": prompt}],
        "stream": True
    }
    payload = json.dumps(data)
    headers = {'Content-Type': 'application/json'}
    return requests.post(url, headers=headers, data=payload, stream=True)

def gen_stream(prompt):
    response = get_stream_response(prompt)
    for chunk in response.iter_lines():
        chunk = chunk.decode("utf8")
        if chunk[:5] == "data:":
            chunk = chunk[5:]
        yield chunk
        time.sleep(0.01)

@app.post("/eb_stream")    # 前端调用的path
async def eb_stream(request: Request):
    body = await request.json()
    prompt = body.get("prompt")
    return StreamingResponse(gen_stream(prompt))

各环境介绍

  • python:基于fastapi发布路由,使用uvicorn创建HTTP服务
  • java:maven管理依赖,使用HttpServer创建HTTP服务
  • C#:利用HttpListener创建HTTP服务

Image 3: a screen shot of a chinese website with chinese text


AI小匠
4 声望0 粉丝

专业大模型服务私信联系