最近在学习大模型的时候,有时候会遇到要写API的时候,这个时候我就遇见了FastAPI,我发现这个是一个很好的库,可以很方便的让我们构建一个属于自己的API,所以今天我也写一下这个入门教程和大家一起分享一下,同时也让我们解密一下,OpenAI和一些公司的API,可能是怎么写和怎么做的。
FastAPI介绍 FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.8+ 并基于标准的 Python 类型提示。
文档 : https://fastapi.tiangolo.com
源码 : https://github.com/tiangolo/fastapi
关键特性:
快速 :可与 NodeJS 和 Go 并肩的极高性能(归功于 Starlette 和 Pydantic)。最快的 Python web 框架之一 。
高效编码 :提高功能开发速度约 200% 至 300%。*
更少 bug :减少约 40% 的人为(开发者)导致错误。*
智能 :极佳的编辑器支持。处处皆可自动补全,减少调试时间。
简单 :设计的易于使用和学习,阅读文档的时间更短。
简短 :使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。
健壮 :生产可用级别的代码。还有自动生成的交互式文档。
标准化 :基于(并完全兼容)API 的相关开放标准:OpenAPI (以前被称为 Swagger) 和 JSON Schema 。
安装及依赖 Python 3.8 及更高版本
FastAPI 站在以下巨人的肩膀之上:
我们有可能还会需要一个 ASGI 服务器,可以使用Uvicorn
示例 创建 创建一个 main.py 文件并写入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from typing import Union from fastapi import FastAPIapp = FastAPI() @app.get("/" ) def read_root (): return {"Hello" : "World" } @app.get("/items/{item_id}" ) def read_item (item_id: int , q: Union [str , None ] = None ): return {"item_id" : item_id, "q" : q}
如果我们需要加入异步编程的话,我们就需要改一下代码,加入async/await和async def
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from typing import Union from fastapi import FastAPIapp = FastAPI() @app.get("/" ) async def read_root (): return {"Hello" : "World" } @app.get("/items/{item_id}" ) async def read_item (item_id: int , q: Union [str , None ] = None ): return {"item_id" : item_id, "q" : q}
如果对于异步编程有点兴趣的话,可以看看这个讲解,我觉得还是很不错的,这也加强了代码的并发能力。
运行 通过以下命令进行运行服务器
1 2 3 4 5 6 7 $ uvicorn main:app --reload INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Started reloader process [28720] INFO: Started server process [28722] INFO: Waiting for application startup. INFO: Application startup complete.
uvicorn main:app 命令含义如下:
main:main.py 文件(一个 Python “模块”)。
app:在 main.py 文件中通过 app = FastAPI() 创建的对象。
—reload:让服务器在更新代码后重新启动。仅在开发时使用该选项。
这里面着重提一下reolab参数 ,这个相当于我们在开发是对代码进行修改的同时,服务器也在变化,这样就方便我们进行开发和学习,但是如果开发完毕以后,我们可以去掉—reload ,防止不小心动到代码改变了api的访问
检查 使用浏览器访问 http://127.0.0.1:8000/items/5?q=somequery。
你将会看到如下 JSON 响应:
1 {"item_id": 5, "q": "somequery"}
你已经创建了一个具有以下功能的 API:
通过 路径 / 和 /items/{item_id} 接受 HTTP 请求。
以上 路径 都接受 GET 操作 (也被称为 HTTP 方法 )。
/items/{item_id} 路径 有一个 路径参数 item_id 并且应该为 int 类型。
/items/{item_id} 路径 有一个可选的 str 类型的 查询参数 q。
API文档 交互式 API 文档 现在访问 http://127.0.0.1:8000/docs。
你会看到自动生成的交互式 API 文档(由 Swagger UI 生成):
可选的 API 文档 访问 http://127.0.0.1:8000/redoc。
你会看到另一个自动生成的文档(由 ReDoc 生成):
大模型API实战 比如我现在想使用一个大模型,比如就是阿里的通义千问的大模型,我希望能写一个api接口进行对其调用,有点类似与OpenAI一样写一个接口,这样就方便我们进行去调用,而不用每次跑一堆代码。
Qwen模型下载与使用 比如我们可以从Qwen中获取对应的模型,https://huggingface.co/Qwen/Qwen-7B-Chat
从里面我们可以看到多轮对话的快速使用代码,这对我们写API有很大的帮助,我们从中可以看到主要的流程,实际上还是蛮简单的,就是导入模型后,进行传入参数,参数一般有三个,一个是一开始定义的分词器tokenizer ,另外两个就比较重要,分别是问题和历史记录,所以我们希望得到的api应该是有这两个输入的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 from transformers import AutoModelForCausalLM, AutoTokenizerfrom transformers.generation import GenerationConfigtokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B-Chat" , trust_remote_code=True ) model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B-Chat" , device_map="auto" , trust_remote_code=True ).eval () response, history = model.chat(tokenizer, "你好" , history=None ) print (response)response, history = model.chat(tokenizer, "给我讲一个年轻人奋斗创业最终取得成功的故事。" , history=history) print (response)response, history = model.chat(tokenizer, "给这个故事起一个标题" , history=history) print (response)
编写FastAPI代码 所以弄清楚了原理以后,我们就可以开始利用FastAPI写以下的代码了,为了更好的使用api,除了prompt和history两个参数之外,还加入了max_lenth和temperature等参数,这些参数实际上都是model.chat里面进行使用的,这样更好的去设置和学习。等到返回结果以后,就会返回时间和成功的标志,这样我们就获取了结果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 from fastapi import FastAPI, Requestfrom transformers import AutoTokenizer, AutoModelForCausalLM, GenerationConfigimport uvicornimport jsonimport datetimeimport torchDEVICE = "cuda" DEVICE_ID = "0" CUDA_DEVICE = f"{DEVICE} :{DEVICE_ID} " if DEVICE_ID else DEVICE def torch_gc (): if torch.cuda.is_available(): with torch.cuda.device(CUDA_DEVICE): torch.cuda.empty_cache() torch.cuda.ipc_collect() app = FastAPI() @app.post("/" ) async def create_item (request: Request ): global model, tokenizer json_post_raw = await request.json() json_post = json.dumps(json_post_raw) json_post_list = json.loads(json_post) prompt = json_post_list.get('prompt' ) history = json_post_list.get('history' ) max_length = json_post_list.get('max_length' ) top_p = json_post_list.get('top_p' ) temperature = json_post_list.get('temperature' ) response, history = model.chat( tokenizer, prompt, history=history, max_length=max_length if max_length else 2048 , top_p=top_p if top_p else 0.7 , temperature=temperature if temperature else 0.95 ) now = datetime.datetime.now() time = now.strftime("%Y-%m-%d %H:%M:%S" ) answer = { "response" : response, "history" : history, "status" : 200 , "time" : time } log = "[" + time + "] " + '", prompt:"' + prompt + '", response:"' + repr (response) + '"' print (log) torch_gc() return answer if __name__ == '__main__' : tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B-Chat" , trust_remote_code=True ) model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B-Chat" , device_map="auto" , trust_remote_code=True ).eval () model.generation_config = GenerationConfig.from_pretrained("Qwen/Qwen-7B-Chat" , trust_remote_code=True ) model.eval () uvicorn.run(app, host='0.0.0.0' , port=6006 , workers=1 )
运行及使用API 我们运行方式很简单,直接在服务器终端运行
加载完毕后出现如下信息说明成功。
默认部署在 6006 端口,通过 POST 方法进行调用,可以使用curl调用,如下所示:
1 2 3 curl -X POST "http://127.0.0.1:6006" \ -H 'Content-Type: application/json' \ -d '{"prompt": "你好", "history": []}'
也可以使用python中的requests库进行调用,如下所示:
1 2 3 4 5 6 7 8 9 10 11 import requests import json def get_completion(prompt): headers = {'Content-Type': 'application/json'} data = {"prompt": prompt, "history": []} response = requests.post(url='http://127.0.0.1:6006', headers=headers, data=json.dumps(data)) return response.json()['response'] if __name__ == '__main__': print(get_completion('你好'))
得到的返回值如下所示:
1 2 3 4 5 6 { "response":"你好!很高兴为你服务。有什么我可以帮助你的吗?", "history":[["你好","你好!很高兴为你服务。有什么我可以帮助你的吗?"]], "status":200, "time":"2023-11-26 1:14:20" }
总结 我觉得在有时候我们要实现一个API的时候,我们可以用FastAPI快速实现,并且得到一个不错的结果,这也是我学习的初衷,有时候一些服务器可能可以当做API来使用来调用,其实也方便去使用,也可以部署后成为商业产品,类似于OpenAI一样。
最后感谢一下FastAPI的文档,让我学习到很多,在里面还有更详细的使用方案,大家也可以去学习一下,然后再感谢一下datawhale的self-llm项目,也是在里面我学习到了使用FastAPI,大家如果对大模型感兴趣也可以关注一下。
self-llm项目:https://github.com/datawhalechina/self-llm
FastAPI学习文档:https://fastapi.tiangolo.com/zh/learn/