学习大模型应用开发(第二章)

官方地址

如何将官方大模型封装成本地api

由于讯飞星火认知大模型需要使用 websocket 连接来调用,而其他大模型直接使用 request 调用,例如百度文心、ChatGPT 等存在显著差异。不同调用方式的模型,不能统一调用,这个时候就需要在程序代码中增加很多复杂的业务逻辑、调用细节,增加了程序开发的工作量,也增加了出现 Bug 的概率。

可以使用 FastAPI,对不同的大模型 API 再进行一层封装,将其映射到本地接口上,从而通过统一的方式来调用本地接口实现不同大模型的调用。通过这样的手段,可以极大程度减少对于模型调用的工作量和复杂度。

在这里,以讯飞星火大模型 API 为例,讲解如何将通用大模型 API 封装成本地 API,从而实现同一方式的 API 调用。

要实现本地 API 封装,首先需要安装 fastapi 第三方库,pip安装即可 接下来导入第三方库,并创建一个 API 对象:app = FastAPI() # 创建 api 对象, 本地 API 一般通过 POST 方式进行访问,即参数会附加在 POST 请求中,需要定义一个数据模型来接收 POST 请求中的数据:python使用class

python 复制代码
# 定义一个数据模型,用于接收POST请求中的数据 
class Item(BaseModel): 
    prompt : str # 用户 
    prompt temperature : float # 温度系数 
    max_tokens : int # token 上限 
    if_list : 
        bool = False # 是否多轮对话
  • prompt:即用户输入的 Prompt。我们默认为单轮对话调用,因此 prompt 默认为一句输入;
  • 如果将 if_list 设置为 True,那么就是多轮对话调用,
  • prompt 应为一个已构造好(即有标准 role、content 格式)的列表字符串 ·
  • temperature:温度系数
  • max_tokens:回答的最大 token 上限
  • if_list:是否多轮对话,默认为 False

创建一个post请求的api站点

  1. @app.post("/spark/")
  2. async def get_spark_response(item: Item): # 实现星火大模型调用的 API 端点
  3. response = get_spark(item) return responseST 请求的 API 端点:

定义一个函数来实现对星火 API 的调用:

ini 复制代码
import SparkApiSelf

# 首先定义一个构造参数函数
def getText(role, content, text = []):
    # role 是指定角色,content 是 prompt 内容
    jsoncon = {}
    jsoncon["role"] = role
    jsoncon["content"] = content
    text.append(jsoncon)
    return text

def get_spark(item):
    # 配置 spark 秘钥
    #以下密钥信息从控制台获取
    appid = "9f922c84"     #填写控制台中获取的 APPID 信息
    api_secret = "YjU0ODk4MWQ4NTgyNDU5MzNiNWQzZmZm"   #填写控制台中获取的 APISecret 信息
    api_key ="5d4e6e41f6453936ccc34dd524904324"    #填写控制台中获取的 APIKey 信息
    domain = "generalv2"    # v2.0版本
    Spark_url = "ws://spark-api.xf-yun.com/v2.1/chat"  # v2.0环境的地址

    # 构造请求参数
    if item.if_list:
        prompt = item.prompt
    else:
        prompt = getText("user", item.prompt)

    response = SparkApiSelf.main(appid,api_key,api_secret,Spark_url,domain,prompt, item.temperature, item.max_tokens)
    return response

代码基本都是官方的,应该是没有大问题,有啥的话可以私聊哦,作者最近也在跟着官方团队一起学习。

注意,由于星火给出的示例 SparkApi 中将 temperature、max_tokens 都进行了封装,我们需要对示例代码进行改写,暴露出这两个参数接口,我们实现了一个新的文件 SparkApiSelf,对其中的改动如下:

首先,我们对参数类中新增了 temperature、max_tokens 两个属性:

ini 复制代码
class Ws_Param(object):
    # 初始化
    def __init__(self, APPID, APIKey, APISecret, Spark_url):
        self.APPID = APPID
        self.APIKey = APIKey
        self.APISecret = APISecret
        self.host = urlparse(Spark_url).netloc
        self.path = urlparse(Spark_url).path
        self.Spark_url = Spark_url
        # 自定义
        self.temperature = 0
        self.max_tokens = 2048

在生成请求参数的函数中,增加这两个参数并在构造请求数据时加入参数:

python 复制代码
def gen_params(appid, domain,question, temperature, max_tokens):
    """
    通过appid和用户的提问来生成请参数
    """
    data = {
        "header": {
            "app_id": appid,
            "uid": "1234"
        },
        "parameter": {
            "chat": {
                "domain": domain,
                "random_threshold": 0.5,
                "max_tokens": max_tokens,
                "temperature" : temperature,
                "auditing": "default"
            }
        },
        "payload": {
            "message": {
                "text": question
            }
        }
    }
    return data

run 函数中调用生成参数时加入这两个参数:

scss 复制代码
def run(ws, *args):
    data = json.dumps(gen_params(appid=ws.appid, domain= ws.domain,question=ws.question, temperature = ws.temperature, max_tokens = ws.max_tokens))
    ws.send(data)

最后,由于 WebSocket 是直接打印到终端,但我们需要将最后的结果返回给用户,我们需要修改 main 函数,使用一个队列来装填星火流式输出产生的结果,并最终集成返回给用户:

ini 复制代码
def main(appid, api_key, api_secret, Spark_url,domain, question, temperature, max_tokens):
    # print("星火:")
    output_queue = queue.Queue()
    def on_message(ws, message):
        data = json.loads(message)
        code = data['header']['code']
        if code != 0:
            print(f'请求错误: {code}, {data}')
            ws.close()
        else:
            choices = data["payload"]["choices"]
            status = choices["status"]
            content = choices["text"][0]["content"]
            # print(content, end='')
            # 将输出值放入队列
            output_queue.put(content)
            if status == 2:
                ws.close()

    wsParam = Ws_Param(appid, api_key, api_secret, Spark_url)
    websocket.enableTrace(False)
    wsUrl = wsParam.create_url()
    ws = websocket.WebSocketApp(wsUrl, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open)
    ws.appid = appid
    ws.question = question
    ws.domain = domain
    ws.temperature = temperature
    ws.max_tokens = max_tokens
    ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
    return ''.join([output_queue.get() for _ in range(output_queue.qsize())])
相关推荐
颜淡慕潇37 分钟前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
尘浮生2 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea
尚学教辅学习资料2 小时前
基于SpringBoot的医药管理系统+LW示例参考
java·spring boot·后端·java毕业设计·医药管理
monkey_meng3 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马3 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng3 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
paopaokaka_luck7 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
码农小旋风9 小时前
详解K8S--声明式API
后端
Peter_chq9 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml49 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍